ExecuTorch

ExecuTorch uruchamia programy PyTorch na urządzeniach brzegowych. LibreYOLO przechwytuje model za pomocą torch.export w trybie strict, przeprowadza lowering do XNNPACK i zapisuje program .pte razem z plikiem metadanych JSON jako jedną całość.

Flaga
export(format="executorch")
Zapisuje
Jeden program .pte plus plik metadanych .pte.json
Extra
pip install "libreyolo[executorch]"
Ponowne wczytanie
LibreYOLO("weights/LibreYOLO9t.pte")
Kształty
Stałe. dynamic=True i batch != 1 są odrzucane.
Precyzja
Tylko FP32. half=True i int8=True są odrzucane.
Delegat
XNNPACK, CPU. delegate='xnnpack' to jedyna akceptowana wartość.

Instalacja

Instalacja
# Celowo poza libreyolo[all]: ExecuTorch ogranicza, z którą# wersją Torch może być łączony.pip install "libreyolo[executorch]"

Ten extra celowo znajduje się poza libreyolo[all], ponieważ ExecuTorch przypina wersję Torch, z którą działa, a jego instalacja przeciągnęłaby całe środowisko na tę parę. Zainstaluj go w środowisku, w którym takie ograniczenie jest akceptowalne.

W systemie Windows krok lowering wywołuje plik wykonywalny flatc dostarczany z ExecuTorch. Jeśli nie ma go w PATH, eksport zgłasza RuntimeError z takim komunikatem, a rozwiązaniem jest uruchomienie z Developer PowerShell dla Visual Studio 2022.

Eksport

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9t.pt") # Zapisuje weights/LibreYOLO9t.pte i weights/LibreYOLO9t.pte.jsonpath = model.export(format="executorch", imgsz=640)print(path)
CLI
libreyolo export --model LibreYOLO9t.pt --format executorch --imgsz 640
Argumenty
model.export(    format="executorch",    imgsz=640,             # int lub (wysokość, szerokość)    batch=1,               # każda inna wartość zgłasza ValueError    dynamic=False,         # True zgłasza ValueError    delegate="xnnpack",    # jedyna akceptowana wartość    device="cpu",          # każde inne urządzenie zgłasza ValueError    output_path=None,      # None zapisuje weights/<stem>.pte)

Przechwytywanie odbywa się przez torch.export.export(..., strict=True), czyli rzeczywiste przechwycenie grafu z guardami, a nie zapisany trace. Odczyty skalarów po stronie hosta i przepływ sterowania zależny od danych są odrzucane, zamiast być po cichu wpisywane na stałe, więc kilka rodzin zawodzi w tym miejscu, choć gdzie indziej trace kończy się powodzeniem; przyczyny są zapisane dla każdej kombinacji w macierzy wsparcia.

Krok lowering uruchamia to_edge_transform_and_lower z partitionerem XNNPACK. Jeśli wynik nie zawiera żadnych partycji delegowanych, eksport zgłasza błąd, zamiast oznaczać jako XNNPACK program korzystający wyłącznie z przenośnych kerneli.

Program i sidecar są zapisywane razem. Oba są przygotowywane, oba są podmieniane, a błąd cofa wszystko do poprzedniego stanu, więc niekompletna para nigdy nie trafia na dysk.

Uruchomienie artefaktu

Przez LibreYOLO
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("weights/LibreYOLO9t.pte")result = model.predict(SAMPLE_IMAGE)print(result.boxes.xyxy[:3])
Samo środowisko uruchomieniowe ExecuTorch
import jsonfrom pathlib import Path import torchfrom executorch.runtime import Runtime runtime = Runtime.get()print(runtime.backend_registry.is_available("XnnpackBackend")) program = runtime.load_program(Path("weights/LibreYOLO9t.pte").read_bytes())method = program.load_method("forward") # Na tej ścieżce preprocessing i postprocessing są po stronie użytkownika.outputs = method.execute((torch.zeros(1, 3, 640, 640),))print([tensor.shape for tensor in outputs]) meta = json.load(open("weights/LibreYOLO9t.pte.json"))print(meta["model_family"], meta["task"], meta["executorch_delegate"])

LibreYOLO() rozpoznaje sufiks .pte i zwraca ten sam obiekt Results co checkpoint. Sidecar jest obowiązkowy przy wczytywaniu: bez pliku <program>.pte.json backend zgłasza FileNotFoundError, ponieważ sam program nie niesie nazw klas, zadania ani rozmiaru wejścia. Backend sprawdza też, czy zainstalowane środowisko uruchomieniowe udostępnia XnnpackBackend, zanim zacznie wczytywanie, i czyta program z bajtów zamiast mapować plik, co pozwala uniknąć trzymania blokady pliku w systemie Windows przez cały czas życia backendu.

Drugi snippet to ścieżka przez samo środowisko uruchomieniowe. Preprocessing, dekodowanie, NMS i przeskalowanie współrzędnych są tam po stronie użytkownika.

Ograniczenia

Batch 1, stały kształt, FP32, CPU. Zarówno batch != 1, jak i dynamic=True zgłaszają ValueError, zanim eksport cokolwiek zmieni, half=True i int8=True są odrzucane podczas walidacji, a urządzenie inne niż CPU nie jest przyjmowane.

delegate przyjmuje w tej wersji "xnnpack" i nic więcej.

Eksporty klasyfikacji niosą dwa dodatkowe klucze metadanych, crop_pct i interpolation, dzięki czemu środowisko uruchomieniowe może odtworzyć stosowaną przez daną rodzinę politykę zmiany rozmiaru i przycięcia środka.

Zablokowane pozycje wskazują konkretny błąd, a nie kategorię. Detekcja i segmentacja w D-FINE trafiają na nieobsługiwany odczyt ContextVar w deformowalnej uwadze przy przechwytywaniu w trybie strict, a wymuszenie ręcznej ścieżki grid-sample serializuje się, ale potem zawodzi w czasie działania na nieprawidłowej kolejności wymiarów delegowanego tensora. DEIM i DEIMv2 przechodzą przechwytywanie, lowering i serializację, po czym zawodzą podczas wykonania. Segmentacja semantyczna w EoMT zawodzi na wyrażeniu symbolicznym zależnym od danych w ścieżce masek. Matting w BiRefNet przechwytuje się przy 1024 na 1024, ale nie ma wariantu out dla torchvision::deform_conv2d. Restauracja w SwinIR wczytuje się ponownie, a potem zawodzi w aten::alias_copy.out z powodu niezgodnych kolejności wymiarów.

Pełną siatkę rodzin i zadań zawiera macierz eksportu. Dla jednej kombinacji:

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

Odczytane z libreyolo/export/executorch.py, libreyolo/export/exporter.py, libreyolo/export/support.py, libreyolo/backends/executorch.py i pyproject.toml na gałęzi dev.