YOLO11n目标检测实战:从环境搭建到模型部署的完整记录 标题里写着“学习笔记”其实就是我拿 YOLO11n 做目标检测练手的整个记录。这个项目前后折腾了两周多从环境搭建到训练、调优、推理、再折腾导出部署中间踩了不少坑也把目标检测的整个标准流程完整走了一遍。这篇笔记不打算写成教科书而是按我自己实操的顺序把每一步怎么想、怎么做、在哪卡住、最后怎么解决都记下来给同样想从零跑通 YOLO11n 目标检测的朋友一个参考。不管你是刚接触目标检测算法还是已经用过 YOLOv5、YOLOv8 想换个新版本试试这篇里都有能直接抄作业的部分。我尽量把命令、配置、参数和结果都说清楚也会放一些我实际训练时的曲线和问题排查记录方便你对照自己的情况。1. 项目背景与整体设计思路1.1 为什么挑 YOLO11n 做目标检测先交代一下背景。我手上有一个需要做物品识别的场景大致流程是把摄像头画面里的目标框出来并标出类别。画面里的目标不大环境光线一塌糊涂偶尔还有遮挡。调研了一圈最终选了 Ultralytics 在 2024 年 9 月发布的 YOLO11而且挑的是最小的 YOLO11n。选择理由有三层。第一YOLO11 是当时最新的 YOLO 系列版本结构上在 YOLOv8 基础上改进了骨干网络和颈部设计官方给的精度在 COCO 数据集上不输甚至超过 v8 同规模版本推理速度也更快。第二n 版本是 nano 的缩写模型体积最小、参数量最少只有大约 2.6M 参数适合验证整套流程跑起来压力小。第三Ultralytics 的生态做得够好从训练到导出一条龙不用自己写太多胶水代码对学习阶段来说非常友好。实际用下来的感受是YOLO11n 就是一个典型的高性价比入门模型。它的精度肯定不如 s、m、l 这些大版本但它的推理速度和模型体积优势很明显尤其适合 CPU 上做测试或者丢到边缘设备上跑。我当时的需求对实时性要求不算高但希望先跑通整个目标检测全流程所以选它再合适不过。1.2 YOLO11 相比前代的关键变化要理解 YOLO11n最好先知道 YOLO11 整体改了啥。从 YOLOv8 到 YOLO11Ultralytics 没把网络推倒重来但做了几个关键改进。一是骨干网络里用了新的 C3K2 模块可以理解成把 v8 的 C2f 做了一定的精简用更少的花销保留足够的信息流动。二是引入了 C2PSA 模块实际上是把一个 PSAPosition-Sensitive Attention 结构类似自注意力机制塞进特征提取路径里让特征图在不同尺度上的表达能力更强。三是检测头仍然是解耦头分类分支和回归分支分开输出而且保持 anchor-free也就是直接预测目标中心到边框四边的距离不再像老 YOLO 那样依赖预设 anchor。这些改动对我们做项目的人来说直观感受是模型在同等体积下精度更高了小目标检测能力有所提升而且训练配置和前代基本兼容迁移成本低。我用 YOLO11n 之前试过 YOLOv8n同样是 nano 版本在同一个数据集上 YOLO11n 的 mAP50-95 能高出大概 1 到 2 个点推理速度几乎没变。另外还要提一句YOLO11 不仅仅做目标检测官方把同一套骨架扩展到了实例分割、姿态估计、旋转框检测和分类五种任务。也就是说你拿 YOLO11n 练手目标检测之后想横向扩展学习其他任务只需要改改配置换权重思路完全一致这一点对学习来说性价比很高。1.3 整个项目的路线规划我给自己定的学习路线是“三步走”。第一步是把环境跑通用一个公开小数据集比如 COCO 的小样本子集或者自建的数据集完整走一遍标注到训练到测试的流程。第二步是理解关键指标和损失搞清楚 mAP、Precision、Recall 到底在衡量什么训练曲线应该怎么看。第三步是部署把训练好的模型导出成 ONNX再做一次简单的推理验证看看在普通 CPU 环境下能不能达到可用速度。这个路线一开始看起来很简单实际上每一步都有坑。环境依赖版本冲突、数据集格式不对、训练时显存不够、导出后推理结果和 PyTorch 不一致这些都是我真实遇到过的。所以这篇笔记的核心不是展示一个完美的结果而是把那些检查点、排查手段和记录下来的曲线都整理出来让你少走弯路。2. 环境准备与数据集设计2.1 环境安装的版本选择YOLO11 依赖 PyTorch 和 Ultralytics 库。这里有一个特别容易踩的坑Ultralytics 的版本迭代非常快很多网上教程用的是旧版本 API到了新版函数签名变了跑起来报错会让人怀疑人生。我当时用的是 Python 3.10 PyTorch 2.1.0 CUDA 11.8搭配 ultralytics 8.3.x 系列整个组合用下来最稳。安装命令其实就一行pip install ultralytics如果机器上有 NVIDIA 显卡需要确保 PyTorch 版本和 CUDA 驱动匹配。我当时先装了 CPU 版 PyTorch后来又重装 GPU 版来回折腾了一次教训是安装前一定先用nvidia-smi看驱动支持的 CUDA 版本再决定装对应 PyTorch 版本。没显卡也不用担心YOLO11n 比较小CPU 也能训练只是慢一些。这里放一个我后来的检查清单python -c import torch; print(torch.__version__)确认 PyTorch 版本。python -c import torch; print(torch.cuda.is_available())确认 GPU 可用。yolo version确认 Ultralytics 版本。提示如果只做推理和测试只装 ultralytics 和 PyTorch 就够了。如果要做导出最好再装 onnx、onnxruntime、onnxsim。装的时候建议用虚拟环境避免污染系统 Python。2.2 数据集标注与格式整理训练目标检测模型必须要有带标注的数据集。我的场景里用了自建的图片集数量不多前后大概 800 张用 labelImg 手工标注。标注格式选择的是 YOLO 格式也就是每张图片对应一个 txt 文件每一行代表一个目标格式是类别id x_center y_center width height这里注意坐标值都是归一化到 0 到 1 的相对值框的位置是相对图片宽高的比例。我第一次标注时把坐标写成了绝对像素值训练时模型直接不收敛后来才发现是格式理解错了。标注完成后要把数据集按约 8:2 的比例分成训练集和验证集并整理成这样的目录结构dataset/ images/ train/ val/ labels/ train/ val/同时需要写一个 data.yaml 配置文件Ultralytics 就是靠它找到数据集路径和类别信息的。我的配置大概是path: /path/to/dataset train: images/train val: images/val nc: 2 names: [cat, dog]要注意 path 尽量写绝对路径因为训练脚本的工作目录经常变化相对路径容易找不到数据。我一开始写的是相对路径换了个目录再跑一路报错后来改成绝对路径才消停。2.3 训练时自动数据增强的感受Ultralytics 框架自带了一套比较强的数据增强策略包括 Mosaic、随机仿射变换、HSV 色彩抖动、翻转、缩放等。默认配置下模型训练时会自动做这些增强不需要我们额外写代码。Mosaic 增强是 YOLO 系列非常核心的技巧它把四张图拼成一张图喂给模型相当于在一个 batch 里让模型看到更丰富的上下文对小目标检测和整体泛化能力帮助很大。不过 Mosaic 增强也有副作用就是如果训练数据里的目标分布和真实场景差太多模型可能在真实画面上表现不佳。所以官方在训练后期会逐渐关闭 Mosaic让模型在接近真实分布的图上做微调这个机制在 Ultralytics 里默认开启叫 “close_mosaic” 策略。我从实际效果来看YOLO11n 在自建数据集上即使是默认增强就已经能让 mAP50 摸到 0.85 以上。如果你的数据集场景比较特殊比如都是低光照图像建议把 hsv_h、hsv_s 这些色彩增强参数适当调低避免颜色抖动太大导致模型学不到有效特征。3. 模型训练与调优全记录3.1 训练脚本与关键参数选择我用的是 Ultralytics 的标准训练入口启动命令长这样yolo train modelyolo11n.pt datadata.yaml epochs100 imgsz640 batch16 lr00.01几个关键参数说一下。modelyolo11n.pt表示从官方预训练权重开始微调这会比从零训练收敛快很多最终精度也更高。官方权重是在 COCO 上预训练过的已经学会了通用的特征表达。imgsz640是输入分辨率。分辨率越高模型看得越清楚但显存和延迟都会增加。YOLO11n 比较轻量我用 640 是折中。batch16是批次大小取决于显卡显存。我用的是一块 8G 显存的卡YOLO11n 跑 640 分辨率 batch16 刚好能放下。显存不足时优先减 batch之后再考虑降分辨率。lr00.01是初始学习率。微调场景下这个值不用太大大了反而容易把预训练特征毁掉。还有一个我比较喜欢的参数是cos_lrTrue它会让学习率按余弦方式从初始值衰减到接近 0效果比固定学习率更稳。训练时还可以配合patience20开启早停连续 20 个 epoch 验证集指标不涨就自动停止省时间。3.2 训练过程观察与曲线判断我在训练过程中会盯几个指标PPrecision、RRecall、mAP50、mAP50-95。mAP50是 IoU 阈值设为 0.5 时的平均精度比较宽容主要看模型有没有把目标找出来mAP50-95是把 IoU 从 0.5 到 0.95 按步长 0.05 取了十个阈值后求平均更严格更能反映框的位置精度。举个我当时训练过程的例子。前 20 个 epochmAP50 涨得特别快从 0 一路升到 0.7但 mAP50-95 只有 0.4 左右说明框的位置还不够精细。20 到 60 epoch 时mAP50 开始缓慢上升最终到 0.91mAP50-95 也涨到 0.75。后面 60 到 100 个 epoch 基本是在震荡中微微爬升。Waitting这里我要特别说一句如果你看到 mAP50 很高但 mAP50-95 偏低不用着急这是非常常见的情况。mAP50 衡量的是“能不能找到目标”mAP50-95 衡量的是“找得准不准”。当两个指标差距超过 0.15 的时候我一般会先检查标注框是否贴边标注框比实际目标大一圈或者没有紧贴边缘都会导致 mAP50-95 上不去。另一个重点是观察训练集 loss 和验证集 loss 的走势。训练集 loss 持续下降但验证集 loss 停住甚至反弹就是过拟合信号。自建数据集只有 800 张图我在跑 100 epoch 的时候就明显感觉到60 epoch 之后验证集 loss 已经不怎么降了训练集 loss 还在往下走典型的过拟合。解决办法是加早停、加增强、减少训练轮数或者换一个更大的预训练模型做迁移学习。3.3 指标解读与一次失败调优复盘我在训练到大概第 50 个 epoch 时发现模型对画面里的小目标检测效果很差很多小物体会漏检。当时第一反应是加大输入分辨率从 640 改成 1280。结果显存不够batch 从 16 降到 8 才能跑训练时间直接翻倍最终 mAP50-95 确实涨了一点但推理速度也被拖下来了。这个尝试踩的坑是小目标检测不是单纯加大分辨率就能解决的。小目标在特征图里占的像素太少默认的三层检测头对大目标更友好。YOLO11n 作为 nano 版本特征表示能力有限对小目标的特征提取天生弱一些。我后来的处理方式是一方面增加了小目标类别的样本数量把包含小尺寸目标的图片复制并做 random crop 增强另一方面调整了mosaic和scale增强范围让模型在训练时多看到不同尺寸的目标。另外正式推理时把conf阈值从默认的 0.25 降到 0.15宁可多一点误检也要减少漏检。这几个操作叠加下来小目标的召回率提升了不少虽然 mAP50-95 提升幅度不大但实际业务场景里能用的目标检测模型往往更需要权衡漏检和误检而不是只看一个聚合指标。顺便提一下如果你做红外小目标检测除了 mAP 之外一般还要关注检测率 DR、虚警率 FAR、信杂比增益等指标。YOLO 系列在这种极低信噪比场景下需要做很多预处理和后处理优化已经不是单纯训练一个模型能搞定的了。4. 推理测试与问题排查实战4.1 推理流程与测试脚本训练完成后进入测试阶段。最直接的推理方式是yolo predict modelruns/detect/train/weights/best.pt source./test_images conf0.25或者用 Python 接口方便接进自己的程序from ultralytics import YOLO model YOLO(runs/detect/train/weights/best.pt) results model.predict(source./test_images, conf0.25, iou0.45, imgsz640) for result in results: boxes result.boxes.xyxy.cpu().numpy() scores result.boxes.conf.cpu().numpy() classes result.boxes.cls.cpu().numpy() print(boxes, scores, classes)这里的iou参数是 NMS 非极大值抑制的阈值默认 0.45。NMS 的作用是当多个框重叠在一起时保留置信度最高的框去掉重复框。这个值调低框会更精简调高可能会保留更多重叠框。我一般不动它除非目标特别密集才适当降低到 0.4。我测试的时候会准备一段带遮挡和暗光场景的视频拿视频流跑到代码里用 OpenCV 读帧丢给模型再把画了框的帧输出。这样才能真正看出模型在连续帧里的稳定性。结果发现一个问题单张图片测试时精度看着不错但视频里目标在运动时偶尔会有某几帧漏检这就是模型的时域稳定性问题。4.2 小目标检测与遮挡场景的整改我的项目里小目标和遮挡是两大难点。第一次实际测试时在遮挡场景中模型经常把两个目标框成一个框或者直接漏检。排查下来有两个原因。第一个原因是 NMS 阈值设置不合理。当两个目标靠得很近它们的预测框重叠度很高NMS 会认为这是同一个目标从而干掉其中一个框。这时我会降低iou阈值到 0.35 左右同时在训练时增强遮挡样本的比例。第二个原因是数据集中缺少“部分可见”的样本。模型没有见过遮挡目标的形态自然学不会。我补了一批半遮挡样本同时在训练时加上了随机 erasing 增强人为模拟遮挡情况模拟遮挡效果对提升遮挡场景召回率非常有效。小目标方面我在数据集里对小目标做了过采样也就是让小目标样本的出现频率更高。另外还试过在模型输出的特征层上做多尺度融合直接把浅层特征和深层特征 concat 到一起不过这个改动需要改网络结构对 YOLO11n 来说有点费劲我建议初学者还是先从数据和推理参数入手。4.3 常见错误与排查速查表我在整个过程中整理了一份问题排查速查表都是实操中容易遇到的情况现象可能原因解决办法训练 loss 直接 NaN学习率过大、数据里有异常标注降低 lr0检查数据集标签是否有越界坐标所有预测框集中在一个地方数据增强过强、训练不收敛降低 mosaic 权重检查标注格式归一化推理结果比 PyTorch 差很多导出模型时尺寸不一致导出和推理都用相同 imgsz显卡显存不足batch 太大或 imgsz 太大先减 batch再考虑减 imgszmAP 很高但实际效果差训练数据与测试场景分布不一致补充真实场景数据调整 conf 阈值相同输入每次输出不一致开启了随机增强或没有固定随机种子推理时关掉 augment训练时设 seed0CPU 推理太慢模型浮点运算量仍偏大导出成 int8 量化模型或换更小模型这里的每一项我都实际碰到过尤其是前两个。训练 loss 出现 NaN 那次我排查到最后发现是数据标签里的坐标出现了大于 1 的值因为归一化处理时按错误的分母算了。这个坑如果你也踩了建议写一个校验脚本跑训练前先扫描所有 txt 文件检查坐标是否都在 0~1 区间。5. 模型导出与部署实战5.1 导出 ONNX 并完成 CPU 推理训练好的模型要在真实业务中用不能总依赖 PyTorch 环境。我第一个尝试是导出成 ONNX 格式Ultralytics 命令是yolo export modelruns/detect/train/weights/best.pt formatonnx opset12 simplifyTrue导出之后可以用 onnxruntime 做 CPU 推理import onnxruntime as ort import cv2 import numpy as np session ort.InferenceSession(best.onnx) input_name session.get_inputs()[0].name image cv2.imread(test.jpg) image cv2.resize(image, (640, 640)) image image[:, :, ::-1].transpose(2, 0, 1) # BGR - RGB, HWC - CHW image np.ascontiguousarray(image, dtypenp.float32) image / 255.0 image np.expand_dims(image, axis0) outputs session.run(None, {input_name: image})这里有几个容易搞错的点。第一是颜色通道顺序OpenCV 读进来是 BGR但模型在 PyTorch 端用的是 RGB导出 ONNX 后输入同样需要转成 RGB。第二是归一化PyTorch 里的输入是 0~1 浮点数ONNX 导出时模型本身没包含归一化层你要在预处理里手动做。第三是输入尺寸导出时固定成了 640x640喂给模型的图片尺寸必须匹配。第一次做 ONNX 推理时我输出的框坐标跟 PyTorch 对不上排查了半天最后发现是预处理时transpose的维度写错了把通道放在了最后。这种问题最好写一个前后处理函数统一封装避免每次手动写顺序出错。5.2 TensorRT 加速的初步尝试在大模型部署场景ONNX 只是中间格式真正要提速一般会在 NVIDIA GPU 上用 TensorRT 引擎。Ultralytics 也支持直接导出 TensorRTyolo export modelbest.pt formatengine halfTrue device0第一次导出 TensorRT 引擎会做算子融合和显存优化过程比较慢但引擎生成之后推理速度快很多。我拿同一张图测试PyTorch GPU 推理大概 6 毫秒TensorRT 能压到 2 到 3 毫秒。YOLO11n 本身就是 nano 版本到了 TensorRT 之后实时性在视频流场景下完全够用。TensorRT 部署踩坑点主要在动态尺寸上。默认导出会固定输入尺寸如果希望同时支持不同分辨率输入需要设置动态轴。但 YOLO 后处理对输入尺寸敏感动态尺寸意味着输出层的形状也会变后处理代码要按实际输出动态计算。这个复杂度对学习阶段来说太高我建议先用固定尺寸跑通后续再优化。5.3 误检漏检的工程后处理部署之后你会发现精度指标只能反映一部分情况真正上线前还要做工程上的后处理。我常用的一个技巧是跟踪去抖。对视频帧来说单帧检测偶尔会闪一下用一个简单的时间序列滤波如果连续多帧都检测到且框的位置平稳变化才输出这个框。对不稳定的检测结果直接丢掉这样用户体验会好很多。另一个技巧是把检测结果按场景分流。我们的业务场景里不同时间段的光照差别很大白天和晚上的最优conf阈值完全不同。我用两套阈值做判断白天conf0.3晚上conf0.18效果比统一阈值好很多。这属于便宜又实用的工程优化手段。再有一个是类别置信度校正。YOLO 输出的类别分数是网络直接预测的但有些类别的先验概率差别很大比如常见的物体类别和罕见类别。我后面简单记录每个类别的真实出现频率推理时将类别分数除以频率的平方根做归一化这个技巧在类别不平衡的数据集上有一定效果但需要自己做实验不能盲目照搬。6. 学习复盘与后续扩展方向6.1 对目标检测流程的整体认识跑完整个 YOLO11n 项目我对目标检测算法整体流程的理解跟刚开始完全不同。所谓目标检测本质上是“在图片里找在哪里 是什么”这两个问题同时求解。YOLO 系列把它统一成回归问题网络直接预测框坐标和类别概率所以评价一个检测模型不能只看分类对不对还要看框得准不准、漏检多不多、误检多不多几个维度互相牵制。数据、模型、训练、推理、部署每个环节都可能让最终效果变差。刚开始我以为模型结构是最重要的后来发现对大多数项目来说数据的质量比模型结构更能决定上限。标注框不准确、类别没有代表性、场景覆盖不全这些即使换更强的模型也救不回来。另外我也意识到YOLO11n 这类小模型在端侧部署优势明显但它的表达能力有限。如果你的场景真的需要检测非常小、非常密集的目标或者目标和背景极其相似nano 版本大概率不够用得考虑 s 或 m 版本甚至尝试 transformer 结构的检测器。虽然那类模型计算量更大但在某些复杂场景下的建模能力确实是 YOLO 这类卷积网络比不了的。6.2 后续可以尝试的扩展方向这个项目做完之后我还有几个想继续深入的方向。第一个是旋转目标检测。YOLO11 本身就支持 OBB 旋转框在遥感图像或者工业零件检测场景里用旋转框比水平框效果更好因为目标本身是有角度的水平框会框进大量背景。第二个是实例分割YOLO11-seg 在检测的同时输出像素级掩码对需要精确轮廓的场景很有用。第三个是多模态目标检测比如结合文本提示做 open-vocabulary 检测或者结合点云做 3D 目标检测这两个方向算是目标检测下一个阶段的趋势也正好能补上我现在对通用检测器边界的认知。不过这些方向学起来都需要额外花时间。我这篇笔记写到这里主要想传达的是YOLO11n 是一个很好的学习载体它体积小、生态好、流程完整但真正决定你做不做得成一个项目还是看你能不能把数据和技术方案拧成一股绳。踩过坑之后我的体会很深。刚开始我总想着找“最强的模型”后来发现先跑通一个足够小的模型、把指标和推理链路吃透再带着问题去扩展效率高得多。如果你也在拿 YOLO11n 做目标检测建议别急着堆数据堆模型先把一个样本量小的数据集从头到尾跑顺畅再去碰复杂问题这条路我替你走了一遍值得走。