使用 Ultralytics 导出非 YOLO 的 PyTorch 模型:一套 API 打通 10 种部署格式
使用 Ultralytics 导出非 YOLO 的 PyTorch 模型一套 API 打通 10 种部署格式【免费下载链接】ultralyticsUltralytics YOLO26, YOLO11, YOLOv8 — object detection, instance segmentation, semantic segmentation, image classification, pose estimation, object tracking项目地址: https://gitcode.com/GitHub_Trending/ul/ultralytics本文介绍 Ultralytics 中面向非 YOLO 模型的独立导出工具集通过ultralytics.utils.export模块下的一组torch2*/onnx2*函数将任意torch.nn.Moduletimm 图像模型、torchvision 分类器/检测器或自研网络统一转换为 ONNX、TorchScript、OpenVINO、CoreML、TensorFlow SavedModel/Frozen Graph、NCNN、MNN、PaddlePaddle 与 ExecuTorch 格式。读完后你可以掌握统一调用的导出流程与各格式的依赖安装、量化FP16/INT8选项、导出后用后端类做数值一致性校验的方法以及加载运行导出产物的完整方式。1. 为什么用 Ultralytics 导出非 YOLO 模型将 PyTorch 模型部署到生产环境通常需要为每个目标平台准备一套不同的导出器ONNX 用torch.onnx.exportApple 设备用coremltoolsTensorFlow 用onnx2tfNCNN 用pnnx……每个工具有自己的 API、依赖坑和产物约定。Ultralytics 在 ultralytics/utils/export/ 下提供了一批独立导出工具函数把这些工具收敛到同一个调用模式上。其核心价值一套 API 覆盖 10 种格式只需学会一种调用约定而不是十来种共享的工具层导出辅助函数集中在ultralytics.utils.export安装好对应后端的包后各格式可以保持相同的调用模式与 YOLO 导出同一代码路径这些辅助函数同时也是 Ultralytics YOLO 各导出格式YOLO(...).export(format...)的底层实现内置 FP16 与 INT8 量化对支持的格式OpenVINO、CoreML、MNN、NCNN可直接传quantize参数CPU 即可导出导出步骤本身不需要 GPU任何笔记本都可以本地执行。从 ultralytics/utils/export/init.py 的__all__列表可以看到该模块完整导出的函数集合torch2onnx、torch2torchscript、torch2openvino、torch2coreml、torch2ncnn、torch2paddle、torch2executorch、onnx2mnn、onnx2saved_model、keras2pb以及若干面向特定硬件的格式onnx2engine、onnx2ascend、onnx2deepx、onnx2qnn、onnx2rknn、torch2axelera、torch2imx、torch2coreai、tflite2edgetpu。本文聚焦其中对任意torch.nn.Module开放的 10 种通用格式。2. 快速开始最快路径是两行代码导出 ONNX全程不涉及任何 YOLO 代码安装pip install ultralytics onnx timm即可import timm import torch from ultralytics.utils.export import torch2onnx model timm.create_model(resnet18, pretrainedTrue).eval() torch2onnx(model, torch.randn(1, 3, 224, 224), output_fileresnet18.onnx)3. 支持的导出格式总览各torch2*函数接收一个标准的torch.nn.Module和一个示例输入张量MNN、TF SavedModel 与 TF Frozen Graph 则经由 ONNX 或 Keras 中间产物转换。两者均不需要任何 YOLO 专属属性。格式函数安装产物ONNXtorch2onnx()ultralytics/utils/export/engine.pypip install onnx.onnx文件TorchScripttorch2torchscript()ultralytics/utils/export/torchscript.py随 PyTorch 自带.torchscript文件OpenVINOtorch2openvino()ultralytics/utils/export/openvino.pypip install openvino_openvino_model/目录CoreMLtorch2coreml()ultralytics/utils/export/coreml.pypip install coremltools.mlpackageTF SavedModelonnx2saved_model()ultralytics/utils/export/tensorflow.py见第 9 节详细依赖_saved_model/目录TF Frozen Graphkeras2pb()ultralytics/utils/export/tensorflow.py见第 9 节详细依赖.pb文件NCNNtorch2ncnn()ultralytics/utils/export/ncnn.pypip install ncnn pnnx_ncnn_model/目录MNNonnx2mnn()ultralytics/utils/export/mnn.pypip install MNN.mnn文件PaddlePaddletorch2paddle()ultralytics/utils/export/paddle.pypip install paddlepaddle x2paddle_paddle_model/目录ExecuTorchtorch2executorch()ultralytics/utils/export/executorch.pypip install executorch_executorch_model/目录关于 ONNX 作为中间格式MNN、TF SavedModel 与 TF Frozen Graph 的导出都先经过 ONNX。正确顺序是先导出 ONNX再转换。关于元数据嵌入多个导出函数支持可选的metadata字典如torch2torchscript(..., metadata{author: me})在格式支持时会把自定义键值对嵌入产物中。例如 TorchScript 会将其序列化为 JSON 写入 zip 归档的config.txt附加文件见 [ultralytics/utils/export/torchscript.py](https://link.gitcode.com/i/0630ece0fff907962d86beb35f9db6b1)MNN 则通过--bizCode 参数写入见 ultralytics/utils/export/mnn.py。4. 导出前的通用约定下文所有示例使用同一组准备代码来自 timm 的预训练 ResNet-18处于评估模式import timm import torch model timm.create_model(resnet18, pretrainedTrue).eval() im torch.randn(1, 3, 224, 224)警告导出前务必调用model.eval()。Dropout、BatchNorm 等训练专用层在推理时的行为不同跳过.eval()会导出结果错误的模型。5. 导出为 ONNXfrom ultralytics.utils.export import torch2onnx torch2onnx(model, im, output_fileresnet18.onnx)动态 batch 尺寸可传入dynamic字典torch2onnx(model, im, output_fileresnet18_dyn.onnx, dynamic{images: {0: batch_size}})默认 opset 为14默认输入名为images。可以通过opset、input_names、output_names参数覆盖。从 ultralytics/utils/export/engine.py 的源码可以看到更多细节默认输出名是output_names[output0]而非输入名多输入模型可传入张量元组im: torch.Tensor | tuple[torch.Tensor, ...]内部调用torch.onnx.export时固定do_constant_foldingTrue源码注释提示在 torch1.12 的 DNN 推理场景下如遇到兼容问题可考虑关闭常量折叠函数使用ThreadingLocked()装饰器保证同一模型文件的线程安全导出该模块还包含best_onnx_opset()与modelopt_quantize_onnx()等辅助函数服务于 YOLO 导出链路的 TensorRT 11 强类型构建与通用模型导出无直接关系。6. 导出为 TorchScript无需任何额外依赖底层使用torch.jit.trace。from ultralytics.utils.export import torch2torchscript torch2torchscript(model, im, output_fileresnet18.torchscript)ultralytics/utils/export/torchscript.py 中可以看到 trace 使用了strictFalse, check_traceFalse参数以放宽对动态结构模型的检查并通过_extra_files{config.txt: json.dumps(metadata)}把可选元数据嵌入归档。7. 导出为 OpenVINOfrom ultralytics.utils.export import torch2openvino ov_model torch2openvino(model, im, output_dirresnet18_openvino_model)输出目录内包含固定文件名的model.xml与model.bin一对文件resnet18_openvino_model/ ├── model.xml └── model.bin可传dynamicTrue启用动态输入形状、quantize16做 FP16、quantize8做 INT8 量化INT8 额外要求calibration_dataset参数。依赖要求为openvino2024.0.0macOS 15.4 上为2025.2.0且torch2.1。从 ultralytics/utils/export/openvino.py 的实现看几个关键点值得注意函数先把模型torch.jit.trace成 ScriptModule 再交给ov.convert_model避免 OpenVINO 内部以check_traceTrue重新 trace 时在含 NMS 的结构上出现Graphs differed across invocations!这类非确定性失败FP16 通过ov.save_model(..., compress_to_fp16True)完成即压缩存储权重而非改写图INT8 走nncf.quantize使用QuantizationPreset.MIXED预设校准集大小取calibration_dataset.get_length() or 300即尽量使用完整校准集而非 nncf 默认的 300 批多输入模型支持传入张量列表/元组im参数类型为torch.Tensor | list[torch.Tensor] | tuple[torch.Tensor, ...]。8. 导出为 CoreMLimport 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_namesNone, output_fileresnet18.mlpackage)对分类模型向classifier_names传入类别名列表可以为 CoreML 模型附加分类头。依赖要求coremltools9.0、torch1.11、numpy2.3.5且不支持 Windows。警告BlobWriter not loaded错误。coremltools9.0仅发布了 Python 3.10–3.13 的 wheelmacOS 与 Linux。在更新的 Python 版本上原生 C 扩展加载会失败因此 CoreML 导出请使用 Python 3.10–3.13。源码层面ultralytics/utils/export/coreml.py可以看到函数先把模型 trace 成 TorchScript 再调用ct.convert默认转换目标为mlprogrammlmodelFalse时mlmodelTrue时转为传统neuralnetwork格式ML Program 转换默认 FP16若未请求量化则会显式钉住compute_precisionct.precision.FLOAT32quantize8时ML Program 路径使用coremltools.optimize.coreml.palettize_weightskmeans 模式做权重 INT8 调色板量化MLModel 路径则用quantization_utils.quantize_weights保存.mlpackage失败时会自动回退为保存.mlmodel源码注释指向 coremltools 在 Python 3.11 与 Windows 上的已知问题metadata字典中的description/author/license/version会被写入 CoreML 模型的对应字段其余键写入user_defined_metadata。9. 导出为 TensorFlow SavedModelTF SavedModel 导出以 ONNX 为中间步骤from ultralytics.utils.export import onnx2saved_model, torch2onnx torch2onnx(model, im, output_fileresnet18.onnx) keras_model onnx2saved_model(resnet18.onnx, output_dirresnet18_saved_model)函数返回 Keras 模型同时会在输出目录中生成 FP32 与 FP16 两份 LiteRT 文件.tfliteresnet18_saved_model/ ├── saved_model.pb ├── variables/ ├── assets/ ├── fingerprint.pb ├── resnet18_float32.tflite └── resnet18_float16.tflite传quantize8可在旁边追加一份 INT8.tflite。完整依赖要求tensorflow2.0.0,2.19.0onnx2tf1.26.3,1.29.0tf_keras2.19.0sng4onnx1.0.1onnx_graphsurgeon0.3.26ai-edge-litert1.2.0,1.4.0macOS其他平台为ai-edge-litert1.2.0onnxslim0.1.82onnx1.12.0,2.0.0protobuf5从 ultralytics/utils/export/tensorflow.py 看转换实际由onnx2tf.convert完成函数会按上述约束自动check_requirements安装缺失依赖Python 3.13 环境会自动放宽到tensorflow2.19.0与onnx2tf2.3.0,2.3.16的新版本区间INT8 路径会在输出目录临时写入校准图像文件转换完成后把*_dynamic_range_quant.tflite重命名为*_int8.tflite并删除附带的 int16 激活版本。另外源码默认隐藏 GPUtf.config.set_visible_devices([], GPU)保证非 CUDA 导出不会分配显存如需在 CUDA 设备上导出传cudaTrue。10. 导出为 TensorFlow Frozen Graph承接上一节的 SavedModel 导出将返回的keras_model转为冻结的.pb图from pathlib import Path from ultralytics.utils.export import keras2pb keras2pb(keras_model, output_filePath(resnet18_saved_model/resnet18.pb))实现上ultralytics/utils/export/tensorflow.py调用convert_variables_to_constants_v2将变量固化为常量再通过tf.io.write_graph写出 GraphDef得到可直接用于 TF C/Lite 部署的推理图。11. 导出为 NCNNfrom ultralytics.utils.export import torch2ncnn torch2ncnn(model, im, output_dirresnet18_ncnn_model)目录内包含固定文件名的 param/bin 以及 Python 封装resnet18_ncnn_model/ ├── model.ncnn.param ├── model.ncnn.bin └── model_ncnn.pytorch2ncnn()在首次使用时会检查ncnn与pnnx是否可用。源码ultralytics/utils/export/ncnn.py显示ncnn以--no-deps方式安装避免连带引入 opencv-pythonpnnx目前钉死在20260526版本源码注释说明是为了规避 PNNX 20260704 的 NCNN 推理段错误待上游修复后调整转换通过pnnx.export一次生成 NCNN 与 PNNX 两侧产物quantize16会追加fp16True参数导出完成后会清理debug.bin/debug.param等调试文件及pnnx_args列出的中间文件若提供metadata则额外写出metadata.yaml。12. 导出为 MNNMNN 导出要求以 ONNX 文件为输入先导出 ONNX 再转换from ultralytics.utils.export import onnx2mnn, torch2onnx torch2onnx(model, im, output_fileresnet18.onnx) onnx2mnn(resnet18.onnx, output_fileresnet18.mnn)支持quantize16FP16与quantize8INT8 权重量化。依赖要求MNN2.9.6且torch1.10。源码ultralytics/utils/export/mnn.py内部调用MNN.tools.mnnconvert.convert量化参数映射为--weightQuantBits 8INT8 权重与--fp16FP16metadata通过--bizCode以 JSON 写入转换产生的.__convert_external_data.bin临时文件会被自动清理。13. 导出为 PaddlePaddlefrom ultralytics.utils.export import torch2paddle torch2paddle(model, im, output_dirresnet18_paddle_model)目录内包含 PaddlePaddle 的模型与参数文件resnet18_paddle_model/ ├── model.pdmodel └── model.pdiparams需要x2paddle以及匹配平台的 PaddlePaddle 发行版CUDApaddlepaddle-gpu3.0.0,3.3.0ARM64 CPUpaddlepaddle3.0.0其他 CPUpaddlepaddle3.0.0,3.3.0不支持 NVIDIA Jetson。源码ultralytics/utils/export/paddle.py开头有assert not IS_JETSON的显式断言并按输入张量所在设备与平台自动选择上述候选版本区间转换调用x2paddle.convert.pytorch2paddle(jit_typetrace, input_examples[im])3.3.0的版本上限对应 PaddlePaddle 上游的已知问题。14. 导出为 ExecuTorchfrom ultralytics.utils.export import torch2executorch torch2executorch(model, im, output_dirresnet18_executorch_model)导出的.pte文件保存在输出目录内resnet18_executorch_model/ └── model.pte要求torch2.9.0与匹配的 ExecuTorch 运行时pip install executorch。运行时用法参见 ExecuTorch 集成文档。实现ultralytics/utils/export/executorch.py走的是torch.export.export(model, (im,))的 AOT 导出路径再经to_edge_transform_and_lower(..., partitioner[XnnpackPartitioner()])分区到 XNNPACK 后端并序列化为model.pte提供metadata时会额外保存metadata.yaml。15. 校验导出模型导出完成后、交付之前应先与原始 PyTorch 模型做数值一致性校验。一个快速的冒烟测试是用ultralytics.nn.backends中的ONNXBackend对比输出尽早发现 trace 或量化错误import numpy as np import timm import torch from ultralytics.nn.backends import ONNXBackend model timm.create_model(resnet18, pretrainedTrue).eval() im torch.randn(1, 3, 224, 224) with torch.no_grad(): pytorch_output model(im).numpy() onnx_model ONNXBackend(resnet18.onnx, devicetorch.device(cpu)) onnx_output onnx_model(im)[0] diff np.abs(pytorch_output - onnx_output).max() print(fMax difference: {diff:.6f}) # FP32 ONNX 导出约为 1e-6关于期望差异容差是按格式而非全局统一的。在 ResNet-18 上FP32 导出的 ONNX、TF SavedModel 与 LiteRT 约为1e-6TorchScript 恰好为0NCNN 是离群值约1e-2——因为其 CPU 运行时默认启用 FP16 打包与运算FP32 导出实际也以半精度执行。差异远超该格式自身基线通常意味着存在不支持的算子、输入形状错误或模型未处于 eval 模式。FP16 与 INT8 导出的容差更宽松且应使用真实数据而非随机张量做验证。对其他运行时输入张量名可能不同。例如 OpenVINO 使用模型 forward 参数名通用模型通常是x而torch2onnx默认是images见第 5 节。16. 运行导出后的模型非 YOLO 模型导出后可以通过常规YOLO()API 加载。由于上述导出不携带 Ultralytics 的任务task或输入尺寸imgsz元数据需要显式传入task并且imgsz要与导出时使用的示例张量一致from ultralytics import YOLO results YOLO(resnet18.onnx, taskclassify)(path/to/image.jpg, imgsz224) print(results[0].probs.top1)imgsz在导出具有固定输入形状时尤为关键上述 ONNX 与 TF SavedModel 导出会拒绝默认值 640。TorchScript 与 NCNN 导出虽然可能接受其他尺寸但两个导出器都不保证这一点——它们都基于示例张量 trace因此模型中任何 flatten 进Linear层的结构都会固定尺寸请自行验证自己的导出。此外imgsz会被向上取整为模型 stride 的整数倍无元数据时该 stride 为 32。因此一个 200x200 的定形状导出即使imgsz200与之匹配实际也会被送入 224x224 并被拒绝。对于不是 32 整数倍的输入尺寸请直接调用后端类。直接调用后端类若不想经过 Ultralytics 的预处理与后处理、只处理裸张量可直接使用ultralytics.nn.backends中各格式对应的后端类用法与上面校验示例相同。每个后端接收导出产物与设备且可直接调用callable格式后端输入布局ONNXONNXBackendultralytics/nn/backends/onnx.pyBCHWTorchScriptTorchScriptBackendultralytics/nn/backends/pytorch.pyBCHWOpenVINOOpenVINOBackendultralytics/nn/backends/openvino.pyBCHWCoreMLCoreMLBackendultralytics/nn/backends/coreml.pyBHWCTF SavedModel / Frozen GraphTensorFlowBackendultralytics/nn/backends/tensorflow.pyBHWCLiteRTLiteRTBackendultralytics/nn/backends/litert.pyBCHWNCNNNCNNBackendultralytics/nn/backends/ncnn.pyBCHWPaddlePaddlePaddleBackendultralytics/nn/backends/paddle.pyBCHWMNNMNNBackendultralytics/nn/backends/mnn.pyBCHWExecuTorchExecuTorchBackendultralytics/nn/backends/executorch.pyBCHWTensorFlowBackend覆盖两种格式默认formatsaved_model使用冻结图时请传formatpb。有件事是YOLO()路径会替你处理、而直接调用后端时不会的输入布局CoreMLBackend与TensorFlowBackend期望 BHWC 布局。先执行im.permute(0, 2, 3, 1)转置BCHW 张量会直接抛形状不匹配错误自动求导用torch.inference_mode()包裹调用。TorchScriptBackend返回的张量仍携带梯度图后处理无元数据时后端会将task保留为None、names为空。LiteRTBackend仍会按输出是 YOLO 框的假设对 3 维输出按图像尺寸做反归一化——这对 3 维输出的非 YOLO 模型是错误的分类 logits 这类二维输出则不受影响。17. 已知限制多输入支持不一致torch2onnx与torch2openvino接受示例张量的元组/列表可处理多输入模型torch2torchscript、torch2coreml、torch2ncnn、torch2paddle、torch2executorch假设单一输入张量。ExecuTorch 需要flatcExecuTorch 运行时依赖 FlatBuffers 编译器。macOS 上用brew install flatbuffersUbuntu 上用apt install flatbuffers-compiler。无内嵌元数据上述导出不携带 Ultralytics 任务与输入尺寸元数据YOLO()无法推断二者必须显式传入见第 16 节。仅限 YOLO 的格式Axelera 与 Sony IMX500 导出依赖 YOLO 专属模型属性不适用于通用模型。平台专属格式TensorRT 需要 NVIDIA GPURKNN 需要rknn-toolkit2SDK仅 LinuxEdge TPU 需要edgetpu_compiler二进制仅 Linux。18. 常见问题Q1能用 Ultralytics 导出哪些模型任何torch.nn.Module。包括来自 timm、torchvision 的模型以及任意自研 PyTorch 模型。导出前模型必须处于评估模式model.eval()。ONNX 与 OpenVINO 额外接受示例张量元组以支持多输入模型。Q2哪些格式可以无 GPU 导出全部支持的格式TorchScript、ONNX、OpenVINO、CoreML、TF SavedModel、TF Frozen Graph、NCNN、PaddlePaddle、MNN、ExecuTorch都可以在 CPU 上导出导出过程本身不需要 GPU。TensorRT 是唯一需要 NVIDIA GPU 的格式。Q3需要什么版本的 Ultralytics请使用8.4.38的 Ultralytics该版本包含ultralytics.utils.export模块与标准化的output_file/output_dir参数。Q4能把 torchvision 模型导出为 CoreML 用于 iOS 部署吗可以。torchvision 的分类器、检测器与分割模型都可以通过torch2coreml导出为.mlpackage。对图像分类模型向classifier_names传入类别名列表即可烘焙进分类头。请在 macOS 或 Linux 上执行导出CoreML 不支持 Windows。iOS 部署细节参见 CoreML 集成文档。Q5能把导出模型量化为 INT8 或 FP16 吗可以针对多个格式。导出到 OpenVINO、CoreML、MNN 或 NCNN 时传quantize16FP16或quantize8INT8。OpenVINO 的 INT8 额外需要calibration_dataset参数用于训练后量化PTQ。各格式的量化取舍详见对应格式的集成页面。Q6如何验证导出模型与原始模型一致用相同输入分别运行原始 PyTorch 模型与导出模型再比较输出。用对应后端加载导出文件例如 ONNX 用ONNXBackend检查最大绝对差并以该格式自身的基线为标尺判断以本文的 ResNet-18 为例FP32 ONNX、TF SavedModel 与 LiteRT 约为1e-6TorchScript 为0NCNN 约1e-2因其 CPU 运行时默认 FP16。差距明显偏大则指向不支持的算子、错误的输入形状或模型未处于 eval 模式。可运行示例见第 15 节。小结这套工具让任意 PyTorch 模型从一个普通的torch.nn.Module出发经由同一套一致的 API 走到部署就绪的 ONNX、OpenVINO、CoreML、TensorFlow 或移动端运行时产物。选择与目标硬件匹配的格式先做数值一致性校验见第 15 节再按对应集成文档完成运行时特定的部署步骤即可构成一条完整的非 YOLO 模型交付链路。【免费下载链接】ultralyticsUltralytics YOLO26, YOLO11, YOLOv8 — object detection, instance segmentation, semantic segmentation, image classification, pose estimation, object tracking项目地址: https://gitcode.com/GitHub_Trending/ul/ultralytics创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考