YOLO 架构详解:从 YOLOv3 到 YOLO26#
每一个 Ultralytics YOLO 模型都由三个阶段构建而成:提取特征的骨干网络(backbone)、跨尺度融合特征的颈部网络(neck),以及预测边界框和类别的头部网络(head)。本指南记录了构成每个阶段的模块,以及它们从 YOLOv3 到 YOLO26 的演变过程,并将每个组件追溯到 ultralytics/cfg/models/ 下配置文件中的定义以及 ultralytics/nn/modules/ 中的模块类。
每个模型都在 YAML 文件中以声明方式定义为层的有序列表,其中每一层都遵循 [from, repeats, module, args] 格式:输入来自哪一层(或哪些层)、模块重复的次数、层类(Conv、C3k2、SPPF、Detect 等)以及构造函数参数。Model YAML Configuration Guide 记录了这种格式(包括 repeats 和 args 如何随变体的深度和宽度倍数进行缩放),以及完整的模块解析系统。本指南重点介绍模块本身及其在不同版本之间的变化。
三个阶段#
每个 Ultralytics YOLO 模型都将图像通过三个顺序阶段进行路由,每个阶段都有明确的任务:
| 阶段 | 任务 | 输出 |
|---|---|---|
| Backbone | 在多个分辨率下从输入图像中提取特征 | 步长为 8、16 和 32 的特征图(P3、P4、P5) |
| Neck | 跨尺度融合特征,使小目标和大目标都能拥有上下文信息 | 多尺度融合特征图 |
| Head | 从融合后的特征中预测边界框和类别分数 | 每个锚点的检测结果 |
基本单元是 Conv 块(定义于 conv.py):按顺序应用的二维卷积、批量归一化(batch normalization)和 SiLU 激活函数。下面所有的更大模块都是通过组合 Conv 块构建的。
架构图#
每版本都保留相同的 backbone → neck → head 骨架并改变特定阶段。下方的标签页展示了各版本的结构:backbone 和 neck 阶段遵循 ultralytics/cfg/models/ 中的配置,而 YOLOv3 和 YOLOv5 的 head 则以其原始的 anchor-based 形式绘制,而不是它们软件包配置实际采用的无 anchor u 变体 head。逐个查看标签页可以了解每一代新增的内容。简而言之,演进过程是:YOLOv3 是一个仅有 FPN、基于 anchor 的检测器;YOLOv5 添加了自下而上的 PAN 路径和 SPPF;YOLOv8 切换到带有无 anchor、DFL head 的 C2f 模块;YOLO11 插入了 C2PSA 注意力和 C3k2 模块;YOLO26 则添加了 SPPF 残差,并使 head 变为无 NMS 和无 DFL。节点颜色遵循文档图表惯例:绿色表示输入,蓝色表示 backbone,石板灰表示空间池化和注意力,橙色表示 neck,紫色表示 head 和输出。
flowchart TD
IN[Input 640x640]:::start --> ST[Conv stem<br/>5x stride-2 down to P1-P5]:::proc
ST --> BB[Darknet-53 backbone<br/>stacked Bottleneck]:::proc
BB --> FPN[Neck FPN only<br/>top-down Upsample + Concat]:::decide
FPN --> HD[Detect head<br/>3 scales, anchor-based]:::out
HD --> O[Predictions + NMS]:::out
classDef start fill:#4CAF50,color:#fff
classDef proc fill:#2196F3,color:#fff
classDef decide fill:#FF9800,color:#fff
classDef out fill:#9C27B0,color:#fffYOLOv3 和 YOLOv5 图表展示了最初的基于锚框的头部。ultralytics 软件包自带无锚框的 YOLOv3u 和 YOLOv5u 配置——它们拥有与 Darknet-53 和 C3 相同的骨干网络,但配备了 YOLOv8 的 Detect 头部——这些内容在检测头部(Detection Head)下有详细描述。
Backbone 块:Bottleneck → C3 → C2f → C3k2#
骨干网络在步长为 2 的 Conv 下采样层之间堆叠了一个重复的 CSP(跨阶段局部,Cross-Stage Partial)块。这个重复的块在各个版本中变化最大。以下所有块都位于 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: bottleneck path m(cv1(x)) concatenated with bypass cv2(x), then fused by cv3
return self.cv3(torch.cat((self.m(self.cv1(x)), self.cv2(x)), 1))只有最终的瓶颈输出到达融合卷积,因此 cv3 看到 2 个特征图。
C2f (YOLOv8)#
YOLOv8 的 C2f(“带 2 个卷积、速度更快的 CSP 瓶颈”)改变了到达融合卷积的特征:
cv1 = Conv(c1, 2 * c, 1),然后chunk(2)将输出拆分为两个c通道的张量。nBottleneck(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;例如,[-1, 2, C3k2, [512, True]] 在 512 个输出通道处构建一个 C3k2 模块,其内部块为 C3k(因为 c3k=True)。对于 CSP 模块,repeats 字段——此处为 2,在按变体的深度倍数缩放之前——成为块的内部重复次数,而不是堆叠独立的模块。
空间池化:SPP → SPPF#
在 backbone 的末尾,空间金字塔池化模块扩大了感受野。YOLOv5 用 SPPF(空间金字塔池化 - 快速)替换了原始的多核 SPP:一个单一的 MaxPool2d(kernel_size=5, stride=1, padding=2) 按顺序应用了 n = 3 次,输入和所有三个池化输出被拼接并通过 1x1 Conv 进行融合。这在数学上等同于 SPP(k=(5, 9, 13)) 但成本更低,因为链式的 5x5 池化覆盖了较大卷积核的感受野。
YOLO26 传递了一个捷径标志(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 backbone。
Neck:FPN + PAN#
颈部网络将骨干网络的 P3/P4/P5 特征图与自顶向下的特征金字塔网络(FPN)以及随后的自底向上的路径聚合网络(PAN)进行融合。在 YAML 头部部分,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 头部没有步长为 2 的下采样),没有 YOLOv5 引入的自底向上的 PAN 路径。
检测头:基于锚点 → 无锚点 → 无 NMS#
头部网络将三个融合的特征图转换为针对检测任务的预测。其设计在各个版本中发生了变化,从基于锚框到无锚框,再到无 NMS。
无锚框、解耦的 Detect#
原始的 YOLOv3 和 YOLOv5 使用了基于 anchor 的、耦合的 head:预定义的 anchor 框以及用于框和类别预测的共享分支。独立的 ultralytics/yolov3 和 ultralytics/yolov5 仓库保留了该基于 anchor 的设计。主要的 ultralytics 软件包反而搭载了无 anchor 的 YOLOv3u 和 YOLOv5u 变体 —— 即具有 YOLOv8 无 anchor Detect head 的相同 Darknet-53 和 C3 backbone —— 并且这里记录的 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 个箱(bins)上的分布,而不是单个标量(来自广义焦点损失(Generalized Focal Loss)的积分形式)。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)中,为每个对象产生单个预测,从而去掉了非极大值抑制(Non-Maximum Suppression)(NMS)后处理步骤。有关导出和迁移的详细信息,请参阅端到端检测指南(End-to-End Detection guide)。reg_max: 1— 只有一个箱时,self.dfl变成nn.Identity()和no = nc + 4;头部直接回归坐标,并且导出的 ONNX 图中不会出现 DFL 操作。
在其五个模型尺寸(n/s/m/l/x)中,YOLO26 在 COCO 上达到了 40.9-57.5 的 mAP,T4 TensorRT 延迟为 1.7-11.8 ms,正如 YOLO26 论文中所报告的那样。
版本总结#
| 版本 | Backbone 块 | 空间池化 | 注意力 | 检测头 | 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 + 捷径 | C2PSA | 无锚框、无 NMS(end2end) | 已移除(reg_max=1) |
有关逐个模型的详细信息、性能表格和使用示例,请参阅 YOLOv3、YOLOv5、YOLOv8、YOLO11 和 YOLO26 的单独页面。
亲自检查架构#
model.info() 方法会打印层、参数和 FLOPs 摘要,并且解析后的模块列表可在 model.model.model 上获取。
from ultralytics import YOLO
# Load a pretrained model
model = YOLO("yolo11n.pt")
# Fuse Conv + BatchNorm layers so counts match the published specs
model.fuse()
# Print a summary: layers, parameters, gradients, GFLOPs
model.info()
# Inspect the detection head (the last module in the network)
head = model.model.model[-1]
print(type(head).__name__, "| reg_max:", head.reg_max, "| end2end:", head.end2end)跨三个世代运行该代码片段可以以数字方式展示这些变化。这些是来自 ultralytics 软件包的真实融合模型输出,与每个模型页面上公布的参数和 FLOPs 数量相匹配:
| 模型 | 层数 | 参数量 | GFLOPs | reg_max | end2end | DFL 层 |
|---|---|---|---|---|---|---|
| YOLOv8n | 72 | 3,151,904 | 8.7 | 16 | False | DFL |
| YOLO11n | 100 | 2,616,248 | 6.5 | 16 | False | DFL |
| YOLO26n | 122 | 2,408,932 | 5.4 | 1 | True | Identity |
YOLO26n 报告了 reg_max=1、end2end=True 以及一个 Identity DFL 层——这是其无 NMS、无 DFL 头部的架构特征。
参数和 FLOPs 值是针对融合模型(model.fuse())报告的,该模型将每个 Conv 与其批量归一化(batch normalization)层进行了合并。这与公布的规格相符;刚加载的检查点在融合前会报告稍高的计数。
结论#
在各个版本中,YOLO 架构每次更改一个阶段:backbone 从 Darknet-53 演变为带有 C2PSA 注意力的基于 CSP 的 C3、C2f 和 C3k2 模块;neck 保持其 FPN + PAN 结构,同时 SPP 变成了 SPPF;head 则从基于 anchor 转变为无 anchor,然后演变为 YOLO26 的无 NMS、无 DFL 的端到端设计。
要定义自定义架构,请参阅模型 YAML 配置指南(Model YAML Configuration Guide),或在模型页面上比较模型。如有疑问,请在 GitHub 或 Discord 上与我们联系。
常见问题解答#
YOLO 模型具有一个骨干网络(backbone),用于在 8、16 和 32 的步长(strides)下提取图像特征;一个颈部(neck),通过 FPN 和 PAN 在不同尺度上融合这些特征;以及一个头部(head),用于预测边界框(bounding boxes)和类别得分。从 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的 backbone 和 neck 模块替换为C3k2,在SPPF之后插入了一个C2PSA自注意力模块,并将 head 的分类分支切换为更轻量的深度可分离卷积。两者都保留了相同的无 anchor、解耦的Detecthead 以及带有reg_max=16DFL 回归,因此这些更改在降低参数量和 FLOPs 的同时提高了准确率,而不是重新设计检测接口。现代 Ultralytics YOLO 模型都是无锚框的。YOLOv8、YOLO11 和 YOLO26 使用无锚框、解耦的
Detect头部,为边界框回归和分类设置了单独的分支。最初的 YOLOv3 和 YOLOv5 是基于锚框的,但 Ultralytics 将它们作为 YOLOv3u 和 YOLOv5u 变体发布,其配置使用了与 YOLOv8 相同的无锚框头部。是的——YOLO26 设置了
end2end=True,这为Detect提供了一个一对一头部,每个对象产生单个预测,并去掉了早期模型所需的非极大值抑制后处理步骤。有关详细信息,请参阅端到端检测指南(End-to-End Detection guide)。DFL 将每个边界框坐标回归为
reg_max个箱(bins)上的 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和end2end之类的属性。完整的架构定义在模型的YAML 配置文件中。