下面的介绍都是基于VGG16 的Faster RCNN网络,各网络的差异在于Conv layers层提取特征时有细微差异,至于后续的RPN层、Pooling层及全连接的分类和目标定位基本相同.
网络结构
1、Conv layers
Faster RCNN首先是支持输入任意大小的图片的,比如上图中输入的PxQ,进入网络之前对图片进行了规整化尺度的设定,如可设定图像短边不超过600,图像长边不超过1000,我们可以假定MxN=1000x600(如果图片少于该尺寸,可以边缘补0,即图像会有黑色边缘)
① 13个conv层:kernel_size=3,pad=1,stride=1;
卷积公式:
所以,conv层不会改变图片大小(即:输入的图片大小=输出的图片大小)
② 13个relu层:激活函数,不改变图片大小
③ 4个pooling层:kernel_size=2,stride=2;pooling层会让输出图片是输入图片的1/2
经过Conv layers,图片大小变成(M/16)x(N/16),即:60x40(1000/16≈60,600/16≈40);则,Feature Map就是60x40x512-d(注:VGG16是512-d,ZF是256-d),表示特征图的大小为60x40,数量为512
2、RPN(Region Proposal Networks):
Feature Map进入RPN后,先经过一次3x3的卷积,同样,特征图大小依然是60x40,数量512,这样做的目的应该是进一步集中特征信息,接着看到两个全卷积,即kernel_size=1x1,p=0,stride=1;
如上图中标识:
① rpn_cls:60x40x512-d ⊕ 1x1x512x18 ==> 60x40x9x2
逐像素对其9个Anchor box进行二分类
② rpn_bbox:60x40x512-d ⊕ 1x1x512x36==>60x40x9x4
逐像素得到其9个Anchor box四个坐标信息(其实是偏移量,后面介绍)
Anchors的生成规则
前面提到经过Conv layers后,图片大小变成了原来的1/16,在生成Anchors时,我们先定义一个base_anchor
,也就是特征图上的一点,映射到原图像中就是16x16,坐标是[0,0,15,15],ratios=[0.5, 1, 2]scales=[8, 16, 32]。
1、
当[0,0,15,15],面积保持不变的时候,生成三个不同ratios=[0.5, 1, 2]的anchors
对应代码,(ps这是做标签的时候用的,RPN训练时候直接生成)
size_ratios = size / ratios #256/ratios[0.5,1,2]=[512,256,128] #round()方法返回x的四舍五入的数字,sqrt()方法返回数字x的平方根
ws = np.round(np.sqrt(size_ratios)) #ws:[23 16 11]
hs = np.round(ws * ratios) #hs:[12 16 22],ws和hs一一对应
如果经过scales变化,即长、宽分别均为 (16x8=128)、(16x16=256)、(16x32=512),对应anchor box如图
上述两步的结果合起来:
特征图大小为6040,所以会一共生成6040*9=21600个Anchor box
源码中,通过width:(060)*16,height(040)*16建立shift偏移量数组,再和base_ancho基准坐标数组累加,得到特征图上所有像素对应的Anchors的坐标值,是一个[216000,4]的数组
RPN对应keras代码:
def rpn(shared_layers, num_anchors):
x = Convolution2D(512, (3, 3), padding='same', activation='relu', kernel_initializer='normal', name='rpn_conv1')(
base_layers)
x_class = Convolution2D(num_anchors, (1, 1), activation='sigmoid', kernel_initializer='uniform',
name='rpn_out_class')(x)
x_regr = Convolution2D(num_anchors * 4, (1, 1), activation='linear', kernel_initializer='zero',
name='rpn_out_regress')(x)
return [x_class, x_regr, base_layers]
生成的anchors经过极大值抑制筛选过滤。
3、Roi Pooling:
输入的是RPN层产生的region proposal(假定有300个region proposal box)和VGG16最后一层产生的特征图(6040 512-d),遍历每个region proposal,将其坐标值缩小16倍,这样就可以将在原图(1000x600)基础上产生的region proposal映射到60x40的特征图上,从而将在feature map上确定一个区域(定义为RB)。
在feature map上确定的区域RB*,根据参数pooled_w:7,pooled_h:7,将这个RB区域划分为77,即49个相同大小的小区域,对于每个小区域,使用max pooling方式从中选取最大的像素点作为输出,这样,就形成了一个77的feature map。
以此,参照上述方法,300个region proposal遍历完后,会产生很多个77大小的feature map,故而输出的数组是:[300,512,7,7],作为下一层的全连接的输入
4 全连接层:
经过roi pooling层之后,batch_size=300, proposal feature map的大小是7*7,512-d,对特征图进行全连接,参照下图,最后同样利用Softmax Loss和L1 Loss完成分类和定位
通过full connect层与softmax计算每个region proposal具体属于哪个类别(如人,马,车等),输出cls_prob概率向量;同时再次利用bounding box regression获得每个region proposal的位置偏移量bbox_pred,用于回归获得更加精确的目标检测框
即从PoI Pooling获取到7x7大小的proposal feature maps后,通过全连接主要做了:
4.1)通过全连接和softmax对region proposals进行具体类别的分类
4.2)再次对region proposals进行bounding box regression,获取更高精度的rectangle box