YOLO 架构详解:从 YOLOv3 到 YOLO26#
每个 Ultralytics YOLO 模型都由三个阶段构成:提取特征的 主干网络、跨尺度融合特征的 颈部网络,以及预测边界框和类别的 检测头。本指南介绍各阶段所包含的模块,以及这些模块从 YOLOv3 到 YOLO26 的变化,并追溯每个组件在 ultralytics/cfg/models/ 下配置文件中的定义,以及 ultralytics/nn/modules/ 中的模块类。
每个模型都以声明式方式定义在 YAML 文件中,文件由按顺序排列的层组成;每层都遵循 [from, repeats, module, args] 格式:输入来自哪些层、模块重复多少次、层类(Conv、C3k2、SPPF、Detect,……),以及构造函数参数。模型 YAML 配置指南详细介绍了这种格式,包括 repeats 和 args 如何随变体的深度和宽度倍数缩放,以及完整的模块解析系统。本指南聚焦于模块本身,以及它们在不同版本间的变化。
三个阶段#
每个 Ultralytics YOLO 模型都会依次将图像送入三个阶段,每个阶段各司其职:
| 阶段 | 任务 | 输出 |
|---|---|---|
| 主干网络 | 从输入图像的多个分辨率中提取特征 | 步长为 8、16 和 32 的特征图(P3、P4、P5) |
| 颈部网络 | 跨尺度融合特征,为小目标和大目标都提供上下文信息 | 融合后的多尺度特征图 |
| 检测头 | 根据融合后的特征预测边界框和类别分数 | 每个锚点的检测结果 |
基本单元是 Conv 块(定义于 conv.py:由 2D 卷积、批归一化和 SiLU 激活依次组成。下文中的每个更大型模块都由多个 Conv 块组合而成。
架构图#
每个版本都保留相同的 backbone → neck → head 骨架,只调整特定阶段。下方的选项卡展示了各版本的结构:backbone 和 neck 阶段遵循 ultralytics/cfg/models/ 中的配置,而 YOLOv3 和 YOLOv5 的 head 则以原始的基于锚框形式绘制,而非其软件包配置实际采用的无锚框 u 变体 head。逐个查看选项卡,可以了解每一代新增的内容。简而言之,演进过程如下:YOLOv3 是仅使用 FPN、基于锚框的检测器;YOLOv5 增加了自底向上的 PAN 路径和 SPPF;YOLOv8 切换到 C2f 模块,并采用无锚框的 DFL head;YOLO11 加入了 C2PSA 注意力机制和 C3k2 模块;YOLO26 则增加了 SPPF 残差结构、移除 DFL,并加入可选的无 NMS head。
YOLOv3 和 YOLOv5 的图示展示了原始的基于锚框检测头。ultralytics 软件包提供无锚框的 YOLOv3u 和 YOLOv5u 配置:它们采用相同的 Darknet-53 和 C3 主干网络,并使用 YOLOv8 的 Detect 检测头,详见检测头一节。
主干网络模块:Bottleneck → C3 → C2f → C3k2#
主干网络在步长为 2 的 Conv 下采样层之间堆叠重复的 CSP(跨阶段局部连接)模块。这个重复模块是各版本间变化最大的部分。下面所有模块都位于 block.py 中;c1/c2 分别表示输入/输出通道,c = 0.5 * c2 表示隐藏层宽度。
Bottleneck(YOLOv3)#
基本单元是 Bottleneck:包含两个 Conv 层(默认卷积核为 (3, 3)),并在 shortcut=True 和 c1 == c2 时可选地执行残差相加。YOLOv3 的 Darknet-53 主干网络直接堆叠这些单元,不进行 CSP 分支,并在三个尺度(步长为 8、16、32)上进行检测。
C3(YOLOv5)#
YOLOv5 的 C3 将输入拆分后分别送入两个 1x1 卷积:cv1 依次经过 n 个 Bottleneck 模块(卷积核依次为 (1, 1) 和 (3, 3)),cv2 则绕过这些模块。两条路径拼接后,由第三个 1x1 Conv 卷积进行融合:
def forward(self, x):
# C3:瓶颈路径 m(cv1(x)) 与旁路 cv2(x) 拼接,然后由 cv3 融合
return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1))只有最后一个瓶颈输出会到达融合卷积,因此 cv3 会接收 2 个特征图。
C2f(YOLOv8)#
YOLOv8 的 C2f(“带两个卷积的 CSP Bottleneck,更快”)改变了到达融合卷积的特征:
cv1 = Conv(c1, 2 * c, 1),然后chunk(2)将输出拆分为两个c通道的张量。n个Bottleneck(c, c)模块(卷积核为(3, 3)、(3, 3))依次运行,每个模块都接收前一个模块的输出。- 所有
n + 2个中间张量都会拼接,并由cv2 = Conv((2 + n) * c, c2, 1)融合。
C3 将 2 个特征图传入融合卷积,而 C2f 会传入 n + 2 个特征图,也就是重复利用每个中间瓶颈输出。
C3k2(YOLO11 和 YOLO26)#
YOLO11 和 YOLO26 使用 C3k2,这是 C2f 的子类,会替换重复单元。根据构造函数标志,每个 n 模块会变成以下其中一种:
- 普通的
Bottleneck(默认,c3k=False), - 一个
C3k模块(c3k=True)——一种可配置卷积核大小的C3变体,或 - 一组
Bottleneck+PSABlock模块(attn=True)。
第二个 YAML 参数会设置 c3k,但当缩放级别为 m、l 或 x 时,会强制设为 True——这就是一个 yolo11.yaml 如何适配所有五种变体的方式。因此,[-1, 2, C3k2, [512, False]] 在 n 和 s 处构建 Bottleneck 内部模块,而在 m、l 和 x 处构建 C3k 内部模块;512 是缩放前的通道数,经过变体的宽度倍数缩放后,在 n 处变为 128,在 x 处变为 768。对于 CSP 模块,repeats 字段(此处为 2,之后还会按变体的深度倍数缩放)会成为模块内部的重复次数,而不是用于堆叠独立模块。
空间池化:SPP → SPPF#
在主干网络末端,空间金字塔池化模块会扩大感受野。YOLOv5 将原来的多卷积核 SPP 替换为 SPPF(快速空间金字塔池化):对 MaxPool2d(kernel_size=5, stride=1, padding=2) 连续应用 n = 3 次,将输入和三个池化输出拼接,再由 1x1 Conv 卷积进行融合。从数学上看,这与 SPP(k=(5, 9, 13)) 等价,但计算成本更低,因为串联的 5x5 池化覆盖了较大卷积核的感受野。
YOLO26 会传入 shortcut 标志(SPPF, [1024, 5, 3, True]);由于 c1 == c2 == 1024 位于最深层,SPPF 会添加残差连接(return y + x)。
空间注意力:C2PSA(YOLO11 及后续版本)#
YOLO11 在 SPPF 之后加入了 C2PSA。这是一个 CSP 模块,其活动分支由一组 n 个 PSABlock(位置敏感注意力)模块构成:cv1 = Conv(c1, 2 * c, 1) 将特征拆分,一半经过 PSABlock 模块堆栈,cv2 = Conv(2 * c, c1, 1) 再融合拼接结果。每个 PSABlock 都会应用多头注意力,然后接一个两层前馈网络(Conv(c, 2 * c, 1) → Conv(2 * c, c, 1)),两者各自都带有残差连接。YOLO26 保留了相同的 C3k2 + C2PSA 主干网络。
颈部网络:FPN + PAN#
颈部网络先通过自顶向下的特征金字塔网络(FPN)融合主干网络的 P3/P4/P5 特征图,再通过自底向上的路径聚合网络(PAN)进行融合。在 YAML 的 head 部分,FPN 对应 nn.Upsample + Concat(将语义信息传递到更高分辨率),PAN 对应步长为 2 的 Conv + Concat(将定位信息向上传递):
# YOLO11 head (FPN top-down, then PAN bottom-up)
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 6], 1, Concat, [1]] # cat backbone P4
- [-1, 2, C3k2, [512, False]] # 13
# ... second upsample + concat to P3 ...
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 13], 1, Concat, [1]] # cat head P4 (PAN)
- [-1, 2, C3k2, [512, False]] # 19颈部网络会复用对应版本的主干网络模块——YOLOv5 使用 C3,YOLOv8 使用 C2f,YOLO11 和 YOLO26 使用 C3k2——因此每个合并点都会运行与主干网络相同的模块。三个融合后的输出会送入检测头。YOLOv3 是个例外:它的颈部网络只有自顶向下的 FPN(其 YAML head 没有步长为 2 的下采样),不包含 YOLOv5 引入的自底向上 PAN 路径。
检测头:基于锚框 → 无锚框 → 无 NMS#
检测头将三个融合后的特征图转换为目标检测任务的预测结果。它的设计历经多个版本,从基于锚框到无锚框,再到无需 NMS。
无锚框、解耦的 Detect#
原始的 YOLOv3 和 YOLOv5 使用基于锚框的耦合检测头:使用预定义锚框,并通过共享分支预测边界框和类别。独立的 ultralytics/yolov3 和 ultralytics/yolov5 仓库保留了这种基于锚框的设计。主 ultralytics 软件包则提供无锚框的 YOLOv3u 和 YOLOv5u 变体:它们采用相同的 Darknet-53 和 C3 主干网络,并搭配 YOLOv8 的无锚框 Detect 检测头;此处介绍的 yolov3.yaml 和 yolov5.yaml 配置指的是这些 u 变体,而非历史设计。
Detect 检测头(head.py)采用无锚框、解耦设计:每个金字塔层级运行两个并行分支,直接在网格点上进行预测,而不是针对锚框进行预测。
- 边界框分支(
cv2):Conv(x, c2, 3)→Conv(c2, c2, 3)→Conv2d(c2, 4 * reg_max, 1)。 - 类别分支(
cv3): 在 YOLO11 和 YOLO26 中,两个深度可分离模块(DWConv+1x1 Conv)→Conv2d(c3, nc, 1);YOLOv8 使用旧版变体,即两个3x3 Conv层 →Conv2d(c3, nc, 1)。
因此,每个锚点会输出 no = nc + 4 * reg_max 个值。移除预定义锚框后,超参数中就不再需要调整锚框尺寸和长宽比。
分布焦点损失(DFL)#
YOLOv8 和 YOLO11 将 4 个边界框坐标分别表示为在 reg_max = 16 个区间上的概率分布,而非单个标量(采用广义焦点损失的积分形式)。DFL 模块将 4 * reg_max 个边界框通道重塑为 (4, reg_max),在 reg_max 个区间上应用 softmax,并取期望区间索引作为预测坐标——即用每个区间索引乘以其 softmax 概率,再求和。该操作通过固定的 1x1 卷积实现,其权重为区间索引 arange(reg_max),因此加权求和只需一次点积。
YOLO26:无需 NMS、无需 DFL#
YOLO26 设置了两个由检测头直接读取的 YAML 参数:
end2end: True—Detect会将分支深度复制到一对一检测头(one2one_cv2/one2one_cv3),使其学会为每个目标生成单个预测。此 YAML 设置会创建两个训练检测头;运行时,nms=False会选择一对一检测头,并移除非极大值抑制(NMS)后处理步骤。推理和导出详情请参阅端到端检测指南。reg_max: 1— 当区间数为 1 时,self.dfl会变为nn.Identity()和no = nc + 4;检测头直接回归坐标,导出的 ONNX 图中不会出现 DFL 操作。
在五种模型尺寸(n/s/m/l/x)下,根据 YOLO26 论文报告,YOLO26 在 COCO 上的 mAP 为 40.9-57.5,T4 上 TensorRT 延迟为 1.7-11.8 ms。
各版本摘要#
| 版本 | 主干网络模块 | 空间池化 | 注意力 | 检测头 | DFL |
|---|---|---|---|---|---|
| YOLOv3 | Darknet-53(Bottleneck) | 基础配置中无 | 无 | 原始版本:基于锚框;u 变体:无锚框 | 否 / 是(u) |
| YOLOv5 | C3(CSP) | SPPF | 无 | 原始版本:基于锚框;u 变体:无锚框 | 否 / 是(u) |
| YOLOv8 | C2f | SPPF | 无 | 无锚框、解耦 | 是(reg_max=16) |
| YOLO11 | C3k2 | SPPF | C2PSA | 无锚框、解耦 | 是(reg_max=16) |
| YOLO26 | C3k2 | SPPF + shortcut | C2PSA | 无锚框、双检测头;可选无 NMS | 已移除(reg_max=1) |
各模型的详细信息、性能表格和使用示例,请参阅 YOLOv3、YOLOv5、YOLOv8、YOLO11 和 YOLO26 的独立页面。
亲自检查架构#
model.info() 方法会打印层、参数和 FLOPs 摘要,解析后的模块列表可通过 model.model.model 查看。
from ultralytics import YOLO
# 加载预训练模型
model = YOLO("yolo11n.pt")
# 融合 Conv + BatchNorm 层,使计数与已发布的规格一致
model.fuse()
# 打印摘要:层、参数、梯度、GFLOPs
model.info()
# 检查检测头(网络中的最后一个模块)
head = model.model.model[-1]
print(type(head).__name__, "| reg_max:", head.reg_max, "| DFL layer:", type(head.dfl).__name__)在三个不同代际的模型上运行这段代码,可以从数值上看出变化。这些是 ultralytics 软件包生成的真实融合模型输出,与各模型页面公布的参数量和 FLOPs 数量一致:
| 模型 | 层数 | 参数量 | GFLOPs | reg_max | DFL 层 |
|---|---|---|---|---|---|
| YOLOv8n | 72 | 3,151,904 | 8.7 | 16 | DFL |
| YOLO11n | 100 | 2,616,248 | 6.5 | 16 | DFL |
| YOLO26n | 120 | 2,408,932 | 5.5 | 1 | Identity |
YOLO26n 报告的 reg_max=1,以及一个 Identity DFL 层。默认情况下,预测和验证使用带 NMS 的一对多模式;设置 nms=False 可进行无 NMS 推理。两个检测头都会参与训练。
报告的参数量和 FLOPs 数值对应融合后的模型(model.fuse()),该模型将每个 Conv 与其批归一化层合并。这与已发布的规格一致;刚加载的检查点在融合前报告的计数会略高。
结论#
在不同版本中,YOLO 架构逐步调整各个阶段:backbone 从 Darknet-53 演进为基于 CSP 的 C3、C2f 和 C3k2 模块,并加入 C2PSA 注意力机制;neck 保留了 FPN + PAN 结构,同时 SPP 演进为 SPPF;head 则从基于锚框转为无锚框,最终演进为 YOLO26 不使用 DFL 的设计,并配备可选的无 NMS 端到端 head。
要定义自定义架构,请参阅模型 YAML 配置指南,或在模型页面上比较模型。如有疑问,请通过 GitHub 或 Discord 联系我们。
常见问题#
YOLO 模型包含一个主干网络,用于以 8、16 和 32 的步幅从图像中提取特征;一个颈部网络,用于通过 FPN 和 PAN 融合不同尺度的特征;以及一个检测头,用于预测边界框和类别分数。从 YOLOv3 到 YOLO26,所有 Ultralytics YOLO 模型都遵循这套三阶段设计。
C2f(YOLOv8)是一个 CSP 模块,会在融合卷积之前拼接每个内部Bottleneck(即n + 2特征图)的输出,而较早的C3只传递 2 个输出。C3k2(YOLO11 和 YOLO26)是C2f的子类;当其c3k标志启用时,它可以将每个Bottleneck替换为C3k模块(这是一个可配置内核大小的C3变体)。两者都定义在block.py中。YOLO11 对 YOLOv8 做了三项结构性调整:将主干网络和颈部网络中的
C2f模块替换为C3k2,在SPPF之后插入C2PSA自注意力模块,并将检测头的分类分支改为更轻量的深度可分离卷积。两者都保留了相同的无锚框、解耦式Detect检测头,并使用reg_max=16DFL 回归,因此这些改动降低了参数量和 FLOPs,同时提升了准确率,而没有重新设计检测接口。现代 Ultralytics YOLO 模型均采用无锚框设计。YOLOv8、YOLO11 和 YOLO26 使用无锚框的解耦式
Detect检测头,其中回归框和分类分别由独立分支处理。最初的 YOLOv3 和 YOLOv5 基于锚框,但 Ultralytics 提供的是 YOLOv3u 和 YOLOv5u 变体,其配置使用与 YOLOv8 相同的无锚框检测头。DFL 将每个边界框坐标回归为在
reg_max个区间上的 softmax 分布(YOLOv8 和 YOLO11 中默认使用 16 个区间),并将期望值作为坐标,而不是预测单个标量。YOLO26 设置reg_max=1,因此 DFL 层会变成恒等运算,检测头直接回归坐标,导出的 ONNX 或 TensorRT 计算图中也不会出现 DFL 运算。在 Python 中加载模型并调用
model.info(),即可查看层数、参数量和 GFLOPs 摘要。解析后的层位于model.model.model中——例如,model.model.model[-1]是Detect检测头,其中包含reg_max和dfl等属性。完整架构定义在模型的 YAML 配置文件中。