ncnn

ncnn è la libreria di inferenza su CPU di Tencent per i target mobile. LibreYOLO converte tramite PNNX, scrivendo un grafo model.ncnn.param accanto a un file di pesi model.ncnn.bin e a un metadata.yaml che porta con sé la famiglia, il task e i nomi delle classi.

Flag
export(format="ncnn")
Scrive
Una directory con model.ncnn.param, model.ncnn.bin e metadata.yaml
Extra
pip install "libreyolo[ncnn]"
Si ricarica con
LibreYOLO("weights/LibreYOLO9t_ncnn")
Forme
Fisse. I metadati registrano dynamic=False indipendentemente dal flag.
Precisione
Solo FP32. half=True e int8=True vengono rifiutati.

Installazione

Installazione
# pnnx converte, ncnn esegue il risultato.pip install "libreyolo[ncnn]"

L'extra installa entrambe le metà della toolchain: pnnx effettua la conversione e ncnn esegue il risultato. Nessuna delle due passa per ONNX sul percorso principale.

Esportazione

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9t.pt") # Scrive la directory weights/LibreYOLO9t_ncnnpath = model.export(format="ncnn", imgsz=640)print(path)
CLI
libreyolo export --model LibreYOLO9t.pt --format ncnn --imgsz 640
Argomenti
model.export(    format="ncnn",    imgsz=640,        # int, oppure (altezza, larghezza)    batch=1,    simplify=True,    # si applica solo al percorso di fallback ONNX    opset=None,       # automatico; si applica solo al percorso di fallback ONNX    output_path=None, # None scrive weights/<stem>_ncnn) # half=True e int8=True vengono rifiutati durante la validazione.

L'artefatto è una directory. weights/LibreYOLO9t_ncnn contiene model.ncnn.param, model.ncnn.bin e metadata.yaml; tutti e tre sono un unico artefatto e si spostano insieme.

La conversione prova prima PNNX direttamente da PyTorch. Se fallisce, esporta un grafo ONNX statico in una directory temporanea e ci lancia sopra il tool da riga di comando pnnx, e l'esportazione solleva un errore solo quando falliscono entrambi i percorsi, riportando i due errori. opset e simplify quindi influiscono solo sul fallback.

YOLOX ha bisogno di una riscrittura per potersi convertire. Il suo layer Focus usa slicing con stride, che PNNX non riesce ad abbassare di livello, quindi l'esportazione lo sostituisce con pixel_unshuffle e permuta i canali di ingresso della convoluzione successiva per compensare il diverso ordinamento dei canali. L'output è numericamente identico, e i pesi originali vengono ripristinati dopo l'esportazione.

Eseguire l'artefatto

Tramite LibreYOLO
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("weights/LibreYOLO9t_ncnn")result = model.predict(SAMPLE_IMAGE)print(result.boxes.xyxy[:3])
ncnn puro
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 accetta una singola immagine CHW, non un 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"]) # Il preprocessing e il postprocessing sono a tuo carico su questo percorso.

LibreYOLO() riconosce qualsiasi directory che contenga model.ncnn.param e model.ncnn.bin, legge metadata.yaml e restituisce lo stesso oggetto Results del checkpoint.

Il secondo snippet è il percorso a runtime puro, e due dettagli differiscono da ogni altro formato qui presente. ncnn lavora su una singola immagine CHW anziché su un batch, quindi non c'è un asse di batch iniziale. I nomi dei blob arrivano dal file .param; PNNX scrive in0 e out0 per convenzione, e il backend fa il parsing del file invece di darli per scontati. Preprocessing, decodifica, NMS e riscalatura delle coordinate sono a tuo carico su quel percorso.

Vincoli

FP32 su un canvas fisso. half=True e int8=True vengono entrambi rifiutati durante la validazione, e i metadati esportati registrano dynamic=False qualunque cosa dicesse il flag, così nessun backend assume un asse che il grafo non ha.

Ogni famiglia in stile DETR viene rifiutata in preflight: detr, deformable_detr, dinodetr, dfine, lwdetr, deim, deimv2, rtdetr, rtdetrv2, rtdetrv4, rfdetr e ec. Il messaggio è lo stesso per tutte: il modello ha bisogno di operazioni di decoder o di sampling non disponibili in ncnn, e punta invece a ONNX, OpenVINO, TorchScript o TensorRT.

Quello che si converte è ampio sul fronte convoluzionale: YOLO9 e YOLO9-E2E, YOLOX, PicoDet, YOLO-NAS in rilevamento e posa, i più vecchi detector YOLO1, YOLO3, YOLO4 e YOLO7, le quattro famiglie di classificazione CNN, la segmentazione semantica PIDNet, il rilevamento di punti FOMO a 96 per 96 fissi, ZipDepth, NAFNet e Real-ESRGAN.

Le voci bloccate nominano il fallimento concreto. I grafi transformer di solito lasciano dietro di sé nodi pnnx.Expression non supportati, il che produce una rete senza blob di input eseguibile, ed è questo che ferma DINOv2, CLIP, SigLIP2 e SegFormer. BiRefNet richiede la convoluzione deformabile di torchvision, che PNNX non riesce ad abbassare di livello. Il grafo convertito di YOLO2 termina il runtime di ncnn su Windows con una divisione intera per zero nativa durante l'estrazione dell'output.

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

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

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