Fast R-CNN: 我变快了,也变强了!
點擊“小詹學Python”,選擇“置頂”公眾號
重磅干貨,第一時間送達
本文經(jīng)作者授權轉載,禁二次轉載
來源 | @知乎?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 一次又一次地前向傳播提取特征、標注樣本數(shù)據(jù)、保存在硬盤里的喲,每一張圖片的每一個proposal都得跑一次喲,想想都覺得惡心。而作者而說明了,需要GPU花2.5天的時間才能處理完5K張VOC07trainval里的圖片,產(chǎn)生的訓練樣本占用的空間得好幾百個GB。想想都覺得惡心\嘔。順便溫馨提示一下,每張圖生成的樣本最好單獨生成一個文件夾保存,別把這這個數(shù)量級的樣本放在同一個文件夾里喲,即使是最好的SSD也招架不住這樣的文件夾,當你幡然醒悟想要rm -r -f dir 重新來過時,漫長的等待足夠讓您好好睡一覺了,別問我為什么知道這么多~淚目。
隨著 Fast R-CNN 的到來,以上問題也就不復存在辣!相比 R-CNN,除了各種快(見下段原論文引用)Fast R-CNN 有以下幾個特性:
1. 更高的mAP。
2. 不用分段訓練,整個網(wǎng)絡可以通過使用多任務損失函數(shù),一次性訓練好。
3. 訓練可以更新網(wǎng)絡層中的所有權重。
4. 無需苦逼生成訓練樣本緩存在硬盤上,節(jié)省了空間。
Fast R-CNN 的整體網(wǎng)絡如下圖所示:
接下來按照物體檢測的大框架:候選框->特征提取->分類->精調(diào)位置。一步步來說吧。
一、提出候選框?
和R-CNN一樣,候選框的提出使用 selective search 方法。
selective search:
http://www.huppelen.nl/publications/selectiveSearchDraft.pdf https://blog.csdn.net/mao_kun/article/details/50576003
二、特征提取
使用深度卷積神經(jīng)網(wǎng)絡進行特征提取,在論文中作者分別使用了從小到大三種網(wǎng)絡進行實驗:?
1. S: CaffeNet 即小型版的 AlexNet?
2. M: VGG_CNN_ M_ 1024 一看名字就知道是小型一點的 VGG?
3. L: VGG-16?
值得注意的是,以上網(wǎng)絡的全連接層都被去掉了,這意味著:輸入的尺寸大小勞資不用管辣哈哈哈哈哈!!!(想起R-CNN里RBG大神辛辛苦苦想了四種辦法將Proposal區(qū)域變成 227 x 227 再喂給 AlexNet 就覺得熏疼)
也就是說,特征提取網(wǎng)絡最終輸出的是 C 層的 Feature Maps 。?
等等,好像有什么不對?我想要得到的是圖片中某個Proposal區(qū)域的特征向量啊,沒特征向量我怎么判斷這個Proposal區(qū)域到底有沒有物體嘛!?
這就需要用到 ROI max-pooling 了。對于這個細節(jié)網(wǎng)上很少有可以把它說清楚的,本文將結合 Pytorch 實現(xiàn)代碼,保證讓您看得明明白白的。
首先,啥是Proposal區(qū)域?在Fast R-CNN中,Proposal區(qū)域就是用 selective search 在圖片上生成的可能含有被檢測物體的框框們,而這個框框,可以用左上角和右下角的坐標表示,即: (x1,y1,x2,y2) ,它們都是 [0,1] 范圍內(nèi)的 float 數(shù),表示框框在圖片中的相對位置。?
現(xiàn)在我們的目標是:對于一個Proposal框,在神經(jīng)網(wǎng)絡輸出的C 層 Feature Maps找到對應的部分。具體該怎么做呢?如果整張圖片的經(jīng)過特征提取網(wǎng)絡生成的 Feature Maps 尺寸是 (C,W,H) ,那么框框對應的坐標是:
其中 Floor 表示下取整, Ceil 表示上取整。這個框出來的部分就代表著Proposal區(qū)域經(jīng)過神經(jīng)網(wǎng)絡提取到的特征,另外 C 保持不變,將其平展開成一維向量后就表示Proposal區(qū)域的特征向量辣。?
新的問題來了,Proposal框大小不同也就意味著對應的 Feature Maps 上的大小不同,大小不同平鋪出來的一維特征向量也不同,那怎么辦??
這就是 ROI max-pooling 需要做的事情了:將不同尺寸Proposal區(qū)域所對應的 Feature Maps 變成相同尺寸的,在 Pytorch 中可以使用 torch.nn.AdaptiveAvgPool2d 來實現(xiàn),無論輸入的 Feature Maps 是什么尺寸,它都可以通過調(diào)整stride、padding等參數(shù)給你輸出成統(tǒng)一大小的尺寸。下面是 Pytorch 代碼:
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張圖片經(jīng)VGG輸出的 Feature Maps?
rois:單張圖片中包含N組Proposal框的 (x1,y1,x2,y2)?
roi_idx:rois對應的圖片序號
三、分類以及邊框回歸
簡單,分類通過將上面提取出的特征向量使用全連接網(wǎng)絡輸出 N+1 類的置信度即可,而邊框回歸也是通過全連接網(wǎng)絡輸出 (N+1) x 4 個數(shù)。?
另外一個細節(jié)是,論文中采用了 SVD 對這兩個全連接層的計算進行了加速:?
(這篇博客寫得不錯,推薦閱讀)
圖像分類任務中,用于卷積層計算的時間比用于全連接層計算的時間多,而在目標檢測任務中,selective search算法提取的建議框比較多【約2k】,幾乎有一半的前向計算時間被花費于全連接層,就Fast R-CNN而言,RoI池化層后的全連接層需要進行約2k次【每個建議框都要計算】,因此在Fast R-CNN中可以采用SVD分解加速全連接層計算;
具體如何實現(xiàn)呢??
物體分類和窗口回歸都是通過全連接層實現(xiàn)的,假設全連接層輸入數(shù)據(jù)為 x ,輸出數(shù)據(jù)為 y ,全連接層參數(shù)為 W ,尺寸為 u×v ,那么該層全連接計算為: y=Wx,計算復雜度為 u×v ;
若將W進行SVD分解,并用前t個特征值近似代替,即:
那么原來的前向傳播分解成兩步:
計算復雜度為 u×t+v×t ,若 t<min(u,v)t<min(u,v) ,則這種分解會大大減少計算量;
在實現(xiàn)時,相當于把一個全連接層拆分為兩個全連接層,第一個全連接層不含偏置,第二個全連接層含偏置;實驗表明,SVD分解全連接層能使mAP只下降0.3%的情況下提升30%的速度,同時該方法也不必再執(zhí)行額外的微調(diào)操作。
作者:WoPawn?
來源:CSDN?
原文:https://blog.csdn.net/WoPawn/article/details/52463853
四、損失函數(shù)
Fast R-CNN 雖是 two-stage 算法,但可以通過 one-stage 訓練好,這意味著,損失函數(shù)包含多個任務目標:
最后附上 Fast R-CNN 結構圖和具體細節(jié):
(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
最新干貨,我在看??
總結
以上是生活随笔為你收集整理的Fast R-CNN: 我变快了,也变强了!的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 「编程面试题库」,大佬开发的一款小程序~
- 下一篇: Dropout的前世与今生