ncnn
ncnn es la biblioteca de inferencia en CPU de Tencent para targets móviles. LibreYOLO convierte a través de PNNX, escribiendo un grafo model.ncnn.param junto a un archivo de pesos model.ncnn.bin y un metadata.yaml que lleva la familia, la tarea y los nombres de clase.
- Flag
export(format="ncnn")- Escribe
- Un directorio con model.ncnn.param, model.ncnn.bin y metadata.yaml
- Extra
pip install "libreyolo[ncnn]"- Se recarga con
LibreYOLO("weights/LibreYOLO9t_ncnn")- Formas
- Fijas. Los metadatos registran dynamic=False independientemente del flag.
- Precisión
- Solo FP32. half=True e int8=True se rechazan.
Instalación
# pnnx convierte, ncnn ejecuta el resultado.pip install "libreyolo[ncnn]"El extra trae las dos mitades del toolchain: pnnx realiza la conversión y
ncnn ejecuta el resultado. Ninguna de las dos pasa por ONNX en la ruta principal.
Exportación
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9t.pt") # Escribe el directorio 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, o (alto, ancho) batch=1, simplify=True, # solo se aplica a la ruta de respaldo por ONNX opset=None, # automático; solo se aplica a la ruta de respaldo por ONNX output_path=None, # None escribe weights/<stem>_ncnn) # half=True e int8=True se rechazan durante la validación.El artefacto es un directorio. weights/LibreYOLO9t_ncnn contiene
model.ncnn.param, model.ncnn.bin y metadata.yaml; los tres son un único
artefacto y se mueven juntos.
La conversión intenta primero PNNX directamente desde PyTorch. Si eso falla, exporta
un grafo ONNX estático a un directorio temporal y llama sobre él a la herramienta de
línea de comandos pnnx, y la exportación solo lanza un error cuando fallan ambas
rutas, informando de los dos errores. Por tanto, opset y simplify solo afectan a
la ruta de respaldo.
YOLOX necesita una reescritura para poder convertirse siquiera. Su capa Focus usa
slicing con stride, que PNNX no puede bajar de nivel, así que la exportación la
sustituye por pixel_unshuffle y permuta los canales de entrada de la convolución
siguiente para compensar el distinto orden de canales. La salida es numéricamente
idéntica, y los pesos originales se restauran después de la exportación.
Ejecutar el artefacto
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 toma una única imagen CHW, no 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"]) # El preprocesado y el postprocesado corren de tu cuenta en esta ruta.LibreYOLO() reconoce cualquier directorio que contenga model.ncnn.param y
model.ncnn.bin, lee metadata.yaml y devuelve el mismo objeto Results que el
checkpoint.
El segundo snippet es la ruta del runtime a secas, y hay dos detalles que difieren
de todos los demás formatos aquí. ncnn trabaja sobre una única imagen CHW en lugar
de sobre un batch, así que no hay eje de batch inicial. Los nombres de los blobs
salen del archivo .param; PNNX escribe in0 y out0 por convención, y el backend
parsea el archivo en lugar de darlos por supuestos. El preprocesado, la
decodificación, el NMS y el reescalado de coordenadas corren de tu cuenta en esa
ruta.
Restricciones
FP32 sobre un lienzo fijo. half=True e int8=True se rechazan ambos durante la
validación, y los metadatos exportados registran dynamic=False dijera lo que
dijera el flag, de modo que ningún backend asume un eje que el grafo no tiene.
Todas las familias de tipo DETR se rechazan en el preflight: detr,
deformable_detr, dinodetr, dfine, lwdetr, deim, deimv2, rtdetr,
rtdetrv2, rtdetrv4, rfdetr y ec. El mensaje es el mismo para todas: que el
modelo necesita operaciones de decoder o de sampling no disponibles en ncnn, y
apunta en su lugar a ONNX, OpenVINO, TorchScript o TensorRT.
Lo que sí convierte es amplio por el lado convolucional: YOLO9 y YOLO9-E2E, YOLOX, PicoDet, YOLO-NAS en detección y pose, los detectores más antiguos YOLO1, YOLO3, YOLO4 y YOLO7, las cuatro familias de clasificación CNN, la segmentación semántica PIDNet, la detección de puntos FOMO a 96 por 96 fijos, ZipDepth, NAFNet y Real-ESRGAN.
Las entradas bloqueadas nombran el fallo concreto. Los grafos transformer suelen
dejar atrás nodos pnnx.Expression no soportados, lo que produce una red sin blob
de entrada ejecutable, y eso es lo que detiene a DINOv2, CLIP, SigLIP2 y SegFormer.
BiRefNet necesita la convolución deformable de torchvision, que PNNX no puede bajar
de nivel. El grafo convertido de YOLO2 termina el runtime de ncnn en Windows con una
división entera por cero nativa durante la extracción de la salida.
Para la rejilla completa de familias y tareas, consulta la matriz de exportación. Para una combinación concreta:
libreyolo formats --family yolo9 --task detect