Introduction

LibreYOLO is an MIT-licensed object detection library that provides a unified Python API across four architectures: YOLOX, YOLOv9, RT-DETR, and RF-DETR. One interface for prediction, training, validation, and export, regardless of which model family you use.

python
1from libreyolo import LibreYOLO
2
3model = LibreYOLO("LibreYOLOXs.pt")
4results = model("image.jpg", conf=0.25, save=True)
5print(results.boxes.xyxy)

Key features

  • Unified API across YOLOX, YOLOv9, RT-DETR, and RF-DETR
  • Auto-detection of model architecture, size, and class count from weights
  • Tiled inference for large/high-resolution images
  • ONNX, TorchScript, TensorRT, OpenVINO, and NCNN export with embedded metadata
  • ONNX Runtime, TensorRT, OpenVINO, and NCNN inference backends
  • COCO-compatible validation with mAP metrics
  • Accepts any image format: file paths, URLs, PIL, NumPy, PyTorch tensors, raw bytes

Installation

Requirements

  • Python 3.10+
  • PyTorch 1.7+

From PyPI

bash
1pip install libreyolo

From source

bash
1git clone https://github.com/Libre-YOLO/libreyolo.git
2cd libreyolo
3pip install -e .

Optional dependencies

bash
1# ONNX export and inference
2pip install libreyolo[onnx]
3# or: pip install onnx onnxsim onnxscript onnxruntime
4
5# RT-DETR support
6pip install libreyolo[rtdetr]
7# or: pip install transformers timm
8
9# RF-DETR support
10pip install libreyolo[rfdetr]
11# or: pip install rfdetr transformers timm supervision
12
13# TensorRT export and inference (NVIDIA GPU)
14pip install libreyolo[tensorrt]
15# Note: TensorRT itself requires manual installation (depends on CUDA version)
16
17# OpenVINO export and inference (Intel CPU/GPU/VPU)
18pip install libreyolo[openvino]
19# INT8 export also needs: pip install nncf
20
21# NCNN export and inference
22pip install libreyolo[ncnn]
23# or: pip install pnnx ncnn

If using uv, the most reliable path is an isolated venv per extra:

bash
1# ONNX environment
2uv venv .venv-onnx
3uv pip install --python .venv-onnx/bin/python -e '.[onnx]'
4
5# RT-DETR environment
6uv venv .venv-rtdetr
7uv pip install --python .venv-rtdetr/bin/python -e '.[rtdetr]'
8
9# Repeat with .[rfdetr], .[openvino], .[ncnn], or .[tensorrt] as needed

This avoids mutating the project environment and keeps optional dependencies isolated. Vendor-specific extras such as TensorRT, OpenVINO, and NCNN may still require platform-specific native packages.

Quickstart

Load a model and run inference

python
1from libreyolo import LibreYOLO
2
3# Auto-detects architecture and size from the weights file
4model = LibreYOLO("LibreYOLOXs.pt")
5
6# Run on a single image
7result = model("photo.jpg")
8
9print(f"Found {len(result)} objects")
10print(result.boxes.xyxy) # bounding boxes (N, 4)
11print(result.boxes.conf) # confidence scores (N,)
12print(result.boxes.cls) # class IDs (N,)

Save annotated output

python
1result = model("photo.jpg", save=True)
2# Saved under runs/detect/predict*/photo.jpg by default

Process a directory

python
1results = model("images/", save=True, batch=4)
2for r in results:
3 print(f"{r.path}: {len(r)} detections")

Available Models

YOLOX

SizeCodeInput sizeUse case
Nano"n"416Edge devices, mobile
Tiny"t"416Edge devices, faster
Small"s"640Balanced speed/accuracy
Medium"m"640Higher accuracy
Large"l"640High accuracy
XLarge"x"640Maximum accuracy
python
1from libreyolo import LibreYOLO
2
3model = LibreYOLO("LibreYOLOXn.pt")
4# model = LibreYOLO("LibreYOLOXt.pt")
5# model = LibreYOLO("LibreYOLOXs.pt")
6# model = LibreYOLO("LibreYOLOXm.pt")
7# model = LibreYOLO("LibreYOLOXl.pt")
8# model = LibreYOLO("LibreYOLOXx.pt")

YOLOv9

SizeCodeInput sizeUse case
Tiny"t"640Fast inference
Small"s"640Balanced
Medium"m"640Higher accuracy
Compact"c"640Best accuracy
python
1from libreyolo import LibreYOLO
2
3model = LibreYOLO("LibreYOLO9t.pt")
4# model = LibreYOLO("LibreYOLO9s.pt")
5# model = LibreYOLO("LibreYOLO9m.pt")
6# model = LibreYOLO("LibreYOLO9c.pt")

RT-DETR

SizeCodeInput sizeUse case
ResNet-18"r18"640Fastest RT-DETR variant
ResNet-34"r34"640Balanced speed/accuracy
ResNet-50"r50"640General-purpose default
ResNet-50-m"r50m"640Higher accuracy
ResNet-101"r101"640Largest RT-DETR variant
python
1from libreyolo import LibreYOLORTDETR
2
3model = LibreYOLORTDETR(size="r50")

RF-DETR

SizeCodeInput sizeUse case
Nano"n"384Edge
Small"s"512Balanced
Medium"m"576Higher accuracy
Large"l"704Maximum accuracy
python
1from libreyolo import LibreYOLORFDETR
2
3model = LibreYOLORFDETR(size="s")

Factory function (recommended)

The LibreYOLO() factory auto-detects everything from the weights file:

python
1from libreyolo import LibreYOLO
2
3# Auto-detects: YOLOX, size=s, 80 classes
4model = LibreYOLO("LibreYOLOXs.pt")
5
6# Auto-detects: YOLOv9, size=c, 80 classes
7model = LibreYOLO("LibreYOLO9c.pt")
8
9# Auto-detects: RT-DETR
10model = LibreYOLO("LibreRTDETRr50.pt")
11
12# RF-DETR checkpoints also work when you point at an actual checkpoint file
13model = LibreYOLO("/path/to/checkpoint_best_regular.pth")
14
15# ONNX models work too
16model = LibreYOLO("model.onnx")
17
18# TensorRT engines
19model = LibreYOLO("model.engine")
20
21# OpenVINO models (directory with model.xml)
22model = LibreYOLO("model_openvino/")
23
24# NCNN models (directory with model.ncnn.param + model.ncnn.bin)
25model = LibreYOLO("model_ncnn/")

For recognized official checkpoint filenames, LibreYOLO can auto-download missing weights. For custom filenames and RF-DETR checkpoints, prefer explicit local paths or the family-specific constructors.

Prediction

Basic prediction

python
1result = model("image.jpg")

All prediction parameters

python
1result = model(
2 "image.jpg",
3 conf=0.25, # confidence threshold (default: 0.25)
4 iou=0.45, # NMS IoU threshold (default: 0.45)
5 imgsz=640, # input size override (default: model's native)
6 classes=[0, 2, 5], # filter to specific class IDs (default: all)
7 max_det=300, # max detections per image (default: 300)
8 save=True, # save annotated image (default: False)
9 output_path="out/", # where to save (default: runs/detect/predict*/)
10 color_format="auto", # "auto", "rgb", or "bgr"
11 output_file_format="png", # output format: "jpg", "png", "webp"
12)

model.predict(...) is an alias for model(...).

Supported input formats

LibreYOLO accepts images in any of these formats:

python
1# File path (string or pathlib.Path)
2result = model("photo.jpg")
3result = model(Path("photo.jpg"))
4
5# URL
6result = model("https://example.com/image.jpg")
7
8# PIL Image
9from PIL import Image
10img = Image.open("photo.jpg")
11result = model(img)
12
13# NumPy array (HWC or CHW, RGB or BGR, uint8 or float32)
14import numpy as np
15arr = np.random.randint(0, 255, (480, 640, 3), dtype=np.uint8)
16result = model(arr)
17
18# OpenCV (BGR) — specify color_format
19import cv2
20frame = cv2.imread("photo.jpg")
21result = model(frame, color_format="bgr")
22
23# PyTorch tensor (CHW or NCHW)
24import torch
25tensor = torch.randn(3, 640, 640)
26result = model(tensor)
27
28# Raw bytes
29with open("photo.jpg", "rb") as f:
30 result = model(f.read())
31
32# Directory of images
33results = model("images/", batch=4)

Working with results

Every prediction returns a Results object (or a list of them for directories):

python
1result = model("image.jpg")
2
3# Number of detections
4len(result) # e.g., 5
5
6# Bounding boxes in xyxy format (x1, y1, x2, y2)
7result.boxes.xyxy # tensor of shape (N, 4)
8
9# Bounding boxes in xywh format (center_x, center_y, width, height)
10result.boxes.xywh # tensor of shape (N, 4)
11
12# Confidence scores
13result.boxes.conf # tensor of shape (N,)
14
15# Class IDs
16result.boxes.cls # tensor of shape (N,)
17
18# Combined data: [x1, y1, x2, y2, conf, cls]
19result.boxes.data # tensor of shape (N, 6)
20
21# Metadata
22result.orig_shape # (height, width) of original image
23result.path # source file path (or None)
24result.names # {0: "person", 1: "bicycle", ...}
25
26# Move to CPU / convert to numpy
27result_cpu = result.cpu()
28boxes_np = result.boxes.numpy()

Class filtering

Filter detections to specific class IDs:

python
1# Only detect people (class 0) and cars (class 2)
2result = model("image.jpg", classes=[0, 2])

Tiled Inference

For images much larger than the model's input size (e.g., satellite imagery, drone footage), tiled inference splits the image into overlapping tiles, runs detection on each, and merges results.

python
1result = model(
2 "large_aerial_image.jpg",
3 tiling=True,
4 overlap_ratio=0.2, # 20% overlap between tiles (default)
5 save=True,
6)
7
8# Extra metadata on tiled results
9result.tiled # True
10result.num_tiles # number of tiles used
11result.saved_path # output directory when save=True
12result.tiles_path # directory containing per-tile crops
13result.grid_path # grid visualization image

When save=True with tiling, LibreYOLO saves:

  • final_image.jpg — full image with all merged detections drawn
  • grid_visualization.jpg — image showing tile grid overlay
  • tiles/ — individual tile crops
  • metadata.json — tiling parameters and detection counts

If the image is already smaller than the model's input size, tiling is skipped automatically.

Training

YOLOX training

python
1from libreyolo import LibreYOLOX
2
3model = LibreYOLOX(size="s")
4
5results = model.train(
6 data="coco128.yaml", # path to data.yaml (required)
7
8 # Training parameters
9 epochs=100, # default: 100
10 batch=16,
11 imgsz=640,
12
13 # Optimizer
14 lr0=0.01, # initial learning rate
15 optimizer="SGD", # "SGD", "Adam", "AdamW"
16
17 # System
18 device="0", # GPU device ("", "cpu", "cuda", "0", "0,1")
19 workers=8,
20 seed=0,
21
22 # Output
23 project="runs/train",
24 name="exp",
25 exist_ok=False,
26
27 # Training features
28 amp=True, # automatic mixed precision
29 patience=50, # early stopping patience
30 resume=False, # resume from loaded checkpoint
31)
32
33print(f"Best mAP50-95: {results['best_mAP50_95']:.3f}")
34print(f"Best checkpoint: {results['best_checkpoint']}")

After training, the model instance is automatically updated with the best weights.

Training results dict

python
1{
2 "final_loss": 2.31,
3 "best_mAP50": 0.682,
4 "best_mAP50_95": 0.451,
5 "best_epoch": 87,
6 "save_dir": "runs/train/exp",
7 "best_checkpoint": "runs/train/exp/weights/best.pt",
8 "last_checkpoint": "runs/train/exp/weights/last.pt",
9}

Resuming training

python
1model = LibreYOLOX("runs/train/exp/weights/last.pt", size="s")
2results = model.train(data="coco128.yaml", resume=True)

Custom dataset YAML format

data.yaml
1path: /path/to/dataset
2train: images/train
3val: images/val
4test: images/test # optional
5
6nc: 3
7names: ["cat", "dog", "bird"]

YOLOv9 training

python
1from libreyolo import LibreYOLO9
2
3model = LibreYOLO9("LibreYOLO9c.pt", size="c")
4
5results = model.train(
6 data="coco128.yaml",
7 epochs=300, # default: 300
8 batch=16,
9 imgsz=640,
10 lr0=0.01,
11 optimizer="SGD",
12 device="0",
13 workers=8,
14 seed=0,
15 project="runs/train",
16 name="yolo9_exp", # default: "yolo9_exp"
17 exist_ok=False,
18 resume=False,
19 amp=True,
20 patience=50,
21)
22
23print(f"Best mAP50-95: {results['best_mAP50_95']:.3f}")

YOLOv9 training uses the same parameter API as YOLOX but defaults to epochs=300 and name="yolo9_exp". It does not have a pretrained parameter.

RT-DETR training

python
1from libreyolo import LibreYOLORTDETR
2
3model = LibreYOLORTDETR(size="r50")
4
5results = model.train(
6 data="coco128.yaml",
7 epochs=72, # default: 72
8 batch=4, # default: 4
9 imgsz=640,
10 lr0=1e-4,
11 lr_backbone=1e-5,
12 optimizer="AdamW",
13 scheduler="linear",
14 device="0",
15 workers=4,
16 seed=0,
17 project="runs/train",
18 name="rtdetr_exp",
19 exist_ok=False,
20 pretrained=True,
21 resume=False,
22 amp=True,
23 patience=50,
24)

RT-DETR training uses the YOLO-style data.yaml pipeline, but it has its own defaults and adds lr_backbone plus scheduler.

RF-DETR training

RF-DETR uses a different training API that wraps the original rfdetr implementation:

python
1from libreyolo import LibreYOLORFDETR
2
3model = LibreYOLORFDETR(size="s")
4
5results = model.train(
6 data="path/to/dataset", # Roboflow/COCO format directory
7 epochs=100,
8 batch_size=4,
9 lr=1e-4,
10 output_dir="runs/train",
11)

RF-DETR datasets use COCO annotation format:

text
1dataset/
2 train/
3 _annotations.coco.json
4 image1.jpg
5 image2.jpg
6 valid/
7 _annotations.coco.json
8 image1.jpg

Validation

Run COCO-standard evaluation on a validation set:

python
1results = model.val(
2 data="coco128.yaml", # dataset config
3 batch=16,
4 imgsz=640,
5 conf=0.001, # low conf for mAP calculation
6 iou=0.6, # NMS IoU threshold
7 split="val", # "val", "test", or "train"
8 save_json=False, # save predictions as COCO JSON
9 verbose=True, # print per-class metrics
10)
11
12print(f"mAP50: {results['metrics/mAP50']:.3f}")
13print(f"mAP50-95: {results['metrics/mAP50-95']:.3f}")

Validation results dict

By default, LibreYOLO uses COCO evaluation and returns 12 standard metrics:

python
1{
2 "metrics/mAP50-95": 0.489, # COCO primary metric (AP@[.5:.95])
3 "metrics/mAP50": 0.721, # AP@0.5 (PASCAL VOC style)
4 "metrics/mAP75": 0.534, # AP@0.75 (strict)
5 "metrics/mAP_small": 0.291,
6 "metrics/mAP_medium": 0.532,
7 "metrics/mAP_large": 0.648,
8 "metrics/AR1": 0.362, # Average Recall (max 1 det)
9 "metrics/AR10": 0.571,
10 "metrics/AR100": 0.601,
11 "metrics/AR_small": 0.387,
12 "metrics/AR_medium": 0.641,
13 "metrics/AR_large": 0.739,
14}

Set use_coco_eval=False in ValidationConfig for legacy precision/recall metrics.

Export

Export PyTorch models to ONNX, TorchScript, TensorRT, OpenVINO, or NCNN for deployment.

Quick export

python
1# ONNX (default)
2model.export()
3
4# TorchScript
5model.export(format="torchscript")
6
7# TensorRT (requires NVIDIA GPU + TensorRT)
8model.export(format="tensorrt")
9
10# OpenVINO (optimized for Intel hardware)
11model.export(format="openvino")
12
13# NCNN (via PNNX)
14model.export(format="ncnn")

All export parameters

python
1path = model.export(
2 format="onnx", # "onnx", "torchscript", "tensorrt", "openvino", or "ncnn"
3 output_path="model.onnx", # output file (auto-generated if None)
4 imgsz=640, # input resolution (default: model's native)
5 opset=13, # ONNX opset version (RT-DETR / RF-DETR default to 17)
6 simplify=True, # run onnxsim graph simplification
7 dynamic=True, # enable dynamic batch axis
8 half=False, # export in FP16
9 batch=1, # batch size for static graph
10 device=None, # device to trace on (default: model's current device)
11 int8=False, # INT8 quantization (TensorRT / OpenVINO only)
12 data=None, # calibration dataset for INT8
13 fraction=1.0, # fraction of calibration data to use
14 workspace=4.0, # TensorRT workspace size (GB)
15 hardware_compatibility="none", # TensorRT compatibility mode
16 gpu_device=0, # GPU device index for TensorRT
17 trt_config=None, # optional TensorRT YAML config path
18 verbose=False, # verbose logging
19)

OpenVINO INT8 export additionally requires nncf. NCNN export writes a directory containing model.ncnn.param, model.ncnn.bin, and metadata.yaml.

ONNX metadata

Exported ONNX files include embedded metadata:

KeyExample value
libreyolo_version"1.0.0"
model_family"yolox"
model_size"s"
nb_classes"80"
names'{"0": "person", "1": "bicycle", ...}'
imgsz"640"
dynamic"True"
half"False"

This metadata is automatically read back when loading the model with OnnxBackend.

Using the exporter factory directly

python
1from libreyolo.export import BaseExporter
2
3exporter = BaseExporter.create("onnx", model)
4path = exporter(dynamic=True, simplify=True)

ONNX Inference

Run inference using ONNX Runtime instead of PyTorch. Useful for deployment environments without PyTorch.

python
1from libreyolo import OnnxBackend
2
3model = OnnxBackend("model.onnx")
4
5result = model("image.jpg", conf=0.25, iou=0.45, save=True)
6print(result.boxes.xyxy)

Auto-metadata

If the ONNX file was exported by LibreYOLO, class names and class count are read automatically from the embedded metadata:

python
1# Export with metadata
2model.export(format="onnx", output_path="model.onnx")
3
4# Load — names and nb_classes auto-populated
5onnx_model = OnnxBackend("model.onnx")
6print(onnx_model.names) # {0: "person", 1: "bicycle", ...}
7print(onnx_model.nb_classes) # 80

For ONNX files without metadata (e.g., exported by other tools), specify nb_classes manually:

python
1model = OnnxBackend("external_model.onnx", nb_classes=20)

Device selection

python
1# Auto-detect (CUDA if available, else CPU)
2model = OnnxBackend("model.onnx", device="auto")
3
4# Force CPU
5model = OnnxBackend("model.onnx", device="cpu")
6
7# Force CUDA
8model = OnnxBackend("model.onnx", device="cuda")

Prediction parameters

OnnxBackend supports the core prediction API shared by the runtime backends:

python
1result = model(
2 "image.jpg",
3 conf=0.25,
4 iou=0.45,
5 imgsz=640,
6 classes=[0, 2],
7 max_det=300,
8 save=True,
9 output_path="output/annotated.jpg", # final file path when save=True
10 color_format="auto",
11)

Runtime backends do not expose PyTorch-only options such as tiling, overlap_ratio, or output_file_format.

Runtime backends also handle saving a little differently from the PyTorch wrappers: if you set output_path, pass a final file path, not a directory. If you omit it, the current backend default is under runs/detections/.

TensorRT Inference

Run inference using TensorRT for maximum throughput on NVIDIA GPUs. Requires CUDA plus the TensorRT Python bindings.

python
1from libreyolo import TensorRTBackend
2
3model = TensorRTBackend("model.engine")
4
5result = model("image.jpg", conf=0.25, iou=0.45, save=True)
6print(result.boxes.xyxy)

Auto-detection via factory

The LibreYOLO() factory automatically detects .engine files:

python
1from libreyolo import LibreYOLO
2
3# Auto-detects TensorRT engine
4model = LibreYOLO("model.engine")

TensorRTBackend supports the same core runtime-backend prediction API as ONNX and OpenVINO, including the same file-path-only output_path behavior for save=True.

OpenVINO Inference

Run inference using OpenVINO, optimized for Intel CPUs, GPUs, and VPUs.

python
1from libreyolo import OpenVINOBackend
2
3model = OpenVINOBackend("model_openvino/")
4
5result = model("image.jpg", conf=0.25, iou=0.45, save=True)
6print(result.boxes.xyxy)

Auto-detection via factory

The LibreYOLO() factory automatically detects OpenVINO model directories:

python
1from libreyolo import LibreYOLO
2
3# Auto-detects OpenVINO directory
4model = LibreYOLO("model_openvino/")

OpenVINOBackend reads metadata.yaml when present and supports the same core runtime-backend prediction API.

NCNN Inference

Run inference using NCNN for lightweight deployment on CPU or Vulkan-capable GPU targets.

python
1from libreyolo import NcnnBackend
2
3model = NcnnBackend("model_ncnn/")
4
5result = model("image.jpg", conf=0.25, iou=0.45, save=True)
6print(result.boxes.xyxy)

Auto-detection via factory

The LibreYOLO() factory automatically detects NCNN model directories:

python
1from libreyolo import LibreYOLO
2
3# Auto-detects NCNN directory
4model = LibreYOLO("model_ncnn/")

An NCNN export directory contains model.ncnn.param, model.ncnn.bin, and usually metadata.yaml.

API Reference

LibreYOLO (factory)

python
1LibreYOLO(
2 model_path: str,
3 size: str = None, # auto-detected from weights
4 reg_max: int = 16, # YOLOv9 only
5 nb_classes: int = None, # auto-detected from weights
6 device: str = "auto",
7) -> LibreYOLOX | LibreYOLO9 | LibreYOLORTDETR | LibreYOLORFDETR | OnnxBackend | TensorRTBackend | OpenVINOBackend | NcnnBackend

Auto-detects model architecture, size, and class count from the weights file. It also handles .onnx, .engine, OpenVINO directories containing model.xml, and NCNN directories containing model.ncnn.param plus model.ncnn.bin.

Prediction (PyTorch model wrappers)

python
1model(
2 source, # image input (see supported formats)
3 *,
4 conf: float = 0.25,
5 iou: float = 0.45,
6 imgsz: int = None,
7 classes: list[int] = None,
8 max_det: int = 300,
9 save: bool = False,
10 batch: int = 1,
11 output_path: str = None,
12 color_format: str = "auto",
13 tiling: bool = False,
14 overlap_ratio: float = 0.2,
15 output_file_format: str = None,
16) -> Results | list[Results]

Prediction (runtime backends)

python
1backend(
2 source,
3 *,
4 conf: float = 0.25,
5 iou: float = 0.45,
6 imgsz: int = None,
7 classes: list[int] = None,
8 max_det: int = 300,
9 save: bool = False,
10 batch: int = 1,
11 output_path: str = None, # final file path when save=True
12 color_format: str = "auto",
13) -> Results | list[Results]

If output_path is omitted for a runtime backend, the current default save location is runs/detections/.

Results

python
1result = Results(
2 boxes: Boxes,
3 orig_shape: tuple[int, int], # (height, width)
4 path: str | None,
5 names: dict[int, str],
6)
7
8len(result) # number of detections
9result.cpu() # copy with tensors on CPU

Boxes

python
1boxes = Boxes(boxes, conf, cls)
2
3boxes.xyxy # (N, 4) tensor — x1, y1, x2, y2
4boxes.xywh # (N, 4) tensor — cx, cy, w, h
5boxes.conf # (N,) tensor — confidence scores
6boxes.cls # (N,) tensor — class IDs
7boxes.data # (N, 6) tensor — [xyxy, conf, cls]
8
9len(boxes) # number of boxes
10boxes.cpu() # copy on CPU
11boxes.numpy() # copy as numpy arrays

model.export()

python
1model.export(
2 format: str = "onnx", # "onnx", "torchscript", "tensorrt", "openvino", or "ncnn"
3 *,
4 output_path: str = None,
5 imgsz: int = None,
6 opset: int = 13,
7 simplify: bool = True,
8 dynamic: bool = True,
9 half: bool = False,
10 batch: int = 1,
11 device: str = None,
12 int8: bool = False,
13 data: str = None, # calibration data for INT8
14 fraction: float = 1.0, # fraction of calibration data
15 workspace: float = 4.0, # TensorRT workspace (GB)
16 hardware_compatibility: str = "none",
17 gpu_device: int = 0,
18 trt_config = None, # optional TensorRT YAML config path
19 verbose: bool = False,
20) -> str # path to exported file or directory

BaseExporter

python
1from libreyolo.export import BaseExporter
2
3exporter = BaseExporter.create("onnx", model)
4path = exporter(dynamic=True, simplify=True)
5
6BaseExporter.create("ncnn", model)(output_path="model_ncnn")

model.val()

python
1model.val(
2 data: str = None, # path to data.yaml
3 batch: int = 16,
4 imgsz: int = None,
5 conf: float = 0.001,
6 iou: float = 0.6,
7 device: str = None,
8 split: str = "val", # "val", "test", or "train"
9 save_json: bool = False,
10 verbose: bool = True,
11) -> dict

Returns (COCO evaluation, default):

python
1{
2 "metrics/mAP50-95": float, # COCO primary metric
3 "metrics/mAP50": float,
4 "metrics/mAP75": float,
5 "metrics/mAP_small": float,
6 "metrics/mAP_medium": float,
7 "metrics/mAP_large": float,
8 "metrics/AR1": float,
9 "metrics/AR10": float,
10 "metrics/AR100": float,
11 "metrics/AR_small": float,
12 "metrics/AR_medium": float,
13 "metrics/AR_large": float,
14}

model.train() (YOLOX)

python
1model.train(
2 data: str, # path to data.yaml (required)
3 *,
4 epochs: int = 100,
5 batch: int = 16,
6 imgsz: int = 640,
7 lr0: float = 0.01,
8 optimizer: str = "SGD",
9 device: str = "",
10 workers: int = 8,
11 seed: int = 0,
12 project: str = "runs/train",
13 name: str = "exp",
14 exist_ok: bool = False,
15 pretrained: bool = True,
16 resume: bool = False,
17 amp: bool = True,
18 patience: int = 50,
19) -> dict

Returns:

python
1{
2 "final_loss": float,
3 "best_mAP50": float,
4 "best_mAP50_95": float,
5 "best_epoch": int,
6 "save_dir": str,
7 "best_checkpoint": str,
8 "last_checkpoint": str,
9}

model.train() (YOLOv9)

python
1model.train(
2 data: str, # path to data.yaml (required)
3 *,
4 epochs: int = 300,
5 batch: int = 16,
6 imgsz: int = 640,
7 lr0: float = 0.01,
8 optimizer: str = "SGD",
9 device: str = "",
10 workers: int = 8,
11 seed: int = 0,
12 project: str = "runs/train",
13 name: str = "yolo9_exp",
14 exist_ok: bool = False,
15 resume: bool = False,
16 amp: bool = True,
17 patience: int = 50,
18) -> dict

Returns the same dict as YOLOX training.

model.train() (RT-DETR)

python
1model.train(
2 data: str, # path to data.yaml (required)
3 *,
4 epochs: int = 72,
5 batch: int = 4,
6 imgsz: int = 640,
7 lr0: float = 1e-4,
8 lr_backbone: float = 1e-5,
9 optimizer: str = "AdamW",
10 scheduler: str = "linear",
11 device: str = "",
12 workers: int = 4,
13 seed: int = 0,
14 project: str = "runs/train",
15 name: str = "rtdetr_exp",
16 exist_ok: bool = False,
17 pretrained: bool = True,
18 resume: bool = False,
19 amp: bool = True,
20 patience: int = 50,
21) -> dict

model.train() (RF-DETR)

python
1model.train(
2 data: str, # path to dataset directory
3 epochs: int = 100,
4 batch_size: int = 4,
5 lr: float = 1e-4,
6 output_dir: str = "runs/train",
7 resume: str = None,
8 **kwargs, # additional RF-DETR training args
9) -> dict

OnnxBackend

python
1OnnxBackend(
2 onnx_path: str,
3 nb_classes: int = 80, # auto-read from metadata if available
4 device: str = "auto",
5)

Runs inference on an ONNX model with ONNX Runtime. Supports the runtime-backend prediction API shown above.

TensorRTBackend

python
1TensorRTBackend(
2 engine_path: str,
3 nb_classes: int | None = None,
4 device: str = "auto",
5)

Runs inference on a TensorRT .engine file and can read metadata from an adjacent .json sidecar.

OpenVINOBackend

python
1OpenVINOBackend(
2 model_dir: str,
3 nb_classes: int | None = None,
4 device: str = "auto",
5)

Runs inference on an OpenVINO model directory containing model.xml and optionally metadata.yaml.

NcnnBackend

python
1NcnnBackend(
2 model_dir: str,
3 nb_classes: int | None = None,
4 device: str = "auto",
5)

Runs inference on an NCNN model directory containing model.ncnn.param, model.ncnn.bin, and optionally metadata.yaml.

ValidationConfig

python
1from libreyolo import ValidationConfig
2
3config = ValidationConfig(
4 data="coco128.yaml",
5 data_dir=None, # override dataset root directory
6 batch_size=16,
7 imgsz=640,
8 conf_thres=0.001,
9 iou_thres=0.6,
10 max_det=300,
11 split="val", # "val", "test", or "train"
12 device="auto",
13 save_json=False,
14 verbose=True,
15 half=False,
16 use_coco_eval=True, # use COCO eval (12 keys); False for legacy
17 num_workers=4,
18)
19
20# Load/save YAML
21config = ValidationConfig.from_yaml("config.yaml")
22config.to_yaml("config.yaml")

Architecture Guide

This section is for contributors who want to understand the codebase internals.

Base class design

PyTorch model families inherit from BaseModel in libreyolo/models/base/model.py. Subclasses implement these abstract methods:

MethodPurpose
_init_model()Build and return the nn.Module
_get_available_layers()Return layer-name to module mapping
_get_preprocess_numpy()Return the NumPy preprocessor used for export / calibration
_preprocess()Image to tensor conversion
_forward()Model forward pass
_postprocess()Raw output to detection dicts

BaseModel provides the shared wrapper behavior: prediction, export, validation, size/name metadata, and training helpers. The actual single-image, batch, and tiled inference flow lives in libreyolo/models/base/inference.py, while deployment runtimes live under libreyolo/backends/.

Package structure

text
1libreyolo/
2 __init__.py # Public API exports
3 models/
4 __init__.py # LibreYOLO() factory + model registry bootstrap
5 base/
6 model.py # BaseModel
7 inference.py # Shared prediction pipeline
8 yolox/
9 model.py
10 nn.py
11 utils.py
12 yolo9/
13 model.py
14 nn.py
15 utils.py
16 rtdetr/
17 model.py
18 nn.py
19 trainer.py
20 utils.py
21 rfdetr/
22 model.py
23 utils.py
24 train.py
25 backends/
26 base.py # BaseBackend runtime wrapper
27 onnx.py # OnnxBackend
28 tensorrt.py # TensorRTBackend
29 openvino.py # OpenVINOBackend
30 ncnn.py # NcnnBackend
31 utils/
32 results.py # Results and Boxes classes
33 image_loader.py # Unified image loading
34 general.py # Path helpers, NMS, tiling utilities
35 export/
36 exporter.py # BaseExporter and format registry
37 onnx.py # ONNX export logic
38 torchscript.py # TorchScript export logic
39 tensorrt.py # TensorRT export logic
40 openvino.py # OpenVINO export logic
41 ncnn.py # NCNN export logic
42 training/
43 config.py # YOLOXTrainConfig / YOLOv9TrainConfig
44 trainer.py # YOLOXTrainer
45 v9_trainer.py # YOLOv9Trainer
46 dataset.py # Training dataset
47 augment.py # Mosaic, mixup, etc.
48 loss.py # YOLOX loss functions
49 scheduler.py # LR schedulers
50 ema.py # Exponential moving average
51 validation/
52 config.py # ValidationConfig
53 detection_validator.py # DetectionValidator
54 metrics.py # DetMetrics, mAP computation
55 base.py # BaseValidator
56 preprocessors.py # Per-model val preprocessing
57 data/
58 utils.py # Dataset loading, YAML parsing
59 yolo_coco_api.py # YOLO-to-COCO annotation bridge
60 config/
61 datasets/ # Built-in dataset YAML configs (coco8, coco128, coco5000, coco, etc.)

Adding a new model family

  1. 1Create libreyolo/models/newmodel/model.py with a class inheriting BaseModel
  2. 2Implement all abstract methods
  3. 3Create the supporting network and utilities under libreyolo/models/newmodel/
  4. 4Add the import to libreyolo/models/__init__.py so the registry sees it
  5. 5Export the class from libreyolo/__init__.py
  6. 6(Optional) Override val_preprocessor_class if validation preprocessing differs from the standard path

Export architecture

BaseExporter in libreyolo/export/exporter.py is the export entrypoint. Concrete exporters register themselves through subclass registration, and callers use BaseExporter.create(format, model) to get the right implementation:

python
1from libreyolo.export import BaseExporter
2
3onnx_exporter = BaseExporter.create("onnx", model)
4ncnn_exporter = BaseExporter.create("ncnn", model)

To add a new export format, implement a new BaseExporter subclass with a unique format_name and import it from libreyolo/export/exporter.py so the registry is populated.

Dataset Format

YOLOX, YOLOv9, and RT-DETR use YOLO-style datasets configured via data.yaml. RF-DETR uses COCO-format annotations and is documented separately below.

data.yaml structure

data.yaml
1path: /absolute/path/to/dataset # dataset root
2train: images/train # directory path, relative to path
3val: images/val # directory path, relative to path
4test: images/test # optional
5
6nc: 80 # number of classes
7names: [ # class names
8 "person", "bicycle", "car", "motorcycle", "airplane",
9 "bus", "train", "truck", "boat", "traffic light",
10 # ...
11]

File-list variant

The same YAML format can also point train, val, or test at .txt files containing one image path per line:

coco.yaml
1path: /absolute/path/to/coco
2train: train2017.txt
3val: val2017.txt
4test: test-dev2017.txt
5
6nc: 80
7names: ["person", "bicycle", "car", "..."]

Directory layout

text
1dataset/
2 images/
3 train/
4 img001.jpg
5 img002.jpg
6 val/
7 img003.jpg
8 labels/
9 train/
10 img001.txt
11 img002.txt
12 val/
13 img003.txt

Label format

One text file per image. Each line is one object:

text
1<class_id> <center_x> <center_y> <width> <height>

All coordinates are normalized to [0, 1] relative to image dimensions.

Example (img001.txt):

img001.txt
10 0.5 0.4 0.3 0.6
22 0.1 0.2 0.05 0.1

Built-in datasets

LibreYOLO ships built-in dataset configs under libreyolo/config/datasets/ and can auto-download supported datasets on first use:

python
1# These download automatically on first use
2results = model.val(data="coco8.yaml")
3results = model.train(data="coco128.yaml", epochs=10)

RF-DETR dataset format

RF-DETR uses COCO-format annotations (JSON) instead of YOLO text labels:

text
1dataset/
2 train/
3 _annotations.coco.json
4 image1.jpg
5 valid/
6 _annotations.coco.json
7 image1.jpg