1. 项目概述
1.1 YOLO11n 是什么,为什么值得专门记一份笔记
先交代一下背景。YOLO11 是 Ultralytics 在 2024 年 9 月底推出的目标检测模型系列,距离 YOLOv8 发布大约过去了一年半。作为 YOLOv8 的继任者,YOLO11 并不是简单的“数字 +1”,它在模型结构上做了几处实打实的改动,比如用 C3k2 模块替换了原来的 C2f 模块,新增了 C2PSA 注意力机制,还在检测头里继续沿用并优化了 Anchor-Free 的设计思路。YOLO11n 是 YOLO11 系列里最轻量级的版本,n 代表 nano,参数只有 260 万左右,模型权重文件大小约 5.4 MB。
我为什么专门给 YOLO11n 写一份学习笔记?原因很直接:在 YOLO11 的五个版本(n/s/m/l/x)里,nano 版本是最适合作为入门学习范本的。它结构完整,没有像 s/m/l/x 那样为了追求精度把通道数和层数堆得很高,反而更容易把每个模块的输入输出、特征图尺寸变化、参数量分布看懂。而且在实际落地场景里,YOLO11n 的推理速度在 CPU 上也能跑到一个可用的水平,边缘设备上配合 TensorRT 或 ONNX Runtime 甚至能实时运行,属于“麻雀虽小五脏俱全”的类型。
这篇博客适合谁来看?我觉得有三类人:第一类是用 YOLOv5/v8 做过项目、想了解 YOLO11 到底改了什么的开发者;第二类是刚接触目标检测,需要一条完整线路把环境搭建、模型训练、推理部署串起来的新手;第三类是手头有具体检测任务(比如安全帽检测、工件缺陷检测、小目标检测),想知道 YOLO11n 怎么调参、怎么排查问题的人。我不会把这篇写成官方文档的翻译版,而是从“踩坑 + 验证 + 拆解”的角度,把我实际跑通 YOLO11n 训练、推理、导出的全过程和一些心得记录下来。
1.2 目标检测这个任务,在这份笔记里到底拆成几块
目标检测本身不是一个单一动作,它是一个“输入图像 -> 输出边界框 + 类别标签 + 置信度”的完整流程。官方的 YOLO11 仓库把整条链路封装得很简单,几行代码就能跑起来,但越是封装得好,越容易让使用者忽略底层在发生什么。所以这份笔记我打算按下面几条线来拆:
模型结构线:YOLO11n 的网络由 Backbone(主干网络)、Neck(特征融合)、Head(检测头)三部分组成。Backbone 负责提取图像特征,Neck 负责把不同尺度的特征融合起来,Head 负责在融合后的特征图上预测目标的位置和类别。每一部分在 YOLO11 里都有具体的模块撑起来,我会逐一拆解。
数据流线:从一张 640x640 的输入图像开始,经过 Backbone 得到三个不同尺度的特征图(80x80、40x40、20x20),每个特征图上的每个网格负责预测若干个候选框,最后通过 NMS(非极大值抑制)筛选出最终的检测结果。这条线是理解 YOLO 系列“Anchor-Free + 多尺度预测”的关键。
训练流程线:数据准备、配置参数、启动训练、监控指标、结果评估。这是做项目时最常打交道的一段,也是我笔记里记录最多的地方。
部署扩展线:模型导出(ONNX/TensorRT)、推理加速、以及针对特定场景(小目标、红外目标、多模态输入)的改进方向。
我后面所有内容都会围绕这几条线展开,这样当你拿到一个具体项目时,至少能定位到“问题出在哪个环节”,而不是对着报错日志发呆。
2. YOLO11n 的核心结构拆解:从 Backbone 到 Head
2.1 Backbone:C3k2 模块和 C2PSA 是怎么工作的
YOLO11n 的 Backbone 是整个模型的特征提取器,输入一张 640x640x3 的图像,输出一系列不同尺度的特征图。相比 YOLOv8 的 Backbone,YOLO11 最明显的改动是用 C3k2 模块替换了 C2f 模块。
C3k2 这个名字乍看有点绕,拆开看就清楚了。C3 指的是它保留了 CSP(Cross Stage Partial)的设计思路,也就是把特征分成两条路径,一条走主干,一条走旁路,最后再融合。k 代表 kernel,指的是模块内部使用的卷积核大小,默认配置里 k=3。2 代表模块内部的 Bottleneck(瓶颈模块)重复次数。
用生活化的类比来解释 CSP 结构:想象一条生产线,如果所有零件都走同一条传送带,那么每个工位都要处理全部零件,效率低且容易堵住。CSP 结构相当于把传送带分成两条,一条处理核心零件,一条处理辅助零件,最后在末端汇合。这样既减少了重复计算,又保留了足够的信息流。
C2PSA 是 YOLO11 另一个新增模块,它是在特征提取的后半段引入的注意力机制。PSA 全称是 Position-Sensitive Attention,位置敏感注意力。通俗理解:普通卷积是对整张特征图做相同的操作,而注意力机制会让模型学会“哪里更重要”。比如检测一张街景图,模型通过 C2PSA 学会了把更多计算资源集中在行人、车辆所在的区域,而不是天空和路面。
我实际测试过,YOLO11n 的 Backbone 在 COCO 数据集上的特征提取能力相比 YOLOv8n 略有提升,体现在最终 mAP 上大约有 0.5 到 1 个百分点的增益,同时参数量反而下降了。这说明结构调整是有效的,而不是靠堆参数换精度。
2.2 Neck 和 Head:多尺度特征融合与 Anchor-Free 检测头的设计逻辑
Neck 部分,YOLO11 沿用了 PAN-FPN(Path Aggregation Network - Feature Pyramid Network)的结构。FPN 解决的是“多尺度目标”问题:大目标需要高层级、语义信息丰富的特征图,小目标需要低层级、细节信息丰富的特征图。FPN 自顶向下传递语义信息,PAN 再自底向上传递定位信息,两者组合起来,保证三个尺度的特征图都同时具备语义和定位能力。
具体到 YOLO11n,Neck 输出的三个特征图尺寸分别是:
| 特征图层级 | 特征图尺寸 | 对应感受野 | 擅长检测的目标尺度 |
|---|---|---|---|
| P3(浅层) | 80x80 | 小感受野 | 小目标 |
| P4(中层) | 40x40 | 中等感受野 | 中目标 |
| P5(深层) | 20x20 | 大感受野 | 大目标 |
Head 部分,YOLO11 继续使用 Anchor-Free 的 Decoupled Head 设计。所谓 Anchor-Free,指的是不再预先设定一组固定大小和比例的锚框(Anchor),而是让每个网格直接预测目标中心点是否落在自己内部,同时回归出边界框的宽高。YOLOv8 就已经这么设计了,YOLO11 保留了这一思路。
为什么 Anchor-Free 逐渐成为主流?因为传统 Anchor-Based 方法(比如 YOLOv2/v3 时代)需要针对特定数据集做 K-Means 聚类来设计锚框,换一个数据集就要重新聚类,而且锚框数量多、正负样本不均衡问题严重。Anchor-Free 直接绕开了锚框设计这一步骤,让模型自己学习目标形状的先验,大大简化了训练流程。
Decoupled Head 的意思是分类和回归分开走两条分支。分类分支预测每个网格属于各个类别的概率,回归分支预测边界框的中心点偏移和宽高。分开的好处是减少任务之间的干扰——分类关注的是“这是什么”,回归关注的是“在哪里”,两者优化目标不同,共用参数容易互相冲突。
3. 环境准备与模型运行:从零搭建 YOLO11n 训练环境
3.1 硬件配置与依赖安装的具体建议
先说硬件。YOLO11n 是个小模型,训练成本不算高,但也不是随便一台电脑就能跑得很舒服。我的建议分三档:
- 最低配置:8GB 显存的 GPU(GTX 1070 Ti、RTX 3060 及以上),或者 16GB 内存的 CPU 机器。nano 模型可以在 CPU 上训练,但速度很慢,一个 epoch 可能要跑几十分钟,适合 debug 代码验证流程。
- 推荐配置:RTX 3060 12GB 或 RTX 4070 及以上显存,这样 batch size 可以开到 16 甚至 32,训练速度和显存占用都比较理想。
- 极致配置:A100/H100 这类加速卡,适合训练 s/m/l/x 大模型,nano 级别用不上这么高端的卡。
依赖安装方面,Ultralytics 的安装非常友好,一行命令就能装好:
pip install ultralytics但要注意几个细节。第一,PyTorch 的安装建议先装 CUDA 版再装 ultralytics,否则 pip 会默认拉取 CPU 版本。第二,ultralytics 会自动检测 GPU 环境,如果你在服务器上跑但 nvidia-smi 没配置好,训练日志里会出现device: cpu,这时候要做的是检查 CUDA 环境,而不是代码本身。第三,建议用 conda 建一个独立环境,避免和其他项目的依赖冲突。我自己的环境是 Python 3.10 + PyTorch 2.1.0 + CUDA 11.8 + ultralytics 8.3.x,这套组合目前已经稳定跑了几个月。
验证环境是否正常,一行代码:
from ultralytics import YOLO model = YOLO("yolo11n.pt") results = model("https://ultralytics.com/images/bus.jpg") for r in results: r.show()如果能看到检测结果可视化,说明环境没问题,可以进入下一步。
3.2 用预训练权重跑一次推理:看懂输出结果的每个字段
第一次跑推理,不要只图“看到结果”,要看懂模型返回的数据结构。我建议用下面的代码把所有输出字段打印出来:
from ultralytics import YOLO model = YOLO("yolo11n.pt") results = model("bus.jpg", verbose=True) for r in results: boxes = r.boxes print("检测框数量:", len(boxes)) print("xyxy坐标:\n", boxes.xyxy) print("置信度:\n", boxes.conf) print("类别索引:\n", boxes.cls) print("类别名称:", [model.names[int(i)] for i in boxes.cls])你会发现每个检测框实际上包含五部分信息:归一化中心点坐标(xywh)、边界框左上右下坐标(xyxy)、置信度分数、类别索引。这些字段在后续做各类后处理时会频繁用到。
我还习惯在推理时关注两个额外信息:检测耗时和每个类的分布。Ultralytics 默认会在日志里输出Speed: 5.0ms preprocess, 20.0ms inference, 2.0ms postprocess per image at 640x640,这个数据在 GPU 上一般几毫秒,在 CPU 上可能是几十毫秒。如果 CPU 推理超过 100ms,就要考虑模型优化手段,比如导出成 ONNX 或量化fp16。
用 nano 模型跑了 COCO 预训练权重,80 类目标都能检测,但小目标的漏检率明显高于中大型目标,这也是 YOLO 系列的通病,后面我们会专门说这个问题。
4. 制作自己的检测数据集:不只是“标注完就能训练”
4.1 数据采集的注意事项:练出来的模型上限由数据决定
很多新手容易犯一个错误:把大部分时间花在模型调参上,却忽略了数据质量。实际上,目标检测项目里“数据决定上限,模型只是逼近这个上限”。你在 YOLO11n 上调参调得再好,数据里根本没有你想要检测的样本,模型也不可能凭空学会。
数据采集上有几个我实际踩过的坑,列出来供参考:
- 场景多样性 > 样本数量:同样是检测安全帽,如果你只在一种光照、一个角度、一个背景下采集了 10000 张图,不如在多种光照、多个角度、多个背景下采集 3000 张图有效。模型没见过多样场景,在真实环境里就会“穿帮”。
- 负样本必须包含:负样本指的是不包含目标、但外观和场景与正样本相近的图片。比如检测缺陷工件,负样本就是外观正常的工件图片。加入负样本能让模型学会“区分”而不是“记忆”,显著降低误检率。
- 小目标样本要单独补充:前面说过 YOLO 对 32x32 像素以下的小目标检测效果有限,如果你项目里小目标占比高,尽量多采集一些远距离拍摄的样本,或者用高分辨率相机拍摄后不裁剪、直接作为训练数据,让模型能看到的原始小目标多起来。
- 避免标注噪声:标注框不准是模型精度上不去的隐藏杀手。一个框偏移了 10 个像素,分类可能不受影响,但回归损失会一直居高不下。多人协作标注时,建议制定统一的标注规范,框要紧贴目标边缘,遮挡部分按可辨识区域标注,标注模糊目标时宁可不标,也绝不乱标。
4.2 数据标注与 YOLO 格式解析:txt 文件里每行数字的含义
YOLO 系列使用的是最简单的标签格式:每个图片对应一个同名 txt 文件,每一行代表一个目标,格式为class_id x_center y_center width height,其中x_center y_center width height都是相对于图片宽度和高度的归一化坐标。
举个例子,一张 640x480 的图片里有一个目标,标注框左上角坐标 (160, 120),右下角坐标 (480, 360)。那么:
- 框的宽度 = 480 - 160 = 320,高度 = 360 - 120 = 240
- 中心点 x = 160 + 320/2 = 320,y = 120 + 240/2 = 240
- 归一化:x_center = 320/640 = 0.5,y_center = 240/480 = 0.5,width = 320/640 = 0.5,height = 240/480 = 0.5
对应的 txt 内容就是0 0.5 0.5 0.5 0.5(假设 class_id 为 0)。
标注工具方面,我推荐 Roboflow 或者 LabelImg。Roboflow 是在线的,支持团队协作和自动数据增强,但免费版导出有次数限制。LabelImg 是离线开源软件,基于 Python + Qt,操作简单,适合个人项目。带边界框的标注任务,用这两个都够了。
标注完成后的数据集目录结构应该是这样的:
dataset/ ├── images/ │ ├── train/ │ │ ├── img001.jpg │ │ └── img002.jpg │ └── val/ │ ├── img101.jpg │ └── img102.jpg ├── labels/ │ ├── train/ │ │ ├── img001.txt │ │ └── img002.txt │ └── val/ │ ├── img101.txt │ └── img102.txt └── data.yamldata.yaml 是数据集的配置文件,内容包括路径、类别数量和类别名称:
path: /path/to/dataset train: images/train val: images/val nc: 2 names: ['helmet', 'person']注意 path 字段建议用绝对路径,这样在不同的工作目录下运行train.py都能正确定位到数据。类别名称的顺序必须和标注时的 class_id 一一对应,否则训练出来的模型类别全错。
5. 模型训练:参数详解与调优实战
5.1 训练命令和关键超参数的选择逻辑
数据准备好了,就可以启动训练。官方最简单的训练命令是:
yolo detect train data=data.yaml model=yolo11n.pt epochs=100 imgsz=640 batch=16但如果你只是照抄命令跑,很多坑会踩得莫名其妙。我把训练时最关键的几个参数逐个拆开说。
imgsz(输入图像尺寸)
这个参数直接决定模型能看到的细节量。imgsz=640 是默认值,一般够用。如果你的目标偏小,可以尝试 imgsz=1024 或 1280,相当于把图像放大后再输入网络,小目标的像素面积也会变大,更容易被检测到。代价是显存占用和训练时间显著增加,YOLO11n 在 imgsz=640 下显存占用大约 4GB,开到 1280 可能需要 10GB 以上。我建议先保持 640 训练一版作为 baseline,最后两三个 epoch 再用高分辨率微调,这样兼顾效率和精度。
batch(批大小)
batch 大小决定了一次迭代中模型能看到的图片数量。batch 越大,梯度的方向越稳定,训练越平稳,但显存占用也越大。YOLO11n 在 16GB 显存下 batch=32 没问题,8GB 显存建议 batch=16。如果你的显存比较紧张,可以启用梯度累加,ultralytics 里没有直接的参数,但可以通过 PyTorch 的 Accumulate 机制实现,不过这会延长训练时间。
还有一个需要留意的点:batch 大小和学习率是配套调整的,batch 翻倍,学习率一般也要相应调大。Ultralytics 默认会自动做这个缩放,但它在实测中做的比较保守,追求极限效果时还是建议手动微调学习率。
epochs(训练轮数)
epochs 决定模型遍历整个数据集的次数。对 YOLO11n 这种小模型,COCO 数据集上 300 轮是常规操作,但自己的小数据集一般 100 轮左右就收敛了。怎么判断收敛没有?直接看训练日志里的 loss 曲线和验证集 mAP 曲线,如果 mAP 在连续 20 轮内提升不超过 0.5%,基本可以停了,再训下去反而容易过拟合。
optimizer(优化器)
YOLO11 默认使用 SGD 优化器,动量为 0.937,权重衰减 0.0005。这套参数是 Ultralytics 在 COCO 上久经考验的组合。但如果你想追求更快的收敛速度,可以试试 AdamW,学习率可以设低一些,比如 0.001 左右。我的经验是:数据量小(几千张)、目标类别少(2到5类)时,AdamW 比 SGD 收敛更快;数据量大、类别多时,SGD 最终精度往往更高。
patience(早停机制)
这个参数非常实用。它表示在验证集 mAP 连续多少轮没有提升时自动停止训练。默认值是 100,如果你的时间有限,可以调小到 30。训练中断时 Ultralytics 会自动保存最佳权重,重启时会从断点接着训练。这个功能在模型训练中断电、服务器重启时救过我多次。实战中哪怕任务再急,也强烈建议保留早停机制,而不是盲目跑满 epochs。
5.2 训练日志与指标解读:loss 曲线、mAP、Precision、Recall 怎么看
训练过程中,终端会输出类似下面这样的日志:
Epoch GPU_mem box_loss cls_loss dfl_loss Instances Size 49/100 2.35G 0.7213 0.4521 0.8912 112 640对新手来说,这些 loss 数字刚开始看可能没有直观概念,但有一个大致的判断依据:box_loss(边界框回归损失)和 cls_loss(分类损失)在训练开始时偏高,随着轮次增加应该稳定下降;如果某个 loss 一直在波动不下降,说明模型在这个任务上学得不好,需要检查数据或者调整超参数。
更重要的指标是评估集的输出。训练完成后,模型会自动在验证集上评估,并输出:
- mAP50:IoU 阈值为 0.5 时的平均精度均值。这个指标比较宽松,一般自己项目里追求 mAP50 在 0.9 以上比较理想。
- mAP50-95:IoU 阈值从 0.5 到 0.95 每隔 0.05 取一次平均。这个指标更严格,COCO 上 YOLO11n 大约在 0.39 左右。自己项目的 mAP50-95 只要比随机猜测明显高就有意义,不用刻意追求极限。
- Precision(精确率):模型预测为正样本中真正是正样本的比例。精确率高说明误检少。
- Recall(召回率):所有正样本中被正确检出的比例。召回率高说明漏检少。
精确率和召回率是一对矛盾的指标。在实际项目里,如果误检造成的影响大,应该调高置信度阈值,提升精确率;如果漏检影响大,则应该调低阈值,提升召回率。这个权衡在实际部署时非常重要。
我习惯在训练结束后自动跑一版结果可视化:
yolo detect predict model=runs/detect/train/weights/best.pt source=/path/to/test/images save=True拿到结果图后,我会把典型的错误案例截图保存下来,分析是漏检(模型没检测出来)、误检(检测了错误目标)还是定位不准(检测框偏移严重)。根据不同错误类型去反推到数据的哪个环节出了问题,这比盲目调参有效得多。
6. 常见问题与排查技巧实录
6.1 问题速查表与对应解决方案
训练和推理过程中我实测遇到过不少问题,把它们整理成表格,方便各位直接检索:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 训练时 loss 降不下去 | 数据标注错误或类别不平衡 | 检查标注质量,查看每类的目标数量分布,对少样本类别做数据增强 |
| 训练显存溢出(OOM) | batch 太大或 imgsz 太大 | 减小 batch 或 imgsz,启用梯度累加 |
| 推理时检测框特别多且重叠 | NMS 阈值设置过低 | 调高 NMS 的 IoU 阈值,比如从 0.45 调到 0.7 |
| 小目标完全检测不到 | imgsz 太小或训练数据小目标太少 | 增大 imgsz,补充小目标样本,或者用 SaHI 切图推理 |
| 模型把所有目标都识别成同一类 | 类别不平衡,某类样本占绝对优势 | 对多数类别降采样,对少数类别过采样或加增强 |
| 训练精度高但实际部署效果差 | 训练数据和部署场景差异大 | 收集部署场景的图片加入训练集,做域适应 |
| 同一张图多次推理结果不一致 | 模型处于训练模式,BN 层行为不同 | 推理前调用 model.eval(),或者用 ultralytics 的 predict 接口 |
| CPU 推理特别慢 | 模型没有优化,使用 fp32 精度 | 导出为 ONNX 并用 onnxruntime 推理,或者量化成 int8 |
6.2 小目标检测的专项优化思路
前面多次提到小目标检测是 YOLO 的薄弱环节,这里专门展开说。在 COCO 数据集上,YOLO11n 对小于 32x32 像素的目标,检测精度相比中大目标会出现明显下降。根本原因是:默认 imgsz=640 时,小目标经过多次下采样后,在特征图上占的像素非常少,可能只剩一两个像素点,信息几乎丢失。
优化小目标检测,我实践下来有四个方向,按难度从低到高排列:
方向一:增大输入分辨率。将 imgsz 从 640 提升到 1280,小目标在特征图中的占比提升四倍。这是最简单粗暴的方法,缺点是训练和推理速度变慢。
方向二:Tiling(切图)。推理时将大图切成若干小块,每个小块分别送入模型检测,最后再将结果合并。省显存且有效,缺点是小图之间重叠区域的目标可能被重复检测,需要做合并去重。
方向三:数据增强。在训练时对含小目标的图像进行随机裁剪放大,模仿“镜头拉近”的效果,让模型看到更多小目标的细节。Ultralytics 的 mosaic 增强已经部分实现这个功能,但可以再叠加随机 4 倍裁剪增强,效果更明显。
方向四:特征融合改进。对 YOLO11 的 Neck 做 P2 层扩展,也就是增加一个 160x160 的高分辨率特征图输出,专门用于小目标检测。这个方向改动最大,需要修改模型结构,不是入门内容,但如果你真的遇到小目标项目且前三招不够用时,值得尝试。
6.3 迁移学习和少样本场景的训练技巧
很多实际项目没有几万张标注数据,可能只有几百张甚至几十张。这种情况下从头训练一个模型不现实,合理的选择是用 COCO 预训练权重做迁移学习。
迁移学习的关键在于“冻底层、调顶层”。Backbone 的低层网络学到的是通用特征(边缘、纹理、颜色),这些特征对任何目标检测任务都有用,不需要重新学习。而 Neck 和 Head 更接近任务本身,需要重点调整。实际操作中不需要手动冻结太多层,Ultralytics 提供了freeze参数,比如freeze=10表示冻结前 10 层。我自己的经验是:数据量很少(100 张以内)时,冻结 Backbone 的大部分层,只训练 Neck 和 Head;数据量达到几百张以上,可以冻结较少层,让更多层参与微调。
少样本场景下还有一个实用技巧是基于预训练模型做固定特征提取,也就是用 YOLO11n 的 Backbone 提取特征,再加一个简单的分类头,进行线性探测(Linear Probing)。这种方式在类别极少的场景(二分类)下效果异常好,因为它把目标检测问题退化成特征分类问题,大大减少了需要学习的参数数量。
6.4 模型导出与部署中的实际经验
训练好的模型最终要部署到实际环境中,这个过程主要有两条路:ONNX Runtime 和 TensorRT。
导出 ONNX 的命令很简单:
yolo export model=best.pt format=onnx opset=12导出后会在本地生成 best.onnx 文件,配合 onnxruntime-gpu 可以在 NVIDIA GPU 上获得比原始 PyTorch 更低的推理延迟。我实测 YOLO11n 在 RTX 3060 上用 ONNX Runtime 推理大约 5ms 每帧,比 PyTorch 原生推理快了约 30%。
如果能接受 NVIDIA 平台专属的方案,TensorRT FP16 是性能的最优解:
yolo export model=best.pt format=engine device=0 half=TrueTensorRT 的引擎文件是特定于 GPU 型号的,换一张显卡就要重新导出。这个特性在部署到不同机器时需要特别留意。另外,TensorRT 引擎文件很大(几十 MB 到几百 MB),和原始 5MB 的 nano 权重相比体积差距不小,如果对模型体积敏感(比如嵌入式设备存储有限),需要在性能和体积之间做权衡。
我在部署时还遇到过一个坑:导出 ONNX 时模型输出的张量形状是(1, 84, 8400),其中 84 = 4(坐标) + 80(COCO 类别数),8400 是三个尺度特征图的网格点总数(8080 + 4040 + 20*20 = 8400)。这个输出格式和旧版 YOLO 的 Anchor-Based 输出不一样,解析时需要按照坐标 + 分类置信度 + 逐类别分数的顺序来处理。如果直接套用旧版解析代码,边界框坐标全乱,这属于新手常踩的坑。
7. 热词背后的技术延伸:从 YOLO11n 延伸到目标检测的更多边界
7.1 Transformer 目标检测与 YOLO11 的对比
很多初学者在学习 YOLO 系列时会关心一个问题:既然 DETR、Deformable DETR 等基于 Transformer 的目标检测模型已经在精度上超越了一众 YOLO 模型,为什么 YOLO 依然活跃在工业界?
核心原因是速度与精度的平衡点不同。Transformer 模型虽然精度高,但推理较慢,部署成本高。而 YOLO 系列一直坚持“端到端单阶段检测 + 轻量化结构”的设计理念,可以在保持接近的精度下,把推理速度做到实时甚至超实时。这也是为什么在实际项目中,尤其是视频流检测、边缘设备部署等场景,YOLO 依然是最广泛的选择。
我自己的体会是:如果对精度极为苛刻、场景允许 GPU 服务器推理(比如离线图片分析),可以考虑 DETR 风格模型;如果任务涉及实时视频流、嵌入式设备、机器人视觉,YOLO11n 是“性价比”很高的选择。
7.2 小目标检测和红外目标的特殊处理
小目标检测在热词中反复出现(小目标检测、红外小目标检测、多模态目标检测),这说明它在学术和工业界都是关注焦点。红外小目标检测是一个更细分的场景:图像是红外热像仪拍的,目标通常是远距离的行人、车辆或飞行器,在图像中只占几个像素到十几个像素,且与背景温差不大,对比度极低。
这个场景下,YOLO11n 的通用结构并不太适用,常见的改进方案是结合空域和频域信息做协同检测。所谓空域,就是图像本身的空间信息,每个像素点的亮暗和纹理;所谓频域,是通过傅里叶变换把图像分解成不同频率的成分,小目标往往对应高频成分,而背景对应低频成分。空域-频域协同的思路是:先在频域找到可疑的高频区域,将其作为候选区域反馈到空域网络中进行精细分类和定位。这样可以把小目标的信噪比显著提升,大幅降低漏检率。
YOLO11n 本身没有直接的频域处理模块,但你可以把它作为空域检测的基础网络,把频域增强后的结果(比如高频残差图)作为额外的输入通道或分支,与原始图像特征融合后一起送入 YOLO11n 的 Backbone。这种方案在小目标检测的工程实践中证明效果不错。
7.3 多模态目标检测和点云 3D 目标检测的方向
多模态目标检测是另一个值得关注的方向。它的核心是融合多种传感器数据,比如可见光图像 + 红外图像,或者图像 + 激光雷达点云。多模态信息互补:可见光图像有丰富的纹理和颜色信息,红外图像不受光照影响但纹理很少,点云数据有精确的三维空间信息但缺乏语义。
在多模态场景下,YOLO11n 可以作为一个模态分支的特征提取器。比如在“图像 + 点云”融合方案中,图像经过 YOLO11n 提取 2D 特征,点云经过 PointPillars 或 VoxelNet 提取 3D 特征,两个特征图通过某种融合模块(早期融合、晚期融合或注意力融合)合并后,再进行目标检测。这里最关键的问题是特征对齐:2D 图像坐标和 3D 点云坐标不在同一个空间,需要通过相机内外参做精确投影,这是整个方案中最耗时且最容易出错的部分。
对于三维目标检测,YOLO 思路同样可以迁移,比如点云版本的“YOLO”模型(如 PointPillars)把点云划分成柱子(Pillar),用 2D 卷积处理,输出的是带方向的 3D 检测框。如果你已经掌握了 YOLO11n 的检测流程,转向 3D 检测时会发现很多概念是相通的——anchor、损失函数、NMS 后处理,只是从 2D 坐标系扩展到了 3D 坐标系。
8. 我用下来的几点补充体会
最后再分享几个没有归到前面章节里的细节。
第一点是关于 YOLO11n 和 YOLOv8n 的对比。如果你之前用过 YOLOv8n,会发现 YOLO11n 的 API 几乎完全兼容,代码和配置文件可以直接迁移。但实测下来,相同数据集、相同超参数下,YOLO11n 的 mAP50-95 比 YOLOv8n 高出约 1 到 1.5 个百分点,推理速度还略快一些。所以如果是新项目,直接选 YOLO11n 就对了;老项目如果已经在生产环境稳定跑了,也没有必要为了升级而升级。
第二点是模型的版本选择。YOLO11 有 n/s/m/l/x 五个版本,参数规模从 260 万到 2000 万不等。我见过不少新人一上来就选 x 版本,结果 8GB 显存的机器直接爆显存,于是在那边调来调去。正确的做法是先从 nano 版本起步,用同一套数据跑通全流程,确认项目的可行性和数据质量,再根据精度需求逐步升级到 s 或 m。大部分项目数据量、场景复杂度有限,nano 或 s 版本完全够用,不要盲目追求大模型。
第三点是关于数据集版本管理的经验。做目标检测项目时数据集会经常迭代:今天加了一批新数据,明天修了一批标注错误。如果不做版本管理,就会出现“训练结果A和训练结果B对不上,但谁也不知道哪个数据集是新的”这种尴尬情况。我在团队里习惯用数据集文件夹的名字带版本号(比如dataset_v3_20240401),并且每次训练前把 data.yaml 里的路径和版本号写进训练日志的自定义字段。这样即使几个月后回来看,也能清楚知道每个模型是用哪份数据训出来的。
最后是一个关于超参数搜索的小技巧。Ultralytics 提供了自动超参数搜索功能,底层使用遗传算法。虽然跑一次搜索可能比较耗时,但在追求最佳精度时值得使用。初学者可以先使用默认参数获得一个基准结果,再逐步展开搜索,最后在验证集上对比精度差异。手动调整时,注意记录每次修改的参数值、改动原因和解训练结果,纵使排查问题也能快速定位到是哪一步改动引起的。
这份笔记基本上把我跑通 YOLO11n 目标检测项目的完整过程和学习心得都覆盖了,从环境搭建、数据准备、模型训练到推理部署和常见问题排查,每个环节都有具体的操作步骤和踩坑经验。目标检测这几年发展很快,但这套流程链路很稳,吃透了它,以后无论是转向更复杂的模型结构、多模态融合,还是在具体领域做深度优化,都会有一个扎实的底子。