Ultralytics YOLO27: 加入候补名单。
Get Started
训练你的第一个 YOLO 模型·部署·课程 10/10
课程初级

导出以便部署

将 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。

学习成果

你可以将训练好的模型导出为适合部署目标的格式,并通过同条件对比和验证,证明导出结果与 best.pt 一致。

快速通道
如果你已经熟悉相关内容,以下是简要版。
  1. yolo export model=runs/detect/pills_v1/weights/best.pt format=onnx——从这里开始。

  2. Intel CPU 使用 OpenVINO;NVIDIA GPU 和 Jetson 使用 TensorRT;Apple 设备使用 CoreML;Android 使用 LiteRT;Snapdragon NPU 使用 QNN。

  3. 在同一张图像上对比 .pt 和导出模型,并在 .pt 端使用 rect=False。

  4. 在训练时使用的 imgsz 下验证两者;mAP50-95 应当一致。

实践操作

示例:导出为 ONNX#

Ultralytics Platform 模型导出选项卡,列出了 ONNX、TensorRT、CoreML 和 OpenVINO 等部署格式

yolo export model=runs/detect/pills_v1/weights/best.pt format=onnx
PyTorch: 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
dynamicFalse接受可变输入尺寸,而不是固定形状
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 计时,以便在部署前了解实际速度。

为你的目标设备选择格式#

Ultralytics Platform 生命周期:使用 SAM 智能标注、在云端 GPU 上训练,并部署到全球各区域,包含集成合作伙伴徽标

目标格式说明
通用默认选择:适用于 Linux、Windows 和 Mac 上的服务器与桌面设备onnx在 CPU 或 GPU 上使用 ONNX Runtime;最容易验证的导出格式
NVIDIA GPU 和 Jetsonengine (TensorRT)在 NVIDIA 上速度最快;在设备上导出。参见 使用 TensorRT 优化
Intel CPU 和集成 GPUopenvino借助 Intel 内核实现真正的 CPU 加速。参见 在 CPU 上使用 OpenVINO
iPhone、iPad 和 Mac 应用coreml原生支持;使用 Apple Neural Engine
Android 及其他移动或嵌入式设备litert移动设备建议使用 INT8
Snapdragon NPUqnn借助 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

症状:你将 imgsz=640 传给 best.onnx,日志仍显示 320x320。原因:静态导出模型只有一种输入尺寸,该尺寸在导出时设定。解决方法:按实际运行尺寸导出(imgsz=640),或使用 dynamic=True 导出。

TensorRT 引擎与设备绑定

在 A100 上构建的 .engine 无法在 Jetson Orin 上运行,也可能无法兼容 TensorRT 升级。请在目标设备上使用该设备将运行的 TensorRT 版本进行导出。ONNX 可移植;引擎则不行。

除非另行指定,否则 INT8 会使用 COCO8 进行校准

在 INT8 导出时不设置 data,Ultralytics 会发出警告,然后使用默认的 COCO8 样本进行校准——这 8 张图像和你的药片毫不相像。请传入你自己的数据:model.export(format="litert", quantize=8, data="my_dataset/data.yaml")。

你已完成部署#

现在,你已经训练好了 best.pt,获得了与基线对照的验证证据、适用于运行时的导出文件,以及导出结果与原始模型一致的证明。这就是完整流程——数据、训练、验证、导出、部署——生产团队会按计划运行这套流程。Ultralytics YOLO 生产部署将从经过验证的导出模型继续讲解,涵盖优化后的运行时、跟踪流水线、多流服务和监控。

试试看

将你的 pills_v1/weights/best.pt 导出为 ONNX,然后运行 parity.py 和 val_export.py。不使用 rect=False,重新运行 parity.py,并记录 .pt 数量的变化。提交四项结果:匹配的检测数量、最大框差异、两个 mAP50-95 数值,以及一行说明实际部署目标所需格式及原因的话。

提交
git add -A && git commit -m "feat(deploy): exported best.pt to onnx for production runtime"
完成条件
满足以下所有条件,即表示你已完成本课程。
  • runs/detect/pills_v1/weights/best.onnx 已存在,并通过 YOLO() 进行预测。

  • 使用 rect=False 时,检测数量一致,最大框差异小于 1 px。

  • 在设置一致的情况下,ONNX 和 .pt 的验证 mAP50-95 相同,而且你已说明目标格式及原因。

显示解答
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
接下来做什么

课程已完成——参加最终测验,获取 训练你的第一个 YOLO 模型 证书,然后继续学习 Ultralytics YOLO 生产部署。

登录以保存学习进度