Image classification
Image classification assigns one label distribution to a whole image and locates nothing inside it. The task key is classify.
Definition
Image classification produces one score per class for the whole image and no coordinates at all. It answers what is in the picture, never where, which is what separates it from object detection.
classify is the canonical task key, and the -cls suffix in a checkpoint
filename selects it. That suffix is required rather than optional on
classification families, so LibreResNet50.pt is not read as a classifier and
only LibreResNet50-cls.pt is.
predict() fills result.probs and leaves boxes empty. .data is the
full score vector, .top1 the index of the highest score and .top1conf its
value, .top5 the five highest indices in descending order and .top5conf
their scores. Indices point into result.names. Slicing a Results object
never truncates probs, because the vector belongs to the image rather than to
one row.
Models
Trainable image classifiers include: ResNet,
ConvNeXt, MobileNetV4,
EfficientNetV2 and
DINOv2. The first four run on the base package and ship
published weights. DINOv2 needs pip install "libreyolo[rfdetr]" and has no
LibreYOLO-hosted checkpoint: it loads the upstream backbone with a randomly
initialized linear head, so it is a fine-tuning starting point rather than a
ready predictor.
Five more predict, validate and export, but their train() raises
NotImplementedError: ViT, Swin,
VGG, AlexNet and
DeiT.
CLIP and SigLIP2 classify without
a fixed label set. They score the image against text prompts, so
set_classes() defines the classes at call time and there is no training step
for a new label set at all. Both also serve the embed task.
ConvNeXt V2 adds supervised classification with CC-BY-NC-4.0 pretrained weights. PE supports zero-shot classification; V-JEPA 2 trains video classification probes.
Predict
Weights download from Hugging Face on first use and are cached locally.
from libreyolo import LibreYOLO, SAMPLE_IMAGE # The -cls suffix in the filename selects the task, so no task# argument is needed.model = LibreYOLO("LibreResNet50-cls.pt")result = model(SAMPLE_IMAGE, save=True) print(result.names[result.probs.top1], float(result.probs.top1conf))print(result.probs.top5)libreyolo predict model=LibreResNet50-cls.pt save=True \ source=https://raw.githubusercontent.com/LibreYOLO/libreyolo/release/libreyolo/assets/parkour.jpgfrom libreyolo import LibreYOLO, SAMPLE_IMAGE result = LibreYOLO("LibreResNet50-cls.pt")(SAMPLE_IMAGE)probs = result.probs # .data is the full (C,) vector; top5/top5conf are ordered views.print(probs.data.shape)for index, score in zip(probs.top5, probs.top5conf): print(result.names[index], float(score))from libreyolo import LibreYOLO, SAMPLE_IMAGE # CLIP scores the image against text prompts, so the label set is# set at call time instead of baked into the checkpoint.model = LibreYOLO("LibreCLIPb32-cls.pt")model.set_classes(["a person jumping", "an empty street", "a parked car"])result = model(SAMPLE_IMAGE) print(model.names[result.probs.top1], float(result.probs.top1conf))conf, iou and max_det have no effect here: there are no candidates to
threshold or suppress, only one distribution. See
prediction for sources, streaming and result handling.
Dataset format
Classification uses a directory tree, not label files and not a YAML. data is
the dataset root.
dataset/ train/ tench/000001.jpg parachute/000002.jpg val/ tench/000101.jpg parachute/000102.jpgtrain/ is required for training and it defines the class-to-index mapping by
sorted folder name, so the first folder alphabetically becomes class 0. val/
is required for validation. A test/ split may be present and the default
train and validate commands do not use it. Any split other than train has to
contain the same class folder names as the expected class set, which is what
makes a mismatch fail loudly rather than score as a wrong prediction. The
accepted image extensions are .jpg, .jpeg, .png, .bmp, .webp, .tif
and .tiff.
data accepts three things: a path to a directory containing a train/ split,
a .zip URL, or one of the known dataset names, imagenette160 and smoke10,
which download and cache on first use.
The canonical loader is libreyolo.data.classify_dataset.
Train
from libreyolo import LibreYOLO # imagenette160 is a known dataset name and downloads on first use.# Pass a directory with a train/ split for your own data.model = LibreYOLO("LibreResNet50-cls.pt")model.train(data="imagenette160", epochs=5)libreyolo train model=LibreResNet50-cls.pt data=imagenette160 epochs=5libreyolo train model=LibreResNet50-cls.pt data=imagenette160 \ epochs=50 device=0,1 batch=-1There is no nc to declare: the class count comes from the folder names under
train/, and the final linear layer is rebuilt to match it while the backbone
transfers unchanged. See training for datasets, augmentation,
multi-GPU and loggers.
ResNet, ConvNeXt, ConvNeXt V2, MobileNetV4, EfficientNetV2 and DINOv2 support cls_pw or class_weights loss weighting. Classification scale controls crop area, and crop_pct controls evaluation cropping. See augmentations.
The resize filter is part of the model. Set model.interpolation to "bilinear", "bicubic", "nearest" or "bilinear_no_antialias" before training: training, val(), predict(), INT8 calibration and export all use it, and save(), best.pt and last.pt record it, so a reload keeps it. Any other name raises ValueError. "bilinear_no_antialias" resizes with plain bilinear and no antialiasing everywhere, RandomResizedCrop included, for models that will run behind a runtime resize without antialiasing. MobileNetV4, ResNet, ConvNeXt, ConvNeXt V2, EfficientNetV2, DeiT, Swin and ViT default to bicubic; AlexNet and VGG to bilinear.
Validate
val() returns a dictionary of metrics/ keys, computed over the val/
split of the dataset root.
from libreyolo import LibreYOLO model = LibreYOLO("LibreResNet50-cls.pt") # A dict of metrics/ keys, plus top1, top5 and confusion_matrix.metrics = model.val(data="imagenette160") print(metrics["metrics/accuracy_top1"])print(metrics["metrics/accuracy_top5"])print(metrics.top1, metrics.top5)libreyolo val model=LibreResNet50-cls.pt data=imagenette160metrics/accuracy_top1 is the share of images whose highest-scoring class is
the true one, and it is the headline number, the one training uses to pick the
best epoch. metrics/accuracy_top5 is the share whose true class appears
anywhere in the five highest-scoring classes, which says less the fewer classes
the dataset has. The dictionary also carries fitness, a copy of the top-1
value.
ImageFolder validation also returns macro metrics/precision, metrics/recall and metrics/f1, averaging over classes present in the validation targets. Unpredicted classes contribute zero precision. Default fitness remains top-1 accuracy. Validation and calibration use the model evaluation transform.
The result is a dict subclass with three attributes: top1 and top5 hold
the two accuracy values, and confusion_matrix counts each image at its top-1
class against its label, indexed matrix[predicted, true]. plots=True writes
it as counts to confusion_matrix.png and as shares of each label to
confusion_matrix_normalized.png. Above 2,000 classes the dense matrix and its
plots are unavailable, and nonzero(), tp_fp() and class_accuracy() read
the counts instead; see Validation and metrics.
Export
from libreyolo import LibreYOLO model = LibreYOLO("LibreResNet50-cls.pt")model.export(format="onnx")libreyolo export model=LibreResNet50-cls.pt format=onnxfrom libreyolo import LibreYOLO, SAMPLE_IMAGE # The factory routes on the file suffix, so an exported artifact loads# like a checkpoint and returns the same Results object.model = LibreYOLO("LibreResNet50-cls.onnx")result = model(SAMPLE_IMAGE) print(result.probs.top1, result.probs.top1conf)An exported artifact loads back through LibreYOLO() on its file suffix, so a
.onnx or .engine file behaves like a checkpoint and returns the same
Results. Format coverage differs by family; the matrix on each model page is
generated from the validated set rather than typed by hand. See
export and deploy for the formats, their extras and their
constraints.