介紹
本系列文章將會向大家介紹下R-CNN系列深度學(xué)習(xí)網(wǎng)絡(luò)是如何來逐步進化(從檢測精度與執(zhí)行時間兩個方向)以解決物體識別問題的。此篇是該系列文章的第一篇,試圖向大家詳細描述下2014年來自伯克利的Ross Girshick是如何前瞻性地使用深度學(xué)習(xí)CNN網(wǎng)絡(luò)來初次成功解決物體識別問題的。
何為物體檢測(object detection)問題?
物體檢測問題要解決的是如何讓計算機來認識出圖片中的具體物體及它們在圖片中所處的位置。本質(zhì)上它是模式識別學(xué)科的一個基本問題。
物體識別問題的解決方法
過去在深度學(xué)習(xí)網(wǎng)絡(luò)大規(guī)模使用之前一般會使用傳統(tǒng)的機器學(xué)習(xí)方法通過對圖片進行特征工程以選取有效的特征,進而其于所選擇的特征進行建模(如邏輯回歸、SVM、貝葉斯網(wǎng)絡(luò)等)以來識別出圖片之上所具有的位置及其位置。2014年之后,隨著深度學(xué)習(xí)網(wǎng)絡(luò)在分類問題中的成功應(yīng)用(典型的像Alexnet網(wǎng)絡(luò)在2012年的ILSVRC分類識別競賽中取得第一名),越來越多關(guān)注機器學(xué)習(xí)方法的人開始考慮使用深度學(xué)習(xí)方法來解決他們自己領(lǐng)域的問題。其中物體識別問題也是受益于深度學(xué)習(xí)的發(fā)展而被更好地解決。此系列文章都是基于深度學(xué)習(xí)網(wǎng)絡(luò)去解決物體檢測問題。而它也是目前最有效的解決物體檢測問題的方法。
R-CNN物體檢測系統(tǒng)結(jié)構(gòu)
- 下圖是R-CNN用于進行物體檢測的流水線圖。對于此模型,它的輸入為需要檢測物體的圖片,其輸出則是圖片中每個具體的物體名稱以及它們在圖片中所處的位置;
- 對于輸入的每張圖片,先采用傳統(tǒng)的特征區(qū)域提取辦法(此處使用Selective Search方法,其它可選的方法還有objectness,constrained parametric min-cuts (CPMC) 等)提取出固定數(shù)目的
區(qū)域提案來(此處為2000個),然后將每個區(qū)域提案(Region proposal)進行變形為固定大小(此處為227x227)的圖以作為接下來CNN網(wǎng)絡(luò)的輸入; - 每個由上步產(chǎn)生并變形為固定大小的圖經(jīng)過CNN網(wǎng)絡(luò)后輸出為一個特征向量(經(jīng)過了若干CNN層后,由FC層變化為最終的一維特征向量);
- 由上步CNN處理過后的一維特征向量作為接下來SVM的輸入進行SVM物體識別分類,從而決定出此區(qū)域方案屬于哪一類;
- 以上四個步驟都能在下圖中得到反映。但實際上作者還有另外一個處理步驟即使用最后由CNN生成的特征向量來生成邏輯回歸模型以對每個區(qū)域提案在圖片中的位置進行調(diào)整。而此步驟在作者的討論中有提及卻
沒能很好地反映在下圖當(dāng)中。
如何訓(xùn)練此模型?
既然是機器學(xué)習(xí)模型,那么就涉及到如何訓(xùn)練的問題。以下為此模型的詳細訓(xùn)練方法。
- 先使用ILSVRC2012分類數(shù)據(jù)集來預(yù)訓(xùn)練我們上圖中所用到的CNN網(wǎng)絡(luò),此步驟中只使用分類的數(shù)據(jù)集使得我們的CNN網(wǎng)絡(luò)學(xué)會基本的圖像識別(在圖像level上的而不是其上的具體物體,因為此處用到的數(shù)據(jù)集中也
不含有包含物體具體位置信息的Annotation box); - 上個階段完成后,我們使用真正要進行物體檢測的數(shù)據(jù)集(此處為VOC0712數(shù)據(jù)集)所生成的有著固定大小的區(qū)域提案對trained過的CNN網(wǎng)絡(luò)繼續(xù)進行訓(xùn)練(此方法又叫finetune),最終經(jīng)過一定的epochs數(shù)目,
就得到了trained好的我們最終將采用的CNN網(wǎng)絡(luò); - 使用上個步驟trained好的CNN網(wǎng)絡(luò),我們可以將每個圖片上的區(qū)域提案轉(zhuǎn)換為一個定長的(此處為4096)特征向量;將此特征向量作為輸入,我們按下來再訓(xùn)練一個N個(此處N為圖片上物體可能的類別數(shù)目)SVM二分
類模型來解決特征區(qū)域的分類問題,如此就能確定出我們最開始使用Selective Search方法所得到的圖片上的
某個區(qū)域提案有多大的概率屬于哪一類物體; - 至此問題看似完美解決了,可實際中作者實驗卻發(fā)現(xiàn)此方法檢測出的物體的位置存在著較大的偏差。作者于是使用CNN網(wǎng)絡(luò)中Pool5層輸出的feature map作為特征,來重新訓(xùn)練了一個邏輯回歸模型以來對特征提案的
位置信息進行較正,最終得到了較高的MAP值。
實際部署所需的時間及其它性能分析
R-CNN算是首次使用CNN的方法來提取圖片中的特征(有效地避免了傳統(tǒng)機器學(xué)習(xí)算法中特征工程的使用)以進行圖片中物體檢測。與之前的方法相比,它可以使用一個可共享參數(shù)(多個不同的類別之間)的CNN來得到圖片的特征進行再基于此特征對每個類分別訓(xùn)練不同的SVM模型進行后續(xù)的分類。最終在實際平臺上測試時,此方法每處理一張圖片上的區(qū)域提案獲取與相應(yīng)的CNN特征,平均需要在GPU上耗費13s,在CPU上則為53s。作者在論文中還有使用UVA的方法來近似模擬矩陣相乘運算以減少計算時間。 最后在VOC2007數(shù)據(jù)集上,它的MAP值能達到59%。
實際代碼示例
-
使用Selective search方法提取圖中的區(qū)域提案
function boxes = selective_search_boxes(im, fast_mode, im_width)
% Based on the demo.m file included in the Selective Search IJCV code.
% Parameters. Note that this controls the number of hierarchical
% segmentations which are combined.
colorTypes = {'Hsv', 'Lab', 'RGI', 'H', 'Intensity'};
% Here you specify which similarity functions to use in merging
simFunctionHandles = {@SSSimColourTextureSizeFillOrig, ...
@SSSimTextureSizeFill, ...
@SSSimBoxFillOrig, ...
@SSSimSize};
% Thresholds for the Felzenszwalb and Huttenlocher segmentation algorithm.
% Note that by default, we set minSize = k, and sigma = 0.8.
% controls size of segments of initial segmentation.
ks = [50 100 150 300];
sigma = 0.8;
% After segmentation, filter out boxes which have a width/height smaller
% than minBoxWidth (default = 20 pixels).
minBoxWidth = 20;% Comment the following three lines for the 'quality' version if fast_mode colorTypes = colorTypes(1:2); % 'Fast' uses HSV and Lab simFunctionHandles = simFunctionHandles(1:2); % Two different merging strategies ks = ks(1:2); end idx = 1; for j = 1:length(ks) k = ks(j); % Segmentation threshold k minSize = k; % We set minSize = k for n = 1:length(colorTypes) colorType = colorTypes{n}; [boxesT{idx} blobIndIm blobBoxes hierarchy priorityT{idx}] = ... Image2HierarchicalGrouping(im, sigma, k, minSize, colorType, simFunctionHandles); idx = idx + 1; end end boxes = cat(1, boxesT{:}); % Concatenate boxes from all hierarchies priority = cat(1, priorityT{:}); % Concatenate priorities % Do pseudo random sorting as in paper priority = priority .* rand(size(priority)); [priority sortIds] = sort(priority, 'ascend'); boxes = boxes(sortIds,:); boxes = FilterBoxesWidth(boxes, minBoxWidth); boxes = BoxRemoveDuplicates(boxes); if scale ~= 1 boxes = (boxes - 1) * scale + 1; end R-CNN finetune model prototxt file ( CAFFE )
input: "data"
input_dim: 10
input_dim: 3
input_dim: 227
input_dim: 227
layers {
bottom: "data"
top: "conv1"
name: "conv1"
type: CONVOLUTION
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
convolution_param {
num_output: 96
kernel_size: 11
stride: 4
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layers {
bottom: "conv1"
top: "conv1"
name: "relu1"
type: RELU
}
layers {
bottom: "conv1"
top: "pool1"
name: "pool1"
type: POOLING
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
bottom: "pool1"
top: "norm1"
name: "norm1"
type: LRN
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layers {
bottom: "norm1"
top: "conv2"
name: "conv2"
type: CONVOLUTION
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
convolution_param {
num_output: 256
pad: 2
kernel_size: 5
group: 2
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 1
}
}
}
layers {
bottom: "conv2"
top: "conv2"
name: "relu2"
type: RELU
}
layers {
bottom: "conv2"
top: "pool2"
name: "pool2"
type: POOLING
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
bottom: "pool2"
top: "norm2"
name: "norm2"
type: LRN
lrn_param {
local_size: 5
alpha: 0.0001
beta: 0.75
}
}
layers {
bottom: "norm2"
top: "conv3"
name: "conv3"
type: CONVOLUTION
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
convolution_param {
num_output: 384
pad: 1
kernel_size: 3
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layers {
bottom: "conv3"
top: "conv3"
name: "relu3"
type: RELU
}
layers {
bottom: "conv3"
top: "conv4"
name: "conv4"
type: CONVOLUTION
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
convolution_param {
num_output: 384
pad: 1
kernel_size: 3
group: 2
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 1
}
}
}
layers {
bottom: "conv4"
top: "conv4"
name: "relu4"
type: RELU
}
layers {
bottom: "conv4"
top: "conv5"
name: "conv5"
type: CONVOLUTION
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
convolution_param {
num_output: 256
pad: 1
kernel_size: 3
group: 2
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 1
}
}
}
layers {
bottom: "conv5"
top: "conv5"
name: "relu5"
type: RELU
}
layers {
bottom: "conv5"
top: "pool5"
name: "pool5"
type: POOLING
pooling_param {
pool: MAX
kernel_size: 3
stride: 2
}
}
layers {
bottom: "pool5"
top: "fc6"
name: "fc6"
type: INNER_PRODUCT
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
inner_product_param {
num_output: 4096
weight_filler {
type: "gaussian"
std: 0.005
}
bias_filler {
type: "constant"
value: 1
}
}
}
layers {
bottom: "fc6"
top: "fc6"
name: "relu6"
type: RELU
}
layers {
bottom: "fc6"
top: "fc6"
name: "drop6"
type: DROPOUT
dropout_param {
dropout_ratio: 0.5
}
}
layers {
bottom: "fc6"
top: "fc7"
name: "fc7"
type: INNER_PRODUCT
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
inner_product_param {
num_output: 4096
weight_filler {
type: "gaussian"
std: 0.005
}
bias_filler {
type: "constant"
value: 1
}
}
}
layers {
bottom: "fc7"
top: "fc7"
name: "relu7"
type: RELU
}
layers {
bottom: "fc7"
top: "fc7"
name: "drop7"
type: DROPOUT
dropout_param {
dropout_ratio: 0.5
}
}
layers {
bottom: "fc7"
top: "fc8_pascal"
name: "fc8_pascal"
type: INNER_PRODUCT
blobs_lr: 1
blobs_lr: 2
weight_decay: 1
weight_decay: 0
inner_product_param {
num_output: 21
weight_filler {
type: "gaussian"
std: 0.01
}
bias_filler {
type: "constant"
value: 0
}
}
}
layers {
bottom: "fc8_pascal"
top: "prob"
name: "prob"
type: SOFTMAX
}
參考文獻
- Rich feature hierarchies for accurate object detection and semantic segmentation, Ross Girshick, 2014.
- https://github.com/rbgirshick/rcnn.