YOLOv8模型基础与导出:从网络结构到ONNX
好,咱们正式开始动手前的热身环节。
YOLOv8的结构、训练保存、导出ONNX——这三件事搞明白,后面所有部署工作才能站得住脚。
我见过不少同学,模型训完直接拿PyTorch的.pt文件往生产环境塞,结果推理慢得离谱,还各种报错。
说白了,部署的第一步,就是搞清楚你的模型到底长什么样,以及怎么把它变成通用格式。
YOLOv8网络结构速览
YOLOv8的结构,我习惯把它拆成三块来看:
- Backbone(主干网络):负责提取特征。YOLOv8用的是CSPDarknet的改进版,加入了C2f模块。
- Neck(颈部):负责融合多尺度特征。FPN+PAN结构,让不同尺寸的目标都能被照顾到。
- Head(检测头):负责输出预测结果。YOLOv8换成了解耦头(Decoupled Head),分类和回归分开走。
为什么这么设计?
你想想看,工业场景里目标大小差异很大——一个画面里可能既有大设备,又有小螺丝。
Backbone提取基础特征,Neck把深浅层信息揉在一起,Head再各自干活。分工明确,效率才高。
核心变化:YOLOv8相比v5,最大的改动就是Head部分。v5的耦合头把分类和回归绑在一起,v8解耦后,收敛更快,精度也更高。我在项目中实测过,同样数据下mAP能涨1-2个点。
下面这张图,是我自己画的结构简图,帮你快速建立整体认知:
PyTorch模型训练与权重保存
训练这块,我不打算讲太多理论——网上教程一抓一大把。
我重点说说权重保存的那些坑,这才是部署环节最容易翻车的地方。
训练流程速览
- 准备数据:标注格式转成YOLO格式(txt文件,每行一个目标)。
- 配置yaml文件:指定数据路径、类别数、类别名。
- 选择预训练权重:yolov8n.pt / yolov8s.pt / yolov8m.pt 等。
- 开始训练:
yolo train model=yolov8n.pt data=coco128.yaml epochs=100 - 保存权重:训练完成后,
runs/detect/train/weights/下会有best.pt和last.pt。
我的习惯:训练时把 patience 设成 20-30 个epoch,早停机制能帮你省不少时间。另外,batch 大小根据显存来,别贪大——我见过有人把batch设到64,结果显存爆了,白跑半天。
权重文件里到底有什么?
很多人以为 .pt 文件就是个模型结构,其实不是。
PyTorch的 .pt 文件是一个字典,里面包含:
| 键名 | 内容 | 部署时是否需要 |
|---|---|---|
model |
模型的状态字典(state_dict) | ✅ 需要 |
epoch |
当前训练轮数 | ❌ 不需要 |
optimizer |
优化器状态 | ❌ 不需要 |
best_score |
最佳mAP分数 | ❌ 不需要 |
args |
训练参数 | ❌ 不需要 |
看到了吧?
一个 .pt 文件里,真正对部署有用的只有 model 这一项。
其他都是训练过程的“副产品”。
注意:千万不要直接把训练好的 .pt 文件扔到生产环境去推理!
原因有三:1) 文件体积大,加载慢;2) 依赖PyTorch环境;3) 推理速度远不如优化后的格式。
正确的做法是:先导出成ONNX,再转成TensorRT或OpenVINO。
导出为ONNX格式
ONNX(Open Neural Network Exchange)说白了就是模型界的“通用语言”。
不管你是用PyTorch、TensorFlow还是其他框架训的模型,都能转成ONNX。
然后ONNX又可以转成各种推理引擎的格式——TensorRT、OpenVINO、ONNX Runtime都支持。
导出命令
YOLOv8官方已经封装好了导出接口,一行命令搞定:
yolo export model=best.pt format=onnx opset=12
或者用Python代码:
from ultralytics import YOLO
model = YOLO('best.pt')
model.export(format='onnx', opset=12, dynamic=True)
关键参数说明
| 参数 | 说明 | 建议值 |
|---|---|---|
opset |
ONNX算子集版本 | 12 或 13(兼容性好) |
dynamic |
是否支持动态batch | True(工业场景推荐) |
simplify |
是否简化模型结构 | True(减少冗余算子) |
imgsz |
输入图像尺寸 | 640(与训练时一致) |
避坑指南:
我曾经在导出时忘了设 dynamic=True,结果模型只能接受固定batch size的输入。
到了生产环境,客户端传来的图片数量不固定,推理服务直接报错。
后来排查了半天才发现是这个问题。所以,工业场景下务必开启动态batch。
导出后的验证
导出完别急着走,先验证一下ONNX模型能不能正常跑:
import onnx
import onnxruntime as ort
# 检查模型结构
onnx_model = onnx.load('best.onnx')
onnx.checker.check_model(onnx_model)
# 用ONNX Runtime跑一次推理
session = ort.InferenceSession('best.onnx')
input_name = session.get_inputs()[0].name
output_name = session.get_outputs()[0].name
import numpy as np
dummy_input = np.random.randn(1, 3, 640, 640).astype(np.float32)
result = session.run([output_name], {input_name: dummy_input})
print('ONNX导出成功,输出shape:', result[0].shape)
如果这一步没报错,恭喜你,模型已经成功从PyTorch的“温室”里搬出来了。
接下来就可以进入下一阶段的优化和部署了。
小技巧:用 onnx-simplifier 工具再跑一遍简化,能去掉很多冗余的Shape和Reshape算子。
安装命令:pip install onnx-simplifier,然后 python -m onnxsim best.onnx best_simplified.onnx。
简化后的模型体积更小,推理速度也能提升5%-10%。
本章小结
咱们这一章把YOLOv8的底牌翻了个底朝天:
- 网络结构:Backbone提取特征 → Neck融合多尺度 → Head解耦输出
- 权重保存:.pt文件里只有model是部署需要的,其他都是训练垃圾
- ONNX导出:一行命令搞定,但别忘了开dynamic和simplify
嗯,到这里,你的模型已经准备好“走出实验室”了。
下一阶段,咱们就要开始真正的手艺活了——模型量化与精度调优。