查看全课大纲(第 61 / 93 节)
  1. 1.计算机视觉概述
  2. 2.计算机视觉应用场景
  3. 3.困难与挑战
  4. 4.开源库介绍
  5. 5.图像显示与存储
  6. 6.CLAHE
  7. 7.腐蚀膨胀与开闭运算
  8. 8.滤波与边缘填充
  9. 9.各种滤波
  10. 10.图像金字塔
  11. 11.傅里叶变换
  12. 12.短时傅里叶变换与小波变换
  13. 13.颜色特征与颜色直方图
  14. 14.几何特征_边缘
  15. 15.几何特征-角点与斑点
  16. 16.局部特征-SIFT特征描述子
  17. 17.局部特征-SURF特征描述子
  18. 18.局部特征-ORB特征描述子
  19. 19.其他特征描述子
  20. 20.传统图像分割技术
  21. 21.GraphCut
  22. 22.GrabCut
  23. 23.人脸检测的传统方法
  24. 24.行人检测的传统方法HOG+SVM
  25. 25.行人检测DPM
  26. 26.人工神经网络的架构
  27. 27.目标函数与梯度下降
  28. 28.误差反向传播
  29. 29.可手算的神经网络
  30. 30.改进目标函数与克服梯度消散
  31. 31.神经网络之传统神经网络与深度网络的差异
  32. 32.各种梯度下降算法
  33. 33.如何选择合适的梯度下降算法
  34. 34.避免过适应
  35. 35.CNN的架构
  36. 36.CNN的误差反向传播_卷积层
  37. 37.CNN的误差反向传播_池化层
  38. 38.分类所用的数据集
  39. 39.Alexnet详解
  40. 40.VGG详解
  41. 41.GoogLeNet_v1
  42. 42.BatchNormalization
  43. 43.GoogLeNet_v3v4
  44. 44.ResNet
  45. 45.ResNeXt
  46. 46.CNN设计准则
  47. 47.图像检索与推土机距离
  48. 48.基于颜色相似性
  49. 49.基于形状相似性
  50. 50.基于纹理相似性
  51. 51.基于局部特征相似性
  52. 52.DL的二值哈希编码
  53. 53.高维空间中检索KDTree
  54. 54.高维空间中检索LSH
  55. 55.目标识别任务综述
  56. 56.RCNN
  57. 57.SPP-Net
  58. 58.Fast R-CNN
  59. 59.Faster R-CNN
  60. 60.R-CNN系列模型回顾
  61. 61.R-FCN的设计思路
  62. 62.R-FCN的实现
  63. 63.YOLOv1
  64. 64.YOLOv2_9000
  65. 65.YOLOv3
  66. 66.图像分割应用场景与数据集
  67. 67.上采样的实现方式
  68. 68.FCN网络架构的由来
  69. 69.FCN构建细节
  70. 70.DeepLabv1
  71. 71.CRF
  72. 72.DeepLabv2
  73. 73.DeepLabv3
  74. 74.特定的医学影像分割任务
  75. 75.U-Net
  76. 76.3D U-Net
  77. 77.V-Net
  78. 78.DenseNet
  79. 79.病理切片分析任务及数据集
  80. 80.病理切片分析
  81. 81.图说任务及其传统处理方法
  82. 82.深度语言模型与RNN
  83. 83.LSTM及其变种
  84. 84.NIC模型
  85. 85.SAT模型
  86. 86.图说的性能指标
  87. 87.判别模型与生成模型
  88. 88.KL散度与JS散度
  89. 89.VAE
  90. 90.GAN的基本原理
  91. 91.DCGAN与CGAN
  92. 92.Wasserstein GAN
  93. 93.SRGAN

R-FCN的设计思路

小象实战讲义 · 基于深度学习的计算机视觉

在目标检测领域,随着基础网络从AlexNet、VGG向ResNet、GoogLeNet等全卷积化网络演进,直接将Faster R-CNN等经典框架嫁接于新网络之上遇到了性能瓶颈。本节将深入剖析这一矛盾的核心——检测任务的位置敏感性与分类任务的位置不变性之间的冲突,并引出R-FCN(Region-based Fully Convolutional Networks)如何通过“全卷积化”设计,在保持高精度的同时大幅提升检测速度。

💡 核心导读

  • 传统R-CNN结构的局限性:基于AlexNet/VGG的“全卷积子网络+全连接子网络”结构,在适配ResNet等全卷积网络时,RoI-wise子网络的计算无法共享,成为速度瓶颈。
  • 检测与分类的根本矛盾:检测网络需要位置敏感性以精确定位,而分类网络需要位置不变性以保证识别鲁棒性。深度全卷积网络(如ResNet)的深层特征具有强不变性,不利于定位。
  • R-FCN的核心创新:通过引入位置敏感分值图和位置敏感RoI池化,将位置信息显式编码到全卷积网络中,实现了整个检测网络(包括分类与回归分支)的完全卷积化,所有计算均可共享,从而在精度与速度间取得优异平衡。

从经典结构到全卷积网络的适配困境

在Faster R-CNN及其前身中,网络结构通常基于如AlexNet或VGG这类“老式”CNN设计。这类网络具有清晰的模块划分:

  • 全卷积子网络:通常指网络前部的若干组卷积层(如VGG的conv1-conv5)。这部分计算是独立于RoI(Region of Interest) 的,即整张输入图像只需经过一次前向传播,特征提取的计算可以被图像中所有候选区域共享。
  • 全连接子网络:位于网络后部,用于最终的分类与边界框回归。在目标检测框架中,RoI池化层通常被插入在全卷积子网络与全连接子网络之间。这样,每个由RPN(Region Proposal Network)生成的候选区域(RoI)会被映射到特征图上,并经过RoI池化调整为固定尺寸,然后各自独立地通过后续的全连接子网络进行分类和回归。这部分计算是RoI-wise的,无法共享。

这种“前半共享,后半独立”的结构,在基础网络本身也具备类似划分(如VGG的conv部分和fc部分)时,显得非常自然。

然而,随着ResNet、GoogLeNet等现代网络架构的出现,情况发生了变化。为了减少参数、缓解过拟合并提升性能,这些网络极大地减少了全连接层的使用。以ResNet-101为例,它包含100个卷积层,最后仅接一个全局平均池化层和一个用于ImageNet 1000类分类的全连接层。网络的“全卷积化”成为趋势。

当试图将Faster R-CNN的头部(两个分支的全连接网络)直接嫁接在ResNet-101的末端(即去掉最后的全连接层)时,研究者发现检测性能出现了明显的下降。其根本原因在于任务属性的冲突:

  1. 分类任务需要位置不变性:理想的分类器应该能够识别出物体,无论它出现在图像的哪个位置。深度卷积网络通过层层池化和非线性变换,其深层特征确实具备了较强的平移不变性。例如,一张猫的图片,无论猫在左上角还是右下角,ResNet-101的深层特征都应能将其识别为“猫”。
  2. 检测任务需要位置敏感性:检测不仅要识别物体,还要给出其精确的边界框位置。因此,检测网络需要对物体的位置移动保持敏感。如果特征过于“不变”,网络将难以区分物体在图像中的细微位置变化,从而导致定位不准。

直接将RoI池化层放在ResNet-101的末端,意味着每个RoI都使用具有强不变性的深层特征进行分类和回归。这虽然对分类有利,但却严重损害了定位精度,造成了检测性能与分类性能的不匹配。

一种“不自然”的折中方案及其缺陷

为了解决上述矛盾,一个直观的改进思路是:将RoI池化层提前。例如,对于ResNet-101,将前91层卷积作为共享的卷积子网络,在第91层后插入RoI池化层,再用conv5_x剩余的9层主路卷积作为RoI-wise的子网络(另有1个投影捷径,故这一段的卷积算子共10个,但主路仍按9层计,91 + 9 = 100层)。

import numpy as np

# 模拟ResNet-101的特征图尺度变化(仅示意)
# 假设输入图像尺寸为 800x600
input_h, input_w = 600, 800

# ResNet-101通常包含5个stage,下采样率为32
# 最终特征图尺寸约为 input_size / 32
feat_map_h, feat_map_w = input_h // 32, input_w // 32
print(f"输入图像尺寸: {input_h}x{input_w}")
print(f"网络末端(第100层卷积)输出特征图尺寸: {feat_map_h}x{feat_map_w}")

# 假设第91层位于第4个stage末尾,下采样率为16
feat_map_h_91, feat_map_w_91 = input_h // 16, input_w // 16
print(f"第91层卷积输出特征图尺寸: {feat_map_h_91}x{feat_map_w_91}")
print(f"特征图尺度对比: 第91层({feat_map_h_91}x{feat_map_w_91}) 比 网络末端({feat_map_h}x{feat_map_w}) 更大")
输入图像尺寸: 600x800
网络末端(第100层卷积)输出特征图尺寸: 18x25
第91层卷积输出特征图尺寸: 37x50
特征图尺度对比: 第91层(37x50) 比 网络末端(18x25) 更大

这种设计将RoI池化置于一个空间分辨率更高的特征图上(例如37x50而非18x25),理论上有利于保留更多的位置信息,从而提升定位精度。实验也证实,这种“不自然”的设计确实带来了准确率的提升。

然而,它引入了新的问题:速度下降。因为RoI池化层之后的这10个卷积(conv5_x的9层主路卷积加1个投影捷径),仍然是RoI-wise的。假设一张图像产生300个候选区域,那么这300个区域的特征图都需要独立地经过这10层卷积计算。这相当于进行了300次小型卷积网络的前向传播,计算开销巨大,严重拖慢了检测速度。

R-FCN:全卷积化的解决方案

R-FCN的核心目标非常明确:实现目标检测网络的完全卷积化,使得所有计算(包括分类和回归)都能在整张图像上共享,彻底消除RoI-wise的子网络。

其创新点主要在于两个关键设计:

1. 位置敏感分值图

R-FCN在共享的卷积主干网络(如ResNet-101)之后,添加了一个特殊的卷积层,用于生成位置敏感分值图。假设我们要检测的类别数为C(加上背景类为C+1),并且我们将每个RoI划分成一个k x k的规则网格(论文示意图以k=3为例,正式实验配置为k=7)。

对于每一个类别c,我们不是只生成一个分值图,而是生成k x k个分值图。每个分值图专门负责预测该类别物体出现在RoI内某个特定相对位置的概率。例如,k=3时,这9个位置分别是:左上、中上、右上、左中、中心、右中、左下、中下、右下。

因此,这个特殊卷积层的输出通道数为 k * k * (C + 1)。对于输入图像,我们只需经过一次前向传播,就能得到所有类别、所有相对位置的分值图。

2. 位置敏感RoI池化

在得到位置敏感分值图后,对于每一个候选区域RoI,我们进行一种特殊的池化操作——位置敏感RoI池化。

  1. 将当前RoI区域同样划分为k x k个网格(bin)。
  2. 对于第(i, j)个网格(i, j从0到k-1),它只从对应类别c的第(i*k + j)个分值图中进行池化(通常是平均池化)。
  3. 池化后,我们得到一个k x k的网格,每个格子包含了物体某部分出现在对应相对位置的“证据”。
  4. 最后,将这k x k个格子的值进行求和,即得到该RoI属于类别c的最终得分(论文的公式用求和;课件与下面的演示代码则取平均,两者只差常数因子1/k²,各类别得分的相对大小与argmax预测类别不变)。

这个过程显式地将位置信息编码到了分类决策中。如果一个RoI确实包含目标物体,并且定位准确,那么其各个部分(如人的头、躯干、四肢)就应该落在RoI内正确的相对位置上,从而从对应的分值图中获得高分。反之,如果定位不准或根本不是目标,那么各个网格池化得到的分数就会很低或相互矛盾,最终得分也低。

import numpy as np

# 模拟R-FCN的位置敏感分值图与池化过程
np.random.seed(42) # 固定随机种子,保证输出确定

# 假设特征图尺寸为 40x60,类别数为20(人、车、狗...),k=3
H, W, C, k = 40, 60, 20, 3
# 生成位置敏感分值图 (H, W, k*k*(C+1)),这里用随机数模拟卷积输出
# 我们只关注‘人’这个类别(假设类别索引0为人)
score_maps_all = np.random.randn(H, W, k*k*(C+1))
# 提取‘人’类对应的 k*k=9 个通道的分值图
person_score_maps = score_maps_all[:, :, 0:9] # 假设前9个通道对应‘人’类

print(f"位置敏感分值图(‘人’类)形状: {person_score_maps.shape}")
print(f"每个图对应RoI内一个相对位置: 共 {k}x{k}={k*k} 个图\n")

# 假设有一个RoI,其坐标 (x1, y1, x2, y2) 映射到特征图上的区域为 (ry, rx, rh, rw)
# 简化为一个具体的区域:从(10,15)开始,高20,宽25
ry, rx, rh, rw = 10, 15, 20, 25
roi_feat = person_score_maps[ry:ry+rh, rx:rx+rw, :]

# 位置敏感RoI池化:将roi_feat划分为3x3网格,在每个通道对应的网格内做平均池化
pooled = np.zeros((k, k))
# 为简化,这里按整数除法分箱,边缘余数未纳入;真实实现会用浮点边界覆盖整个 RoI
bin_h, bin_w = rh // k, rw // k

for i in range(k):
    for j in range(k):
        # 第 (i,j) 个网格
        h_start = ry + i * bin_h
        h_end = min(ry + (i+1) * bin_h, ry+rh)
        w_start = rx + j * bin_w
        w_end = min(rx + (j+1) * bin_w, rx+rw)
        # 对应第 (i*k + j) 个通道图
        channel_idx = i * k + j
        bin_values = person_score_maps[h_start:h_end, w_start:w_end, channel_idx]
        pooled[i, j] = np.mean(bin_values)

print("RoI池化后得到的 3x3 网格值:")
print(pooled)
print()
# 最终得分:对3x3网格值求平均
final_score = np.mean(pooled)
print(f"‘人’类在该RoI上的最终得分(投票后): {final_score:.4f}")
位置敏感分值图(‘人’类)形状: (40, 60, 9)
每个图对应RoI内一个相对位置: 共 3x3=9 个图

RoI池化后得到的 3x3 网格值:
[[-0.09602184  0.03350679 -0.14356285]
 [ 0.03835107 -0.33898509 -0.07624601]
 [-0.05805505  0.13031784 -0.46478488]]

‘人’类在该RoI上的最终得分(投票后): -0.1084

边界框回归分支采用完全相同的设计,只是其输出的通道数变为 4 * k * k(对应4个坐标偏移量),并通过相同的位置敏感RoI池化得到回归结果。

通过这种巧妙的设计,R-FCN成功地将整个检测网络变成了一个全卷积网络。图像只需经过一次前向传播,就能生成所有必需的分值图。后续对于成百上千个RoI的处理,都仅仅是简单的、无参数的池化操作和求平均,计算量极低。从而在保持与Faster R-CNN相当甚至更优精度的同时,获得了显著的检测速度提升(论文报告约为 2.5–20 倍,具体取决于主干网络与实现配置)。

# R-FCN 网络结构示意 (伪代码)
输入图像 I
1. 共享卷积主干 (如ResNet-101) -> 特征图 F
2. RPN网络 (在F上运行) -> 候选区域提案 RoIs
3. 位置敏感卷积层 (接在主干后):
   - 输入: 特征图 F
   - 输出: 
        * 分类分支: 分值图 P_cls, 形状为 [H, W, k*k*(C+1)]
        * 回归分支: 分值图 P_reg, 形状为 [H, W, 4*k*k]
4. 对于每个RoI:
   a. 位置敏感RoI池化 (在P_cls上) -> 得到 k x k 网格分类得分
   b. 在k x k维度上求平均 -> 得到 (C+1) 维分类得分向量
   c. 位置敏感RoI池化 (在P_reg上) -> 得到 k x k x 4 回归偏移量
   d. 在k x k维度上求平均 -> 得到 4 维边界框回归向量
5. 非极大值抑制 (NMS) -> 输出最终检测框

📝 动手练一练

  1. 概念辨析:请用自己的话解释,为什么在深度全卷积网络(如ResNet)中,分类任务所追求的“位置不变性”与检测任务所要求的“位置敏感性”会构成一对矛盾?这种矛盾在Faster R-CNN直接嫁接ResNet时,是如何具体影响性能的?
👉 点击查看参考答案

矛盾根源:分类任务的目标是识别“是什么”,希望网络能够忽略物体在图像中的位置变化,聚焦于其本质特征(如纹理、形状),这要求特征具有平移不变性。检测任务的目标是“在哪里”和“是什么”,精确定位要求网络能够感知物体位置的细微变化,这要求特征具有平移敏感性(或方差)。深度卷积网络通过堆叠卷积和池化层,深层特征会逐渐丢失细节位置信息,变得对平移不敏感,这与检测任务的定位需求相悖。

性能影响:当Faster R-CNN将RoI池化层直接放在ResNet末端时,每个RoI使用的是具有强不变性的深层特征。这使得:

  • 分类分支:可能表现良好,因为深层特征不变性强,有利于识别。
  • 回归分支:表现变差,因为用于回归的深层特征对位置变化不敏感,网络难以学习精确的边界框偏移量。 最终导致整体检测性能(尤其是定位精度mAP)下降,出现分类性能与检测性能不匹配的现象。
  1. 思路理解:R-FCN通过“位置敏感分值图”和“位置敏感RoI池化”来解决上述矛盾。请简述这一方案是如何在不引入RoI-wise子网络的前提下,让网络同时具备分类能力(基于整体判断)和位置感知能力(基于局部网格)的?
👉 点击查看参考答案

R-FCN的方案可以概括为“分而治之,投票决策”:

  1. 分而治之(位置编码):网络不再为整个RoI输出一个单一的类别得分,而是为每个类别生成k x k个分值图,每个图专门负责预测物体某一部分(对应RoI内一个特定相对位置)出现的可能性。这相当于将物体的位置信息显式地编码到了网络输出中。
  2. 投票决策(池化与聚合):对于每个RoI,进行位置敏感池化。将RoI划分为k x k网格,每个网格只从对应位置的分值图中提取特征值。这样,如果RoI定位准确且包含目标,其各个部分就会从正确的分值图中获得高分;如果定位不准或没有目标,各网格得分会很低或混乱。最后,对k x k个网格的得分进行平均(投票),得到该RoI的最终类别得分。高分意味着RoI内物体的各个部分都出现在了“正确”的相对位置上,这同时蕴含了“它是某类物体”(分类)和“它被框得很准”(定位)两层信息。 通过这种方式,分类决策依赖于对物体各部分相对位置的综合性判断,从而在完全卷积的共享计算框架下,统一了分类所需的不变性与定位所需的敏感性。

本章小结

本节我们深入探讨了R-FCN产生的背景及其核心设计思路。我们认识到,目标检测技术的发展始终围绕着精度与速度的平衡,以及如何更好地适配基础网络架构的演进。R-FCN的创新在于它敏锐地抓住了检测网络中“位置敏感”与“位置不变”这一对核心矛盾,并通过全卷积化和位置敏感编码的巧妙设计,近乎完美地解决了ResNet等现代网络在检测任务中遇到的适配难题,为后续的端到端、全卷积化检测器设计提供了重要思路。

今天,R-FCN 已被 Mask R-CNN、Cascade R-CNN 等两阶段后续以及 YOLO 系列、DETR 等单阶段/Transformer 检测器取代;但“位置敏感分值图 + 位置敏感池化”把位置信息显式编码进全卷积网络的思路,仍是理解全卷积检测器的重要一环。

📋 行动清单

  • 厘清传统Faster R-CNN结构与全卷积网络(如ResNet)直接结合时,在结构和性能上分别会遇到什么问题。
  • 理解“位置敏感性”与“位置不变性”这两个概念在图像分类和目标检测任务中的不同需求及其矛盾点。
  • 掌握R-FCN中“位置敏感分值图”和“位置敏感RoI池化”两个关键组件的设计动机与工作流程,能够阐述它们是如何实现全卷积化检测的。

—— 小象教研组