news 2026/9/1 1:54:18

YOLOv11源码实战:从推理结果保存到自定义训练与小目标优化

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
YOLOv11源码实战:从推理结果保存到自定义训练与小目标优化

简介:YOLOv11 是 YOLO 目标检测系列的新一代算法,ultralytics 版本在此基础上进一步优化了工程易用性。这份压缩包共含 46 个文件,仅 7.34MB,体积轻量,主要文件类型包括 Python 脚本(.py)、可执行程序(.exe)、动态链接库(.dll)和 Python 扩展模块(.pyd),并带有 cmd 命令配置、md/txt 说明文档及 license 授权文件。包内明显集成了可运行的 Python 环境与源码级组件,配套构建、安装、测试等命令脚本及若干辅助工具脚本,可在 Windows 平台上快速部署或二次开发,适用于快速验证环境、学习源码结构或离线部署等场景。目前已有 210 人学习,对于希望低成本接触 ultralytics 版 YOLOv11 的入门者来说,是一个可以快速上手的小型代码环境。 如果你手头刚好有这样一个压缩包,大概率是刚接触YOLO,或者在网上看到别人分享后顺手存了下来。不管哪种情况,解压完看到一整个ultralytics目录时,最懵的往往不是代码看不懂,而是不知道从哪里开始。实际上,这套源码就是目标检测领域这几年最活跃的仓库之一,YOLOv11(代码里一般写作YOLO11)是它当前主推的检测模型,一次把目标检测、实例分割、姿态估计、旋转框识别和图像分类全部收进了同一个引擎,接口统一得相当彻底。这篇博文不会逐行讲源码,而是把“解压之后到部署之前”这一路的完整链路拆开:推理结果怎么保存、网络结构在哪个文件里改、自定义数据集怎么训、小目标怎么优化,最后再聊聊ultralytics对RT-DETR这类非YOLO模型的支持方式。适合刚入门目标检测的学生、要落地项目的工程师,以及想基于源码做模型改进的人。

1. 解压之后别急着跑:先把源码包变成可调试的环境

1.1 为什么我一直推荐用独立环境装这套源码

ultralytics对Python版本不算挑剔,但torch版本往往比你想的更敏感。直接用系统Python装,哪天系统上有另一个项目需要降级torch,两边就会互相打架。我自己的习惯是用conda单独建一个环境,Python版本固定在3.10。PyTorch 2.0往后对3.8以上的支持都不错,3.10是在兼容性和第三方库覆盖面上最稳的,没必要去追3.12或3.13。

conda create -n yolo11 python=3.10 -y conda activate yolo11

很多人会在这一步卡住,因为conda默认源在国内速度一般。装完环境后顺手换一下国内镜像源,几分钟就能省下大把等待时间,属于装环境的基本操作。

1.2 可编辑安装才是研究源码的正确姿势

如果你只是“用”YOLOv11,直接pip install ultralytics就够了。但既然你手里拿的是源码包,我建议用可编辑安装:

cd ultralytics pip install -e .

-e .的意思是安装当前目录下的项目,但不会把代码复制到site-packages,而是原地引用。之后你改了ultralytics包里的任何py文件,下一次import就会生效,不用反复重装。对于想读源码、改结构、二次开发的人来说,这一步几乎是必须的。如果只是临时跑一下推理,直接pip装也行,但代码原目录就变成了“参考文档”,改什么都没反应,调试成本一下就上来了。

torch我习惯显式装,不依赖ultralytics自动拉依赖:

pip install torch torchvision --index-url https://download.pytorch.org/whl/cu121

如果你的机器没有GPU,把cu121换成CPU版本即可,推理一样能跑,只是训练会很痛苦。

1.3 一行命令验证整条链路是否跑通

装完到底成没成,跑一次最小推理就清楚了:

yolo predict model=yolo11n.pt source='https://ultralytics.com/images/bus.jpg'

第一次运行会自动下载yolo11n.pt权重,默认放在当前目录。如果下载特别慢,可以去GitHub的Releases页面手动下载权重文件放到项目根目录,CLI会优先识别本地文件。跑完之后,结果会自动存到runs/detect/predict/下,包含原图加检测框的可视化结果。这一步能通过,说明torch、ultralytics、权重加载、推理管线、结果保存这条链路已经全通了。

验证安装版本也可以用:

import ultralytics print(ultralytics.__version__)

能看到类似0.3.x的版本号,就说明包导入正常。

1.4 目录结构里最值得先看的几个文件

解压后你会看到ultralytics/是主包,examples/tests/docs/是辅助。我建议先翻这几个文件,比从入口一路读下去高效得多:

  • ultralytics/cfg/models/11/yolov11.yaml:网络结构定义,v11的backbone和head全在这里;
  • ultralytics/cfg/datasets/coco8.yaml:一个迷你数据集配置,跑训练demo时直接用这个;
  • ultralytics/engine/predictor.py:推理主逻辑,preprocess、inference、postprocess全在这里;
  • ultralytics/engine/trainer.py:训练主循环,loss、optimizer、scheduler都从这里进去。

先把这几个文件各翻一遍,你对整个项目的骨架就有概念了。

2. 用几种姿势调用推理,以及结果的保存与落地

2.1 CLI和Python两套入口怎么选

ultralytics同时提供了CLI和Python API。CLI适合快速验证和批处理,一条命令就能跑完一个文件夹:

yolo predict model=yolo11n.pt source=./images imgsz=640 conf=0.25 device=0

source参数很宽容,单张图片、文件夹、视频文件、摄像头ID、甚至URL都能直接传。conf是置信度阈值,低于这个值的框会被过滤掉。iou控制NMS的容忍度,越小越严格。imgsz默认640,显存紧张就降到512或480。

Python API适合嵌入到项目里,后面要接业务逻辑。两种入口底层是同一套代码,没有功能差异,选哪种纯看场景。

2.2 results对象里到底装了什么

以Python API为例:

from ultralytics import YOLO model = YOLO("yolo11n.pt") results = model.predict("bus.jpg") r = results[0] print(r.boxes.xyxy) # [N, 4],左上右下坐标 print(r.boxes.conf) # [N],每个框的置信度 print(r.boxes.cls) # [N],类别索引 print(r.names) # {0: 'person', 1: 'bus', ...} print(r.masks) # 分割任务才有 print(r.keypoints) # 姿态任务才有

注意predict返回的是一个列表,每个元素对应一张输入图,即使你只输入了一张图,也要先取results[0]。坐标和类别都是tensor,如果后续要转列表或者存数据库,记得先.cpu().numpy()再处理。

2.3 三种保存结果的方式:自动保存、手动可视化和结构化导出

这是很多人第一次用v11会卡住的地方,热词里“yolov11保存推理结果”反复出现,确实是个高频需求。

第一种最省事,predict时加save=True

results = model.predict("bus.jpg", save=True)

结果自动存到runs/detect/predict/,文件名自动生成,不用自己管。

第二种是手动可视化,适合你想把检测框画到特定位置、或者给结果加后处理:

from PIL import Image im_bgr = r.plot(line_width=2) im_rgb = Image.fromarray(im_bgr[..., ::-1]) im_rgb.save("output.jpg")

plot()返回的是BGR顺序的numpy数组,直接用PIL保存会偏蓝。用[..., ::-1]把通道翻回来就行。如果你用cv2.imwrite写,就不用翻转,OpenCV自己就是BGR顺序。

第三种是结构化导出,适合对接业务系统,把检测结果变成可以入库的数据:

import json r.save_txt("labels/") # 每行:class cx cy w h,归一化坐标,YOLO格式 r.save_crop("crops/") # 把每个目标抠出来单独存图 data = json.loads(r.tojson()) # 完整JSON,含坐标、置信度、类别,可入数据库

三种方式各有用处:自动保存省事,手动可视化灵活,结构化导出负责对接下游。批量推理时建议用stream=True,它会把图片按需加载,处理一帧释放一帧,不会一次性把所有结果都压在内存里:

results = model.predict(source="videos/street.mp4", save=True, stream=True) for res in results: print(len(res.boxes))

2.4 一个很容易坑的问题:图片颜色不对

如果你用plot后用matplotlib显示,颜色会偏蓝,不是模型错了,是通道顺序问题。这类问题刚入门时几乎人人都会遇到,记住一点:ultralytics内部处理图像用的是BGR,plot返回的也是BGR,只要显示层用OpenCV就没错,用PIL/matplotlib就得手动转RGB。

3. 读懂yolov11的yaml:从网络结构到参数规模的映射

3.1 四个基础规格与scale参数

yolov11的yaml文件在ultralytics/cfg/models/11/yolov11.yaml。打开后你会在最顶上看到一段scales配置,这就是模型规格的调节器:

规格depth_multiplewidth_multiplemax_channels典型场景
yolo11n0.330.251024边缘设备、实时性优先
yolo11s0.330.501024一般服务端推理
yolo11m0.670.50768精度与速度均衡
yolo11l1.001.00512高精度任务
yolo11x1.001.00512精度优先,显存充足

depth控制每个block堆叠几层,width控制通道数的缩放系数,max_channels控制通道数上限。以yolo11n为例,width是0.25,意味着基准64通道会变成16通道,这就是为什么n版模型只有两三百万参数。你得理解这个机制,后面想自己定义“比n大一点、比s小一点”的规格时,直接改scales就行,不用一个个层去调。

3.2 C3k2、C2PSA和Detect:三个关键词看懂v11的设计

v11相比v8,主干上最核心的变化是C3k2和C2PSA。

C3k2是从C3和C2f一路演化来的。它把输入特征在中间分叉,一部分走标准卷积和split,另一部分直接concat过去,减少了中间变量占用的内存,同时让梯度回传路径更短。这个名字看起来新,本质上是对v8里C2f的又一次“轻量化重排”。

C2PSA是v11放进backbone最后一层(倒数第二层)的模块,在C2结构的第二条路径里嵌入了多头自注意力机制。这一步的意图很直接:让网络在高层特征上增强全局信息的感知,对遮挡、密集目标的表征更友好。注意力模块的参数量和计算开销都不小,所以只放在高层,不在浅层用。

Detect部分依旧是解耦头,分类分支和回归分支分开,回归分支采用anchor-free和DFL。它输出三个尺度的特征图,对应stride 8、16、32,分别负责小、中、大目标。这个设计直接决定了后续“加P2分支”这个优化的可行性。

3.3 从yaml到“层号”:调试网络结构时最实用的技能

yaml里每一行都代表一层,from字段写的是这一层接收哪些层的输出,负号表示相对前面第几层。比如- [-1, 6, C3k2, [512, False, 0.25]]的意思是:输入来自上一层输出,再接6个C3k2模块,通道数512。

想验证自己理解的网络结构,最直接的办法是:

from ultralytics import YOLO model = YOLO("yolo11n.yaml") model.info()

model.info()会打印每一层的输出shape和参数量,每一层的实际张量尺寸一目了然。想知道某个模块输出是什么维度,就改一版看看,比对着论文数结构快多了。

3.4 model.yaml、预训练权重和任务头的关系

YOLO("yolo11n.yaml")代表从网络结构开始初始化,权重全是随机数,这是从零训练的前提。YOLO("yolo11n.pt")则是加载已经训练好的权重,同时也包含结构信息。想从头训练一个自定义任务时,用前者;想在COCO预训练基础上微调时,用后者。ultralytics会自动根据任务切换输出头:detect任务用Detect模块,segment任务用Segment模块,pose任务用Pose模块。所以同一个yaml文件改一下任务设置,就能切换不同的任务头,这一点在改造自定义模型时会非常有用。

4. 自定义数据集训练:一套能直接抄的配置文件与训练参数

4.1 数据目录和标签长什么样

ultralytics默认使用YOLO格式标注,一个txt文件对应一张图片,文件名相同、扩展名不同。目录结构如下:

ROOT/ images/ train/ 0001.jpg 0002.jpg val/ 0001.jpg labels/ train/ 0001.txt 0002.txt val/ 0001.txt

labels里的每行格式是:

class x_center y_center width height

注意三点:类别编号从0开始;坐标全部归一化到0~1之间;imageslabels的子目录名必须一致。很多新手把train和val的图片放一个文件夹、标注放另一个文件夹,结构对不上,就会报 “no labels found”。

4.2 data.yaml的坑:路径写相对还是绝对

data.yaml是训练时的数据集说明文件:

path: /home/user/datasets/myproject train: images/train val: images/val nc: 3 names: ['cat', 'dog', 'bird']

path是根目录,trainval是相对于path的路径。这个字段经常有人写错:写成绝对路径反而容易因为换机器报错,写成相对path下的路径最稳。你可以在命令行里手动跑一个检查命令确认数据集没问题:

yolo val data=myproject.yaml model=yolo11n.pt

如果数据配置有误,这一步会给出比较具体的报错提示。

4.3 一条能跑起来的训练命令

以yolo11s为例:

yolo detect train model=yolo11s.pt data=myproject.yaml epochs=100 imgsz=640 batch=16 device=0 patience=50

参数含义拆开讲:

  • model=yolo11s.pt:加载COCO预训练权重做微调,比model=yolo11s.yaml从零训练收敛快得多,精度通常也更高。
  • batch:按显存来。太大会OOM,太小会让梯度噪声变大。Ultralytics支持batch=-1,让它自动搜索当前显存能容纳的最大batch。
  • epochs:小数据集100轮基本够看趋势,大项目通常200~300。
  • patience:验证集指标连续多少轮不提升就早停,50是常用值,防止过拟合白烧时间。
  • cache=True:小数据集时把数据缓存到内存,加载速度明显提升。

训练产物在runs/detect/train/下,weights/best.ptweights/last.pt的区别要分清:best是按验证集指标选出的最优权重,last是最后一轮的权重。训练中断后可以用resume=True从last.pt继续跑,而不是用best。有人用best.pt去resume,结果优化器状态对不上,效果会打折扣。

常用参数速查:

参数作用我常用的值
lr0初始学习率0.01,微调用0.005
warmup_epochs预热轮数3
cos_lr余弦学习率衰减True
mosaicMosaic增强是否开启1.0,小目标调0.5
fliplr水平翻转概率0.5
scale随机缩放范围0.5~1.5

4.4 第一次训练最容易遇到的三个错

第一个错误是找不到标签。报错 “no labels found in ...”,不用怀疑,就是目录结构或者data.yaml路径对不上,按上面的结构检查一遍。

第二个是CUDA out of memory。先降batch到4或2,再不行就降imgsz到512或480。如果还想再省,把cache=False开成False,减少内存占用。训练是迭代过程,先把管线跑通,再去追性能和内存。

第三个是训练过程中loss突然变NaN。多数情况是标签坐标越界或者某些类别没有训练样本。先用check_det_dataset检查数据集:

from ultralytics.data.utils import check_det_dataset check_det_dataset("myproject.yaml")

它会打印每个类的实例数、目标尺寸分布等信息,一眼就能看出哪个类别样本过少,或者哪些标注坐标异常。

5. 小目标检测优化:我在实际项目里踩过的坑和有效手段

5.1 为什么v11的小目标效果仍然不够好

很多人以为换了新版模型,小目标检测就会自动变好,实际远没这么简单。三个原因叠加导致小目标依然是老大难:

一是输入分辨率。默认imgsz是640,一个20×20像素的小目标缩放到640尺度后可能只剩3×3个像素,特征提取阶段就已经丢掉大部分信息。二是下采样倍数。v11的head在stride 8/16/32上输出特征,stride 32的特征图对于小目标来说,一个目标的信号可能只落在一个格点上。三是数据分布。实际项目里小目标往往占少数,如果标注时框还不准,模型基本学不到有效的小目标特征。

5.2 最直接有效:提高输入分辨率并配合多尺度训练

既然信息在缩放时丢了,最直观的解法就是把输入放大。训练时用1280:

yolo detect train model=yolo11s.pt data=myproject.yaml imgsz=1280 batch=8 device=0

推理时同样用1280:

yolo predict model=best.pt source=test/ imgsz=1280

代价是计算量和显存几乎按分辨率平方上涨,速度会明显变慢。显存不够时用batch=1硬扛,或者开启rect=True,它会让batch内的图片按长宽比分组,减少padding造成的无效计算。

5.3 数据的功夫在数据里:先查目标尺寸分布

改网络之前,先统计一下数据集里小目标占比,按COCO的定义,小于32×32像素算小目标。把标注文件读出来,用归一化框宽高乘以图片宽高,就能算出实际像素尺寸。我做过一个遥感项目,当时小目标占比不到5%,后来把训练集中小目标样本补到20%以上,mAP直接涨了4个点,比改网络结构收益大得多。

5.4 网络层面:给检测头加P2分支

数据补完之后效果还不够,再考虑动网络。社区里常见的做法是给检测头增加P2分支,P2是2倍下采样的特征图,分辨率是输入的1/4,保留了更多小目标的细节纹理。

具体思路是:在backbone的第二个C3k2输出后面接一个通道对齐的卷积,得到P2特征,然后把head里Detect的输入[P3, P4, P5]扩展为[P2, P3, P4, P5],同时调整分类和回归分支的输入通道数。GitHub搜一下yolov11-p2.yaml,能找到很多人改好的版本,原理就是上面这几步。

代价也要讲清楚:P2特征图分辨率高,计算量和显存会明显上涨,训练速度可能下降20%以上,而且大目标的精度有时候会略降。所以P2分支适合小目标占比高、且对延迟不敏感的落地场景,不是万金油。

5.5 推理阶段兜底:放宽NMS和置信度

模型训练完,推理参数也值得调。默认conf是0.25,小目标置信度普遍偏低,降到0.1能捞回不少真目标,代价是假阳性增多。iou从0.45放宽到0.5或0.6,能让NMS不那么激进地合并邻近框。max_det=300可以防止密集场景下目标被截断。

这些参数调完记得在验证集上重新评估,别单凭一两张图的视觉感受下结论。

5.6 小目标改进效果的验证方法

改进有没有效果,不能只看总mAP。训练完看results.png里的PR曲线和召回率,重点观察小目标子集上的Recall变化。如果recall上去了但precision掉了很多,说明模型确实多检出了小目标,只是误检也随之增加,这时候再去调NMS和置信度才有意义。

6. 在ultralytics架构下扩展:RT-DETR接入与模型导出的进阶玩法

6.1 用同一套接口跑RT-DETR

ultralytics不只支持YOLO系列,还顺手把RT-DETR也整合了进来。RT-DETR是端到端检测模型,不需要NMS后处理。热词里反复出现“在ultralytics中训练rtdetr-r18/r34”,说明不少人想把RT-DETR也纳入这套统一训练管线。

官方预训练权重是RT-DETR-L和RT-DETR-X,推理写法:

from ultralytics import RTDETR model = RTDETR("rtdetr-l.pt") results = model.predict("bus.jpg", save=True)

训练自定义数据集时:

yolo detect train model=rtdetr-l.yaml data=myproject.yaml epochs=100 imgsz=640

数据格式和YOLO完全一致,不用额外转换,这是ultralytics把所有模型收编进同一套管线的巨大优势。

6.2 在ultralytics里改造rtdetr-r18/r34的yaml

RT-DETR的backbone是ResNet,在ultralytics的cfg/models/rt-detr/目录下,rtdetr-l.yaml把ResNet拆成了多个stage,每个stage的层数和通道数就是照着ResNet-50来的。想做成r18或r34版本,核心就是对照ResNet结构改yaml里backbone各stage的blocks数量:ResNet-18为[2, 2, 2, 2],ResNet-34为[3, 4, 6, 3],通道数分别对应[64, 128, 256, 512]。neck部分的encoder和decoder隐藏维度可以相应缩小,不然整体计算量还是偏大。

改完之后用yolo detect train model=rtdetr-r18.yaml data=...验证能不能正常解析。RT-DETR走的是集合匹配的loss,显存占用比同规模YOLO高不少,训练时把batch先调小,跑通之后再慢慢往上试。

6.3 模型导出:从best.pt到onnx再到engine

训练完了要部署,ultralytics也给了统一导出入口:

yolo export model=best.pt format=onnx imgsz=640 yolo export model=best.pt format=engine device=0 half=True

第一条导出ONNX,这是中间格式,几乎所有推理框架都能接。第二条导出TensorRT的engine格式,需要宿主机有GPU并且安装好了TensorRT,half=True启用FP16,推理速度通常能再快一截。

导出时注意imgsz必须和部署端要求的输入尺寸一致,导出后再改分辨率又要重新导一次。遇到过ONNX中间节点过多导致推理变慢的情况,优先检查导出的简化选项,比如opset=12这种兼容性设置。

6.4 源码阅读的入口:如果想二次开发,从哪里下手

最后一个话题,回到“源码”本身。想真正深入改造,我建议按这个顺序读:

  • 先读ultralytics/engine/predictor.py,看推理全流程,preprocess、inference、postprocess三个方法分开读;
  • 再读ultralytics/nn/tasks.py里的parse_model,它是把yaml转化成模型结构的核心,读懂了就知道yaml里的每一行参数怎么映射成代码;
  • 最后读对应任务的训练脚本,比如ultralytics/models/yolo/detect/train.py,看loss是怎么组装出来的。

我自己这些年用ultralytics最大的体会是:千万不要一开始就想着去读整个项目,一定要带着一个具体问题去读。比如“小目标检测不好,我想加一个P2层”,那你就沿着yolov11.yaml找到Detect层的输入,再去tasks.py看head怎么构建,顺着这条线走,两天就能把相关逻辑摸透。抛开具体问题去读,很容易在几百个文件里迷路。

模型改进这件事,动结构之前永远先问自己一句:数据干净了吗?分辨率提上去了吗?如果这两个问题都没想清楚就改网络,大概率只是把钱和算力花在了错误的地方。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/1 1:53:55

STEP7-300安装授权与组态下载完整指南:老PLC维护避坑实战

简介:这是一份面向西门子S7-300 PLC编程环境的STEP7绿色版软件包,主要服务于自动化工程师、设备维护人员以及相关专业学生,解决安装版STEP7在系统兼容性、授权许可和部署时间上的常见问题。资源采用zip压缩包方式发放,整体大小仅3…

作者头像 李华
网站建设 2026/9/1 1:52:26

CIBERSORT免疫浸润分析实战:从原理、数据准备到结果解读

简介:本资源是面向生物信息学零基础学习者的转录组下游分析实战配套材料,聚焦免疫微环境解析中的CIBERSORT算法应用,解决科研人员在肿瘤免疫浸润定量分析中常见的数据输入、R代码运行与结果解读难题。压缩包共13个文件,包含5个CSV…

作者头像 李华
网站建设 2026/9/1 1:52:02

门诊病历智能生成系统架构设计:从大模型到落地实践

先说一个核心判断:门诊病历智能生成系统,本质不是“接一个大模型接口”这么简单。它牵涉到数据接入、上下文组装、术语标准化、输出校验、医生交互、权限审计、模型部署和监控告警一整条链路。如果只把注意力放在“生成能力强不强”上,架构设…

作者头像 李华
网站建设 2026/9/1 1:48:58

Faster R-CNN血细胞检测实战:从数据准备到部署全流程

简介:一份基于Faster R-CNN的血液细胞目标检测完整工程资源,面向深度学习目标检测入门者及医学影像分析相关研究人员,适用于血液涂片中的细胞识别与定位任务。包内共1565个文件,包括777个XML标注文件与777张JPG图像、5个模型权重文…

作者头像 李华
网站建设 2026/9/1 1:48:23

51单片机光电测速调速系统实战:从信号整形到PID闭环控制

简介:本资源是一套完整的基于51单片机的光电测转速与调速系统设计资料,面向电子类专业本科生、课程设计及毕业设计学习者,解决电机转速实时检测与显示的核心实践问题。系统以STC89C52单片机为核心,集成槽型光耦光电传感器测速模块…

作者头像 李华