TensorRT

TensorRT compila un grafo in un engine ottimizzato per una sola GPU. LibreYOLO esporta prima un ONNX intermedio, lo analizza con il parser ONNX di TensorRT, costruisce l'engine e scrive accanto a esso i metadati del modello come sidecar JSON.

Flag
export(format="tensorrt")
Scrive
Un file .engine più un sidecar di metadati .engine.json
Extra
pip install "libreyolo[onnx,tensorrt]"
Si ricarica con
LibreYOLO("weights/LibreYOLO9t.engine")
Forme
Statiche per default; dynamic=True aggiunge un profilo di ottimizzazione sull'asse del batch
Precisione
FP32, FP16 (half=True), INT8 (int8=True con data=)
Richiede
Una GPU NVIDIA sia quando costruisci sia quando esegui. Gli engine non si spostano tra architetture di GPU.

Installazione

Sia la build sia l'esecuzione richiedono una GPU NVIDIA con uno stack CUDA funzionante. Per questo formato non esiste un ripiego su CPU.

Installazione
# L'engine viene costruito da un ONNX intermedio, quindi servono entrambi gli extra.pip install "libreyolo[onnx,tensorrt]"
Verificare la toolchain prima di costruire
python -c "import tensorrt, torch; print(tensorrt.__version__, torch.cuda.is_available())"

L'extra tensorrt fissa tensorrt-cu12 e pycuda, e il marker esclude entrambi su macOS. Su una Jetson non usare quell'extra: fissa una build per CUDA 12 su una piattaforma CUDA 13. Usa invece il TensorRT che installa JetPack, come descritto in NVIDIA Jetson.

Esportazione

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9t.pt") # Scrive weights/LibreYOLO9t_fp16.engine e weights/LibreYOLO9t_fp16.engine.jsonpath = model.export(format="tensorrt", half=True)print(path)
CLI
libreyolo export --model LibreYOLO9t.pt --format tensorrt --half
Argomenti
model.export(    format="tensorrt",    imgsz=640,    batch=1,    half=False,    int8=False,    data=None,                      # obbligatorio quando int8=True    dynamic=False,    workspace=4.0,                  # GiB di memoria di lavoro per la build    min_batch=1,                    # limiti del profilo dinamico    opt_batch=1,    max_batch=8,    hardware_compatibility="none",  # oppure "ampere_plus"    gpu_device=0,                   # dispositivo di build su un host multi-GPU    verbose=False,)

L'esportazione avviene in due passi. Il primo scrive un ONNX intermedio in un percorso temporaneo, il secondo lo analizza e costruisce l'engine, e alla fine l'intermedio viene rimosso. workspace è la memoria di lavoro in GiB usata durante la build; un valore più alto permette al builder di provare più kernel e non incide sulla memoria di inferenza.

Il sidecar dei metadati viene scritto accanto all'engine come <engine>.json e registra la precisione che la build ha realizzato davvero. Quando la GPU non ha FP16 veloce o INT8 veloce il builder avvisa e ripiega, e il sidecar riporta la precisione che è uscita, non quella che era stata chiesta.

In FP16 un backbone ViT presente nel grafo viene riconosciuto e i suoi layer float vengono fissati a FP32. I backbone in stile DINOv2 vanno in overflow in FP16 e producono NaN, quindi la build imposta OBEY_PRECISION_CONSTRAINTS e riporta FP16 (FP32 ViT backbone). Sui backbone CNN questa passata non fa nulla.

Batch dinamico

Engine a batch dinamico
from libreyolo import LibreYOLO # L'ONNX intermedio deve avere l'asse del batch dinamico, altrimenti il# profilo non ha nulla a cui agganciarsi.LibreYOLO("LibreYOLO9t.pt").export(    format="tensorrt",    dynamic=True,    min_batch=1,    opt_batch=4,    max_batch=8,    half=True,)

dynamic=True aggiunge un profilo di ottimizzazione che va da min_batch a max_batch, ottimizzato a opt_batch, e registra quei tre valori nel sidecar. Il profilo viene aggiunto solo quando l'ONNX intermedio porta davvero una dimensione di batch dinamica; altrimenti la build scrive nel log che sta usando l'ottimizzazione statica e prosegue.

INT8

INT8 con dati di calibrazione
from libreyolo import LibreYOLO LibreYOLO("LibreYOLO9t.pt").export(    format="tensorrt",    int8=True,    data="coco128.yaml",   # obbligatorio: per questo formato non c'è un valore predefinito    fraction=1.0,)

INT8 usa il calibratore a entropia di TensorRT su un loader di calibrazione LibreYOLO, e data è obbligatorio: questo formato non ha un ripiego a otto immagini. La calibrazione richiede cuda-python o pycuda per il buffer sul dispositivo. La cache di calibrazione è indicizzata su un hash dei byte ONNX, così le scale di un modello non vengono mai riusate per un altro che per caso scrive sullo stesso percorso di output.

half=True e int8=True insieme producono un avviso e costruiscono in INT8, che mantiene un ripiego FP16 per i layer che TensorRT non riesce a quantizzare.

Eseguire l'artefatto

Tramite LibreYOLO
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("weights/LibreYOLO9t_fp16.engine")result = model.predict(SAMPLE_IMAGE)print(result.boxes.xyxy[:3])
TensorRT puro
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)) # I nomi delle classi, il task e la dimensione di input stanno nel sidecar, non nell'engine.# Qui l'allocazione dei buffer, il preprocessing e il postprocessing sono a tuo carico.print(json.load(open(path + ".json"))["names"])

LibreYOLO() si regola sul suffisso .engine, legge dal sidecar i nomi delle classi, il task e lo schema della posa, e restituisce lo stesso oggetto Results del checkpoint. Solleva subito un errore quando non è presente nessun dispositivo CUDA.

Il secondo snippet è il percorso a runtime puro. L'allocazione dei buffer su host e su dispositivo, il preprocessing, il decoding, l'NMS e il riscalamento delle coordinate diventano tutti a tuo carico, e l'engine di per sé non porta i nomi delle classi, quindi il sidecar deve viaggiare insieme a esso.

Vincoli

Un engine serializzato è legato all'architettura della GPU, allo stack dei driver e alla versione di TensorRT che lo ha costruito. Un engine costruito su una workstation non si carica su un'architettura diversa, ed è per questo che il passo di build gira sulla macchina di deployment. hardware_compatibility="ampere_plus" cede un po' di prestazioni in cambio della portabilità su Ampere e successive. Il valore "same_compute_capability" corrisponde a NONE e produce un avviso: l'engine è ottimizzato solo per la GPU corrente, e l'esportazione lo dice invece di rivendicare una portabilità che non ha applicato.

Viene profilato solo l'asse del batch. Una build con dimensioni spaziali dinamiche non fa parte di questo contratto, ed è per questo che FCOS è bloccato: gli servono altezza e larghezza dinamiche con padding per preservare la sua trasformazione di aspetto 800 per 1333.

Bloccati prima del tracing: la segmentazione YOLO9, la segmentazione RTMDet-Ins, SSD, il rilevamento con Faster R-CNN e RetinaNet, e il matting con BiRefNet o FeyNobg, dove TensorRT 10.16 arriva al nodo ONNX condiviso DeformConv e non riesce ad analizzarlo perché ModulatedDeformConv2d non è presente nel registro dei plugin.

Quando una combinazione non è né validata né bloccata, il percorso del converter è disponibile e il progetto non ha registrato una parità di runtime TensorRT per essa. È un'affermazione sulle prove disponibili, non sul fatto che la build riesca.

Per la griglia completa di famiglie e task, vedi la matrice di esportazione. Per una sola combinazione:

Controllare una famiglia e un task prima di costruire
libreyolo formats --family yolo9 --task detect

Letto da libreyolo/export/tensorrt.py, libreyolo/export/exporter.py, libreyolo/export/support.py, libreyolo/backends/tensorrt.py e pyproject.toml sul branch dev.