一文读懂Faster RCNN - 白裳的文章 - 知乎 https://zhuanlan.zhihu.com/p/31426458

fasterrcnn面向的任务

fasterrcnn的任务是目标检测, 属于fastrcnn系列, 该系列通常与yolo系列作为对比.
fasterrcnn属于两阶段检测的实现方式, 完成了端到端的处理, 而且效率和准确率大大优于之前的fastrcnn系列.


image.png

上图, 网络整体结构


image.png
这部分是基于预训练模型(VGG16), 目的是提取图像特征feature map, 之后的处理共享了这些特征.
代码思路: 1, 将图片进行尺寸上的放缩. 2, 使用vgg提取特征, 在提取过程中, 图片经过4次下采样, 最终输出的尺寸变为1/16倍, 深度变为16倍.


image.png
RPN模型, 这是论文的核心, 使用RPN来生成检测框, 正因为它的存在fasterrcnn的效率才如此地高.
RPN网络实际分为2条线,上面一条通过softmax分类anchors获得positive和negative分类, 下面一条用于计算对于anchors的bounding box regression偏移量,以获得精确的proposal. 而最后的Proposal层则负责综合positive anchors和对应bounding box regression偏移量获取proposals,同时剔除太小和超出边界的proposals。其实整个网络到了Proposal Layer这里,就完成了相当于目标定位的功能。
image.png
代码思路:
其实RPN最终就是在原图尺度上,设置了密密麻麻的候选Anchor。然后用cnn去判断哪些Anchor是里面有目标的positive anchor,哪些是没目标的negative anchor。所以,仅仅是个二分类而已!

  • anchor归回

使postive anchor 更接近ground true, 实现是对每个anchor重构出4个位置偏移参数进行学习.

  1. # anchor偏移量回归
  2. def __init__():
  3. self.conv1 = nn.Conv2d(in_channels, mid_channels, 3, 1, 1)
  4. self.loc = nn.Conv2d(mid_channels, n_anchor * 4, 1, 1, 0)
  5. def forward(self, x): #
  6. # 将vgg的输出进行conv1x1卷积,论文中mid_channels = 512
  7. h = F.relu(self.conv1(x))
  8. # (b,c,h,w) -> (b,4*n_anchor,h,w), 深度变为四倍的原因是重构出每个特征点对应的anchors的四个位置偏移.
  9. rpn_locs = self.loc(h)
  10. # (b,4*n_anchor,h,w) -> (b,h,w,4*n_anchor) --view重构-> (b,h*w*n_anchor,4)
  11. rpn_locs = rpn_locs.permute(0, 2, 3, 1).contiguous().view(n, -1, 4) # 得到所有anchor的四个位置偏移.
  12. # 将rpn_locs 传给Proposal模块

image.png

  • anchor分类

将每个特征点的ahchor做一个二分类, 判别是前景还是背景. 原论文使用softmax做二分类,故每个anchor对应两个输出概率. 如果使用logistic的话, 每个anchor指对应一个输出概率, 原理是一样的.
实现: 对每个anchor重构出2个softmax概率输出.

  1. # 前背景分类
  2. def __init__():
  3. self.conv1 = nn.Conv2d(in_channels, mid_channels, 3, 1, 1)
  4. self.score = nn.Conv2d(mid_channels, n_anchor * 2, 1, 1, 0)
  5. def forward(self,x):
  6. # 将vgg的输出进行conv1x1卷积,论文中mid_channels = 512
  7. h = F.relu(self.conv1(x))
  8. # (b,n_anchor,h,w) -> (b,2*n_anchor,h,w). 由softmax分类,每个anchor对应2个概率输出.
  9. rpn_scores = self.score(h)
  10. # (b,2*n_anchor,h,w) -> (b,h,w,2*n_anchor)
  11. rpn_scores = rpn_scores.permute(0, 2, 3, 1).contiguous()
  12. # (b,h,w,2*n_anchor) --重构--> (b, h, w, n_anchor, 2) 计算softmax
  13. rpn_softmax_scores = F.softmax(rpn_scores.view(n, hh, ww, n_anchor, 2), dim=4)
  14. rpn_fg_scores = rpn_softmax_scores[:, :, :, :, 1].contiguous() # 得到前景的分类概率
  15. # (b, hh, ww, n_anchor, 2) --重构->(b,hh*ww*n_anchor*2) 得到所有anchor的前景分类概率
  16. rpn_fg_scores = rpn_fg_scores.view(n, -1)
  17. # (n*hh*ww*n_anchor, 2)--重构--> (b,h*w*n_anchor,2)
  18. rpn_scores = rpn_scores.view(n, -1, 2) # 得到每一张feature map上所有anchor的分类输出值
  19. # rpn_scores 传递给Proposal模块