ncnn
ncnn é a biblioteca de inferência em CPU da Tencent para alvos móveis. O LibreYOLO converte através do PNNX, escrevendo um grafo model.ncnn.param ao lado de um arquivo de pesos model.ncnn.bin e de um metadata.yaml que carrega a família, a tarefa e os nomes das classes.
- Flag
export(format="ncnn")- Escreve
- Um diretório com model.ncnn.param, model.ncnn.bin e metadata.yaml
- Extra
pip install "libreyolo[ncnn]"- Recarrega com
LibreYOLO("weights/LibreYOLO9t_ncnn")- Formas
- Fixas. Os metadados registram dynamic=False independentemente da flag.
- Precisão
- Somente FP32. half=True e int8=True são rejeitados.
Instalação
# O pnnx converte, o ncnn roda o resultado.pip install "libreyolo[ncnn]"O extra instala as duas metades do toolchain: o pnnx faz a conversão e o ncnn
executa o resultado. Nenhum dos dois passa por ONNX no caminho principal.
Exportação
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9t.pt") # Escreve o diretório 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, ou (altura, largura) batch=1, simplify=True, # vale só para o caminho de fallback via ONNX opset=None, # automático; vale só para o caminho de fallback via ONNX output_path=None, # None escreve weights/<stem>_ncnn) # half=True e int8=True são rejeitados durante a validação.O artefato é um diretório. weights/LibreYOLO9t_ncnn contém
model.ncnn.param, model.ncnn.bin e metadata.yaml; os três são um único
artefato e andam juntos.
A conversão tenta o PNNX direto a partir do PyTorch primeiro. Se isso falhar, ela
exporta um grafo ONNX estático para um diretório temporário e chama a ferramenta de
linha de comando pnnx sobre ele, e a exportação só levanta erro quando os dois
caminhos falham, reportando os dois erros. Portanto, opset e simplify afetam
apenas o fallback.
O YOLOX precisa de uma reescrita para sequer converter. Sua camada Focus usa
fatiamento com stride, que o PNNX não consegue rebaixar, então a exportação a troca
por pixel_unshuffle e permuta os canais de entrada da convolução seguinte para
compensar a ordenação diferente dos canais. A saída é numericamente idêntica, e os
pesos originais são restaurados depois da exportação.
Rodar o artefato
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") # O ncnn recebe uma única imagem CHW, não um 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"]) # O pré-processamento e o pós-processamento são por sua conta neste caminho.O LibreYOLO() reconhece qualquer diretório que contenha model.ncnn.param e
model.ncnn.bin, lê o metadata.yaml e devolve o mesmo objeto Results que o
checkpoint.
O segundo snippet é o caminho de runtime puro, e dois detalhes diferem de todos os
outros formatos aqui. O ncnn trabalha sobre uma única imagem CHW em vez de um batch,
então não há eixo de batch na frente. Os nomes dos blobs vêm do arquivo .param; o
PNNX escreve in0 e out0 por convenção, e o backend faz o parse do arquivo em vez
de assumi-los. Nesse caminho, o pré-processamento, a decodificação, o NMS e o
reescalonamento de coordenadas são por sua conta.
Restrições
FP32 em um canvas fixo. half=True e int8=True são ambos rejeitados durante a
validação, e os metadados exportados registram dynamic=False independentemente do
que a flag dizia, para que nenhum backend assuma um eixo que o grafo não tem.
Toda família no estilo DETR é recusada no preflight: detr, deformable_detr,
dinodetr, dfine, lwdetr, deim, deimv2, rtdetr, rtdetrv2, rtdetrv4,
rfdetr e ec. A mensagem é a mesma para todas elas, dizendo que o modelo precisa
de operações de decoder ou de amostragem indisponíveis no ncnn, e apontando para
ONNX, OpenVINO, TorchScript ou TensorRT no lugar.
O que converte é amplo do lado convolucional: YOLO9 e YOLO9-E2E, YOLOX, PicoDet, YOLO-NAS detecção e pose, os detectores mais antigos YOLO1, YOLO3, YOLO4 e YOLO7, as quatro famílias de classificação CNN, a segmentação semântica PIDNet, a detecção de pontos FOMO em 96 por 96 fixos, ZipDepth, NAFNet e Real-ESRGAN.
As entradas bloqueadas nomeiam a falha concreta. Grafos de transformer costumam
deixar para trás nós pnnx.Expression não suportados, o que produz uma rede sem
blob de entrada executável, e é isso que barra DINOv2, CLIP, SigLIP2 e SegFormer. O
BiRefNet precisa da convolução deformável do torchvision, que o PNNX não consegue
rebaixar. O grafo convertido do YOLO2 encerra o runtime do ncnn no Windows com uma
divisão inteira por zero nativa durante a extração da saída.
Para a grade completa de famílias e tarefas, veja a matriz de exportação. Para uma combinação:
libreyolo formats --family yolo9 --task detect