Background & Motivation
最早的分类模型 AlexNet 和 VGG Net,前半部分是卷积自网络,后半部分是一些全连接层,前后部分被一个空间池化层隔开。自然而然传统的二阶段目标检测网络可以看作被 RoI pooling 分成两个子网络,前半部分是参数共享的全卷积网络,后半部分是基于 RoI 区域的不共享参数的 RoI-wise subnetwork(Head)。由于每个 RoI 都是单独计算,因此也增大了开销。但是检测精度与分类网络优秀的性能相比并不算高。文中分析是因为分类任务中物体有平移不变性,而在检测任务中的回归任务必须要求定位出物体的位置,文中称作 translation variance 问题。
On the other hand, the object detection task needs localization representations that are translation-variant to an extent. For example, translation of an object inside a candidate box should produce meaningful responses for describing how good the candidate box overlaps the object.
而这篇论文的 Motivation 就是为了解决 translation variance。SPP、Faster R-CNN 类的方法在 RoI pooling 前都是卷积,是具备平移不变性的,但一旦插入 RoI pooling 之后,后面的网络结构就不再具备平移不变性了。因此,本文想提出来的 position sensitive-score map 和 position-sensitive RoI pooling 是想把目标的位置信息融合进 ROI pooling。同时把耗时的卷积都尽量移到前半部分共享的网络上,来减少开销。
R-FCN
前半部分的 backbone 采用 ResNet-101,其卷积层的最后一层输出是2048维的,在这一层后加上一个1024维的1*1卷积再加上一组特别设定的卷积层将其输出调整为(...,H,W,k^2*(C+1)),其中 C 对应了检测任务中物体的类别数。RPN 中输出的 RoI 在特征图最后一层的对应位置上生成对应(C+1)个类别的 k*k 个 position-sensitive 得分图。
k 可以取3,这样就可以看作3*3特征图上各个对应位置的得分图,比如 { top-left,top-center,top-right,...,bottom-right }(即图中每一个小的长方体都对应输出的 k*k 特征图中的一个位置,也即枚举了每一个类别的部分在特征图中每一个位置出现的可能性)。
之后再接上一个 RoI pooling 操作,这里称作 position-sensitive RoI pooling,这里只聚合了 backbone 最后一层特征以及得分图的各个部分拼接成的 k*k 的特征图(即图中 RoI 的正方体在 k*k 的每一个位置上挑选出各自的特征块)。其每个类别与对应位置的响应如下:
其中 z 是挑选出来的特征块拼成的特征图,x0 和 y0 是该 RoI 左上角的坐标。x 和 y 的范围是1到3,对应 k*k 中的各个位置,n 是该位置内的像素数,相当于进行了平均池化,而最大池化也是可行的但在本文中没有采用。Θ 是可学习的参数。
之后这 k*k 个特征块对各个类别再进行投票,得到各类别的得分:
在将这些得分经过 Softmax 归一化到0和1之间:
通过端到端训练,RoI 层引导加上的一组特别设定的卷积层来学习专门的 position-sensitive 得分图。我们进一步引入 position-sensitive RoI pooling,引导得分图学习到用于目标检测任务的特征。
下面分别是正例和负例:
上图可以看出,如果越多黄色的框内包含物体,则越多特征图(即 Fig 1 中 RoI 的正方体在 k*k 的每一个位置上挑选出各自的特征块,拼接成最后的特征图)中的区域被激活,就会得到更高的分数。
用同样的方法进行了 bounding box 的回归,在加在 backbone 上1024维的卷积层之后,增加一个回归分支。即加上一组特别设定的卷积层将其输出调整为(...,H,W,4*k^2*C)。
Then it is aggregated into a 4-d vector by average voting.
损失函数是分类分支的交叉熵损失和回归分支的回归损失:
文中采用了 hole algorithm,似乎对精度的提升有帮助:
Experiments
各个模块的消融实验:
This RPN is trained following [19], except that the 2-class (object or not) convolutional classifier layer is replaced with a 21-class convolutional classifier layer. For fair comparisons, for this class-specific RPN we use ResNet-101’s conv5 layers with the à trous trick.
In fact, the class-specific RPN is similar to a special form of Fast R-CNN that uses dense sliding windows as proposals.
在 VOC 数据集上的结果:
在 COCO 数据集上的结果:
Conclusion
很多情景下精度的提升并不大,但是比速度 baseline 几乎使其几倍, position-sensitive 得分图和 position-sensitive RoI pooling 的具体细节可能得看代码才能弄懂。
RFCN 提出 psROIpooling,让 proposal 从 bbox map 和 score map 上寻找 RoI,从而取消全连接层,这样不同的 proposal 做的重复的事情就只有后面的 average pooling。
附加
- GoogLeNet
基础卷积块叫做 Inception,4条线路都使用了合适的填充来使输入与输出的高和宽一致。
class Inception(nn.Module):
def __init__(self,in_channels,c1,c2,c3,c4):
super(Inception,self).__init__()
self.conv1 = nn.Conv2d(in_channels,c1,kernel_size = 1)
self.conv2 = nn.Sequential(
nn.Conv2d(in_channels,c2[0],kernel_size = 1),nn.ReLU(),
nn.Conv2d(c2[0],c2[1],kernel_size=3,padding=1),nn.ReLU()
)
self.conv3 = nn.Sequential(
nn.Conv2d(in_channels,c3[0],kernel_size=1),nn.ReLU(),
nn.Conv2d(c3[0],c3[1],kernel_size=5, padding=2),nn.ReLU()
)
self.conv4 = nn.Sequential(
nn.MaxPool2d(kernel_size=3,stride=1,padding=1),
nn.Conv2d(in_channels,c4,kernel_size = 1),nn.ReLU(),
)
def forward(self,X):
return torch.cat(
(
self.conv1(X),
self.conv2(X),
self.conv3(X),
self.conv4(X),
),
dim = 1
)
Inception 块相当于一个有4条线路的子网络。它通过不同窗口形状的卷积层和最大池化层来并行抽取信息,并使用1×1卷积层减少通道数从而降低模型复杂度。GoogLeNet 将多个设计精细的 Inception 块和其他层串联起来。其中 Inception 块的通道数分配之比是在 ImageNet 数据集上通过大量的实验得来的。
class GoogleNet(nn.Module):
def __init__(self,in_channels,classes):
super(GoogleNet,self).__init__()
self.model = nn.Sequential(
nn.Conv2d(in_channels,out_channels=64,kernel_size=7,stride=2,padding=3),nn.ReLU(),
nn.MaxPool2d(kernel_size=3,stride=2),
nn.Conv2d(in_channels=64,out_channels=64,kernel_size=1),nn.ReLU(),
nn.Conv2d(in_channels=64,out_channels=192,kernel_size=3,padding=1),nn.ReLU(),
nn.MaxPool2d(kernel_size=3,stride=2),
Inception(192,c1=64,c2=[96,128],c3=[16,32],c4=32),
Inception(256,c1=128,c2=[128,192],c3=[32,96],c4=64),
nn.MaxPool2d(kernel_size=3,stride=2,padding=1),
Inception(480,c1=192,c2=[96,208],c3=[16,48],c4=64),
Inception(512,c1=160,c2=[112,224],c3=[24,64],c4=64),
Inception(512,c1=128,c2=[128,256],c3=[24,64],c4=64),
Inception(512,c1=112,c2=[144,288],c3=[32,64],c4=64),
Inception(528,c1=256,c2=[160,320],c3=[32,128],c4=128),
nn.MaxPool2d(kernel_size=3,stride=2,padding=1),
Inception(832,c1=256,c2=[160,320],c3=[32,128],c4=128),
Inception(832,c1=384,c2=[192,384],c3=[48,128],c4=128),
nn.AvgPool2d(kernel_size=7,stride=1),
nn.Dropout(p=0.4),
nn.Flatten(),
nn.Linear(1024,classes),
nn.Softmax(dim=1)
)
def forward(self,X:torch.tensor):
for layer in self.model:
X = layer(X)
print(layer.__class__.__name__,'output shape:',X.shape)
GoogLeNet 一共使用 9 个 Inception 块和 AvgPooling 的堆叠来生成其估计值,Inception块之间的 MaxPooling 可降低维度。
- OHEM
记得看这篇文章。
- hole algorithm
即空洞卷积(Dilated/Atrous Convolution),广泛应用于语义分割与目标检测等任务中。语义分割中经典的 deeplab 系列与 DUC 对空洞卷积进行了深入的思考。目标检测中 SSD 与 RFBNet,同样使用了空洞卷积。
总结-空洞卷积(Dilated/Atrous Convolution) - 知乎
- iterative box regression
出自《Cascade R-CNN: Delving into High Quality Object Detection》,通过将 Faster Rcnn 网络级联起来,每个级联的 Faster Rcnn 设置不同的 IoU 阈值。这样每个网络输出的准确度提升一点,用作下一个更高精度的网络的输入,逐步将网络输出的准确度进一步提高。在 Cascade R-CNN 之前,其实也有人研究了基于 Cascade 的方法进行坐标框的优化,如下图所示,这种方法叫做 iterative box regression, 《Object detection via a multi-region & semantic segmentation-aware CNN model》。
不过该方法中所有的 head 都是相同的,这会导致一个问题:在每次迭代后,bounding box 的分布实际上发生了一定的改变,而分类器是基于最开始的 bounding box 来训练的,这样会产生数据分布的偏差。而 Cascade RCNN 是在训练的时候就进行重新采样,规避了数据分布出现偏差。此后把这篇文章里的方法称作 iterative box regression。
While iterative BBox is a post-processing procedure used to improve bounding boxes, cas-caded regression is a resampling procedure that changes the distribution of hypotheses to be processed by the different stages.
转:Cascade R-CNN,一个使你的检测更加准确的网络 - Augustone - 博客园
- multi-scale training 和 multi-scale testing
输入图片的尺寸对检测模型的性能影响相当明显,事实上多尺度是提升精度最明显的技巧之一。在基础网络部分常常会生成比原图小数十倍的特征图,导致小物体的特征描述不容易被检测网络捕捉。通过输入更大、更多尺寸的图片进行训练,能够在一定程度上提高检测模型对物体大小的鲁棒性,仅在测试阶段引入多尺度,也可享受大尺寸和多尺寸带来的增益。
multi-scale training 对全卷积网络有效,一般设置几种不同尺度的图片,训练时每隔一定 iterations 随机选取一种尺度训练。
multi-scale testing 是指测试时生成几个不同尺度的 feature map,每个 proposal 在不同的 feature map 上也有不同的尺度,我们用最接近某一固定尺寸(即 Head 的输入尺寸)的proposal /用 Maxout(element-wise max)的方法选出 proposal 作为后续的输入。
Our convolutional feature maps are extracted from multiple discrete scales, known as a feature pyramid. In the above, a region feature is pooled from a single scale selected from the pyramid following [12]. Next, we incorporate a local competition operation (maxout) [16] into Networks on Convolutional feature maps to improve scale selection from the feature pyramid.
目标检测中的Using multi scales training/testing_qq_409992227的博客-CSDN博客
- 全卷积网络 FCN
实现了从图像像素到像素类别的变换,全卷积网络将中间层特征图的高和宽变换回输入图像的尺寸。因此,输出的类别预测与输入图像在像素级别上具有一一对应关系:给定空间维上的位置,通道维的输出即该位置对应像素的类别预测。
先使用 CNN 抽取图像特征,然后通过 1×1 卷积层将通道数变换为类别个数,最后再通过转置卷积层将特征图的高和宽变换为输入图像的尺寸。 因此,模型输出与输入图像的高和宽相同,且最终输出的通道包含了该空间位置像素的类别预测。
- 转置卷积与上采样
常见的上采样方法有最近邻插值(Nearest neighbor interpolation)、双线性插值(Bi-linear interpolation)、双立方插值(Bi-cubic interpolation)等方法。但是,上述的方法都需要插值操作,而这些插值的操作都充满了人为设计和特征工程的气息,而且也没有网络进行学习的余地。
转置卷积也是一种上采样(up-sampling)的常见方法,但它与基于插值的方法不同,它有可以学习的参数。因此可以由网络去学出一种最优的上采样参数,转置卷积可以用上面的插值方法初始化。
轻松理解转置卷积(transposed convolution)或反卷积(deconvolution)_lanadeus-CSDN博客_转置卷积