导出以便部署
将 best.pt 导出为 ONNX、OpenVINO、TensorRT、CoreML、LiteRT 或 QNN,然后在部署前验证导出模型与 PyTorch 模型一致。
你的 best.pt 需要 Python 和 PyTorch 才能运行;手机、浏览器、Jetson 和生产服务器通常没有这些环境。导出模式只需一次调用,就能将模型转换为这些运行时可用的独立文件。需要注意的是,文件能够加载并不代表结果一定正确;不严谨的对比可能会让正确的导出看起来有问题,也可能掩盖导出中的问题。
在本课中,你将把药丸模型导出为 ONNX,通过相同的 YOLO API 运行;在设置一致的情况下,根据边界框和验证 mAP 证明导出结果与 PyTorch 一致;然后根据目标设备选择合适的格式:ONNX、OpenVINO、TensorRT、CoreML、LiteRT 或 QNN。
实践操作
示例:导出为 ONNX#

yolo export model=runs/detect/pills_v1/weights/best.pt format=onnxPyTorch: starting from 'runs/detect/pills_v1/weights/best.pt' with input shape (1, 3, 320, 320) BCHW and output shape(s) (1, 5, 2100) (5.2 MB)
ONNX: export success ✅ 0.9s, saved as 'runs/detect/pills_v1/weights/best.onnx' (9.3 MB)
Predict: yolo predict task=detect model=runs/detect/pills_v1/weights/best.onnx imgsz=320
Validate: yolo val task=detect model=runs/detect/pills_v1/weights/best.onnx imgsz=320 data=my_dataset/data.yaml逐行说明:
input shape (1, 3, 320, 320):一张图像、3 个颜色通道、固定的 320×320 方形输入——训练时的imgsz已固化到文件中。output shape(s) (1, 5, 2100):每个候选边界框有 4 个坐标值和 1 个类别分数,共有 2,100 个候选框;默认情况下,NMS 在计算图外运行。9.3 MB:ONNX 文件存储 FP32 权重,因此比 FP16 的.pt大。Predict:/Validate::针对导出文件提供的现成命令,已使用正确的imgsz。
几个参数就能满足大多数需求;其余参数请参阅 ONNX 集成指南。
| 参数 | 默认 | 用途 |
|---|---|---|
imgsz | 训练尺寸 | 以其他固定输入尺寸导出,例如 imgsz=640 |
dynamic | False | 接受可变输入尺寸,而不是固定形状 |
quantize | 无(FP32) | 使用 16 导出 FP16 权重(yolo26n.onnx 可将文件大小从 9.5 MB 降至 4.8 MB);对于支持 INT8 的格式,使用 8 |
nms | 无 | nms=True 会将 NMS 嵌入计算图,因此运行时会返回最终边界框 |
示例:验证导出结果是否一致#
YOLO 类也能加载导出文件,因此之前的预测代码无需修改即可使用。使用同一张验证图像对比这两个文件:
from ultralytics import YOLO
image = "my_dataset/images/val/Frame_144.jpg"
pt = YOLO("runs/detect/pills_v1/weights/best.pt")(image, rect=False, verbose=False)[0] # square input, like ONNX
onnx = YOLO("runs/detect/pills_v1/weights/best.onnx")(image, verbose=False)[0]
print(f"pt: {len(pt.boxes)} pills, mean conf {pt.boxes.conf.mean():.3f}")
print(f"onnx: {len(onnx.boxes)} pills, mean conf {onnx.boxes.conf.mean():.3f}")
print(f"max box difference: {(pt.boxes.xyxy - onnx.boxes.xyxy).abs().max():.4f} px")pt: 25 pills, mean conf 0.870
onnx: 25 pills, mean conf 0.870
max box difference: 0.0002 px数量相同,置信度相同,边界框的差异不到一个像素。接下来进行更严格的检查:对整个数据划分进行验证:
from ultralytics import YOLO
pt = YOLO("runs/detect/pills_v1/weights/best.pt").val(data="my_dataset/data.yaml", rect=False, verbose=False)
onnx = YOLO("runs/detect/pills_v1/weights/best.onnx").val(data="my_dataset/data.yaml", verbose=False)
print(f".pt mAP50-95 {pt.box.map:.4f}")
print(f".onnx mAP50-95 {onnx.box.map:.4f}").pt mAP50-95 0.6570
.onnx mAP50-95 0.6570结果完全一致。(.pt 文件的默认矩形验证得分为 0.659:这是输入填充造成的小幅差异,而非导出导致的。)
确认结果一致后,在目标设备上使用 yolo benchmark 计时,以便在部署前了解实际速度。
为你的目标设备选择格式#

| 目标 | 格式 | 说明 |
|---|---|---|
| 通用默认选择:适用于 Linux、Windows 和 Mac 上的服务器与桌面设备 | onnx | 在 CPU 或 GPU 上使用 ONNX Runtime;最容易验证的导出格式 |
| NVIDIA GPU 和 Jetson | engine (TensorRT) | 在 NVIDIA 上速度最快;在设备上导出。参见 使用 TensorRT 优化 |
| Intel CPU 和集成 GPU | openvino | 借助 Intel 内核实现真正的 CPU 加速。参见 在 CPU 上使用 OpenVINO |
| iPhone、iPad 和 Mac 应用 | coreml | 原生支持;使用 Apple Neural Engine |
| Android 及其他移动或嵌入式设备 | litert | 移动设备建议使用 INT8 |
| Snapdragon NPU | qnn | 借助 Hexagon HTP 加速;默认使用 INT8 权重和 16 位激活;使用 name 选择 HTP 架构 |
| Web 浏览器 | 搭配 ONNX Runtime Web 使用 onnx | 较小的模型更切合实际:n 和 s |
from ultralytics import YOLO
model = YOLO("runs/detect/pills_v1/weights/best.pt")
model.export(format="onnx") # 跨平台:ONNX Runtime
model.export(format="openvino") # Intel CPU / iGPU
model.export(format="engine", quantize=16) # NVIDIA TensorRT,FP16(在目标 GPU 上运行)
model.export(format="coreml") # Apple iOS / macOS
model.export(format="litert", quantize=8, data="my_dataset/data.yaml") # Android / 边缘设备,INT8
model.export(format="qnn", name="73", data="my_dataset/data.yaml") # Qualcomm Snapdragon NPU (HTP v73);使用你自己的数据进行校准每次导出都会在权重文件旁边生成文件:best.onnx、best_openvino_model/、best.engine,依此类推。即使最终会使用其他格式,也请从 ONNX 开始:它最容易快速验证,也是其他多种工具链的输入格式。部署选项指南会比较所有格式,而选择部署目标会带你完成选择过程。
模型量化以精度换取更小的体积和更快的速度。FP16(quantize=16)可将文件大小减半,精度几乎不变。INT8(quantize=8)体积更小、速度更快,但需要校准图像——也就是导出过程中用于确定数值范围的代表性帧;Ultralytics 建议至少使用 300 张。部署前务必验证 INT8 模型:精度损失可能微乎其微,也可能很大,具体取决于模型和校准集。
避免这些错误#
症状:.pt 模型在 Frame_144.jpg 上检测到 35 颗药片,而 ONNX 文件只检测到 25 颗,看起来像是导出出了问题。原因:PyTorch 推理会将每张图像填充到与最小步幅对齐的矩形尺寸(这些 16:9 帧为 192×320),而静态 ONNX 模型始终接收 320×320 的正方形输入。输入不同,低置信度检测结果也会不同。解决方法:比较时,将 rect=False 传给 .pt 模型,如 parity.py 所示。
症状:你将 imgsz=640 传给 best.onnx,日志仍显示 320x320。原因:静态导出模型只有一种输入尺寸,该尺寸在导出时设定。解决方法:按实际运行尺寸导出(imgsz=640),或使用 dynamic=True 导出。
在 A100 上构建的 .engine 无法在 Jetson Orin 上运行,也可能无法兼容 TensorRT 升级。请在目标设备上使用该设备将运行的 TensorRT 版本进行导出。ONNX 可移植;引擎则不行。
在 INT8 导出时不设置 data,Ultralytics 会发出警告,然后使用默认的 COCO8 样本进行校准——这 8 张图像和你的药片毫不相像。请传入你自己的数据:model.export(format="litert", quantize=8, data="my_dataset/data.yaml")。
你已完成部署#
现在,你已经训练好了 best.pt,获得了与基线对照的验证证据、适用于运行时的导出文件,以及导出结果与原始模型一致的证明。这就是完整流程——数据、训练、验证、导出、部署——生产团队会按计划运行这套流程。Ultralytics YOLO 生产部署将从经过验证的导出模型继续讲解,涵盖优化后的运行时、跟踪流水线、多流服务和监控。
显示解答
from ultralytics import YOLO
# Train
model = YOLO("yolo26n.pt")
model.train(data="my_dataset/data.yaml", epochs=10, imgsz=320, name="pills_e2e")
# Validate
metrics = model.val()
print(f"mAP50-95 = {metrics.box.map:.3f}") # 0.659
# Export
model.export(format="onnx")parity.py: pt 25 pills, onnx 25 pills, max box difference 0.0002 px
without rect: pt 35 pills (192x320 input) vs onnx 25 (320x320): input mismatch, not an export bug
val_export.py: .pt 0.6570, .onnx 0.6570
Target: Intel laptop CPU -> openvino, for faster CPU inference than ONNX Runtime