Как экспортировать модели 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, не требуются.
| Формат | Функция | Установка | Выходные данные |
|---|---|---|---|
| ONNX | torch2onnx() | pip install onnx | файл .onnx |
| TorchScript | torch2torchscript() | включено в PyTorch | файл .torchscript |
| OpenVINO | torch2openvino() | pip install openvino | каталог _openvino_model/ |
| CoreML | torch2coreml() | pip install coremltools | .mlpackage |
| TF SavedModel | onnx2saved_model() | см. подробные требования ниже | каталог _saved_model/ |
| TF Frozen Graph | keras2pb() | см. подробные требования ниже | файл .pb |
| NCNN | torch2ncnn() | pip install ncnn pnnx | каталог _ncnn_model/ |
| MNN | onnx2mnn() | pip install MNN | файл .mnn |
| PaddlePaddle | torch2paddle() | pip install paddlepaddle x2paddle | каталог _paddle_model/ |
| ExecuTorch | torch2executorch() | pip install executorch | каталог _executorch_model/ |
Экспорт в 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)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.
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.0onnx2tf>=1.26.3,<1.29.0tf_keras<=2.19.0sng4onnx>=1.0.1onnx_graphsurgeon>=0.3.26ai-edge-litert>=1.2.0,<1.4.0на macOS (ai-edge-litert>=1.2.0на других платформах)onnxslim>=0.1.82onnx>=1.12.0,<2.0.0protobuf>=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.pytorch2ncnn() проверяет наличие 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на CUDApaddlepaddle==3.0.0на CPU ARM64paddlepaddle>=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; большие разрывы указывают на неподдерживаемые операции, неверную форму входных данных или на то, что модель не находится в режиме оценки. Пример с возможностью запуска см. в разделе Проверка экспортированной модели.