Ver como Markdown

Esquema de checkpoint

Un archivo .pt de LibreYOLO es un diccionario plano guardado con torch.save. La clave model contiene el state dict; el resto de claves de primer nivel son metadatos que identifican el checkpoint sin analizar el nombre del archivo ni inspeccionar el state dict.

Esquema v1.0

Todo checkpoint .pt oficial de LibreYOLO contiene:

python
{
    "model": state_dict,
    "schema_version": "1.0",
    "libreyolo_version": "0.x.y",
    "model_family": "yolo9",
    "size": "t",
    "task": "detect",
    "nc": 80,
    "names": {0: "cat", 1: "dog"},
    "imgsz": 640,
}
ClaveTipoSignificado
modelstate dictLos pesos del modelo
schema_versionstrVersión del contrato de metadatos; la v1.0 usa la cadena "1.0"
libreyolo_versionstrLa versión que generó el checkpoint
model_familystrUna familia registrada, como yolo9, rfdetr, dfine, ec
sizestrVariante dentro de la familia, como t, s, r18, atto
taskstrNombre canónico de la tarea
ncintNúmero de clases, positivo
namesdictdict[int, str] con claves en 0..nc-1
imgszintResolución de entrada cuadrada y positiva, o el escalar heredado para un contrato rectangular

task es uno de detect, segment, semantic, panoptic, pose, classify, gaze, obb, point, depth, edge, normal, restore, matte, ocr, embed o mesh.

Los checkpoints oficiales escriben todas las claves de names. Los lectores pueden rellenar las claves ausentes con etiquetas class_i para mapeos dispersos heredados, pero las claves fuera de rango no son válidas.

Los checkpoints rectangulares mantienen un imgsz escalar para los lectores antiguos, con el valor max(imgsz_h, imgsz_w), y además escriben imgsz_h e imgsz_w con las dimensiones reales. Un lector que entienda los campos rectangulares debe darles preferencia sobre el escalar. Las familias con un contrato rectangular fijo, como la pose de HRNet, rechazan los tamaños de runtime incompatibles.

El esquema es plano de forma deliberada, y model es un state dict también de forma deliberada.

Leer los metadatos de un checkpoint
from libreyolo import LibreYOLOfrom libreyolo.utils.serialization import unwrap_libreyolo_checkpointimport torch # Descarga un checkpoint y vuelve a guardarlo para que exista una ruta local.LibreYOLO("LibreYOLO9t.pt").save("roundtrip.pt") loaded = torch.load("roundtrip.pt", map_location="cpu", weights_only=False)state_dict, metadata = unwrap_libreyolo_checkpoint(loaded) print(metadata["schema_version"], metadata["model_family"])print(metadata["size"], metadata["task"], metadata["nc"], metadata["imgsz"])print(len(state_dict), "tensors")

Añadidos de pose

La pose suele ser de una sola clase, nc: 1 con person, pero la cabeza de pose de YOLO-NAS también admite pose multiclase con un único esqueleto de keypoints compartido, en cuyo caso nc y names describen las clases igual que en detección. Las exportaciones de pose para runtime emiten scores con forma [batch, anchors, nc].

ClaveSignificado
num_keypointsNúmero positivo de keypoints que usa la cabeza de pose
keypoint_dim2 para etiquetas x,y o 3 para etiquetas x,y,visibility; las salidas del modelo siempre exponen x,y,visibility
oks_sigmasSigmas OKS opcionales por keypoint; cuando no están, se usa el valor por defecto de la tarea para num_keypoints
num_keypoints_per_classRecuentos opcionales de keypoints por clase para cabezas de estilo GroupPose cuyo tensor de keypoints está rellenado por clase; 0 para las clases sin keypoints

Añadidos de mesh

Los checkpoints de mesh usan task: "mesh", nc: 1 y names: {0: "person"}. La disposición de los parámetros varía entre modelos de cuerpo, así que las dimensiones se registran en lugar de darse por supuestas.

ClaveSignificado
body_modelLa parametrización, como mhr; obligatoria, y se usa para interpretar todos los campos siguientes
num_betasNúmero de coeficientes de identidad y forma; 45 en MHR
num_body_poseAnchura del bloque de parámetros de pose corporal; 130 en MHR. Es un vector plano, no un triplete por articulación, porque las articulaciones del rig tienen grados de libertad distintos
num_verticesNúmero de vértices que emite el decodificador; 18439 en MHR
num_jointsNúmero de articulaciones que emite el decodificador; 127 en MHR
rotation_formatCómo se codifican las rotaciones, como euler_zyx en MHR o axis_angle. Nunca se infiere de la forma del tensor, porque un vector de 3 es ambiguo

Marcadores para tareas densas

Varias tareas predicen mapas densos en lugar de clases, así que los campos de tipo clase existen solo por compatibilidad con el esquema.

Tareancnames
depth1{0: "depth"}
edge1{0: "edge"}
restore1{0: "image"}
ocr1{0: "text"}

Las predicciones de edge son mapas densos de probabilidad en float32 dentro de [0, 1].

Los checkpoints de restore pueden añadir degradation, una etiqueta corta de degradación como deblur, denoise o super-resolution; dataset, una etiqueta de procedencia como GoPro o SIDD; y scale, un factor entero positivo de ampliación de la salida respecto a la entrada, por ejemplo 4 para un modelo de superresolución x4. Si falta o vale 1, la imagen restaurada conserva la resolución de entrada. El runtime también deduce la escala a partir de la familia y el tamaño, así que scale es metadato de procedencia y no un requisito en tiempo de carga.

Añadidos de OCR

La familia ppocr distribuye un checkpoint compuesto por cada nivel, cuyo state dict model contiene dos submodelos bajo los espacios de nombres de claves det.* y rec.*.

ClaveSignificado
charsetEl alfabeto CTC completo en orden de índice de salida: el índice 0 es el blank de CTC, después el diccionario de reconocimiento y después el carácter de espacio. Los cargadores deben leerlo del checkpoint, nunca de un archivo aparte
pipelineValores por defecto del pipeline fijados en el momento de la conversión: det_limit_side_len, det_db_thresh, det_db_box_thresh, det_db_unclip_ratio, rec_image_shape. Los argumentos de runtime pueden sobrescribirlos en cada llamada
componentsReservado para etapas opcionales del pipeline como la orientación del documento, el desdoblado y la rotación de las líneas de texto. Vacío en la v1

Metadatos de runtime en la exportación

Los artefactos exportados usan la misma convención de doble escritura rectangular: imgsz_h e imgsz_w se escriben junto al escalar heredado imgsz, y un lector que no entienda los campos rectangulares no debe tratar el escalar en silencio como un contrato cuadrado.

El soporte rectangular en runtime está acotado por familia y por formato. Las exportaciones de la familia YOLO9, HRNet, NAFNet y Real-ESRGAN pueden usar imgsz_h e imgsz_w no cuadrados en los formatos compatibles; las familias o los formatos sin soporte rectangular explícito rechazan esos metadatos en lugar de preprocesar esos artefactos como cuadrados. Las exportaciones de HRNet son cabezas fijas de recorte de persona, con batch uno y en FP32, donde W32 acepta 256x192 y W48 acepta 384x288, y el detector de personas no va embebido en el grafo.

Las exportaciones con NMS embebido pueden añadir estas claves planas:

ClaveSignificado
nmsBooleano en forma de cadena; "true" significa que el grafo incluye una salida de postprocesado embebida
nms_confUmbral de confianza fijado en la salida embebida
nms_iouUmbral de IoU fijado en la salida embebida
max_detNúmero máximo de filas de detección post-NMS que emite la salida embebida
nms_raw_outputBooleano en forma de cadena; "true" significa que el grafo expone además una salida cruda auxiliar del detector

En las exportaciones ONNX de detección de YOLO9 con nms=true, la salida 0 (llamada output) es el tensor post-NMS autónomo con los umbrales fijados en la exportación. Cuando nms_raw_output=true, la salida 1 (llamada raw) queda reservada para los backends de LibreYOLO, de modo que puedan aplicar el recorte nativo al lienzo original y la semántica de predict(conf=..., iou=..., max_det=...) en runtime. Los consumidores de terceros deberían usar la primera salida.

Las exportaciones de pose pueden añadir num_keypoints; keypoint_dim, donde las exportaciones crudas de estilo GroupPose pueden usar valores mayores como 8 cuando el tensor incluye campos de precisión o de logits de clase; num_keypoints_per_class como lista codificada en JSON, donde deben conservarse los huecos de clase con cero keypoints porque definen el esquema; y pose_input, donde "person_crop" significa que el grafo consume un recorte ya extraído y no contiene detector. Las exportaciones de HRNet para runtime exigen ese valor.

Las exportaciones de clasificación pueden añadir crop_pct, un ratio float de recorte central cuyo objetivo de redimensionado previo al recorte es round(imgsz / crop_pct) y que vale 0.875 por defecto cuando no está, e interpolation, "bilinear" o "bicubic", con "bilinear" por defecto.

Las exportaciones de ExecuTorch escriben los metadatos planos en un sidecar <program>.pte.json obligatorio. El contrato v1 es CPU, FP32, batch 1 y un lienzo de entrada fijo, y además exige executorch_version, executorch_delegate igual a "xnnpack" y un executorch_delegate_partitions positivo. El cargador rechaza un sidecar que declare otro delegate, formas dinámicas o una precisión distinta de FP32.

Las exportaciones de MNN escriben los metadatos planos en un sidecar <model>.mnn.json obligatorio. El contrato v1 es CPU, FP32, solo detección y una forma de entrada NCHW fija, y además exige mnn_version, mnn_backend igual a "cpu", mnn_input_names y mnn_output_names ordenados y no vacíos, mnn_input_shape como cuatro enteros positivos en el orden [batch, channels, height, width], y mnn_batch igual a mnn_input_shape[0]. El cargador rechaza los metadatos dinámicos, los que no son FP32, los que no son de detección, los de una familia no soportada o los que tienen formas inconsistentes.

Un .pte y un .mnn son artefactos específicos de un backend, no checkpoints de PyTorch.

Checkpoints cuantizados

Un modelo cuantizado añade una clave plana opcional, quant, que contiene un diccionario de manifiesto con schema, recipe, keep_high_precision, execution, la procedencia de la calibración, module_count y state. Los manifiestos FP8 pueden llevar además fp8_tensorwise_weights, la lista exacta de nombres de módulos QuantLinear cuya escala de pesos es por tensor en lugar de por canal de salida. Un cargador que vea quant reconstruye la estructura de módulos cuantizados y la política de escalado antes de load_state_dict.

state distingue las dos formas del artefacto.

"prepared", la opción por defecto, contiene los pesos maestros en FP32 más los buffers de escala _q_* y se puede entrenar. Un lector sin soporte de cuantización puede ignorar la clave quant y cargar los maestros como un modelo en coma flotante.

"finalized" es la forma de despliegue que escribe export(format="pt"). Se eliminan los maestros y cada módulo cuantizado lleva en su lugar los pesos empaquetados:

RecetaTensores empaquetadosDescuantización
int8weight_packed int8 con la forma original de los pesos, _q_w_scale FP32 por canalweight_packed * scale
fp8weight_packed float8_e4m3fn con la forma original, _q_w_scale FP32 con una entrada por canal de salidaweight_packed * scale
w4a16, w4a8weight_packed uint8, dos códigos de 4 bits por byte, primero el nibble bajo, código q + 8; _q_w_gscale FP32 [out, ngroups], grupo de 128 a lo largo de in_featuresEscala por grupos
int2Cuatro códigos de 2 bits por byte, código q + 2, grupo de 64Escala por grupos
nvfp4weight_packed uint8 [out, ceil(in/16)*8], código sign<<3 | E2M1 level; weight_block_scale float8_e4m3fn [out, ceil(in/16)]; _q_w_amax FP32 por tensorblock_scale * amax / (448 * 6)
mxfp4Igual que nvfp4 pero con bloques de 32 elementos, más weight_block_exp int8 [out, ceil(in/32)]2 ** exponent

Los buffers de rango de activación _q_act_lo, _q_act_hi y _q_calibrated se conservan para int8. El manifiesto registra remainder, "fp16" o "fp32", para los tensores no cuantizados. El desempaquetado reproduce la simulación bit a bit, así que la inferencia finalizada coincide exactamente con la inferencia preparada en el dispositivo donde se finalizó. Esta disposición es el contrato estable para exportadores y runtimes externos.

Checkpoints de entrenamiento

Los checkpoints del entrenador usan el mismo núcleo obligatorio de metadatos y pueden añadir campos planos de entrenamiento y de reanudación:

python
{
    "model": state_dict,
    "epoch": 42,
    "optimizer": optimizer_state_dict,
    "config": {},
    "loss": 1.23,
    "best_metric_key": "metrics/mAP50-95",
    "best_metric_value": 0.51,
    "best_epoch": 39,
    "is_ema_weights": True,
    "train_model": raw_state_dict,
    "ema": ema_state_dict,
    "ema_updates": 12345,
}

is_ema_weights declara si el model de primer nivel está suavizado con EMA. Cuando EMA está activado, train_model, ema y ema_updates conservan el estado de reanudación. Los pesos de inferencia que se publican deberían ser ligeros y no incluir el optimizador, la epoch, la config, la loss ni el estado de reanudación de EMA, salvo que se distribuyan a propósito como checkpoints de entrenamiento.

Por compatibilidad entre versiones, los lectores aceptan los alias heredados de mejor métrica best_mAP50_95, best_mAP50, best_metric y best_metric_name.

Snapshots externos

El esquema rige los archivos .pt creados por LibreYOLO. No renombra ni envuelve los snapshots upstream de varios archivos que usan los niveles de modelos independientes.

El tamaño 14b-a7b de LibreMODUS es una excepción explícita: el alias se resuelve a través de LibreVLM(...) hacia un directorio de archivos upstream fijados, y LibreYOLO ni le añade metadatos v1.0 ni lo republica como un .pt.

Pesos heredados y de terceros

Los escritores nuevos validan de forma estricta y deben emitir metadatos v1.0. Cuando los metadatos faltan o están incompletos, los checkpoints antiguos con aspecto de LibreYOLO se cargan por la vía de compatibilidad con un aviso e instrucciones de conversión, y los checkpoints upstream de terceros se dirigen a la conversión automática. Consulta checkpoints upstream.

Helpers

Los helpers del esquema están en libreyolo.utils.serialization:

python
wrap_libreyolo_checkpoint(
    state_dict,
    *,
    model_family,
    size,
    task,
    nc,
    names=None,
    imgsz=None,
    libreyolo_version=None,
    schema_version="1.0",
    **extra_metadata,
) -> dict

validate_checkpoint_metadata(checkpoint, *, strict=False) -> list[str]

unwrap_libreyolo_checkpoint(loaded, *, strict=False) -> tuple[dict, dict]

validate_checkpoint_metadata no muta nada y devuelve la lista de errores; con strict=True lanza CheckpointMetadataError en su lugar. model.save(path) es la forma soportada de escribir un checkpoint conforme.

Refleja docs/checkpoint_schema.md del repositorio libreyolo en la v1.5.0, contrastado con libreyolo/utils/serialization.py y BaseModel.save.