
1、SPPF vs SPP vs ASPP 结构对比图(含参数量)
SPP,Spatial Pyramid Pooling(空间金字塔池化)
最早由何恺明等人在 2014 年提出,用于解决 CNN 对固定输入尺寸的限制,通过多尺度池化生成固定长度的特征表示。
==================== ① SPP(原始) ====================
输入 (C)
│
┌───────┼───────────────┐
│ │ │ │
MaxPool MaxPool MaxPool Identity
k=5 k=9 k=13
(无参) (无参) (无参) (无参)
│ │ │ │
└───────┴───────┴───────┘
│
Concat (4C)
│
1×1 Conv (4C → C)
参数量:4C × C
👉 总参数:
= 4C²
======================================================
SPPF,Spatial Pyramid Pooling - Fast(快速空间金字塔池化)
SPPF 是 YOLOv5 中引入的 SPP 的高效变体,用串行的小核池化(如多个 5×5 池化)近似 SPP 的多尺度感受野,显著减少计算量,提升推理速度。
==================== ② SPPF(YOLOv5/8) ====================
==================== SPPF(Correct Version) ====================
输入: x (C)
│
1×1 Conv
(C → C/2)
参数:C × (C/2)
│
├───────────────┐
│ │
│ MaxPool k=5
│ │
│ y1
│ │
│ MaxPool k=5
│ │
│ y2
│ │
│ MaxPool k=5
│ │
│ y3
│
└───────────────┘
Concat: [x, y1, y2, y3]
通道数:4 × (C/2) = 2C
│
1×1 Conv
(2C → C)
参数:2C × C
│
输出 (C)
===============================================================
ASPP,Atrous Spatial Pyramid Pooling(空洞空间金字塔池化,也称“扩张空间金字塔池化”)
是 DeepLab 系列(尤其是 DeepLab v2/v3)中提出的模块,利用空洞卷积(atrous convolution)在不同膨胀率下提取多尺度上下文信息,广泛应用于语义分割。
==================== ③ ASPP(DeepLab) ====================
输入 (C)
│
┌────────┬────────┬────────┬────────┐
│ │ │ │
1×1Conv 3×3Conv 3×3Conv 3×3Conv
dilation1 dilation6 dilation12
│ │ │ │
(C→C') (C→C') (C→C') (C→C')
参数:C·C' 9C·C' 9C·C' 9C·C'
│ │ │ │
└────────┴────────┴────────┴────────┘
│
Concat (4C')
│
1×1 Conv (4C' → C)
参数:4C' × C
👉 总参数:
= (1 + 9 + 9 + 9) C·C' + 4C'·C
= **28C·C' + 4C·C' = 32C·C'**
若 C' = C/4(常见):
👉 总参数 ≈ **8C²**
======================================================
2、三者参数量对比(统一尺度)
| 模块 | 参数量级 | 是否重 |
|---|---|---|
| SPP | 4C² | 中等 |
| SPPF | 2.5C²(最轻) | ✅ 最轻 |
| ASPP | ~8C² | ❗ 最重 |
3、关键差异(本质理解)
🟢 SPP
- 多尺度池化(不同kernel)
- 并行结构
- 感受野大,但计算略重复
略去 channel 输入输出对齐的 coding 实现:
class SPP(nn.Module):
def __init__(self):
"""Initializes an SPP module with three different sizes of max pooling layers."""
super().__init__()
self.maxpool1 = nn.MaxPool2d(5, 1, padding=2)
self.maxpool2 = nn.MaxPool2d(9, 1, padding=4)
self.maxpool3 = nn.MaxPool2d(13, 1, padding=6)
def forward(self, x):
"""Applies three max pooling layers on input `x` and concatenates results along channel dimension."""
o1 = self.maxpool1(x)
o2 = self.maxpool2(x)
o3 = self.maxpool3(x)
return torch.cat([x, o1, o2, o3], dim=1)
🔵 SPPF(YOLOv8用的)
- 串行池化(复用计算)
- 更快(Fast)
- 参数更少 + 速度更快
👉 本质优化点:
多个大kernel → 用多个小kernel叠加模拟
略去 channel 输入输出对齐的 coding 实现:
class SPPF(nn.Module):
def __init__(self):
"""Initializes an SPPF module with a specific configuration of MaxPool2d layer."""
super().__init__()
self.maxpool = nn.MaxPool2d(5, 1, padding=2)
def forward(self, x):
"""Applies sequential max pooling and concatenates results with input tensor."""
o1 = self.maxpool(x)
o2 = self.maxpool(o1)
o3 = self.maxpool(o2)
return torch.cat([x, o1, o2, o3], dim=1)
🔴 ASPP
Atrous Spatial Pyramid Pooling(空洞空间金字塔池化,也称“扩张空间金字塔池化”)
- 多尺度 空洞卷积
- 不只是“看不同尺度”
- 而是:
👉 在卷积层建模空间结构
👉 优点:
- 表达能力最强
👉 缺点:
- 参数最多
- 计算最重

class ASPPF(nn.Module):
"""
Atrous Spatial Pyramid Pooling Fast (ASPPF)
用不同膨胀率的空洞卷积替代 SPPF 的串行 MaxPool,实现多尺度特征融合。
# 指定 kernel size + dilations
- [-1, 1, ASPPF, [1024, 3, [1, 2, 4]]]
"""
def __init__(self, c1, c2, k=3, dilations=(1, 2, 4)):
"""
Args:
c1 (int): 输入通道数
c2 (int): 输出通道数
k (int): 卷积核大小,默认 3
dilations (tuple): 空洞率列表,对应多尺度分支
parse_model 会自动将 [c1, c2, *args[1:]] 传入,所以 args[0]=c2, args[1:] 对应 k 和 dilations。
YAML args: [1024, 3, [1, 2, 4]]
↓ ↓ ↓
args[0] args[1] args[2]
↓
c1 = ch[f] (自动从上一层获取)
c2 = args[0] → 1024
↓
最终传入: ASPPF(c1=512, c2=1024, k=3, dilations=[1,2,4])
"""
super().__init__()
c_mid = c1 // 2 # 中间压缩通道数
# 输入压缩:降维减少计算量
self.cv1 = Conv(c1, c_mid, k=1)
# 多尺度空洞卷积分支(每个分支感受野不同)
self.dilated_convs = nn.ModuleList([
Conv(c_mid, c_mid, k=k, d=d) # d=1 普通卷积; d=2,4 空洞卷积
for d in dilations
])
# MaxPool 分支(保留全局上下文,对齐 SPPF 设计)
self.maxpool = nn.MaxPool2d(kernel_size=5, stride=1, padding=2)
# 输出融合:所有分支 concat 后降维
# 分支数 = cv1输出 + len(dilations)个空洞卷积 + 1个maxpool
total_c = c_mid * (1 + len(dilations) + 1)
self.cv2 = Conv(total_c, c2, k=1)
def forward(self, x):
"""多尺度特征提取 → concat → 融合输出"""
x1 = self.cv1(x) # 压缩输入
dilated_outs = [conv(x1) for conv in self.dilated_convs] # 各空洞分支
pool_out = self.maxpool(x1) # MaxPool 分支
# concat: [压缩特征, 空洞d=1, 空洞d=2, 空洞d=4, maxpool]
out = torch.cat([x1, *dilated_outs, pool_out], dim=1)
return self.cv2(out) # 融合降维输出
4、总结
👉 SPP / SPPF:靠池化“看大范围”(轻量)
👉 ASPP:靠卷积“理解空间结构”(更强但更重)
2万+

被折叠的 条评论
为什么被折叠?



