Checkpoint schema

A LibreYOLO .pt file is a flat dictionary saved with torch.save. The model key holds the state dict; the other top-level keys are metadata that identifies the checkpoint without filename parsing or state-dict sniffing.

Schema v1.0

Every official LibreYOLO .pt checkpoint contains:

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,}
KeyTypeMeaning
modelstate dictThe model weights
schema_versionstrMetadata contract version; v1.0 uses the string "1.0"
libreyolo_versionstrThe version that produced the checkpoint
model_familystrA registered family, such as yolo9, rfdetr, dfine, ec
sizestrVariant within the family, such as t, s, r18, atto
taskstrCanonical task name
ncintPositive class count
namesdictdict[int, str] with keys in 0..nc-1
imgszintPositive square input resolution, or the legacy scalar for a rectangular contract

task is one of detect, segment, semantic, panoptic, pose, classify, gaze, obb, point, depth, edge, normal, restore, matte, ocr, embed or mesh.

Official checkpoints write every names key. Readers may pad missing keys with class_i labels for legacy sparse mappings, but out-of-range keys are invalid.

Rectangular checkpoints keep a scalar imgsz for legacy readers, set to max(imgsz_h, imgsz_w), and additionally write imgsz_h and imgsz_w with the real dimensions. A reader that understands the rectangular fields must prefer them over the scalar. Families with a fixed rectangular contract, such as HRNet pose, reject incompatible runtime sizes.

The schema is deliberately flat, and model is deliberately a state dict.

Read the metadata off a checkpoint
from libreyolo import LibreYOLOfrom libreyolo.utils.serialization import unwrap_libreyolo_checkpointimport torch # Download a checkpoint, then re-save it so a local path exists.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")

Pose additions

Pose is usually single-class, nc: 1 with person, but the YOLO-NAS pose head also supports multi-class pose with one shared keypoint skeleton, in which case nc and names describe the classes as in detection. Runtime pose exports emit scores with shape [batch, anchors, nc].

KeyMeaning
num_keypointsPositive keypoint count used by the pose head
keypoint_dim2 for x,y labels or 3 for x,y,visibility labels; model outputs always expose x,y,visibility
oks_sigmasOptional per-keypoint OKS sigmas; the task default for num_keypoints is used when absent
num_keypoints_per_classOptional per-class keypoint counts for GroupPose-style heads whose keypoint tensor is padded by class; 0 for classes without keypoints

Mesh additions

Mesh checkpoints use task: "mesh", nc: 1 and names: {0: "person"}. Parameter layouts differ between body models, so the dimensions are recorded rather than assumed.

KeyMeaning
body_modelThe parameterization, such as mhr; required, and used to interpret every field below
num_betasIdentity and shape coefficient count; 45 for MHR
num_body_poseWidth of the body-pose parameter block; 130 for MHR. A flat vector, not one triplet per joint, because rig joints carry different degrees of freedom
num_verticesVertex count the decoder emits; 18439 for MHR
num_jointsJoint count the decoder emits; 127 for MHR
rotation_formatHow rotations are encoded, such as euler_zyx for MHR or axis_angle. Never inferred from tensor shape, since a 3-vector is ambiguous

Dense-task placeholders

Several tasks predict dense maps rather than classes, so the class-like slots exist only for schema compatibility.

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

Edge predictions are dense float32 probability maps in [0, 1].

Restore checkpoints may add degradation, a short corruption label such as deblur, denoise or super-resolution; dataset, a provenance label such as GoPro or SIDD; and scale, a positive integer output-to-input upscale factor, for example 4 for a x4 super-resolution model. Absent or 1 means the restored image keeps the input resolution. The runtime also derives the scale from the family and size, so scale is provenance metadata rather than a load-time requirement.

OCR additions

The ppocr family ships one composite checkpoint per tier whose model state dict holds two submodels under the det.* and rec.* key namespaces.

KeyMeaning
charsetThe full CTC alphabet in output-index order: index 0 is the CTC blank, then the recognition dictionary, then the space character. Loaders must read it from the checkpoint, never from a side file
pipelinePipeline defaults baked at conversion time: det_limit_side_len, det_db_thresh, det_db_box_thresh, det_db_unclip_ratio, rec_image_shape. Runtime arguments may override them per call
componentsReserved for optional pipeline stages such as document orientation, unwarping and textline rotation. Empty in v1

Export runtime metadata

Exported artifacts use the same rectangular dual-write convention: imgsz_h and imgsz_w are written next to the legacy scalar imgsz, and a reader that does not understand the rectangular fields must not silently treat the scalar as a square contract.

Rectangular runtime support is family-scoped and format-scoped. YOLO9-family, HRNet, NAFNet and Real-ESRGAN exports may use non-square imgsz_h and imgsz_w in supported formats; families or formats without explicit rectangular support reject the metadata rather than preprocessing those artifacts as square. HRNet exports are fixed, batch-one, FP32 person-crop heads, where W32 accepts 256x192 and W48 accepts 384x288, and the person detector is not embedded in the graph.

Embedded-NMS exports may add these flat keys:

KeyMeaning
nmsString boolean; "true" means the graph includes an embedded post-processing output
nms_confConfidence threshold baked into the embedded output
nms_iouIoU threshold baked into the embedded output
max_detMaximum post-NMS detection rows the embedded output emits
nms_raw_outputString boolean; "true" means the graph also exposes an auxiliary raw detector output

For ONNX YOLO9 detection exports with nms=true, output 0 (named output) is the standalone post-NMS tensor at the export-time thresholds. When nms_raw_output=true, output 1 (named raw) is reserved for LibreYOLO backends so they can apply native original-canvas clipping and runtime predict(conf=..., iou=..., max_det=...) semantics. Third-party consumers should use the first output.

Pose exports may add num_keypoints; keypoint_dim, where GroupPose-style raw exports may use larger values such as 8 when the tensor includes precision or class-logit fields; num_keypoints_per_class as a JSON-encoded list, where zero-keypoint class slots must be preserved because they define the schema; and pose_input, where "person_crop" means the graph consumes one already-extracted crop and contains no detector. HRNet runtime exports require that value.

Classification exports may add crop_pct, a float center-crop ratio whose pre-crop resize target is round(imgsz / crop_pct) and which defaults to 0.875 when absent, and interpolation, "bilinear" or "bicubic", defaulting to "bilinear".

ExecuTorch exports write the flat metadata to a required <program>.pte.json sidecar. The v1 contract is CPU, FP32, batch 1 and a fixed input canvas, and it additionally requires executorch_version, executorch_delegate equal to "xnnpack", and a positive executorch_delegate_partitions. The loader rejects a sidecar that claims another delegate, dynamic shapes, or non-FP32 precision.

MNN exports write the flat metadata to a required <model>.mnn.json sidecar. The v1 contract is CPU, FP32, detection-only and a fixed NCHW input shape, and it additionally requires mnn_version, mnn_backend equal to "cpu", ordered non-empty mnn_input_names and mnn_output_names, mnn_input_shape as four positive integers in [batch, channels, height, width] order, and mnn_batch equal to mnn_input_shape[0]. The loader rejects dynamic, non-FP32, non-detection, unsupported-family or inconsistent shape metadata.

A .pte and a .mnn are backend-specific artifacts, not PyTorch checkpoints.

Quantized checkpoints

A quantized model adds one optional flat key, quant, holding a manifest dict with schema, recipe, keep_high_precision, execution, calibration provenance, module_count and state. FP8 manifests may also carry fp8_tensorwise_weights, the exact list of QuantLinear module names whose weight scale is tensorwise rather than per-output-channel. A loader that sees quant rebuilds the quantized module structure and scaling policy before load_state_dict.

state distinguishes the two artifact forms.

"prepared", the default, holds FP32 master weights plus _q_* scale buffers and is trainable. A reader without quantization support may ignore the quant key and load the masters as a float model.

"finalized" is the deployment form written by export(format="pt"). Masters are stripped and each quantized module instead carries packed weights:

RecipePacked tensorsDequantization
int8weight_packed int8 at the original weight shape, _q_w_scale FP32 per channelweight_packed * scale
fp8weight_packed float8_e4m3fn at the original shape, _q_w_scale FP32 one entry per output channelweight_packed * scale
w4a16, w4a8weight_packed uint8, two 4-bit codes per byte, low nibble first, code q + 8; _q_w_gscale FP32 [out, ngroups], group 128 along in_featuresGroup-wise scale
int2Four 2-bit codes per byte, code q + 2, group 64Group-wise scale
nvfp4weight_packed uint8 [out, ceil(in/16)*8], code sign<<3 | E2M1 level; weight_block_scale float8_e4m3fn [out, ceil(in/16)]; _q_w_amax FP32 per tensorblock_scale * amax / (448 * 6)
mxfp4As nvfp4 but 32-element blocks, plus weight_block_exp int8 [out, ceil(in/32)]2 ** exponent

Activation range buffers _q_act_lo, _q_act_hi and _q_calibrated are retained for int8. The manifest records remainder, "fp16" or "fp32", for the non-quantized tensors. Unpacking reproduces the simulation bit for bit, so finalized inference matches prepared inference exactly on the finalizing device. This layout is the stable contract for external exporters and runtimes.

Training checkpoints

Trainer checkpoints use the same required metadata core and may add flat training and resume fields:

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 declares whether the top-level model is EMA-smoothed. When EMA is enabled, train_model, ema and ema_updates preserve resume state. Published inference weights should be lean and should not include optimizer, epoch, config, loss or EMA resume state unless they are intentionally distributed as training checkpoints.

For release compatibility, readers accept the legacy best-metric aliases best_mAP50_95, best_mAP50, best_metric and best_metric_name.

External snapshots

The schema governs LibreYOLO-authored .pt files. It does not rename or wrap multi-file upstream snapshots used by the separate model tiers.

LibreMODUS size 14b-a7b is an explicit exception: the alias resolves through LibreVLM(...) to a directory of pinned upstream files, and LibreYOLO neither adds v1.0 metadata to it nor republishes it as a .pt.

Legacy and foreign weights

New writers validate strictly and must emit v1.0 metadata. When metadata is missing or incomplete, legacy LibreYOLO-looking checkpoints load through the compatibility path with a warning and conversion instructions, and foreign upstream checkpoints route to auto-conversion. See upstream checkpoints.

Helpers

The schema helpers live in 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 is non-mutating and returns the list of errors; with strict=True it raises CheckpointMetadataError instead. model.save(path) is the supported way to write a conforming checkpoint.

Mirrors docs/checkpoint_schema.md in the libreyolo repository at v1.5.0, cross-checked against libreyolo/utils/serialization.py and BaseModel.save.