查看全课大纲(第 57 / 93 节)
- 1.计算机视觉概述
- 2.计算机视觉应用场景
- 3.困难与挑战
- 4.开源库介绍
- 5.图像显示与存储
- 6.CLAHE
- 7.腐蚀膨胀与开闭运算
- 8.滤波与边缘填充
- 9.各种滤波
- 10.图像金字塔
- 11.傅里叶变换
- 12.短时傅里叶变换与小波变换
- 13.颜色特征与颜色直方图
- 14.几何特征_边缘
- 15.几何特征-角点与斑点
- 16.局部特征-SIFT特征描述子
- 17.局部特征-SURF特征描述子
- 18.局部特征-ORB特征描述子
- 19.其他特征描述子
- 20.传统图像分割技术
- 21.GraphCut
- 22.GrabCut
- 23.人脸检测的传统方法
- 24.行人检测的传统方法HOG+SVM
- 25.行人检测DPM
- 26.人工神经网络的架构
- 27.目标函数与梯度下降
- 28.误差反向传播
- 29.可手算的神经网络
- 30.改进目标函数与克服梯度消散
- 31.神经网络之传统神经网络与深度网络的差异
- 32.各种梯度下降算法
- 33.如何选择合适的梯度下降算法
- 34.避免过适应
- 35.CNN的架构
- 36.CNN的误差反向传播_卷积层
- 37.CNN的误差反向传播_池化层
- 38.分类所用的数据集
- 39.Alexnet详解
- 40.VGG详解
- 41.GoogLeNet_v1
- 42.BatchNormalization
- 43.GoogLeNet_v3v4
- 44.ResNet
- 45.ResNeXt
- 46.CNN设计准则
- 47.图像检索与推土机距离
- 48.基于颜色相似性
- 49.基于形状相似性
- 50.基于纹理相似性
- 51.基于局部特征相似性
- 52.DL的二值哈希编码
- 53.高维空间中检索KDTree
- 54.高维空间中检索LSH
- 55.目标识别任务综述
- 56.RCNN
- 57.SPP-Net
- 58.Fast R-CNN
- 59.Faster R-CNN
- 60.R-CNN系列模型回顾
- 61.R-FCN的设计思路
- 62.R-FCN的实现
- 63.YOLOv1
- 64.YOLOv2_9000
- 65.YOLOv3
- 66.图像分割应用场景与数据集
- 67.上采样的实现方式
- 68.FCN网络架构的由来
- 69.FCN构建细节
- 70.DeepLabv1
- 71.CRF
- 72.DeepLabv2
- 73.DeepLabv3
- 74.特定的医学影像分割任务
- 75.U-Net
- 76.3D U-Net
- 77.V-Net
- 78.DenseNet
- 79.病理切片分析任务及数据集
- 80.病理切片分析
- 81.图说任务及其传统处理方法
- 82.深度语言模型与RNN
- 83.LSTM及其变种
- 84.NIC模型
- 85.SAT模型
- 86.图说的性能指标
- 87.判别模型与生成模型
- 88.KL散度与JS散度
- 89.VAE
- 90.GAN的基本原理
- 91.DCGAN与CGAN
- 92.Wasserstein GAN
- 93.SRGAN
SPP-Net
SPP-Net:共享卷积计算与空间金字塔池化
小象实战讲义 · 基于深度学习的计算机视觉
在上一节,我们深入分析了R-CNN模型,其核心问题在于速度“刻骨铭心的慢”。本节我们将介绍其重要的改进模型——SPP-Net。SPP-Net通过两项关键创新,极大地提升了目标检测的效率:一是将卷积计算提前并共享,避免了对数千个候选区域的重复计算;二是引入了空间金字塔池化(Spatial Pyramid Pooling)技术,使得网络能够接受任意尺寸的输入,并生成固定长度的特征向量。理解SPP-Net,是掌握从R-CNN到Fast R-CNN这一技术演进的关键一步。
💡 核心导读
- 核心问题:R-CNN为何慢?根源在于对每个候选区域都独立进行卷积计算,导致大量重复计算。
- 核心改进一(共享计算):SPP-Net将卷积层前移,对整张图片只做一次卷积,然后在得到的特征图上直接提取所有候选区域的特征。
- 核心改进二(SPP层):引入空间金字塔池化层,将任意尺寸的特征图通过“划格子”和池化的方式,转换为固定长度的特征向量,从而解决了全连接层要求固定输入尺寸的限制。
- 关键洞察:卷积层输出的特征图保留了输入图像的空间位置关系,这使得在特征图上定位候选区域成为可能。
- 遗留问题:SPP-Net仍然是一个多阶段训练流程,且SPP层之前的卷积层无法进行微调(fine-tune)。
从R-CNN的瓶颈到SPP-Net的改进思路
R-CNN最致命的缺点是速度慢。回顾其流程:首先用Selective Search从原图中提取约2000个候选区域,然后每个区域都需要经过裁剪或拉伸(warp)预处理,再各自独立送入CNN(如AlexNet)进行卷积特征提取。
这意味着,同一张图片的卷积特征被重复计算了约2000次。计算量巨大,是导致训练和测试过程异常缓慢的根本原因。
那么,一个直观的改进思路是:能否只对整张图片做一次卷积计算,然后让所有候选区域共享这个卷积结果?
SPP-Net正是基于这一思路提出的。它的核心改进有两点:
- 共享卷积计算:直接输入整张图片,进行一次完整的卷积计算。所有候选区域的特征都从这同一份卷积特征图上提取。
- 适应任意尺寸输入:通过空间金字塔池化(SPP) 技术,将不同尺寸的候选区域特征图,统一转换为固定长度的特征向量,从而能够输入到后续的全连接层。
SPP-Net的网络架构与工作原理
整体架构:卷积共享与区域级计算分离
SPP-Net的网络结构清晰地体现了“共享计算”的思想:
输入图片
↓
[共享卷积计算] Conv1 -> Conv2 -> Conv3 -> Conv4 -> Conv5 (生成特征图)
| |
| | (在特征图上定位)
| ↓
| Selective Search (原图产生候选框 → 映射到特征图坐标)
| |
| ↓
| [SPP层] (将不同尺寸区域特征转换为固定长度向量)
| |
| ↓
| [全连接层] Fc6, Fc7, Fc8 (可微调)
| |
| ↓
| [输出头] SVMs分类器 / Bounding Box回归
|
(整图计算,不微调) (区域级计算,可微调)与R-CNN的关键区别在于:
- 卷积层位置:R-CNN是先提取区域,再对每个区域做卷积。SPP-Net是先对整图做卷积,再在特征图上提取区域。
- 微调范围:在SPP-Net中,SPP层之前的所有卷积层(Conv1-5)在微调阶段参数是冻结的,不再更新。只能微调SPP层之后的全连接层(Fc6、Fc7、Fc8)。注意原因不是“SPP层不可导”——划格子和最大值池化本身都是可导的,梯度有明确定义。原论文只说明了“只微调全连接层”这一做法,并未展开分析;Fast R-CNN 论文对此给出的解释是效率:当RoI的感受野较大时,误差穿过SPP层向Conv1-5反传的效率很低,因此实践中选择冻结其下方的卷积层。
关键技术一:为何能在特征图上定位区域?
一个关键问题是:在原始图像上通过Selective Search得到的候选框(Bounding Box),如何对应到卷积层输出的特征图上?
这依赖于卷积神经网络的一个重要性质:卷积层输出的特征图,其空间位置关系与输入图像基本保持一致。
考虑一个卷积核,它可能负责检测“车窗玻璃”这种特征。当它在图像上滑动时,只有在有车窗玻璃的位置,对应的特征图位置才会被激活(呈现高亮)。这意味着,输入图像中某个物体所在的位置,会反映在特征图上相同(或按步长缩放后)的相对位置。
因此,我们只需要将原始图像上的候选框坐标,按照网络前5层卷积的累积步长(例如取16,即特征图边长约为原图的1/16)进行缩放,就能得到该候选框在Conv5输出特征图上的对应区域。这个区域称为感兴趣区域(Region of Interest, RoI)。后续的特征提取(SPP层)就在这个RoI上进行。
# 模拟原始图像和特征图的空间映射关系
# 假设原始图像尺寸为 (224, 224)
orig_h, orig_w = 224, 224
# 假设经过Conv1-5后,特征图尺寸缩小为原来的1/16(步长累积效应)
feat_h, feat_w = orig_h // 16, orig_w // 16 # (14, 14)
# 假设Selective Search在原图上得到一个候选框 [x, y, width, height]
# 坐标是绝对像素值
orig_bbox = [50, 30, 80, 120] # x, y, w, h
# 将其映射到特征图上的坐标(取整)
feat_bbox = [
int(orig_bbox[0] / 16), # x_feat
int(orig_bbox[1] / 16), # y_feat
int(orig_bbox[2] / 16), # w_feat
int(orig_bbox[3] / 16) # h_feat
]
print(f"原始图像候选框: {orig_bbox}")
print(f"映射到特征图上的区域: {feat_bbox}")原始图像候选框: [50, 30, 80, 120]
映射到特征图上的区域: [3, 1, 5, 7]关键技术二:空间金字塔池化(SPP)层
解决了区域定位问题,下一个挑战是:从特征图上提取出的RoI特征图,尺寸各不相同(因为原始候选框大小不一),如何输入到需要固定尺寸输入的全连接层?
R-CNN采用的方法是裁剪(crop)或暴力拉伸(warp):裁剪会把目标直接截断(例如只框住大半个车身),拉伸则会改变长宽比(瘦高的灯塔、扁平的飞机都被压成正方形),两者都会损害区域内容。SPP-Net提出了一个更优雅的解决方案:空间金字塔池化。
从结构上看,SPP层取代了Conv5之后原来的Pool5池化层(因此文献里也常说SPP特征对应“Pool5特征”)。它的操作非常巧妙,其灵感来源于传统的图像特征描述子(如PHOG,即金字塔梯度方向直方图)。它的工作流程如下:
- 确定金字塔层级:对于输入的任意尺寸的RoI特征图(例如尺寸为
h x w x c,其中c是通道数),我们预先定义几个池化网格。- 常见设置是三个层级:
1x1,2x2,4x4。 1x1网格意味着对整个特征图进行池化,得到1个值。2x2网格意味着将特征图均匀划分为2行2列,共4个子区域,每个子区域分别池化。4x4网格同理,划分成16个子区域。
- 常见设置是三个层级:
- 对每个网格进行池化:在每个划分好的子区域(称为“bin”)内,进行最大池化(Max Pooling) 操作。这样,每个bin会输出该区域所有通道上的最大值(如果是多通道,则每个通道独立池化)。
- 拼接成固定向量:将所有层级、所有bin的池化结果(每个bin输出c个值,代表c个通道)按顺序拼接起来,形成一个长的特征向量。
- 对于
1x1,2x2,4x4三个层级,总共的bin数量为 1 + 4 + 16 = 21。 - 如果特征图有256个通道(c=256),那么最终SPP输出的特征向量长度就是 21 * 256 = 5376。
- 对于
这个向量的长度是固定的(由预设的金字塔层级和通道数决定),与输入RoI特征图的具体尺寸(h, w)完全无关。这样就完美解决了全连接层需要固定长度输入的问题。
import numpy as np
def spatial_pyramid_pooling(feature_map, levels=[1, 2, 4]):
"""
简化的空间金字塔池化演示。
feature_map 形状为 (H, W, C):每个 bin 在每个通道上独立做最大池化,
再把所有 bin 的结果按“层级 → 行 → 列 → 通道”的顺序依次拼接。
"""
h, w, c = feature_map.shape
output = []
for level in levels:
# 计算每个bin的尺寸
bin_h = h / level
bin_w = w / level
for i in range(level):
for j in range(level):
# 计算当前bin的边界(取整)
h_start = int(i * bin_h)
h_end = int((i + 1) * bin_h)
w_start = int(j * bin_w)
w_end = int((j + 1) * bin_w)
# 提取当前bin的区域
bin_region = feature_map[h_start:h_end, w_start:w_end, :]
# 进行最大池化:只在空间维度上取最大,通道维保留 → 每个bin输出c个值
pooled_val = np.max(bin_region, axis=(0, 1))
output.extend(pooled_val)
return np.array(output)
# 构造一个模拟的RoI特征图 (6, 6, 1),尺寸是任意的
np.random.seed(42)
roi_feature_map = np.random.randn(6, 6, 1)
print(f"输入特征图形状: {roi_feature_map.shape}")
# 应用SPP,层级为 [1, 2, 4]
spp_output = spatial_pyramid_pooling(roi_feature_map)
print(f"SPP输出向量的长度: {len(spp_output)}")
print(f"输出向量前10个值:\n {spp_output[:10]}")输入特征图形状: (6, 6, 1)
SPP输出向量的长度: 21
输出向量前10个值:
[ 1.85227818 1.57921282 1.52302986 1.85227818 0.82254491 0.49671415
0.64768854 1.52302986 -0.23413696 1.57921282]SPP-Net的训练流程与遗留问题
SPP-Net的训练流程与R-CNN类似,也是一个多阶段过程,但特征来源和微调对象发生了变化:
- 预训练(Pre-training):使用ImageNet数据集预训练一个CNN模型(如AlexNet),得到模型
M。 - 提取SPP特征:将训练图片输入
M,进行前向传播至Conv5层,得到整图的特征图。然后对于每张图片的所有Selective Search候选区域,在特征图上找到对应RoI,并通过SPP层计算出固定长度的特征向量。这一步得到所有区域的SPP特征F。 - 微调全连接层:使用上一步得到的SPP特征
F作为输入,对应的区域类别标签作为输出,只微调网络最后的部分(即SPP层之后的全连接层,如Fc6, Fc7, Fc8),得到微调后的模型M'。注意,Conv1-5的参数在此阶段被冻结。 - 训练SVM分类器:使用微调后模型
M'的某一层全连接层(如Fc7)的输出特征F',训练多个SVM分类器(每类一个),用于最终的类别判断。 - 训练Bounding Box回归器:使用第2步得到的SPP特征
F(来自Conv5后),训练Bounding Box回归模型,用于对候选框的位置进行微调。
SPP-Net带来的性能提升与遗留问题:
- 速度提升:由于共享了卷积计算,特征提取不再需要对约2000个区域各做一遍卷积。整体训练时间约为25.5小时,其中微调全连接层16小时、特征提取5.5小时、SVM与Bounding Box训练4小时;作为对照,R-CNN的总训练时间约84小时。
- 精度并未同步提升:SPP-Net 的主要收益在速度。按本课程 Fast R-CNN 一节对比表的口径(VGG16、VOC 2007),SPP-Net 的 mAP 为 63.1%,反而低于 R-CNN 的 66.0%,因此不能说“精度保持甚至略有提升”。
- 遗留问题:
- 多阶段训练:仍然需要独立训练SVM和Bounding Box回归器,流程复杂。
- 特征存储:仍需将中间特征(SPP特征和Fc7特征)写入磁盘,占用大量空间。
- 无法端到端微调:这是SPP-Net最受诟病的一点。注意不能简单归因为“SPP层不可导”——划格子和最大值池化都是可导的,梯度有定义。真正的原因是效率:Fast R-CNN 论文指出(SPP-Net 原论文并未展开这一分析),当RoI的感受野较大时,误差穿过SPP层向Conv1-5反传的效率很低。因此,网络底部的卷积层无法根据检测任务进行优化,限制了模型的性能上限。
📝 动手练一练
- 概念辨析:SPP-Net中的“共享卷积计算”具体是如何实现的?它与R-CNN的处理方式有何本质区别?为什么这种共享能大幅提升速度?
👉 点击查看参考答案
实现方式:SPP-Net将卷积层提到最前面,整张图片只进行一次前向传播,通过Conv1-5层得到一张特征图。所有Selective Search提取的候选区域,不再从原图截取并单独卷积,而是通过坐标映射,直接在这张共享的特征图上截取对应的区域(RoI)进行后续处理。
本质区别:R-CNN是 “先区域,后卷积”,2000个区域要算2000次卷积。SPP-Net是 “先卷积,后区域”,2000个区域共享1次卷积结果。
提速原因:卷积运算是CNN中计算量最大的部分。SPP-Net避免了将这最耗时的部分重复2000次,因此特征提取阶段的速度得到数量级的提升。
- 手动计算:假设一个RoI特征图尺寸为
8 x 6 x 256(高8,宽6,通道256)。如果SPP层采用[1x1, 2x2, 4x4]的金字塔层级,请问经过SPP层后,输出的特征向量长度是多少?请简述计算过程。
👉 点击查看参考答案
计算过程:
- 确定总bin数:金字塔层级
[1, 2, 4]对应的网格数分别为1x1=1,2x2=4,4x4=16。总bin数 = 1 + 4 + 16 = 21。 - 确定每个bin的输出:对每个bin进行最大池化,由于特征图有256个通道,池化操作在每个通道上独立进行。因此,每个bin会输出一个256维的向量(每个通道一个最大值)。
- 计算总长度:将21个bin的256维向量拼接起来。总特征长度 = 21 (bins) * 256 (channels) = 5376。
答案:输出的特征向量长度为 5376。
本章小结
本节我们深入剖析了SPP-Net,它是目标检测从R-CNN迈向高效化、集成化道路上的关键里程碑。其两大核心创新——共享卷积计算与空间金字塔池化(SPP)——直指R-CNN的效能痛点。共享计算的思想深刻影响了后续所有目标检测模型的设计;而SPP层则巧妙地将传统计算机视觉中的多尺度思想融入深度学习,解决了输入尺寸固定的限制。尽管SPP-Net自身因无法端到端微调等问题未能成为最终解决方案,但它为Fast R-CNN和Faster R-CNN的诞生铺平了道路。
需要如实定位的是:SPP-Net发表于2014年(ECCV),它和随后的Fast R-CNN、Faster R-CNN都属于两阶段检测器的历史阶段。2019年前后起,目标检测的主流逐步转向以YOLO系列为代表的单阶段实时模型,以及以DETR为代表的Transformer检测器,本节这些模型更适合作为理解检测思想演进的基础来学。不过“多尺度池化”的思路并未过时——今天CNN检测器中的SPP/SPPF模块就是它的直系后代。
📋 行动清单
- 理解共享计算:在脑海中清晰复现SPP-Net“先整图卷积,再特征图提区域”的流程,并与R-CNN的流程进行对比。
- 掌握SPP原理:能够不借助资料,解释清楚SPP层如何将任意尺寸的输入转换为固定长度的输出,并说出其与金字塔概念(如PHOG)的联系。
- 分析优劣:列出SPP-Net相对于R-CNN的主要改进点,并指出它仍然存在的至少两个关键问题。
—— 小象教研组