ncnn
ncnn to biblioteka Tencent do inferencji na CPU, przeznaczona na urządzenia mobilne. LibreYOLO konwertuje przez PNNX, zapisując graf model.ncnn.param obok pliku wag model.ncnn.bin oraz plik metadata.yaml, który niesie rodzinę, zadanie i nazwy klas.
- Flaga
export(format="ncnn")- Zapisuje
- Katalog z plikami model.ncnn.param, model.ncnn.bin i metadata.yaml
- Dodatkowo
pip install "libreyolo[ncnn]"- Wczytywanie z powrotem
LibreYOLO("weights/LibreYOLO9t_ncnn")- Kształty
- Stałe. Metadane zapisują dynamic=False niezależnie od flagi.
- Precyzja
- Tylko FP32. half=True i int8=True są odrzucane.
Instalacja
# pnnx konwertuje, ncnn uruchamia wynik.pip install "libreyolo[ncnn]"Ten extra instaluje obie połowy toolchainu: pnnx wykonuje konwersję, a ncnn
uruchamia wynik. Na ścieżce podstawowej żadne z nich nie przechodzi przez ONNX.
Eksport
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9t.pt") # Zapisuje katalog weights/LibreYOLO9t_ncnnpath = model.export(format="ncnn", imgsz=640)print(path)libreyolo export --model LibreYOLO9t.pt --format ncnn --imgsz 640model.export( format="ncnn", imgsz=640, # int lub (wysokość, szerokość) batch=1, simplify=True, # dotyczy wyłącznie zapasowej ścieżki przez ONNX opset=None, # auto; dotyczy wyłącznie zapasowej ścieżki przez ONNX output_path=None, # None zapisuje weights/<stem>_ncnn) # half=True i int8=True są odrzucane podczas walidacji.Artefaktem jest katalog. weights/LibreYOLO9t_ncnn zawiera
model.ncnn.param, model.ncnn.bin i metadata.yaml; wszystkie trzy pliki to
jeden artefakt i przenosi się je razem.
Konwersja najpierw próbuje użyć PNNX bezpośrednio z modelu PyTorch. Jeśli to się
nie uda, eksportuje statyczny graf ONNX do katalogu tymczasowego i wywołuje na nim
narzędzie wiersza poleceń pnnx, a błąd jest zgłaszany dopiero wtedy, gdy zawiodą
obie ścieżki, z opisem obu błędów. Dlatego opset i simplify wpływają wyłącznie
na ścieżkę zapasową.
YOLOX wymaga jednego przepisania, aby konwersja w ogóle się powiodła. Jego warstwa
Focus korzysta z krokowego wycinania, którego PNNX nie potrafi odwzorować, więc
eksport zamienia ją na pixel_unshuffle i permutuje kanały wejściowe następnej
konwolucji, aby skompensować inną kolejność kanałów. Wynik jest numerycznie
identyczny, a oryginalne wagi są przywracane po eksporcie.
Uruchamianie artefaktu
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("weights/LibreYOLO9t_ncnn")result = model.predict(SAMPLE_IMAGE)print(result.boxes.xyxy[:3])import ncnnimport numpy as npimport yaml directory = "weights/LibreYOLO9t_ncnn"net = ncnn.Net()net.load_param(f"{directory}/model.ncnn.param")net.load_model(f"{directory}/model.ncnn.bin") # ncnn przyjmuje pojedynczy obraz CHW, a nie batch.mat_in = ncnn.Mat(np.zeros((3, 640, 640), dtype=np.float32))extractor = net.create_extractor()extractor.input("in0", mat_in)ret, mat_out = extractor.extract("out0")print(ret, np.array(mat_out).shape) meta = yaml.safe_load(open(f"{directory}/metadata.yaml"))print(meta["model_family"], meta["task"], meta["names"]) # Wstępne i końcowe przetwarzanie są na tej ścieżce po stronie użytkownika.LibreYOLO() rozpoznaje każdy katalog zawierający model.ncnn.param i
model.ncnn.bin, odczytuje metadata.yaml i zwraca ten sam obiekt Results co
checkpoint.
Drugi fragment kodu to ścieżka samego środowiska uruchomieniowego i dwa szczegóły
odróżniają ją od każdego innego formatu tutaj. ncnn pracuje na pojedynczym obrazie
CHW, a nie na batchu, więc nie ma wiodącej osi batcha. Nazwy blobów pochodzą z
pliku .param; PNNX zapisuje umownie in0 i out0, a backend parsuje ten plik,
zamiast je zakładać. Wstępne przetwarzanie, dekodowanie, NMS i przeskalowanie
współrzędnych są na tej ścieżce po stronie użytkownika.
Ograniczenia
FP32 na stałym płótnie. half=True i int8=True są odrzucane podczas walidacji,
a wyeksportowane metadane zapisują dynamic=False niezależnie od tego, co mówiła
flaga, więc żaden backend nie zakłada osi, której graf nie ma.
Każda rodzina w stylu DETR jest odrzucana w preflight: detr, deformable_detr,
dinodetr, dfine, lwdetr, deim, deimv2, rtdetr, rtdetrv2, rtdetrv4,
rfdetr i ec. Komunikat jest dla wszystkich taki sam, że model wymaga operacji
dekodera lub próbkowania niedostępnych w ncnn, i wskazuje w zamian ONNX, OpenVINO,
TorchScript lub TensorRT.
To, co się konwertuje, jest szerokie po stronie sieci konwolucyjnych: YOLO9 i YOLO9-E2E, YOLOX, PicoDet, detekcja i estymacja pozy w YOLO-NAS, starsze detektory YOLO1, YOLO3, YOLO4 i YOLO7, cztery rodziny klasyfikacyjne CNN, segmentacja semantyczna PIDNet, detekcja punktowa FOMO w stałym rozmiarze 96 na 96, ZipDepth, NAFNet i Real-ESRGAN.
Zablokowane pozycje wskazują konkretną przyczynę niepowodzenia. Grafy
transformerowe zwykle zostawiają nieobsługiwane węzły pnnx.Expression, co daje
sieć bez uruchamialnego bloba wejściowego, i właśnie to zatrzymuje DINOv2, CLIP,
SigLIP2 oraz SegFormer. BiRefNet wymaga deformowalnej konwolucji z torchvision,
której PNNX nie potrafi odwzorować. Przekonwertowany graf YOLO2 kończy działanie
środowiska uruchomieniowego ncnn w systemie Windows natywnym dzieleniem
całkowitym przez zero podczas pobierania wyjścia.
Pełną siatkę rodzin i zadań zawiera macierz eksportu. Dla jednej kombinacji:
libreyolo formats --family yolo9 --task detect