MNN

MNN é o motor de inferência leve da Alibaba. O LibreYOLO exporta um grafo ONNX estático, converte esse grafo com a ferramenta mnnconvert que vem no pacote MNN e escreve um sidecar JSON registrando os nomes de entrada e de saída, a forma de entrada fixa e os nomes das classes.

Flag
export(format="mnn")
Escreve
Um arquivo .mnn mais um sidecar de metadados .mnn.json
Extra
pip install "libreyolo[mnn]"
Recarrega com
LibreYOLO("weights/LibreYOLO9t.mnn")
Formas
NCHW fixa. dynamic=True é rejeitado.
Precisão
Somente FP32, somente CPU.
Tarefas
Somente detecção nesta versão

Instalação

Instalação
# O extra inclui libreyolo[onnx]: o MNN converte a partir de um intermediário ONNX.pip install "libreyolo[mnn]"
Confirmar que o conversor está no path
mnnconvert --version

O extra inclui libreyolo[onnx], porque a conversão roda sobre um intermediário ONNX. Ele também traz o executável mnnconvert, que o exportador procura primeiro ao lado do interpretador Python ativo e depois no PATH. Um conversor ausente levanta um ImportError que nomeia o comando de instalação, em vez de falhar no meio da conversão.

Exportação

Python
from libreyolo import LibreYOLO model = LibreYOLO("LibreYOLO9t.pt") # Escreve weights/LibreYOLO9t.mnn e weights/LibreYOLO9t.mnn.jsonpath = model.export(format="mnn", imgsz=640)print(path)
CLI
libreyolo export --model LibreYOLO9t.pt --format mnn --imgsz 640
Argumentos
model.export(    format="mnn",    imgsz=640,        # int, ou (altura, largura)    batch=1,          # embutido no artefato    simplify=True,    # onnxsim sobre o intermediário ONNX    output_path=None, # None escreve weights/<stem>.mnn    verbose=False,    # True exibe o log do mnnconvert) # dynamic=True levanta ValueError. half=True e int8=True são rejeitados.

Antes de entregar o grafo, o exportador lê o contrato de entrada do ONNX e recusa qualquer coisa que não consiga expressar: mais de uma entrada de imagem, ou uma forma de entrada com uma dimensão simbólica. O MNN nesta versão exige uma forma NCHW totalmente fixa, e o batch fica embutido no artefato em vez de ser negociado na hora do carregamento.

O sidecar não é burocracia opcional. weights/LibreYOLO9t.mnn.json registra os nomes de entrada e de saída, a forma de entrada fixa, o batch, os nomes das classes, a versão do MNN usada e o backend para o qual o artefato foi construído, e o runtime valida cada um desses campos no carregamento.

No Windows, o MNN 3.6.1 às vezes conclui a conversão e depois encerra durante o desmonte do processo com uma violação de acesso ou um status de fail-fast. O exportador reconhece esses códigos de saída específicos e trata a conversão como bem-sucedida quando o arquivo de saída está presente.

Rodar o artefato

Pelo LibreYOLO
from libreyolo import LibreYOLO, SAMPLE_IMAGE model = LibreYOLO("weights/LibreYOLO9t.mnn")result = model.predict(SAMPLE_IMAGE)print(result.boxes.xyxy[:3])
MNN puro
import json import MNNimport numpy as np meta = json.load(open("weights/LibreYOLO9t.mnn.json"))print(meta["mnn_input_names"], meta["mnn_output_names"], meta["mnn_input_shape"]) runtime = MNN.nn.create_runtime_manager(    ({"backend": 0, "precision": 1, "numThread": 4},))module = MNN.nn.load_module_from_file(    "weights/LibreYOLO9t.mnn",    meta["mnn_input_names"],    meta["mnn_output_names"],    runtime_manager=runtime,    dynamic=False,    shape_mutable=False,) blob = np.zeros(meta["mnn_input_shape"], dtype=np.float32)input_var = MNN.expr.const(    blob, list(blob.shape), MNN.expr.NCHW, MNN.expr.float)outputs = module.forward([input_var])for out in outputs:    print(np.array(MNN.expr.convert(out, MNN.expr.NCHW).read()).shape) # O pré-processamento e o pós-processamento são por sua conta nesse caminho.

LibreYOLO() despacha pelo sufixo .mnn e devolve o mesmo objeto Results que o checkpoint. O carregamento é estrito por design: o sidecar tem que declarar format=mnn, mnn_backend=cpu, dynamic=false, precision=fp32, um tamanho, uma tarefa de detecção, uma forma NCHW fixa e positiva que concorde com o tamanho de imagem registrado, e nomes de classes cobrindo todo índice de 0 a nc - 1. Qualquer divergência levanta um erro em vez de adivinhar.

Predizer com um imgsz diferente daquele para o qual o artefato foi construído também levanta erro, e device é ignorado com um aviso, porque as exportações MNN rodam na CPU aqui.

O segundo snippet é o caminho do runtime puro. O pré-processamento, a decodificação, o NMS e o reescalonamento de coordenadas passam a ser por sua conta ali, e os nomes de entrada e de saída vêm do sidecar porque o carregador de módulos do MNN os quer explicitamente.

Restrições

Somente detecção. O backend recusa qualquer outra tarefa no carregamento, e o lado da exportação acompanha: fora das combinações registradas, a verificação prévia levanta um erro com "MNN v1 has no implemented runtime contract for this family and task."

FP32, CPU, forma fixa. dynamic=True levanta ValueError, e half=True e int8=True são rejeitados durante a validação.

As famílias de detecção validadas são YOLO9, YOLO9-E2E, YOLO9-P2, RF-DETR, EC, RT-DETR, RT-DETRv2, RT-DETRv4, D-FINE, DEIM e YOLO-NAS, cada uma coberta por conversão, recarga de um artefato novo, execução em CPU pelo MNN, checagem de metadados e paridade de detecções pós-NMS batendo com o modelo PyTorch. O DEIMv2 converte, recarrega, executa e preserva as detecções pós-NMS, mas sua rota intermediária em ONNX tem paridade de scores em nível de query incompleta, então ele é registrado como disponível e não como validado.

Para a grade completa de famílias e tarefas, veja a matriz de exportação. Para uma combinação:

Conferir uma família e uma tarefa antes de exportar
libreyolo formats --family yolo9 --task detect

Lido de libreyolo/export/mnn.py, libreyolo/export/exporter.py, libreyolo/export/support.py, libreyolo/backends/mnn.py e pyproject.toml no branch dev.