YOLO Vision 2026:

Как экспортировать модели PyTorch, не являющиеся YOLO, с помощью Ultralytics#

Ultralytics поставляет независимые утилиты экспорта в рамках ultralytics.utils.export, которые объединяют множество бэкендов под единым согласованным интерфейсом. Ты можешь экспортировать любую модель torch.nn.Module, включая модели изображений timm, классификаторы и детекторы torchvision или собственные пользовательские архитектуры, в форматы ONNX, TorchScript, OpenVINO, CoreML, NCNN, PaddlePaddle, MNN, ExecuTorch и TensorFlow SavedModel без необходимости изучать каждый бэкенд по отдельности.

Развертывание моделей PyTorch в продакшене обычно означает использование отдельного экспортера для каждой целевой платформы: torch.onnx.export для ONNX, coremltools для устройств Apple, onnx2tf для TensorFlow, pnnx для NCNN и так далее. У каждого инструмента свой собственный API, особенности работы с зависимостями и соглашения об выводе. Эти утилиты объединяют всё это в единый шаблон вызова.

Почему стоит использовать Ultralytics для экспорта моделей, не являющихся YOLO?#

  • Один API для 10 форматов: изучи один стандарт вызова вместо десятка.
  • Общая поверхность утилит: вспомогательные средства экспорта находятся в ultralytics.utils.export, поэтому после установки пакетов бэкенда ты сможешь использовать один и тот же шаблон вызова для всех форматов.
  • Тот же путь кода, что и у экспорта YOLO: те же вспомогательные инструменты обеспечивают весь экспорт Ultralytics YOLO.
  • Встроенная квантизация FP16 и INT8 для форматов, поддерживающих ее (OpenVINO, CoreML, MNN, NCNN).
  • Работает на CPU: для этапа экспорта не требуется GPU, поэтому ты можешь запускать его локально на любом ноутбуке.

Быстрый старт#

Самый быстрый путь — это экспорт в ONNX в две строки без кода YOLO и без настройки, кроме 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")

Поддерживаемые форматы экспорта#

Функции torch2* принимают стандартный torch.nn.Module и пример входного тензора. MNN, TF SavedModel и TF Frozen Graph обрабатываются через промежуточный артефакт ONNX или Keras. В обоих случаях атрибуты, специфичные для YOLO, не требуются.

ФорматФункцияУстановкаВыходные данные
ONNXtorch2onnx()pip install onnxфайл .onnx
TorchScripttorch2torchscript()включено в PyTorchфайл .torchscript
OpenVINOtorch2openvino()pip install openvinoкаталог _openvino_model/
CoreMLtorch2coreml()pip install coremltools.mlpackage
TF SavedModelonnx2saved_model()см. подробные требования нижекаталог _saved_model/
TF Frozen Graphkeras2pb()см. подробные требования нижефайл .pb
NCNNtorch2ncnn()pip install ncnn pnnxкаталог _ncnn_model/
MNNonnx2mnn()pip install MNNфайл .mnn
PaddlePaddletorch2paddle()pip install paddlepaddle x2paddleкаталог _paddle_model/
ExecuTorchtorch2executorch()pip install executorchкаталог _executorch_model/
ONNX как промежуточный формат

Экспорт в MNN, TF SavedModel и TF Frozen Graph проходит через ONNX в качестве промежуточного шага. Сначала выполни экспорт в ONNX, а затем конвертируй.

Встраивание метаданных

Несколько функций экспорта принимают необязательный словарь metadata (например, torch2torchscript(..., metadata={"author": "me"})), который внедряет пользовательские пары ключ-значение в экспортированный артефакт, если формат это поддерживает.

Пошаговые примеры#

В каждом примере ниже используется одна и та же настройка: предобученная ResNet-18 из timm в режиме оценки (evaluation mode):

import timm
import torch

model = timm.create_model("resnet18", pretrained=True).eval()
im = torch.randn(1, 3, 224, 224)
Всегда вызывай `model.eval()` перед экспортом

Dropout, батч-нормализация и другие слои, используемые только при обучении, ведут себя во время инференса иначе. Пропуск .eval() приводит к некорректным результатам экспорта.

Экспорт в ONNX#

from ultralytics.utils.export import torch2onnx

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

Для динамического размера батча передай словарь dynamic:

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

Набором операций по умолчанию является 14, а именем входных данных по умолчанию — "images". Переопредели их с помощью аргументов opset, input_names или output_names.

Экспорт в TorchScript#

Дополнительные зависимости не нужны. Под капотом используется torch.jit.trace.

from ultralytics.utils.export import torch2torchscript

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

Экспорт в OpenVINO#

from ultralytics.utils.export import torch2openvino

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

Каталог содержит пару с фиксированными именами model.xml и model.bin:

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

Передай dynamic=True для динамических форм входных данных, quantize=16 для FP16 или quantize=8 для квантования INT8. Для INT8 дополнительно требуется аргумент calibration_dataset.

Требуется openvino>=2024.0.0 (или >=2025.2.0 на macOS 15.4+) и torch>=2.1.

Экспорт в 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")

Для моделей классификации передай список имен классов в classifier_names, чтобы добавить классификационную «голову» к модели CoreML.

Требуется coremltools>=9.0, torch>=1.11 и numpy<=2.3.5. Не поддерживается на Windows.

Ошибка `BlobWriter not loaded`

coremltools>=9.0 поставляет колеса (wheels) для Python 3.10–3.13 на macOS и Linux. На более новых версиях Python нативное расширение C не загружается. Используй Python 3.10–3.13 для экспорта CoreML.

Экспорт в TensorFlow SavedModel#

Экспорт в TF SavedModel проходит через ONNX как промежуточный этап:

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")

Функция возвращает модель Keras, а также генерирует файлы TFLite (.tflite) внутри выходного каталога:

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

Требования:

  • 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 на macOS (ai-edge-litert>=1.2.0 на других платформах)
  • onnxslim>=0.1.82
  • onnx>=1.12.0,<2.0.0
  • protobuf>=5

Экспорт в TensorFlow Frozen Graph#

Продолжая экспорт SavedModel выше, конвертируй возвращенную модель keras_model в замороженный граф .pb:

from pathlib import Path

from ultralytics.utils.export import keras2pb

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

Экспорт в NCNN#

from ultralytics.utils.export import torch2ncnn

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

Директория содержит файлы param и bin с фиксированными именами, а также Python-обертку:

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

torch2ncnn() проверяет наличие ncnn и pnnx при первом использовании.

Экспорт в MNN#

Для экспорта в MNN требуется файл ONNX в качестве входа. Сначала экспортируй в ONNX, затем конвертируй:

from ultralytics.utils.export import onnx2mnn, torch2onnx

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

Поддерживает quantize=16 для FP16 и quantize=8 для квантования INT8. Требуется MNN>=2.9.6 и torch>=1.10.

Экспорт в PaddlePaddle#

from ultralytics.utils.export import torch2paddle

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

Директория содержит файлы модели PaddlePaddle и параметров:

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

Требуется x2paddle и подходящий дистрибутив PaddlePaddle для твоей платформы:

  • paddlepaddle-gpu>=3.0.0,<3.3.0 на CUDA
  • paddlepaddle==3.0.0 на CPU ARM64
  • paddlepaddle>=3.0.0,<3.3.0 на других CPU

Не поддерживается на NVIDIA Jetson.

Экспорт в ExecuTorch#

from ultralytics.utils.export import torch2executorch

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

Экспортированный файл .pte сохраняется внутри выходного каталога:

resnet18_executorch_model/
└── model.pte

Требуется torch>=2.9.0 и соответствующая среда выполнения ExecuTorch (pip install executorch). Инструкции по использованию среды выполнения см. в разделе интеграция с ExecuTorch.

Проверь свою экспортированную модель#

После экспорта перед развертыванием проверь численное соответствие с исходной моделью PyTorch. Быстрый дымовой тест с помощью ONNXBackend из ultralytics.nn.backends сравнивает результаты и позволяет вовремя выявить ошибки трассировки или квантования:

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
Ожидаемая разница

Для экспорта в FP32 максимальная абсолютная разница обычно составляет около 1e-5 и должна оставаться значительно ниже 1e-4. Большая разница указывает на неподдерживаемые операции, неверную форму входных данных или на то, что модель не находится в режиме оценки. Экспорт в FP16 и INT8 имеет более мягкие допуски. Проверяй на реальных данных, а не на случайных тензорах.

Для других сред выполнения имя входного тензора может отличаться. Например, OpenVINO использует имя аргумента forward модели (обычно x для общих моделей), в то время как torch2onnx по умолчанию принимает "images".

Известные ограничения#

  • Поддержка нескольких входов неравномерна: torch2onnx и torch2openvino принимают кортеж или список примеров тензоров для моделей с несколькими входами. torch2torchscript, torch2coreml, torch2ncnn, torch2paddle и torch2executorch предполагают наличие одного входного тензора.
  • ExecuTorch требует flatc: Среде выполнения ExecuTorch требуется компилятор FlatBuffers. Установи его с помощью brew install flatbuffers на macOS или apt install flatbuffers-compiler на Ubuntu.
  • Инференс через Ultralytics не поддерживается: Экспортированные модели, не относящиеся к YOLO, не могут быть загружены обратно через YOLO() для инференса. Используй нативную среду выполнения для каждого формата (ONNX Runtime, OpenVINO Runtime и т.д.).
  • Форматы только для YOLO: Экспорт для Axelera и Sony IMX500 требует атрибутов модели, специфичных для YOLO, и недоступен для общих моделей.
  • Форматы для конкретных платформ: TensorRT требует графический процессор NVIDIA. RKNN требует SDK rknn-toolkit2 (только для Linux). Edge TPU требует бинарный файл edgetpu_compiler (только для Linux).

Заключение#

Эти утилиты позволяют превратить любую модель PyTorch — от обычной torch.nn.Module до готового к развертыванию артефакта ONNX, OpenVINO, CoreML, TensorFlow или мобильной среды выполнения — через один согласованный API. Выбери формат, соответствующий твоему целевому оборудованию, проверь численное соответствие с исходной моделью, а затем следуй соответствующему руководству по интеграции для выполнения шагов развертывания под конкретную среду.

FAQ#

  • Любая модель torch.nn.Module. Это включает модели из timm, torchvision или любые пользовательские модели PyTorch. Перед экспортом модель должна находиться в режиме оценки (model.eval()). ONNX и OpenVINO дополнительно принимают кортеж примеров тензоров для моделей с несколькими входами.

  • Все поддерживаемые форматы (TorchScript, ONNX, OpenVINO, CoreML, TF SavedModel, TF Frozen Graph, NCNN, PaddlePaddle, MNN, ExecuTorch) могут экспортироваться на CPU. GPU для самого процесса экспорта не требуется. TensorRT — единственный формат, требующий GPU NVIDIA.

  • Используй утилиту Ultralytics >=8.4.38, которая включает модуль ultralytics.utils.export и стандартизированные аргументы output_file/output_dir.

  • Да. Классификаторы, детекторы и модели сегментации torchvision экспортируются в .mlpackage с помощью torch2coreml. Для моделей классификации изображений передай список имен классов в classifier_names, чтобы встроить классификационную голову. Выполни экспорт на macOS или Linux. CoreML не поддерживается на Windows. Подробности развертывания на iOS см. в интеграции с CoreML.

  • Да, для нескольких форматов. Передай quantize=16 для FP16 или quantize=8 для INT8 при экспорте в OpenVINO, CoreML, MNN или NCNN. INT8 в OpenVINO дополнительно требует аргумент calibration_dataset для постобучающего квантования. Особенности квантования для каждого формата см. на соответствующей странице интеграции.

  • Запусти исходную модель PyTorch и экспортированную модель на одних и тех же входных данных, а затем сравните результаты. Загрузи экспортированный файл с помощью соответствующего бэкенда (например, ONNXBackend для ONNX) и проверь максимальную абсолютную разницу. Для экспорта в FP32 она обычно составляет около 1e-5 и должна оставаться значительно ниже 1e-4; большие разрывы указывают на неподдерживаемые операции, неверную форму входных данных или на то, что модель не находится в режиме оценки. Пример с возможностью запуска см. в разделе Проверка экспортированной модели.

Комментарии