ONNX

ONNX to przenośny format grafu. LibreYOLO trasuje model przez torch.onnx.export, opcjonalnie upraszcza graf i zapisuje rodzinę, zadanie, nazwy klas oraz rozmiar wejścia w metadanych samego pliku, dzięki czemu każdy backend LibreYOLO potrafi odtworzyć postprocessing.

Flaga
export(format="onnx")
Zapisuje
Jeden plik .onnx, metadane osadzone w grafie
Dodatkowo
pip install "libreyolo[onnx]"
Wczytywanie z powrotem
LibreYOLO("weights/LibreYOLO9t.onnx")
Kształty
Domyślnie dynamiczny batch w Pythonie; wyjątki dla poszczególnych zadań poniżej
Precyzja
FP32, FP16 (half=True), INT8 (int8=True, detekcja w YOLO9)

Instalacja

Instalacja
pip install "libreyolo[onnx]"

Dodatek instaluje onnx, onnxsim i onnxruntime. Sam onnx wystarczy, aby zapisać plik; onnxsim wykonuje przebieg upraszczania, a onnxruntime uruchamia artefakt i przeprowadza kalibrację INT8.

Eksport

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9t.pt") # Zapisuje weights/LibreYOLO9t.onnxpath = model.export(format="onnx")print(path)
CLI
libreyolo export --model LibreYOLO9t.pt --format onnx
Argumenty
model.export(    format="onnx",    imgsz=640,        # int albo (wysokość, szerokość)    batch=1,    dynamic=True,     # domyślne w Pythonie; w CLI domyślnie False    simplify=True,    # uruchamia onnxsim na grafie    opset=None,       # None wybiera 13 albo 17 dla rodzin w stylu DETR    half=False,       # wagi i aktywacje w FP16    int8=False,       # QDQ INT8, tylko detekcja w YOLO9    data=None,        # data.yaml do kalibracji, tylko INT8    device=None,      # urządzenie trasowania; None bierze urządzenie modelu    output_path=None, # None zapisuje weights/<stem>.onnx)

Bez output_path plik trafia do weights/ pod rdzeniem nazwy checkpointu, z dopisanym _fp16 lub _int8, gdy zażądano tej precyzji.

dynamic ma domyślnie wartość True w Pythonie i False w CLI. Gdy jest włączone, oś batcha staje się symboliczna, a kilka zadań otwiera się jeszcze szerzej: segmentacja semantyczna otwiera dodatkowo wysokość i szerokość maski, restauracja w Real-ESRGAN otwiera osie przestrzenne, a detektory dwuetapowe zachowują dynamiczną wysokość i szerokość źródła, ponieważ ich skalowanie odbywa się wewnątrz grafu.

opset jest przy pominięciu wybierany osobno dla każdej rodziny. Rodziny w stylu DETR (detr, deformable_detr, dinodetr, dfine, deim, deimv2, ec, lwdetr, rfdetr, rtdetr, rtdetrv2, rtdetrv4) oraz deit, midas i moge2 dostają opset 17, bo dopiero tam aten::scaled_dot_product ma swoje odwzorowanie. Reszta dostaje 13. Matting jest niezależnie od tego podnoszony do 19, ponieważ dekoder w BiRefNet potrzebuje operatora DeformConv, który ONNX definiuje od opsetu 19.

simplify=True uruchamia onnxsim i zachowuje pierwotny graf, jeśli przebieg się nie powiedzie, więc błąd upraszczania jest ostrzeżeniem, a nie niepowodzeniem eksportu. Na macOS arm64 z onnx w wersji 1.22 lub nowszej i onnxsim w wersji 0.6.5 lub starszej przebieg jest pomijany w całości, ponieważ to zestawienie może przerwać proces Pythona.

Wbudowany NMS

Wbudowanie NMS w graf
from libreyolo import LibreYOLO # Tylko detekcja w YOLO9, batch 1. dynamic jest wymuszane na False.LibreYOLO("LibreYOLO9t.pt").export(    format="onnx",    nms=True,    conf=0.25,    iou=0.45,    max_det=300,)
CLI
libreyolo export --model LibreYOLO9t.pt --format onnx --nms \  --conf 0.25 --iou 0.45 --max-det 300

nms=True dotyczy wyłącznie detekcji w YOLO9 i wymaga batcha 1; zażądanie go razem z dynamic=True zapisuje ostrzeżenie i wyłącza tryb dynamiczny. Graf ma wtedy dwa wyjścia: output o kształcie (batch, max_det, 6) oraz raw, czyli niezdekodowany tensor detektora, którego używa własny backend LibreYOLO, aby postprocessing pozostał identyczny jak na ścieżce PyTorch.

DeepStream

deepstream=True to opcja dostępna wyłącznie dla ONNX. Eksportuje graf w układzie, jakiego oczekuje parser NVIDIA DeepStream, i zapisuje obok dwa pliki towarzyszące, config_infer_primary_<stem>.txt oraz <stem>_labels.txt, dzięki czemu artefakt wchodzi do pipeline'u bez ręcznie pisanej konfiguracji.

Wyklucza się wzajemnie z nms=True, a żądanie obu naraz zgłasza ValueError: DeepStream wykonuje tłumienie we własnym etapie klasteryzacji. Przekazanie tej opcji do formatu innego niż ONNX również zgłasza błąd. Siatkę obsługiwanych rodzin i zadań oraz budowanie parsera opisuje DeepStream.

INT8

INT8 z danymi kalibracyjnymi
from libreyolo import LibreYOLO LibreYOLO("LibreYOLO9t.pt").export(    format="onnx",    int8=True,    data="coco128.yaml",   # kilkaset reprezentatywnych obrazów    fraction=1.0,)

int8=True uruchamia statyczną kwantyzację ONNX Runtime i zapisuje graf QDQ z wejściami i wyjściami w float32. Kwantyzowane są tylko węzły Conv i Gemm. Pozostawienie dekodowania w głowicy detekcji w float32 jest celowe: ta konkatenacja miesza współrzędne ramek w skali pikseli z wynikami klas z zakresu od 0 do 1, a pojedyncza skala aktywacji na tensor, zdominowana przez wielkość ramek, sprowadziłaby każdy wynik do zera.

Ta flaga dotyczy obecnie wyłącznie detekcji w YOLO9, a wszystko inne zgłasza NotImplementedError w preflight. Pominięcie data cofa się do coco8.yaml z ostrzeżeniem; osiem obrazów to nie jest reprezentatywny zbiór kalibracyjny. Model skwantyzowany już w PyTorch idzie inną drogą, opisaną na stronie Kwantyzacja.

Uruchamianie artefaktu

Przez LibreYOLO
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("weights/LibreYOLO9t.onnx")result = model.predict(SAMPLE_IMAGE)print(result.boxes.xyxy[:3])
Samo ONNX Runtime
import numpy as npimport onnximport onnxruntime as ort session = ort.InferenceSession(    "weights/LibreYOLO9t.onnx",    providers=["CPUExecutionProvider"],) # Wstępne przetwarzanie i postprocessing są tu po stronie użytkownika.batch = np.zeros((1, 3, 640, 640), dtype=np.float32)outputs = session.run(None, {session.get_inputs()[0].name: batch})print([out.shape for out in outputs]) # Graf niesie rodzinę, zadanie, nazwy klas i rozmiar wejścia.meta = {p.key: p.value for p in onnx.load("weights/LibreYOLO9t.onnx").metadata_props}print(meta["model_family"], meta["task"], meta["imgsz"])

LibreYOLO() rozpoznaje sufiks .onnx i zwraca ten sam obiekt Results co checkpoint .pt, ponieważ nazwy klas, zadanie, rozmiar wejścia i schemat pozy zostały podczas eksportu zapisane w metadata_props grafu. Przy device="auto" sesja bierze CUDAExecutionProvider, gdy ONNX Runtime go zgłasza, a w przeciwnym razie wraca do CPU.

Drugi fragment kodu jest dla czytelników bez zainstalowanego LibreYOLO. Wstępne przetwarzanie, dekodowanie, NMS i przeskalowanie współrzędnych są na tej ścieżce po stronie użytkownika; blok metadanych nadal można odczytać.

Ograniczenia

Nazwy tensorów wyjściowych są ustalone dla każdego zadania i to do nich musi się dopasować konsument, który nie czyta metadanych:

ZadanieNazwy wyjść
Detekcja, głowice siatkowe i kotwicoweoutput
Detekcja, w stylu DETRpred_logits, pred_boxes
Detekcja, RF-DETRdets, labels
Klasyfikacjaoutput
Segmentacja semantycznasemantic_logits
Głębiadepth
Normalna powierzchninormal
Krawędzieedges
Restauracjarestored
Mattingmatte
Spojrzenieyaw_logits, pitch_logits

RF-DETR jest też jedyną rodziną, której tensor wejściowy nazywa się input, a nie images.

Kilka zadań ma w tej wersji kontrakt środowiska uruchomieniowego o stałej rozdzielczości. Głębia, normalna powierzchni i krawędzie odrzucają batch != 1 i wymuszają dynamic=False. Matting wymusza natywny kwadrat 1024, ponieważ tablice pozycji względnych w Swin z BiRefNet są związane ze swoją rozdzielczością. Restauracja wymusza stałe płótno dla każdej rodziny poza Real-ESRGAN, którego generator jest w pełni konwolucyjny.

Prostokątny imgsz działa dla rodzin YOLO9, HRNet, NAFNet i Real-ESRGAN. Rodziny ze stałym kontraktem kwadratowym (clip, deformable_detr, detr, dinodetr, dfine, deim, deimv2, ec, lwdetr, moge2, rtdetr, rtdetrv2, rtdetrv4, rfdetr, siglip2, ssd) odrzucają go wprost.

Dwie kombinacje są odrzucane przed trasowaniem: segmentacja w YOLO9, ponieważ YOLO9 obsługuje w LibreYOLO tylko detekcję, oraz segmentacja w RTMDet-Ins, której dekodowanie masek z dynamicznymi jądrami nie ma kontraktu dla wyeksportowanego środowiska uruchomieniowego.

Pełną siatkę rodzin i zadań zawiera macierz eksportu. Dla jednej kombinacji można zapytać bibliotekę wprost:

Sprawdzenie jednej rodziny i zadania przed eksportem
libreyolo formats --family yolo9 --task detect

Odczytane z libreyolo/export/onnx.py, libreyolo/export/exporter.py, libreyolo/export/support.py, libreyolo/backends/onnx.py i libreyolo/cli/commands/export.py na gałęzi dev.