
简介面向零基础学习者的目标检测实战文档系统讲解YOLOv11从PyTorch训练到ONNX跨平台部署的完整链路。内容涵盖YOLOv11核心架构、环境搭建、数据准备与标注、模型训练及评估优化、ONNX转换与跨平台部署并附常见问题解决方案适合刚接触目标检测或希望在安防监控、自动驾驶、工业检测等场景落地YOLO的开发者。资源为单个PDF文件共45页大小2.29MB支持目录章节跳转与阅读器左侧大纲快速定位文字、图表均显示正常便于按章节查阅和反复学习。目前已有77人学习浏览。文档从零起步拆解每一步操作细节既讲清PyTorch训练流程与参数配置也覆盖ONNX Runtime在不同硬件平台上的部署方法、性能优化和排错思路可帮助读者少走弯路快速打通从算法训练到实际部署的完整闭环。1. YOLOv11 的完整落地链路从 PyTorch 训练到 ONNX 部署值不值得走一遍YOLOv11 的完整落地链路从 PyTorch 训练到 ONNX 跨平台部署中间隔着的不是代码量而是几个容易翻车的关键环节预处理对齐、导出参数、后处理移植。常见场景是模型在训练机上 mAP 不错一旦要换语言、换推理框架到现场设备才发现 .pt 权重根本交不了差。这条路适合两类人一是训练结果停留在笔记本、想真正部署上线的开发者二是刚接触目标检测想系统跑通一遍全流程的新手。下文按训练、导出、验证、部署的顺序把每一步做什么、参数怎么选、哪里最坑讲清楚所有命令基于当前主流的 YOLO 训练工具链照着执行就能跑通。2. 先把地基打牢PyTorch 环境与 YOLOv11 首次推理2.1 环境准备Python 虚拟环境与依赖安装刚开始做目标检测的人最容易在这一步翻车直接在全局环境里装了一堆包torch 版本和工具链互相打架模型训到一半才发现依赖装错了。我一般会先用虚拟环境把项目隔离起来后面换显卡、换机器都不会污染系统 Python。python -m venv yolo-env source yolo-env/bin/activate # Windows PowerShell: yolo-env\Scripts\Activate.ps1 pip install --upgrade pip pip install torch torchvision pip install ultralytics onnx onnxruntime第一行创建虚拟环境第二行激活它后面三条命令分别装训练框架、YOLO 工具链和部署推理库。torch 和 torchvision 如果想用 GPU 加速建议去 PyTorch 官网选对应 CUDA 版本的安装命令如果只是先学流程CPU 版也能完整跑通训练到导出的全过程ONNX 导出这一步完全不需要 GPU。装完后先确认环境没问题python -c import torch, ultralytics, onnxruntime; print(torch.__version__, ultralytics.__version__, onnxruntime.__version__)能打印出版本号就说明三个核心依赖都就位了。常见报错是 ModuleNotFoundError多半是没激活虚拟环境或者 pip 装到了别的 Python 解释器里。检查which python指向的路径是不是当前虚拟环境基本就能定位。2.2 下载预训练权重并完成第一次推理YOLOv11 的模型按尺度分成 n、s、m、l、x 五档n 最轻、x 最重。新手选 n 或 s 就够了训练快、部署也方便。第一次推理用官方预训练权重先建立“正常结果长什么样”的参照系yolo predict modelyolo11n.pt sourcebus.jpg conf0.25 imgsz640 devicecpu这条命令会解析图片、画出检测框并保存结果。首次运行会自动下载权重文件之后都在本地缓存。conf0.25是置信度阈值低于 0.25 的框会被过滤imgsz640是推理输入尺寸devicecpu保证机器上没有 GPU 也能跑。跑通了之后再用 Python 方式调用方便后面把结果拿来做对比from ultralytics import YOLO model YOLO(yolo11n.pt) result model.predict( sourcebus.jpg, conf0.25, imgsz640, devicecpu )[0] print(result.boxes.xyxy) # 检测框左上右下像素坐标 print(result.boxes.conf) # 每个框的置信度 print(result.boxes.cls) # 类别索引 result.save(output.jpg) # 画出结果图这里拿到的result.boxes已经是官方封装好了的坐标是像素值类别已经解码成索引置信度也过滤过了。这套结果要和后面 ONNX 的裸输出做交叉验证所以先把这三行打印记住。2.3 看原始输出为 ONNX 阶段做认知铺垫部署时不能用YOLO(yolo11n.pt)这种高级封装必须面对模型的裸张量。所以在这一步就把原始输出看清楚后面导出 ONNX 时就不会慌。用一张全零输入前向一次观察检测头输出import torch from ultralytics import YOLO model YOLO(yolo11n.pt).model # 底层 nn.Module model.eval() dummy torch.zeros(1, 3, 640, 640) with torch.no_grad(): raw model(dummy) if isinstance(raw, (list, tuple)): raw raw[0] print(原始输出 shape:, tuple(raw.shape))如果是 COCO 的 80 类输出通常是[1, 84, 8400]。这个数字拆开看84 4框坐标 cx、cy、w、h 80类别数8400 是 80×80、40×40、20×20 三个尺度特征图的栅格总数。换成你自己的数据集第二维会变成 4 类别数。注意这里的类别分数还没做 sigmoid坐标是相对 640×640 输入空间的像素值。这个格式就是后面 ONNX 模型输出的格式现在先记住导出后你会发现它一模一样。3. 用自定义数据集训练 YOLOv11目录结构、训练命令与收敛判断3.1 数据目录与标签格式YOLO 标注到底长什么样训练前要把数据整理成工具链认识的目录结构。一个常见做法是 images 放图片、labels 放同名标注文件训练集和验证集分开datasets/my_dataset/ ├── images/ │ ├── train/ # 训练图片 │ └── val/ # 验证图片 ├── labels/ │ ├── train/ # 对应的标注 txt │ └── val/ └── my_dataset.yaml图片名和标注名必须一一对应比如images/train/0001.jpg对应labels/train/0001.txt。每张图片的标注 txt 里每行代表一个目标格式是五个数字类别 id、中心点 x、中心点 y、宽 w、高 h。其中 cx、cy、w、h 全部是 0 到 1 之间的归一化值除以图片宽高后的结果。示例0 0.512 0.421 0.234 0.521 2 0.761 0.803 0.118 0.098第一列类别 id 必须从 0 开始连续编号和后面 yaml 里的 names 顺序一一对应。如果标注工具导出的是 VOC 的 XML 或别的 JSON 格式需要先转成这个格式转换这一步最容易出问题忘了归一化、坐标反了、类别从 1 开始编号。数据集描述文件长这样path: datasets/my_dataset train: images/train val: images/val names: 0: person 1: car 2: helmetpath是相对 yaml 文件所在目录的路径train和val是相对path的图片目录。names的索引顺序必须和标注 txt 里的 id 完全一致错一位后面就是灾难。3.2 启动训练命令、关键参数与选型数据备齐后一条命令启动训练yolo train \ datadatasets/my_dataset/my_dataset.yaml \ modelyolo11n.pt \ epochs100 \ imgsz640 \ batch16 \ patience20 \ device0 \ workers4 \ seed42modelyolo11n.pt表示用预训练权重做微调而不是随机初始化这样小数据集也能有不错的收敛速度。epochs100是最大训练轮数实际会被早停机制打断。imgsz640是训练输入尺寸如果小目标特别多可以试试 960 或 1280但显存和耗时都会涨。batch受显存约束不够就减半。patience20表示验证指标连续 20 轮不提升就提前结束。workers是数据加载线程数4 到 8 比较合适太高反而可能卡住。seed42固定随机种子方便复现。模型尺度怎么选取决于部署目标。跑嵌入式或手机端就选 n精度换取速度服务器上可以选 s 或 m。数据集只有几百张图时一定用预训练权重起步从零训练几乎不可能收敛到可用水平。3.3 训练结果怎么看收敛判断与模型选择训练过程的输出默认在runs/train/exp/目录每次实验递增为 exp、exp2、exp3。这个目录下最重要的两个文件是weights/best.pt和weights/last.ptbest 是验证集指标最好的权重部署用这个last 是最后一轮权重用来断点续训。验证命令yolo val modelruns/train/exp/weights/best.pt datadatasets/my_dataset/my_dataset.yaml训练过程中results.csv会实时记录每一轮的 loss 和指标。重点关注这几列metrics/precision精确率、metrics/recall召回率、metrics/mAP50(B)、metrics/mAP50-95(B)。mAP50 是 IoU 阈值为 0.5 时的平均精度mAP50-95 是 0.5 到 0.95 十个阈值下的平均值后者更严格。判断收敛的经验mAP50 从 0 涨到 0.6 以上一般任务就可用了具体看难度train loss 持续下降但 val mAP 停滞基本是过拟合加数据或减小模型尺度precision 高 recall 低说明漏检多部署时把 conf 阈值调低recall 高 precision 低说明误检多把 conf 阈值调高有一个容易被忽略的陷阱类别分布严重不均衡时mAP50 会虚高因为背景类预测对了也能拉高指标。不要只看 mAP要随机抽几张验证集图片人工确认检测框落点是否合理。这部分判断直接决定你能不能带着信心进入导出环节。4. 把 PyTorch 权重导出成 ONNX导出参数与 Runtime 验证4.1 最小导出命令与参数含义训练完的权重是 PyTorch 格式只能被 PyTorch 的 Runtime 加载。要让模型跑在别的平台需要导出成 ONNX 这种格式中立的中间表示。最小导出命令一句话yolo export modelruns/train/exp/weights/best.pt formatonnx imgsz640 opset12在同目录下会生成best.onnx。导出过程不需要 GPUCPU 就能完成。但真实跨平台部署通常要加两个参数yolo export modelruns/train/exp/weights/best.pt \ formatonnx imgsz640 opset12 dynamicTrue simplifyTrue参数含义和作用参数作用使用注意imgsz导出模型的输入尺寸要和训练尺寸一致否则预处理对不上opsetONNX 算子集版本12 是兼容性较好的选择目标 Runtime 老就用更低的dynamic是否允许动态 batch 和宽高灵活但部分推理框架解析慢甚至不支持simplify用简化工具去除冗余节点一般建议开启能减小模型体积dynamicTrue导出的模型输入名会变成动态轴后面在 onnxruntime 里使用不受限制。如果你的部署场景尺寸固定比如永远跑 640×640就导一版dynamicFalse的固定模型很多嵌入式平台反而更友好。4.2 预处理必须对齐letterbox、RGB 与归一化导出的 ONNX 模型不包含预处理逻辑。训练时用的是 letterbox 等比缩放加填充推理时如果直接cv2.resize拉伸到 640×640宽高比变了检测框必然系统性偏移。这是新手最容易踩的坑先把 letterbox 函数准备好import cv2 import numpy as np def letterbox(img, new_shape(640, 640), color(114, 114, 114)): h, w img.shape[:2] r min(new_shape[0] / h, new_shape[1] / w) nh, nw int(round(h * r)), int(round(w * r)) resized cv2.resize(img, (nw, nh), interpolationcv2.INTER_LINEAR) canvas np.full((new_shape[0], new_shape[1], 3), color, dtypenp.uint8) top, left (new_shape[0] - nh) // 2, (new_shape[1] - nw) // 2 canvas[top:topnh, left:leftnw] resized return canvas, r, top, left这个函数返回三个值填充后的 640×640 图像、缩放比例 r、填充偏移 top 和 left。后处理阶段要把框映射回原图三个值一个都不能丢。记住letterbox 时用灰色填充这也是训练时数据增强的默认行为推理端必须保持一致。4.3 用 ONNX Runtime 跑通验证闭环模型导出后第一步不是拿去部署而是先在本机用 onnxruntime 验证结果和 PyTorch 是否一致。完整推理代码import numpy as np import onnxruntime as ort import cv2 sess ort.InferenceSession(best.onnx, providers[CPUExecutionProvider]) input_name sess.get_inputs()[0].name img cv2.imread(test.jpg) canvas, r, top, left letterbox(img) blob canvas[:, :, ::-1].transpose(2, 0, 1).astype(np.float32) / 255.0 blob blob[None] # (1, 3, 640, 640) out sess.run(None, {input_name: blob})[0] # 期望 shape 是 (1, 4类别数, 8400)如果不是就先转置 if out.shape[2] 4 out.shape[1] - 4: out out.transpose(0, 2, 1)预处理三步BGR 转 RGB[:, :, ::-1]、HWC 转 CHWtranspose(2, 0, 1)、归一化到 0~1/ 255.0。providers指定 CPU 执行后面换 GPU 或别的硬件再增删。接着解码原始输出nc out.shape[1] - 4 pred out[0] # (4nc, 8400) boxes pred[:4] # cx, cy, w, h像素值 cls pred[4:] scores 1.0 / (1.0 np.exp(-cls)) # sigmoid cls_ids np.argmax(scores, axis0) confs np.max(scores, axis0) keep confs 0.25 boxes boxes[:, keep] confs confs[keep] cls_ids cls_ids[keep] # 映射回原图坐标先减填充偏移再除以缩放比 x1 (boxes[0] - boxes[2] / 2 - left) / r y1 (boxes[1] - boxes[3] / 2 - top) / r x2 (boxes[0] boxes[2] / 2 - left) / r y2 (boxes[1] boxes[3] / 2 - top) / r idx cv2.dnn.NMSBoxes( np.column_stack([x1, y1, x2 - x1, y2 - y1]).tolist(), confs.astype(float).tolist(), 0.25, 0.45 )这段代码就是你要在目标平台上移植的全部推理逻辑。验证方法是同一张图分别跑 PyTorch 封装和 ONNX 后处理对比框的位置和类别。两个结果越接近越好如果对不上90% 是预处理不一致而不是模型损坏。先检查输入 tensor 是否逐元素一致再检查输出不要一上来就怀疑导出过程有问题。5. 全流程避坑指南5 个让我翻过车的真实问题这条路我按步骤走了很多遍下面几个问题几乎每次换台机器都会冒出来。按“现象、原因、解决”写方便你对号入座。5.1 训练报 CUDA out of memory现象训练跑到某个 epoch 突然中断终端提示 CUDA out of memory之前跑得好好的看起来毫无规律。原因batch 和 imgsz 的显存需求超出显卡容量。尤其是共享显存的机器其他程序一启动就会挤占显存。还有 workers 开太多导致数据加载进程占额外显存的情况。解决先把 batch 减半从 16 降到 8 再降到 4还不行就把 imgsz 从 640 降到 512。如果数据集不大加cacheFalse避免额外缓存占用。另外训练前用nvidia-smi看看显存是不是被别的东西占了养成开训前检查的好习惯。实在没 GPU 就用 CPU 先跑小数据集验证流程等代码逻辑没问题再上 GPU。5.2 ONNX 推理结果和 PyTorch 对不上现象同一张图PyTorch 能检出 3 个框ONNX 只检出 2 个甚至框的位置整体偏移了半个身位。新手第一反应是导出坏了重导好几遍结果一样。原因预处理不一致。最常见的是推理时用cv2.resize直接拉伸训练时用的是 letterbox 等比缩放其次是忘了 BGR 转 RGB或者归一化时忘了除 255。输入就不一样输出自然对不上。解决把训练时那套预处理原样搬过来严格按 4.2 节的顺序执行。先用 NumPy 保存 PyTorch 推理前预处理好的 tensor再喂给 onnxruntime逐元素对比两个输入是否一致。输入一致但输出不同才是模型或者算子的问题输入就不一致老老实实修预处理。这是血泪经验一大半的“导出翻车”其实都翻在预处理上。5.3 训练 loss 降了但预测结果全乱现象训练过程曲线很好看mAP 也不低但画出来的框类别全是错的“人”被标成“车”而且错得有规律。原因标签类别 id 和 yaml 的 names 顺序错位。比如标注工具从 1 开始编号而 yaml 里 0 号是 person训练时模型学到的映射和你想表达的完全错开。解决训练前先统计一遍所有标注文件的类别 id 范围。写个几行脚本扫描 labels 目录import os ids set() for root, _, files in os.walk(datasets/my_dataset/labels): for f in files: if f.endswith(.txt): with open(os.path.join(root, f)) as fp: for line in fp: ids.add(int(line.split()[0])) print(类别范围:, min(ids), max(ids))如果最大 id 等于 yaml 里 names 的数量减一基本没问题如果出现越界值说明标注或转换脚本有问题先修数据再训练。这个坑我栽过一次修完数据后同样参数重新训练mAP 直接翻倍。5.4 目标运行时加载不了导出的算子现象模型在 PC 上跑得好好的换到嵌入式设备或低版本 Runtime加载时报 Unsupported operator或者能加载但推理直接报错。原因opset 设太高目标 Runtime 版本老算子实现不全。另外如果导出时把 NMS 也打进了图里这个算子在很多推理引擎里属于可选扩展不支持就整个模型跑不了。解决先按 opset12 导出不用追求新版算子集。NMS 不要打进模型图自己在后处理里用 TopK 加 IoU 过滤实现逻辑控制在几十行代码内可移植性最好。动态轴在部分嵌入式平台也是雷区部署尺寸确定后就导一版dynamicFalse的固定模型加载更快也更稳。5.5 CPU 上 ONNX 反而比 PyTorch 慢现象满怀期待导出 ONNX结果在 CPU 上跑起来和 PyTorch 差不多甚至更慢完全没体会到部署框架的加速。原因onnxruntime 的线程数没配默认值在部分机器上表现很差模型本身没简化冗余算子拖累 CPU 执行输入尺寸 960 或 1280 在 CPU 上是灾难级开销。解决先配置 session 的线程参数intra_op_num_threads设为 4 到 8和物理核数对应。导出时开simplifyTrue去掉冗余节点。CPU 推理对输入尺寸极其敏感640 和 1280 的耗时差好几倍。如果这些都调完还慢就该考虑换更小的模型尺度或者做量化了这部分下一章展开。6. 部署前的最后一道工序ONNX 提速与一致性验证习惯模型导出并验证通过后部署前我只做两件事把推理延迟压到可接受范围把“换平台不出错”固化成一个可重复的验证脚本。延迟测试的基准脚本很简单但有几个细节必须注意import time import numpy as np import onnxruntime as ort def latency(model_path, threads4, runs30): so ort.SessionOptions() so.intra_op_num_threads threads so.inter_op_num_threads 1 sess ort.InferenceSession(model_path, so, providers[CPUExecutionProvider]) x np.random.rand(1, 3, 640, 640).astype(np.float32) for _ in range(3): # warmup跳过算子初始化耗时 sess.run(None, {sess.get_inputs()[0].name: x}) t0 time.perf_counter() for _ in range(runs): sess.run(None, {sess.get_inputs()[0].name: x}) return (time.perf_counter() - t0) / runs * 1000 print(CPU 单次耗时:, latency(best.onnx), ms)线程数和耗时不是线性关系4 到 8 线程性价比最高继续加收益很小。warmup 必须有第一次推理包含会话初始化和算子编译不跳过会严重高估延迟。如果目标设备有 GPU可以把模型转成 FP16onnxruntime 的 GPU 执行提供方对 FP16 支持比较好延迟和显存都有改善嵌入式平台则优先尝试 INT8 量化但量化后必须重新跑验证。我的检验习惯是准备 5 到 10 张覆盖不同场景、不同光照的“金标图”先用 PyTorch 跑出基准检测框再到目标平台跑 ONNX逐张计算框的 IoU。任一张 IoU 低于 0.9就不谈性能优化先回去查预处理和导出参数。性能调优有它玄学的一面但流程规范化能砍掉大部分不确定性。这个习惯帮我避免了好几次“部署完才发现框全偏了”的事故。希望帮到你。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。