专栏:YOLO 全面解析与改进
任务:VisDrone2019-DET 无人机目标检测
改进对象:YOLOv8l、YOLOv9c、YOLOv10l、YOLO11l、YOLO12l、YOLO26l
改进模块:SBA(Selective Boundary Aggregation)
改进位置:YOLO Neck / PAN-FPN 中的跨尺度
Concat融合节点训练设置:300 epochs,imgsz=640,batch=128,8 GPU,seed=42
本文面向初学者,完整介绍如何将 SBA 模块迁移到 YOLO 系列检测模型中。文章先给出改进结果,再解释为什么要替换 Concat、SBA 的来源与基本原理、代码和 YAML 如何修改,最后给出 6 个 SBA-YOLO 的 drawio 架构图和实验分析。
1. 改进效果先看结论
本轮实验测试了 6 个 SBA 改进模型。整体结果如下:
| Model | Params(M) | Inference(ms) | mAP50 | mAP50-95 | Precision | Recall |
|---|---|---|---|---|---|---|
| YOLO12l-SBA | 34.79 | 3.74 | 0.4231 | 0.2514 | 0.5387 | 0.4364 |
| YOLOv10l-SBA | 33.91 | 2.97 | 0.4227 | 0.2499 | 0.5745 | 0.4256 |
| YOLO11l-SBA | 33.42 | 2.58 | 0.4191 | 0.2487 | 0.5374 | 0.4316 |
| YOLOv8l-SBA | 51.77 | 3.13 | 0.4153 | 0.2462 | 0.5493 | 0.4299 |
| YOLOv9c-SBA | 33.64 | 2.85 | 0.4163 | 0.2440 | 0.5579 | 0.4330 |
| YOLO26l-SBA | 34.29 | 2.59 | 0.4117 | 0.2422 | 0.5530 | 0.4169 |
最直接的结论是:
| 指标 | 最优模型 | 数值 |
|---|---|---|
| Best mAP50 | YOLO12l-SBA | 0.4231 |
| Best mAP50-95 | YOLO12l-SBA | 0.2514 |
| Best Precision | YOLOv10l-SBA | 0.5745 |
| Best Recall | YOLO12l-SBA | 0.4364 |
| Fastest | YOLO11l-SBA | 2.58 ms |
也就是说,YOLO12l-SBA 是本轮 SBA 实验的综合精度最优模型,YOLOv10l-SBA 的 Precision 最高,YOLO11l-SBA 的速度最快。
2. 与原始 YOLO 基线的对比
原始 YOLO 基线结果如下:
| Model | Params(M) | Inference(ms) | mAP50 | mAP50-95 | Precision | Recall |
|---|---|---|---|---|---|---|
| YOLO12l | 26.40 | 3.34 | 0.4259 | 0.2514 | 0.5574 | 0.4299 |
| YOLO11l | 25.32 | 2.24 | 0.4181 | 0.2464 | 0.5483 | 0.4336 |
| YOLOv8l | 43.64 | 2.71 | 0.4152 | 0.2427 | 0.5503 | 0.4273 |
| YOLOv10l | 25.78 | 2.56 | 0.4115 | 0.2425 | 0.5488 | 0.4185 |
| YOLO26l | 26.19 | 2.24 | 0.4065 | 0.2381 | 0.5512 | 0.4150 |
与基线对比后,SBA 带来的变化如下。由于上一轮基线没有训练 YOLOv9c,因此 YOLOv9c-SBA 只参与本轮 SBA 横向比较,不做增量对比。
| Model | ΔParams(M) | ΔInference(ms) | ΔmAP50 | ΔmAP50-95 | ΔPrecision | ΔRecall |
|---|---|---|---|---|---|---|
| YOLO12l-SBA | +8.39 | +0.40 | -0.0028 | +0.0000 | -0.0187 | +0.0065 |
| YOLOv10l-SBA | +8.13 | +0.41 | +0.0112 | +0.0074 | +0.0257 | +0.0071 |
| YOLO11l-SBA | +8.10 | +0.34 | +0.0010 | +0.0023 | -0.0109 | -0.0020 |
| YOLOv8l-SBA | +8.13 | +0.42 | +0.0001 | +0.0035 | -0.0010 | +0.0026 |
| YOLO26l-SBA | +8.10 | +0.35 | +0.0052 | +0.0041 | +0.0018 | +0.0019 |
从结果可以看到,SBA 的收益与模型结构强相关:
- YOLOv10l-SBA 提升最明显,mAP50 提升 0.0112,mAP50-95 提升 0.0074,Precision 提升 0.0257。
- YOLO26l-SBA 有稳定小幅提升,mAP50-95 提升 0.0041。
- YOLOv8l-SBA 对严格定位指标有提升,mAP50-95 提升 0.0035。
- YOLO12l-SBA 的 Recall 提升,但 Precision 下降,最终 mAP50-95 与原版持平。
- YOLO11l-SBA 的 mAP50-95 小幅提升,但 Recall 略降。
因此,SBA 更适合被理解为一种"跨尺度融合方式改造",它并不必然让所有指标同时提升,而是改变了 Neck 中信息融合的方式,使不同 YOLO 架构表现出不同的精度、召回和速度取舍。
3. 为什么要替换 Concat
YOLO 系列 Neck 通常采用 PAN-FPN 结构进行多尺度特征融合。最常见的融合方式是:
yaml
- [[-1, 6], 1, Concat, [1]]
Concat 的优点是简单、稳定、开销低。它只是把两个特征图沿通道维度拼接起来,然后交给后续的 C2f、C3k2、A2C2f 或 RepNCSPELAN4 继续处理。
但在 VisDrone 这类无人机检测场景中,简单拼接存在三个问题:
- 低层细节和高层语义没有选择机制
低层特征包含边界、纹理和小目标细节,高层特征包含语义和上下文。Concat 只是拼接,不判断哪些信息更重要。 - 背景噪声容易一起进入 Neck
无人机图像中道路、建筑、树木、阴影、标线都可能产生干扰。简单拼接会把目标信息和背景噪声一起传递给后续模块。 - 跨尺度对齐不足
P3、P4、P5 的感受野和语义层级不同,直接拼接可能导致细节和语义融合不充分,尤其影响小目标和密集目标。
SBA 的目标就是让跨尺度融合从"直接拼接"变成"有选择地聚合低层边界细节和高层语义信息"。
4. SBA 模块来源与思想
本文使用的 SBA 是 Selective Boundary Aggregation。在本项目中,SBA 相关参考主要来自两个 PDF:
2212.11677v1.pdf:DuAT: Dual-Aggregation Transformer Network for Medical Image Segmentation2603.22841v1.pdf:UAV-DETR: DETR for Anti-Drone Target Detection
在 DuAT 中,SBA 用于聚合低层特征中的边界信息和高层特征中的语义信息,从而更好地保留边界细节并定位目标区域。虽然原始任务是医学图像分割,但这个思想对无人机小目标检测同样有意义。
在 UAV-DETR 中,SBA 被放入无人机检测 Neck 中,配合跨尺度特征重校准与融合网络,用于过滤背景噪声并融合不同尺度的特征。这一点与 VisDrone 的任务特性非常接近:目标小、背景复杂、尺度变化大。
因此,本文将 SBA 引入 YOLO 的 Neck 中,用它替换原来的 Concat 融合节点。
5. SBA 模块结构
当前项目中加入的 SBA 模块位于:
text
ultralytics/nn/modules/block.py
核心代码如下:
python
class SBA(nn.Module):
def __init__(self, inc, input_dim=64):
super().__init__()
self.input_dim = input_dim
self.d_in1 = Conv(input_dim // 2, input_dim // 2, 1)
self.d_in2 = Conv(input_dim // 2, input_dim // 2, 1)
self.conv = Conv(input_dim, input_dim, 3)
self.fc1 = nn.Conv2d(inc[1], input_dim // 2, kernel_size=1, bias=False)
self.fc2 = nn.Conv2d(inc[0], input_dim // 2, kernel_size=1, bias=False)
self.Sigmoid = nn.Sigmoid()
def forward(self, x):
H_feature, L_feature = x
L_feature = self.fc1(L_feature)
H_feature = self.fc2(H_feature)
g_L_feature = self.Sigmoid(L_feature)
g_H_feature = self.Sigmoid(H_feature)
L_feature = self.d_in1(L_feature)
H_feature = self.d_in2(H_feature)
L_feature = L_feature + L_feature * g_L_feature + (1 - g_L_feature) * Upsample(
g_H_feature * H_feature, size=L_feature.size()[2:], align_corners=False
)
H_feature = H_feature + H_feature * g_H_feature + (1 - g_H_feature) * Upsample(
g_L_feature * L_feature, size=H_feature.size()[2:], align_corners=False
)
H_feature = Upsample(H_feature, size=L_feature.size()[2:])
out = self.conv(torch.cat([H_feature, L_feature], dim=1))
return out
为了方便理解,可以把 SBA 拆成四步:
| 步骤 | 作用 |
|---|---|
| 通道压缩 | 将两个输入分支统一压缩到 input_dim / 2 |
| Sigmoid 门控 | 分别生成高层语义分支和低层细节分支的选择权重 |
| 双向补偿 | 低层特征吸收高层语义,高层特征吸收低层细节 |
| 融合输出 | 将增强后的两路特征拼接,再用 3x3 卷积输出 |
与普通 Concat 不同,SBA 不是简单地把两个张量拼接,而是先用门控机制做选择性增强,再输出一个新的融合特征。
6. SBA 在 YOLO 中的适配方式
原始 YOLO Neck 中通常有 4 个跨尺度融合点:
text
Top-down: P5 -> P4
Top-down: P4 -> P3
Bottom-up: P3 -> P4
Bottom-up: P4 -> P5
原始写法通常是:
yaml
- [[-1, 6], 1, Concat, [1]]
本文改为:
yaml
- [[-1, 6], 1, SBA, [512]]
这里的 [512] 表示 SBA 输出通道数。也就是说,SBA 替换 Concat 后不再输出两个分支通道数之和,而是直接输出指定通道数的融合特征。
以 YOLO26l-SBA 为例,Neck 的关键改动如下:
yaml
head:
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 6], 1, SBA, [512]] # SBA(P5, P4)
- [-1, 2, C3k2, [512, True]]
- [-1, 1, nn.Upsample, [None, 2, "nearest"]]
- [[-1, 4], 1, SBA, [256]] # SBA(P4, P3)
- [-1, 2, C3k2, [256, True]]
- [-1, 1, Conv, [256, 3, 2]]
- [[-1, 13], 1, SBA, [512]] # SBA(P3, P4)
- [-1, 2, C3k2, [512, True]]
- [-1, 1, Conv, [512, 3, 2]]
- [[-1, 10], 1, SBA, [1024]] # SBA(P4, P5)
- [-1, 1, C3k2, [1024, True, 0.5, True]]
- [[16, 19, 22], 1, Detect, [nc]]
这样做的好处是:YOLO 的 P3、P4、P5 检测头仍然保持不变,但 Neck 中每一次跨尺度融合都从静态拼接变成了选择性聚合。
7. 代码改进过程
7.1 在 block.py 中加入 SBA
将 SBA 类加入:
text
ultralytics/nn/modules/block.py
同时在 __all__ 中加入:
python
"SBA",
7.2 在 modules 中导出 SBA
修改:
text
ultralytics/nn/modules/__init__.py
在 .block 导入列表中加入:
python
SBA,
并在 __all__ 中加入:
python
"SBA",
7.3 修改 parse_model 支持 SBA
由于 SBA 的输入是两个特征分支,且输出通道由 YAML 指定,所以需要在 parse_model() 中单独处理:
python
elif m is SBA:
c2 = args[0]
if c2 != nc:
c2 = make_divisible(min(c2, max_channels) * width, 8)
args = [[ch[x] for x in f], c2, *args[1:]]
这段代码的含义是:
- 从 YAML 读取 SBA 输出通道
c2。 - 根据当前模型宽度系数自动缩放通道。
- 自动把两个输入分支的通道数
[ch[x] for x in f]传给 SBA。
因此 YAML 中只需要写:
yaml
- [[-1, 6], 1, SBA, [512]]
不需要手动写输入通道。
7.4 新增 6 个 SBA 模型配置
本文新增了 6 个配置文件:
| 模型 | YAML |
|---|---|
| YOLOv8l-SBA | ultralytics/cfg/models/v8/yolov8l-sba.yaml |
| YOLOv9c-SBA | ultralytics/cfg/models/v9/yolov9c-sba.yaml |
| YOLOv10l-SBA | ultralytics/cfg/models/v10/yolov10l-sba.yaml |
| YOLO11l-SBA | ultralytics/cfg/models/11/yolo11l-sba.yaml |
| YOLO12l-SBA | ultralytics/cfg/models/12/yolo12l-sba.yaml |
| YOLO26l-SBA | ultralytics/cfg/models/26/yolo26l-sba.yaml |
各模型检测头输入保持为原来的 P3/P4/P5 输出:
| 模型 | 检测头类型 | Detect 输入 |
|---|---|---|
| YOLOv8l-SBA | Detect | [15, 18, 21] |
| YOLOv9c-SBA | Detect | [15, 18, 21] |
| YOLOv10l-SBA | v10Detect | [16, 19, 22] |
| YOLO11l-SBA | Detect | [16, 19, 22] |
| YOLO12l-SBA | Detect | [14, 17, 20] |
| YOLO26l-SBA | Detect | [16, 19, 22] |
7.5 修改 benchmark 脚本
benchmark_visdrone_fixed.py 中新增 SBA 模型集合:
python
SBA_YOLO_MODELS = {
"YOLOv8l-SBA": "ultralytics/cfg/models/v8/yolov8l-sba.yaml",
"YOLOv9c-SBA": "ultralytics/cfg/models/v9/yolov9c-sba.yaml",
"YOLOv10l-SBA": "ultralytics/cfg/models/v10/yolov10l-sba.yaml",
"YOLO11l-SBA": "ultralytics/cfg/models/11/yolo11l-sba.yaml",
"YOLO12l-SBA": "ultralytics/cfg/models/12/yolo12l-sba.yaml",
"YOLO26l-SBA": "ultralytics/cfg/models/26/yolo26l-sba.yaml",
}
并将默认测试变体设置为:
python
parser.add_argument(
"--variant",
choices=("baseline", "sba", "both"),
default="sba",
)
这样直接运行脚本时,只会测试 SBA 改进模型。
8. 一键训练和验证
在服务器上直接运行:
bash
python benchmark_visdrone_fixed.py
或显式指定训练参数:
bash
python benchmark_visdrone_fixed.py \
--data ultralytics/cfg/datasets/VisDrone.yaml \
--epochs 300 \
--batch 128 \
--imgsz 640 \
--device 0,1,2,3,4,5,6,7 \
--workers 4
脚本会依次训练并验证:
text
YOLOv8l-SBA
YOLOv9c-SBA
YOLOv10l-SBA
YOLO11l-SBA
YOLO12l-SBA
YOLO26l-SBA
训练结束后,会生成:
text
benchmark_results_VisDrone_fixed.csv
benchmark_results_VisDrone_fixed.md
runs/benchmark_VisDrone/
runs/.benchmark_results/
9. 改进后的 drawio 架构图
本文提供了可编辑 drawio 源文件和 Markdown 可直接显示的 SVG 预览图。
总图:
text
assets/sba_yolo_visdrone/sba_yolo_architectures.drawio
单模型 drawio:
text
assets/sba_yolo_visdrone/yolov8l_sba.drawio
assets/sba_yolo_visdrone/yolov9c_sba.drawio
assets/sba_yolo_visdrone/yolov10l_sba.drawio
assets/sba_yolo_visdrone/yolo11l_sba.drawio
assets/sba_yolo_visdrone/yolo12l_sba.drawio
assets/sba_yolo_visdrone/yolo26l_sba.drawio
图中颜色含义如下:
| 颜色 | 含义 |
|---|---|
| 紫色 | Backbone 或 Neck 中的主特征模块 |
| 绿色 | SPPF、SPPELAN、PSA、C2PSA 等上下文模块 |
| 红色 | Upsample |
| 蓝色 | 下采样卷积、ADown 或 SCDown |
| 橙色 | SBA 融合模块 |
| 青色 | Detect / v10Detect |
9.1 YOLOv8l-SBA
YOLOv8l-SBA 保留 C2f + SPPF 的主体结构,将 PAN-FPN 中 4 个 Concat 融合点替换为 SBA。

9.2 YOLOv9c-SBA
YOLOv9c-SBA 使用 RepNCSPELAN4、ADown 和 SPPELAN,本文将其 Neck 中的跨尺度拼接改为 SBA 选择性融合。

9.3 YOLOv10l-SBA
YOLOv10l-SBA 使用 C2fCIB、SCDown、PSA 和 v10Detect。实验中它获得了本轮最高 Precision。

9.4 YOLO11l-SBA
YOLO11l-SBA 使用 C3k2、SPPF 和 C2PSA。它在本轮实验中推理速度最快,同时 mAP50-95 相比原版略有提升。

9.5 YOLO12l-SBA
YOLO12l-SBA 使用 A2C2f 作为主要 Neck 模块。本轮实验中它的 mAP50 和 mAP50-95 排名第一。

9.6 YOLO26l-SBA
YOLO26l-SBA 保留 YOLO26 的 end-to-end 设置,并使用 SBA 替换原始 Neck 中的 Concat。它相较 YOLO26l 在 mAP50 和 mAP50-95 上都有小幅提升。

10. 实验结果分析
10.1 YOLOv10l-SBA 的提升最明显
从增量表看,YOLOv10l-SBA 是 SBA 改造中提升最明显的模型:
| 指标 | YOLOv10l | YOLOv10l-SBA | 提升 |
|---|---|---|---|
| mAP50 | 0.4115 | 0.4227 | +0.0112 |
| mAP50-95 | 0.2425 | 0.2499 | +0.0074 |
| Precision | 0.5488 | 0.5745 | +0.0257 |
| Recall | 0.4185 | 0.4256 | +0.0071 |
这说明 SBA 与 YOLOv10l 的 C2fCIB、SCDown、PSA 和 v10Detect 组合较为适配。尤其 Precision 提升明显,说明 SBA 替换 Concat 后能够更好地抑制一部分背景噪声和误检。
10.2 YOLO12l-SBA 综合结果仍然最强
虽然 YOLO12l-SBA 相比原始 YOLO12l 没有提升 mAP50-95,但它在所有 SBA 模型中仍然排名第一:
| 指标 | YOLO12l-SBA |
|---|---|
| mAP50 | 0.4231 |
| mAP50-95 | 0.2514 |
| Recall | 0.4364 |
它的 Recall 比原始 YOLO12l 高 0.0065,说明 SBA 对 YOLO12l 的召回有帮助,但 Precision 下降较明显。因此,如果后续继续优化 YOLO12l-SBA,可以重点考虑降低误检,例如调整置信度阈值、损失函数或标签分配策略。
10.3 YOLO11l-SBA 是速度优先版本
YOLO11l-SBA 的推理耗时为 2.58 ms,是本轮 SBA 模型中最快的。相比原始 YOLO11l,它的 mAP50-95 从 0.2464 提升到 0.2487,但 Recall 从 0.4336 降到 0.4316。
因此,YOLO11l-SBA 可以作为速度优先方案。如果应用场景要求实时处理,例如无人机巡检或边缘设备快速预警,它比 YOLO12l-SBA 更适合部署。
10.4 YOLO26l-SBA 有稳定小幅提升
YOLO26l-SBA 相比 YOLO26l:
| 指标 | YOLO26l | YOLO26l-SBA | 提升 |
|---|---|---|---|
| mAP50 | 0.4065 | 0.4117 | +0.0052 |
| mAP50-95 | 0.2381 | 0.2422 | +0.0041 |
| Precision | 0.5512 | 0.5530 | +0.0018 |
| Recall | 0.4150 | 0.4169 | +0.0019 |
这说明 SBA 对 YOLO26l 是稳定正收益,只是代价是参数量和推理时间增加。
10.5 类别层面的观察
从 YOLO12l-SBA 的类别结果看,car 和 bus 依然是最容易检测的类别:
| Class | mAP50 | mAP50-95 |
|---|---|---|
| car | 0.8083 | 0.5678 |
| bus | 0.6050 | 0.4494 |
弱类别仍然集中在小目标和易混淆目标:
| Class | mAP50 | mAP50-95 |
|---|---|---|
| bicycle | 0.1631 | 0.0708 |
| awning-tricycle | 0.1456 | 0.0855 |
这说明 SBA 改善了跨尺度融合,但还不能单独解决极小目标、遮挡和类别混淆问题。后续仍然需要结合 P2 检测头、更强的数据增强或更适合小目标的损失函数。
11. 初学者复现 checklist
如果你想从零复现本实验,可以按下面顺序检查。
- 确认
SBA已加入:
text
ultralytics/nn/modules/block.py
- 确认
SBA已在模块入口导出:
text
ultralytics/nn/modules/__init__.py
- 确认
parse_model()已支持SBA:
text
ultralytics/nn/tasks.py
- 确认 6 个 SBA YAML 存在:
text
ultralytics/cfg/models/v8/yolov8l-sba.yaml
ultralytics/cfg/models/v9/yolov9c-sba.yaml
ultralytics/cfg/models/v10/yolov10l-sba.yaml
ultralytics/cfg/models/11/yolo11l-sba.yaml
ultralytics/cfg/models/12/yolo12l-sba.yaml
ultralytics/cfg/models/26/yolo26l-sba.yaml
- 先用一个模型检查是否能构建:
bash
python -c "from ultralytics import YOLO; YOLO('ultralytics/cfg/models/v10/yolov10l-sba.yaml')"
- 运行完整 benchmark:
bash
python benchmark_visdrone_fixed.py
- 查看输出结果:
text
benchmark_results_VisDrone_fixed.csv
benchmark_results_VisDrone_fixed.md
runs/benchmark_VisDrone/
- 打开结构图:
text
assets/sba_yolo_visdrone/sba_yolo_architectures.drawio
12. 后续改进方向
12.1 只替换部分 Concat
当前做法是替换 Neck 中所有 4 个 Concat。后续可以做消融:
text
Top-down only
Bottom-up only
只替换 P3 融合
只替换 P4/P5 融合
这样可以判断 SBA 到底在哪个尺度最有效。
12.2 与轻量化模块结合
SBA 会增加参数量,当前多数模型增加约 8M 参数。后续可以尝试:
- 降低 SBA 的输出通道。
- 使用 depthwise separable convolution 替换 SBA 内部 3x3 Conv。
- 只在小目标相关的 P3/P4 路径使用 SBA。
12.3 与 P2 小目标检测头结合
VisDrone 中极小目标很多,P3 仍然可能不够细。后续可以在 SBA Neck 基础上加入 P2 检测头,重点观察 pedestrian、people、bicycle、motor 等类别是否提升。
12.4 与 DORGM 组合
SBA 主要改 Neck 融合方式,DORGM 主要增强 Detect 前特征表达。二者作用点不同,后续可以尝试:
text
SBA Neck + DORGM Head
但组合后参数和计算量会进一步增加,需要做速度和精度权衡。
13. 总结
本文将 Selective Boundary Aggregation 引入 YOLO 系列目标检测模型,用 SBA 替换 Neck / PAN-FPN 中的跨尺度 Concat 融合节点,并在 VisDrone2019-DET 数据集上进行验证。实验表明:
- YOLO12l-SBA 在本轮 SBA 模型中综合精度最高,mAP50 为 0.4231,mAP50-95 为 0.2514。
- YOLOv10l-SBA 相比原始 YOLOv10l 提升最明显,mAP50 提升 0.0112,mAP50-95 提升 0.0074,Precision 提升 0.0257。
- YOLO11l-SBA 是本轮最快模型,推理耗时为 2.58 ms,适合速度优先场景。
- YOLO26l-SBA 相比原始 YOLO26l 各项指标均有小幅提升,说明 SBA 对 YOLO26l 是稳定正收益。
- SBA 能增强跨尺度信息融合,但不能单独解决 VisDrone 中极小目标、遮挡和类别混淆问题,后续仍需结合 P2 检测头、轻量化设计和更适合小目标的训练策略。
整体来看,SBA 不是简单增加一个注意力模块,而是把 YOLO Neck 中的"静态拼接"改成"选择性边界与语义聚合"。对于无人机目标检测这类小目标密集、背景复杂、尺度变化明显的场景,它是一个值得继续消融和优化的结构改进方向。
参考资料
2212.11677v1.pdf:DuAT: Dual-Aggregation Transformer Network for Medical Image Segmentation.2603.22841v1.pdf:UAV-DETR: DETR for Anti-Drone Target Detection.- VisDrone 官方数据集仓库:https://github.com/VisDrone/VisDrone-Dataset
- Ultralytics VisDrone 数据集文档:https://docs.ultralytics.com/datasets/detect/visdrone/