YOLO Vision 2026:

Como exportar modelos PyTorch não-YOLO com Ultralytics#

A Ultralytics disponibiliza utilitários de exportação independentes em ultralytics.utils.export que encapsulam vários backends sob uma única interface consistente. Podes exportar qualquer torch.nn.Module, incluindo modelos de imagem timm, classificadores e detetores torchvision, ou as tuas próprias arquiteturas personalizadas, para ONNX, TorchScript, OpenVINO, CoreML, NCNN, PaddlePaddle, MNN, ExecuTorch e TensorFlow SavedModel sem precisares de aprender cada backend separadamente.

Implementar modelos PyTorch em produção significa habitualmente gerir um exportador diferente para cada destino: torch.onnx.export para ONNX, coremltools para dispositivos Apple, onnx2tf para TensorFlow, pnnx para NCNN, e assim por diante. Cada ferramenta tem a sua própria API, peculiaridades de dependências e convenções de saída. Estes utilitários consolidam tudo isto num único padrão de chamada.

Por que usar a Ultralytics para exportação não-YOLO?#

  • Uma única API para 10 formatos: aprenda uma única convenção de chamada em vez de uma dúzia.
  • Superfície de utilitários partilhados: os assistentes de exportação encontram-se em ultralytics.utils.export, por isso, assim que os pacotes do backend estiverem instalados, podes manter o mesmo padrão de chamada em todos os formatos.
  • Mesmo caminho de código das exportações YOLO: os mesmos auxiliares impulsionam todas as exportações Ultralytics YOLO.
  • Quantização FP16 e INT8 integrada para formatos que a suportam (OpenVINO, CoreML, MNN, NCNN).
  • Funciona na CPU: nenhuma GPU é necessária para a etapa de exportação em si, então você pode executá-la localmente em qualquer laptop.

Início Rápido#

O caminho mais rápido é uma exportação de duas linhas para ONNX sem código YOLO e sem nenhuma configuração para além de pip install ultralytics onnx timm:

import timm
import torch

from ultralytics.utils.export import torch2onnx

model = timm.create_model("resnet18", pretrained=True).eval()
torch2onnx(model, torch.randn(1, 3, 224, 224), output_file="resnet18.onnx")

Formatos de Exportação Suportados#

As funções torch2* aceitam um torch.nn.Module padrão e um tensor de entrada de exemplo. O MNN, o TF SavedModel e o TF Frozen Graph passam por um artefacto intermediário ONNX ou Keras. Não são necessários atributos específicos do YOLO em nenhum dos casos.

FormatoFunçãoInstalarSaída
ONNXtorch2onnx()pip install onnxFicheiro .onnx
TorchScripttorch2torchscript()incluído com PyTorchFicheiro .torchscript
OpenVINOtorch2openvino()pip install openvinoDiretório _openvino_model/
CoreMLtorch2coreml()pip install coremltools.mlpackage
TF SavedModelonnx2saved_model()ver requisitos detalhados abaixoDiretório _saved_model/
TF Frozen Graphkeras2pb()ver requisitos detalhados abaixoFicheiro .pb
NCNNtorch2ncnn()pip install ncnn pnnxDiretório _ncnn_model/
MNNonnx2mnn()pip install MNNFicheiro .mnn
PaddlePaddletorch2paddle()pip install paddlepaddle x2paddleDiretório _paddle_model/
ExecuTorchtorch2executorch()pip install executorchDiretório _executorch_model/
ONNX como formato intermediário

As exportações para MNN, TF SavedModel e TF Frozen Graph passam pelo ONNX como um passo intermediário. Exporta primeiro para ONNX e depois converte.

Incorporação de metadados

Várias funções de exportação aceitam um dicionário metadata opcional (por exemplo, torch2torchscript(..., metadata={"author": "me"})) que incorpora pares chave-valor personalizados no artefacto exportado, caso o formato o suporte.

Exemplos passo a passo#

Cada exemplo abaixo usa a mesma configuração, uma ResNet-18 pré-treinada do timm em modo de avaliação:

import timm
import torch

model = timm.create_model("resnet18", pretrained=True).eval()
im = torch.randn(1, 3, 224, 224)
Sempre chame `model.eval()` antes de exportar

O Dropout, a normalização em lote e outras camadas exclusivas de treino comportam-se de forma diferente durante a inferência. Omitir .eval() produz exportações com resultados incorretos.

Exportar para ONNX#

from ultralytics.utils.export import torch2onnx

torch2onnx(model, im, output_file="resnet18.onnx")

Para um tamanho de lote dinâmico, passa um dicionário dynamic:

torch2onnx(model, im, output_file="resnet18_dyn.onnx", dynamic={"images": {0: "batch_size"}})

O opset predefinido é 14 e o nome da entrada predefinido é "images". Podes substituir estes valores com os argumentos opset, input_names ou output_names.

Exportar para TorchScript#

Não são necessárias dependências extra. Utiliza torch.jit.trace internamente.

from ultralytics.utils.export import torch2torchscript

torch2torchscript(model, im, output_file="resnet18.torchscript")

Exportar para OpenVINO#

from ultralytics.utils.export import torch2openvino

ov_model = torch2openvino(model, im, output_dir="resnet18_openvino_model")

O diretório contém um par model.xml e model.bin de nome fixo:

resnet18_openvino_model/
├── model.xml
└── model.bin

Passa dynamic=True para formas de entrada dinâmicas, quantize=16 para FP16 ou quantize=8 para quantização INT8. A quantização INT8 requer adicionalmente um argumento calibration_dataset.

Requer openvino>=2024.0.0 (ou >=2025.2.0 no macOS 15.4+) e torch>=2.1.

Exportar para CoreML#

import coremltools as ct

from ultralytics.utils.export import torch2coreml

inputs = [ct.TensorType("input", shape=(1, 3, 224, 224))]
ct_model = torch2coreml(model, inputs, im, classifier_names=None, output_file="resnet18.mlpackage")

Para modelos de classificação, passa uma lista de nomes de classes para classifier_names para adicionar uma cabeça de classificação ao modelo CoreML.

Requer coremltools>=9.0, torch>=1.11 e numpy<=2.3.5. Não suportado no Windows.

Erro `BlobWriter not loaded`

O coremltools>=9.0 disponibiliza wheels para Python 3.10–3.13 no macOS e Linux. Em versões mais recentes do Python, a extensão C nativa falha ao carregar. Utiliza o Python 3.10–3.13 para a exportação CoreML.

Exportar para TensorFlow SavedModel#

A exportação para TF SavedModel passa pelo ONNX como um passo intermediário:

from ultralytics.utils.export import onnx2saved_model, torch2onnx

torch2onnx(model, im, output_file="resnet18.onnx")
keras_model = onnx2saved_model("resnet18.onnx", output_dir="resnet18_saved_model")

A função devolve um modelo Keras e também gera ficheiros TFLite (.tflite) dentro do diretório de saída:

resnet18_saved_model/
├── saved_model.pb
├── variables/
├── resnet18_float32.tflite
├── resnet18_float16.tflite
└── resnet18_int8.tflite

Requisitos:

  • tensorflow>=2.0.0,<=2.19.0
  • onnx2tf>=1.26.3,<1.29.0
  • tf_keras<=2.19.0
  • sng4onnx>=1.0.1
  • onnx_graphsurgeon>=0.3.26
  • ai-edge-litert>=1.2.0,<1.4.0 no macOS (ai-edge-litert>=1.2.0 noutras plataformas)
  • onnxslim>=0.1.82
  • onnx>=1.12.0,<2.0.0
  • protobuf>=5

Exportar para TensorFlow Frozen Graph#

Continuando a partir da exportação do SavedModel acima, converte o keras_model devolvido num grafo .pb congelado:

from pathlib import Path

from ultralytics.utils.export import keras2pb

keras2pb(keras_model, output_file=Path("resnet18_saved_model/resnet18.pb"))

Exportar para NCNN#

from ultralytics.utils.export import torch2ncnn

torch2ncnn(model, im, output_dir="resnet18_ncnn_model")

O diretório contém arquivos param e bin de nome fixo, juntamente com um wrapper em Python:

resnet18_ncnn_model/
├── model.ncnn.param
├── model.ncnn.bin
└── model_ncnn.py

O torch2ncnn() verifica a existência de ncnn e pnnx na primeira utilização.

Exportar para MNN#

A exportação MNN requer um arquivo ONNX como entrada. Exporte para ONNX primeiro e, em seguida, converta:

from ultralytics.utils.export import onnx2mnn, torch2onnx

torch2onnx(model, im, output_file="resnet18.onnx")
onnx2mnn("resnet18.onnx", output_file="resnet18.mnn")

Suporta quantize=16 para FP16 e quantize=8 para quantização INT8. Requer MNN>=2.9.6 e torch>=1.10.

Exportar para PaddlePaddle#

from ultralytics.utils.export import torch2paddle

torch2paddle(model, im, output_dir="resnet18_paddle_model")

O diretório contém o modelo PaddlePaddle e os arquivos de parâmetros:

resnet18_paddle_model/
├── model.pdmodel
└── model.pdiparams

Requer x2paddle e a distribuição PaddlePaddle correta para a tua plataforma:

  • paddlepaddle-gpu>=3.0.0,<3.3.0 em CUDA
  • paddlepaddle==3.0.0 em CPU ARM64
  • paddlepaddle>=3.0.0,<3.3.0 noutros CPUs

Não suportado em NVIDIA Jetson.

Exportar para ExecuTorch#

from ultralytics.utils.export import torch2executorch

torch2executorch(model, im, output_dir="resnet18_executorch_model")

O ficheiro .pte exportado é guardado dentro do diretório de saída:

resnet18_executorch_model/
└── model.pte

Requer torch>=2.9.0 e um runtime ExecuTorch correspondente (pip install executorch). Para utilização em runtime, consulta a integração ExecuTorch.

Verifique seu modelo exportado#

Após a exportação, verifica a paridade numérica com o modelo PyTorch original antes de o colocar em produção. Um teste rápido com ONNXBackend de ultralytics.nn.backends compara as saídas e sinaliza precocemente erros de rastreio ou de quantização:

import numpy as np
import timm
import torch

from ultralytics.nn.backends import ONNXBackend

model = timm.create_model("resnet18", pretrained=True).eval()
im = torch.randn(1, 3, 224, 224)
with torch.no_grad():
    pytorch_output = model(im).numpy()

onnx_model = ONNXBackend("resnet18.onnx", device=torch.device("cpu"))
onnx_output = onnx_model(im)[0]

diff = np.abs(pytorch_output - onnx_output).max()
print(f"Max difference: {diff:.6f}")  # typically ~1e-5, well under 1e-4 for FP32
Diferença esperada

Para exportações FP32, a diferença máxima absoluta ronda habitualmente 1e-5 e deve manter-se bem abaixo de 1e-4. Diferenças maiores apontam para operações não suportadas, formas de entrada incorretas ou um modelo que não está em modo de avaliação. As exportações FP16 e INT8 têm tolerâncias mais amplas. Valida com dados reais em vez de tensores aleatórios.

Para outros runtimes, o nome do tensor de entrada pode diferir. O OpenVINO, por exemplo, utiliza o nome do argumento forward do modelo (habitualmente x para modelos genéricos), enquanto o torch2onnx predefini para "images".

Limitações conhecidas#

  • O suporte a múltiplas entradas é irregular: torch2onnx e torch2openvino aceitam um tuplo ou lista de tensores de exemplo para modelos com múltiplas entradas. torch2torchscript, torch2coreml, torch2ncnn, torch2paddle e torch2executorch assumem um único tensor de entrada.
  • O ExecuTorch precisa de flatc: O runtime do ExecuTorch requer o compilador FlatBuffers. Instala com brew install flatbuffers no macOS ou apt install flatbuffers-compiler no Ubuntu.
  • Sem inferência através do Ultralytics: Os modelos não YOLO exportados não podem ser carregados de volta através de YOLO() para inferência. Utiliza o runtime nativo para cada formato (ONNX Runtime, OpenVINO Runtime, etc.).
  • Formatos exclusivos para YOLO: As exportações para Axelera e Sony IMX500 requerem atributos de modelo específicos do YOLO e não estão disponíveis para modelos genéricos.
  • Formatos específicos de plataforma: TensorRT requer uma GPU NVIDIA. RKNN requer o SDK rknn-toolkit2 (apenas Linux). Edge TPU requer o binário edgetpu_compiler (apenas Linux).

Conclusão#

Estes utilitários transformam qualquer modelo PyTorch, desde um simples torch.nn.Module até um artefacto pronto para produção em ONNX, OpenVINO, CoreML, TensorFlow ou runtime móvel, através de uma única API consistente. Escolhe o formato que corresponde ao teu hardware de destino, verifica a paridade numérica em relação ao modelo original e, em seguida, segue o guia de integração correspondente para os passos de implementação específicos do runtime.

FAQ#

  • Qualquer torch.nn.Module. Isto inclui modelos de timm, torchvision ou qualquer modelo PyTorch personalizado. O modelo tem de estar em modo de avaliação (model.eval()) antes da exportação. O ONNX e o OpenVINO aceitam adicionalmente um tuplo de tensores de exemplo para modelos de múltiplas entradas.

  • Todos os formatos suportados (TorchScript, ONNX, OpenVINO, CoreML, TF SavedModel, TF Frozen Graph, NCNN, PaddlePaddle, MNN, ExecuTorch) podem ser exportados via CPU. Nenhuma GPU é necessária para o processo de exportação em si. TensorRT é o único formato que requer uma GPU NVIDIA.

  • Utiliza o >=8.4.38 da Ultralytics, que inclui o módulo ultralytics.utils.export e os argumentos normalizados output_file/output_dir.

  • Sim. Os classificadores, detetores e modelos de segmentação da torchvision são exportados para .mlpackage através de torch2coreml. Para modelos de classificação de imagens, passa uma lista de nomes de classes para classifier_names para incorporar uma cabeça de classificação. Executa a exportação no macOS ou Linux. O CoreML não é suportado no Windows. Consulta a integração CoreML para obter detalhes de implementação no iOS.

  • Sim, para vários formatos. Passa quantize=16 para FP16 ou quantize=8 para INT8 ao exportar para OpenVINO, CoreML, MNN ou NCNN. O INT8 no OpenVINO requer adicionalmente um argumento calibration_dataset para quantização pós-treino. Consulta a página de integração de cada formato para conhecer as vantagens e desvantagens da quantização.

  • Executa o modelo PyTorch original e o modelo exportado com a mesma entrada e, em seguida, compara as saídas. Carrega o ficheiro exportado com o backend correspondente (por exemplo, ONNXBackend para ONNX) e verifica a diferença máxima absoluta. Para exportações FP32, esta ronda habitualmente 1e-5 e deve manter-se bem abaixo de 1e-4; discrepâncias maiores apontam para operações não suportadas, uma forma de entrada incorreta ou um modelo que não está em modo de avaliação. Consulta Verify Your Exported Model para ver um exemplo executável.

Comentários