TensorRT

TensorRT compiles a graph into an engine tuned for one GPU. LibreYOLO exports an ONNX intermediate first, parses it with TensorRT's ONNX parser, builds the engine, and writes the model metadata beside it as a JSON sidecar.

Flag
export(format="tensorrt")
Writes
One .engine file plus a .engine.json metadata sidecar
Extra
pip install "libreyolo[onnx,tensorrt]"
Loads back
LibreYOLO("weights/LibreYOLO9t.engine")
Shapes
Static by default; dynamic=True adds a batch-axis optimization profile
Precision
FP32, FP16 (half=True), INT8 (int8=True with data=)
Requires
An NVIDIA GPU at build time and at run time. Engines do not move between GPU architectures.

Install

Both the build and the run need an NVIDIA GPU with a working CUDA stack. There is no CPU fallback for this format.

Install
# The engine is built from an ONNX intermediate, so both extras are needed.pip install "libreyolo[onnx,tensorrt]"
Confirm the toolchain before building
python -c "import tensorrt, torch; print(tensorrt.__version__, torch.cuda.is_available())"

The tensorrt extra pins tensorrt-cu12 and pycuda, and the marker drops both on macOS. On a Jetson, do not use that extra: it pins a CUDA 12 build against a CUDA 13 platform. Use the TensorRT that JetPack installs instead, as described on NVIDIA Jetson.

Export

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9t.pt") # Writes weights/LibreYOLO9t_fp16.engine and weights/LibreYOLO9t_fp16.engine.jsonpath = model.export(format="tensorrt", half=True)print(path)
CLI
libreyolo export --model LibreYOLO9t.pt --format tensorrt --half
Arguments
model.export(    format="tensorrt",    imgsz=640,    batch=1,    half=False,    int8=False,    data=None,                      # required when int8=True    dynamic=False,    workspace=4.0,                  # GiB of build-time scratch    min_batch=1,                    # dynamic profile bounds    opt_batch=1,    max_batch=8,    hardware_compatibility="none",  # or "ampere_plus"    gpu_device=0,                   # build device on a multi-GPU host    verbose=False,)

The export runs in two steps. Step one writes an ONNX intermediate to a temporary path, step two parses it and builds the engine, and the intermediate is removed afterwards. workspace is build-time scratch memory in GiB; a larger value lets the builder try more kernels and does not affect inference memory.

The metadata sidecar is written next to the engine as <engine>.json and records the precision the build actually realized. When the GPU lacks fast FP16 or fast INT8 the builder warns and falls back, and the sidecar reports the precision that came out rather than the one that was asked for.

Under FP16, a ViT backbone in the graph is detected and its float layers are pinned to FP32. DINOv2-style backbones overflow in FP16 and produce NaN, so the build sets OBEY_PRECISION_CONSTRAINTS and reports FP16 (FP32 ViT backbone). The pass is a no-op on CNN backbones.

Dynamic batch

Dynamic batch engine
from libreyolo import LibreYOLO # The ONNX intermediate needs the dynamic batch axis for the profile# to have anything to bind to.LibreYOLO("LibreYOLO9t.pt").export(    format="tensorrt",    dynamic=True,    min_batch=1,    opt_batch=4,    max_batch=8,    half=True,)

dynamic=True adds one optimization profile spanning min_batch to max_batch, optimized at opt_batch, and records those three values in the sidecar. The profile is only added when the ONNX intermediate actually carries a dynamic batch dimension; otherwise the build logs that it is using static optimization and continues.

INT8

INT8 with calibration data
from libreyolo import LibreYOLO LibreYOLO("LibreYOLO9t.pt").export(    format="tensorrt",    int8=True,    data="coco128.yaml",   # required: there is no default for this format    fraction=1.0,)

INT8 uses TensorRT's entropy calibrator over a LibreYOLO calibration loader, and data is mandatory: this format has no eight-image fallback. Calibration needs cuda-python or pycuda for the device buffer. The calibration cache is keyed on a hash of the ONNX bytes, so scales from one model are never reused for another that happens to write to the same output path.

half=True and int8=True together warn and build INT8, which keeps an FP16 fallback for layers TensorRT cannot quantize.

Run the artifact

Through LibreYOLO
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("weights/LibreYOLO9t_fp16.engine")result = model.predict(SAMPLE_IMAGE)print(result.boxes.xyxy[:3])
Bare TensorRT
import json import tensorrt as trt path = "weights/LibreYOLO9t_fp16.engine"runtime = trt.Runtime(trt.Logger(trt.Logger.WARNING))with open(path, "rb") as handle:    engine = runtime.deserialize_cuda_engine(handle.read()) for i in range(engine.num_io_tensors):    name = engine.get_tensor_name(i)    print(engine.get_tensor_mode(name), name, engine.get_tensor_shape(name)) # Class names, task and input size live in the sidecar, not the engine.# Buffer allocation, preprocessing and postprocessing are yours here.print(json.load(open(path + ".json"))["names"])

LibreYOLO() dispatches on the .engine suffix, reads the sidecar for class names, task and pose schema, and returns the same Results object as the checkpoint. It raises immediately when no CUDA device is present.

The second snippet is the bare-runtime path. Host and device buffer allocation, preprocessing, decoding, NMS and coordinate rescaling all become yours, and the engine itself carries no class names, so the sidecar has to travel with it.

Constraints

A serialized engine is tied to the GPU architecture, the driver stack and the TensorRT version that built it. An engine built on a workstation will not load on a different architecture, which is why the build step runs on the deployment machine. hardware_compatibility="ampere_plus" trades some performance for portability across Ampere and newer. The "same_compute_capability" value maps to NONE and warns: the engine is optimized for the current GPU only, and the export says so rather than claiming a portability it did not apply.

Only the batch axis is profiled. A build with dynamic spatial dimensions is not part of this contract, which is why FCOS is blocked: it needs dynamic padded height and width to preserve its 800 by 1333 aspect transform.

Blocked before tracing: YOLO9 segmentation, RTMDet-Ins segmentation, SSD, Faster R-CNN and RetinaNet detection, and BiRefNet or FeyNobg matting, where TensorRT 10.16 reaches the shared ONNX DeformConv node and cannot parse it because ModulatedDeformConv2d is absent from the plugin registry.

Where a combination is neither validated nor blocked, the converter path is available and the project has not recorded TensorRT runtime parity for it. That is a statement about evidence, not about whether the build succeeds.

For the full family and task grid, see the export matrix. For one combination:

Check one family and task before building
libreyolo formats --family yolo9 --task detect

Read from libreyolo/export/tensorrt.py, libreyolo/export/exporter.py, libreyolo/export/support.py, libreyolo/backends/tensorrt.py and pyproject.toml on the dev branch.