目标检测和感受野的总结和想法
先放一下大佬的微信公众号(GiantPandaCV)
接下来我们讲一下目标检测中很重要的一个思想,感受野的计算方法。
经典的目标检测如Faster R-CNN, YOLOv3等都用到了Anchor, 怎么设计Anchor每个目标检测方法各不相同。Faster R-CNN中的Anchor有三种形状,三种长宽比,比如形状有[128, 256, 512]三个,长宽比有[1:1, 1:2, 2:1]三种,这样组合就是9个anchor。YOLOv3中的Anchor是通过K-Means聚类得到的。这些基于anchor的方法的目的是学习一个从Anchor到GT Box的转换函数,下边我们了解一下理论感受野、Anchor、实际感受野三者之间的关系。
先看一张图:
一个kernel size=3的卷积核,通过在原feature map上划窗,然后计算得到的是一个值,这个值是通过计算原来feature map上3×3面积上的值得到的结果,那就说经过这个3×3卷积以后,这一层feature map的感受野就是3×3。如果是两个kernel size=3的卷积核堆叠起来,那么上图黄色的feature map每个值对应最下面的5×5的感受野。
通俗的来讲,感受野其实就是网络最后的输出结果feature_map中,每一个feature_map对应的在原图中所占的像素的大小。
但是感受野其实是有理论感受野和实际感受野的区分的。这点我们最后的时候再讲,现在先讲理论感受野的计算。
**理论感受野:**某一层feature map中的某一个位置,是由前面某一层固定区域输入计算出来的,那这个固定区域就是这个位置的感受野。
一种简单的感受野计算方法
规定一下:k代表kernel size, s代表stride, r代表感受野
第一个feature map(也就是原始图片)的感受野默认为1
经过kernelSize=k, s=1 的卷积层, 感受野计算方法如下:
经过kernelSize=k, s=2 的卷积层, 感受野计算方法如下:
经过s=2的maxpool或avgpool层,感受野计算方法如下:
经过kernelSize=1的卷积层不改变感受野
经过全连接层和Global Average Pooling层的感受野就是整个输入图像
经过多路分支的网络,按照感受野最大支路计算
shortcut层不改变感受野
ReLU、BN、Dropout不改变感受野
全局Stride等于所有层Stride的累乘
全局Padding需要通过以下公式计算(通过feature map反推即可):
P
=
(
f
out
−
1
)
×
stride
−
f
in
+
kernelSize
2
P=\frac{\left(f_{\text {out}}-1\right) \times \text {stride}-f_{\text {in}}+\text {kernelSize}}{2}
P=2(fout−1)×stride−fin+kernelSize
出个计算题,计算VGG16最后一层感受野, 代入公式:
VGG16对应D系列,来计算这一列的感受野(从上往下):
R=(((((1+2+2)x2+2+2)x2+2+2+2)x2+2+2+2)x2+2+2+2)x2=308
S=2x2x2x2x2=32
P=138
实际上tensorflow和pytorch已经有人开发出了计算CNN感受野的模型,实际上VGG16感受野没有那么大,下图是可视化一个416x416大小输入图片的感受野,RF实际上只有212x212。
PS:提供一下pytorch和tensorflow计算感受野的库:
Tensorflow:https://github.com/google-research/receptive_field/
Pytorch:https://github.com/Fangyh09/pytorch-receptive-field
自下而上的计算方法
经过了两个3x3卷积和一个stride=2的maxpooling层,如果按照原来的方法从上往下进行计算,那最后一层每个点的感受野应该是:(1+2+2)x2=10, 要比上图的6要大很多,所以就知道为啥计算的感受野偏大了(没有处理重叠部分),而且也可以发现感受野中间集中更多信息,两边信息处理较少。
单路网络中的计算方法
单路网络就是没有分支的网络,比如VGG。
递推公式:
r
l
−
1
=
s
l
×
r
l
+
(
k
l
−
s
l
)
r_{l-1}=s_{l} \times r_{l}+\left(k_{l}-s_{l}\right)
rl−1=sl×rl+(kl−sl)
通项公式:
r
0
=
∑
l
=
1
L
(
(
k
l
−
1
)
∏
i
=
1
l
−
1
s
i
)
+
1
r_{0}=\sum_{l=1}^{L}\left(\left(k_{l}-1\right) \prod_{i=1}^{l-1} s_{i}\right)+1
r0=∑l=1L((kl−1)∏i=1l−1si)+1
下面这里第4层的时候计算错了,应该是104,所以1,2,3层都计算错了,最终结果应该是212.
多路网络
以上讲解了单路情况下的感受野计算方法,但是现在STOA的卷积网络通常都是拥有多分支的,比如说ResNet、Inception、DenseNet等网络。
多路网络不得不提到对齐问题,感受野是不具有平移不变性,下图就是一个例子:
可以看到,最后一层通过两条不同路径后对应到第一层feature map的感受野的中心是不重合的。这是感受野的一个性质,不过好在大多数现代的网络设计是对齐的,对很多计算机视觉任务来说,都需要对其输出特征,包括目标检测、语义分割、边缘检测、着色等。
在网络对齐时候,所有不同路径都会导致感受野的中心是重合的,所以不同路径必须保持相同的stride。这一点可以观察Inception系列的网络,两条路的Stride是不可能不同的。
在网络对齐的情况下,多路网络的感受野应该是所有分支中最大感受野,比如下边是一个对齐的网络,中心是重合的,感受野的大小就是3。
有了以上的计算方法,我们可以很方便计算所有卷积网络的感受野:
上采样:一般通过插值来实现,假如
α
\alpha
α通过2倍上采样得到
β
\beta
β,那么认为这个层感受野计算等价于与
α
\alpha
α的kernel size相等的卷积。(这个地方不是特别理解,按照自己想的,一般upsample不会改变感受野。