前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Fast R-CNN

Fast R-CNN

作者头像
小小詹同学
发布2019-05-28 20:28:21
7660
发布2019-05-28 20:28:21
举报
文章被收录于专栏:小詹同学

本文经作者授权转载,禁二次转载

来源 | @知乎 Uno Whoiam

原文 | https://zhuanlan.zhihu.com/p/62273673

Fast R-CNN 即 Fast Region-based Convolutional Network,你的直觉没错,它就是R-CNN的升级版。

论文链接:https://arxiv.org/abs/1504.08083

在细说 Fast R-CNN 之前,不妨先看看 R-CNN 有什么令人诟病的地方:

1. 慢,实在是慢,别说实时检测了,47s的等待让坐在电脑前的记几仿佛是一只智障。

2. 训练麻烦,AlexNet、SVMs 以及 bounding-box regression 得一个接一个地训练。

3. 训练占用大量时间和空间(硬盘),除开训练三个模型的时间,SVMs 和 bounding-box regression 的训练样本得用 AlexNet 一次又一次地前向传播提取特征、标注样本数据、保存在硬盘里的哟,每一张图片的每一个proposal都得跑一次哟,想想都觉得恶心。而作者而说明了,需要GPU花2.5天的时间才能处理完5K张VOC07trainval里的图片,产生的训练样本占用的空间得好几百个GB。想想都觉得恶心\呕。顺便温馨提示一下,每张图生成的样本最好单独生成一个文件夹保存,别把这这个数量级的样本放在同一个文件夹里哟,即使是最好的SSD也招架不住这样的文件夹,当你幡然醒悟想要rm -r -f dir 重新来过时,漫长的等待足够让您好好睡一觉了,别问我为什么知道这么多~泪目。

随着 Fast R-CNN 的到来,以上问题也就不复存在辣!相比 R-CNN,除了各种快(见下段原论文引用)Fast R-CNN 有以下几个特性:

Fast R-CNN trains the very deep VGG16 network 9× faster than R-CNN, is 213× faster at test-time, and achieves a higher mAP on PASCAL VOC 2012. Compared to SPPnet, Fast R-CNN trains VGG16 3× faster, tests 10× faster, and is more accurate.

1. 更高的mAP。

2. 不用分段训练,整个网络可以通过使用多任务损失函数,一次性训练好。

3. 训练可以更新网络层中的所有权重。

4. 无需苦逼生成训练样本缓存在硬盘上,节省了空间。

Fast R-CNN 的整体网络如下图所示:

接下来按照物体检测的大框架:候选框->特征提取->分类->精调位置。一步步来说吧。

一、提出候选框

和R-CNN一样,候选框的提出使用 selective search 方法。

selective search: http://www.huppelen.nl/publications/selectiveSearchDraft.pdf https://blog.csdn.net/mao_kun/article/details/50576003

二、特征提取

使用深度卷积神经网络进行特征提取,在论文中作者分别使用了从小到大三种网络进行实验:

1. S: CaffeNet 即小型版的 AlexNet

2. M: VGG_CNN_ M_ 1024 一看名字就知道是小型一点的 VGG

3. L: VGG-16

值得注意的是,以上网络的全连接层都被去掉了,这意味着:输入的尺寸大小劳资不用管辣哈哈哈哈哈!!!(想起R-CNN里RBG大神辛辛苦苦想了四种办法将Proposal区域变成 227 x 227 再喂给 AlexNet 就觉得熏疼)

也就是说,特征提取网络最终输出的是 C 层的 Feature Maps 。

等等,好像有什么不对?我想要得到的是图片中某个Proposal区域的特征向量啊,没特征向量我怎么判断这个Proposal区域到底有没有物体嘛!

这就需要用到 ROI max-pooling 了。对于这个细节网上很少有可以把它说清楚的,本文将结合 Pytorch 实现代码,保证让您看得明明白白的。

首先,啥是Proposal区域?在Fast R-CNN中,Proposal区域就是用 selective search 在图片上生成的可能含有被检测物体的框框们,而这个框框,可以用左上角和右下角的坐标表示,即: (x1,y1,x2,y2) ,它们都是 [0,1] 范围内的 float 数,表示框框在图片中的相对位置。

现在我们的目标是:对于一个Proposal框,在神经网络输出的C 层 Feature Maps找到对应的部分。具体该怎么做呢?如果整张图片的经过特征提取网络生成的 Feature Maps 尺寸是 (C,W,H) ,那么框框对应的坐标是:

其中 Floor 表示下取整, Ceil 表示上取整。这个框出来的部分就代表着Proposal区域经过神经网络提取到的特征,另外 C 保持不变,将其平展开成一维向量后就表示Proposal区域的特征向量辣。

新的问题来了,Proposal框大小不同也就意味着对应的 Feature Maps 上的大小不同,大小不同平铺出来的一维特征向量也不同,那怎么办?

这就是 ROI max-pooling 需要做的事情了:将不同尺寸Proposal区域所对应的 Feature Maps 变成相同尺寸的,在 Pytorch 中可以使用 torch.nn.AdaptiveAvgPool2d 来实现,无论输入的 Feature Maps 是什么尺寸,它都可以通过调整stride、padding等参数给你输出成统一大小的尺寸。下面是 Pytorch 代码:

代码语言:javascript
复制
class SlowROIPool(nn.Module):
 def __init__(self, output_size):
 super().__init__()
 self.maxpool = nn.AdaptiveMaxPool2d(output_size)
 self.size = output_size

 def forward(self, images, rois, roi_idx):
 n = rois.shape[0]
 h = images.size(2)
 w = images.size(3)
 x1 = rois[:,0]
 y1 = rois[:,1]
 x2 = rois[:,2]
 y2 = rois[:,3]

 x1 = np.floor(x1 * w).astype(int)
 x2 = np.ceil(x2 * w).astype(int)
 y1 = np.floor(y1 * h).astype(int)
 y2 = np.ceil(y2 * h).astype(int)
 
 res = []
 for i in range(n):
 img = images[roi_idx[i]].unsqueeze(0)
 img = img[:, :, y1[i]:y2[i], x1[i]:x2[i]]
 img = self.maxpool(img)
 res.append(img)
 res = torch.cat(res, dim=0)
 return res

注:

代码来源:https://github.com/GitHberChen/Fast-RCNN-Object-Detection-Pytorch/blob/master/README.ipynb

images:shape为[N,C,H,W],为N张图片经VGG输出的 Feature Maps

rois:单张图片中包含N组Proposal框的 (x1,y1,x2,y2)

roi_idx:rois对应的图片序号

三、分类以及边框回归

简单,分类通过将上面提取出的特征向量使用全连接网络输出 N+1 类的置信度即可,而边框回归也是通过全连接网络输出 (N+1) x 4 个数。

另外一个细节是,论文中采用了 SVD 对这两个全连接层的计算进行了加速:

(这篇博客写得不错,推荐阅读)

图像分类任务中,用于卷积层计算的时间比用于全连接层计算的时间多,而在目标检测任务中,selective search算法提取的建议框比较多【约2k】,几乎有一半的前向计算时间被花费于全连接层,就Fast R-CNN而言,RoI池化层后的全连接层需要进行约2k次【每个建议框都要计算】,因此在Fast R-CNN中可以采用SVD分解加速全连接层计算;

具体如何实现呢?

物体分类和窗口回归都是通过全连接层实现的,假设全连接层输入数据为 x ,输出数据为 y ,全连接层参数为 W ,尺寸为 u×v ,那么该层全连接计算为: y=Wx,计算复杂度为 u×v ;

若将W进行SVD分解,并用前t个特征值近似代替,即:

那么原来的前向传播分解成两步:

计算复杂度为 u×t+v×t ,若 t<min(u,v)t<min(u,v) ,则这种分解会大大减少计算量;

在实现时,相当于把一个全连接层拆分为两个全连接层,第一个全连接层不含偏置,第二个全连接层含偏置;实验表明,SVD分解全连接层能使mAP只下降0.3%的情况下提升30%的速度,同时该方法也不必再执行额外的微调操作。

作者:WoPawn

来源:CSDN

原文:https://blog.csdn.net/WoPawn/article/details/52463853

四、损失函数

Fast R-CNN 虽是 two-stage 算法,但可以通过 one-stage 训练好,这意味着,损失函数包含多个任务目标:

最后附上 Fast R-CNN 结构图和具体细节:

代码语言:javascript
复制
RCNN (
 (seq): Sequential (
 (0): Conv2d(3, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
 (1): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
 (2): ReLU (inplace)
 (3): Conv2d(64, 64, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
 (4): BatchNorm2d(64, eps=1e-05, momentum=0.1, affine=True)
 (5): ReLU (inplace)
 (6): MaxPool2d (size=(2, 2), stride=(2, 2), dilation=(1, 1))
 (7): Conv2d(64, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
 (8): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
 (9): ReLU (inplace)
 (10): Conv2d(128, 128, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
 (11): BatchNorm2d(128, eps=1e-05, momentum=0.1, affine=True)
 (12): ReLU (inplace)
 (13): MaxPool2d (size=(2, 2), stride=(2, 2), dilation=(1, 1))
 (14): Conv2d(128, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
 (15): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True)
 (16): ReLU (inplace)
 (17): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
 (18): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True)
 (19): ReLU (inplace)
 (20): Conv2d(256, 256, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
 (21): BatchNorm2d(256, eps=1e-05, momentum=0.1, affine=True)
 (22): ReLU (inplace)
 (23): MaxPool2d (size=(2, 2), stride=(2, 2), dilation=(1, 1))
 (24): Conv2d(256, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
 (25): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True)
 (26): ReLU (inplace)
 (27): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
 (28): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True)
 (29): ReLU (inplace)
 (30): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
 (31): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True)
 (32): ReLU (inplace)
 (33): MaxPool2d (size=(2, 2), stride=(2, 2), dilation=(1, 1))
 (34): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
 (35): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True)
 (36): ReLU (inplace)
 (37): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
 (38): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True)
 (39): ReLU (inplace)
 (40): Conv2d(512, 512, kernel_size=(3, 3), stride=(1, 1), padding=(1, 1))
 (41): BatchNorm2d(512, eps=1e-05, momentum=0.1, affine=True)
 (42): ReLU (inplace)
 )
 (roipool): SlowROIPool (
 (maxpool): AdaptiveMaxPool2d (output_size=(7, 7))
 )
 (feature): Sequential (
 (0): Linear (25088 -> 4096)
 (1): ReLU (inplace)
 (2): Dropout (p = 0.5)
 (3): Linear (4096 -> 4096)
 (4): ReLU (inplace)
 (5): Dropout (p = 0.5)
 )
 (cls_score): Linear (4096 -> 21)
 (bbox): Linear (4096 -> 84)
 (cel): CrossEntropyLoss (
 )
 (sl1): SmoothL1Loss (
 )
)

参考链接:

https://github.com/GitHberChen/Fast-RCNN-Object-Detection-Pytorch/blob/master/README.ipynb

本文参与 腾讯云自媒体同步曝光计划,分享自微信公众号。
原始发表:2019-05-28,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 小詹学Python 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档