SSD圖像識別代碼學習筆記

看代碼之前先簡述一下SSD的做法:圖片被送進網絡之後先生成一系列feature map,傳統一點的框架會在feature map(或者原圖)上進行region proposal提取出可能有物體的部分然後進行分類,這一步可能非常費時,所以SSD就放棄了region proposal,而選擇直接生成一系列defaul box(或者叫prior box),然後將這些default box迴歸到正確的位置上去,整個過程通過網絡的一次前向傳播就可以完成,非常方便,如下圖所示。思路類似的算法還有YOLO,不過精度比SSD差了不少。

 

prior_box_layer

這一層完成的是給定一系列feature map後如何在上面生成prior boxSSD的做法很有意思,對於輸入大小是 W×H feature map,生成的prior box中心就是 W×H 個,均勻分佈在整張圖上,像下圖中演示的一樣。在每個中心上,可以生成多個不同長寬比的prior box,如[1/3, 1/2, 1, 2,3]。所以在一個feature map上可以生成的prior box總數是 W×H×length_of_aspect_ratio ,對於比較大的feature map,如VGGconv4_3,生成的prior box可以達到數千個。當然對於邊界上的box,還要做一些處理保證其不超出圖片範圍,這都是細節了。

這裏,先弄清楚下文所說的 defaultbox 以及 featuremap cell 是什麼。看下圖:

·        featuremap cell 就是將 feature map 切分成 8×8 或者 4×4 之後的一個個 格子

·         default box 就是每一個格子上,一系列固定大小的 box,即圖中虛線所形成的一系列 boxes

這裏需要注意的是,雖然priorbox的位置是在 W×H 的格子上,但prior box的大小並不是跟格子一樣大,而是人工指定的,原論文中隨着featuremap從底層到高層,priorbox的大小在0.20.9之間均勻變化。

這裏需要注意的是,雖然priorbox的位置是在 W×H 的格子上,但priorbox的大小並不是跟格子一樣大,而是人工指定的,原論文中隨着feature map從底層到高層,prior box的大小在0.20.9之間均勻變化。


一開始看SSD的時候很困擾我的一點就是形狀的匹配問題:SSD用卷積層做bbox的擬合,輸出的不應該是feature map嗎,怎麼能正好輸出4個座標呢?

這裏的做法有點暴力,比如需要輸出 W×H×length_of_aspect_ratio×4 個座標,就直接用 length_of_aspect_ratio×4 channel的卷積層做擬合,這樣就得到 length_of_aspect_ratio×4 個大小爲 W×H feature map,然後把feature map拉成一個長度爲 W×H×length_of_aspect_ratio×4 的向量,用SmoothL1之類的loss去擬合,效果還意外地不錯……

multibox_loss_layer

FindMatches

我們已經在圖上畫出了prior box,同時也有了ground truth,那麼下一步就是將prior box匹配到ground truth上,這是在 src/caffe/utlis/bbox_util.cpp  FindMatches 函數裏完成的。值得注意的是這裏不光是給每個groudtruth box找到了最匹配的prior box,而是給每個prior box都找到了匹配的groundtruth box(如果有的話),這樣顯然大大增大了正樣本的數量。

MineHardExamples

給每個prior box找到匹配(包括物體和背景)之後,似乎可以定義一個損失函數,給每個prior box標記一個label,扔進去一通訓練。但需要注意的是,任意一張圖裏負樣本一定是比正樣本多得多的,這種嚴重不平衡的數據會嚴重影響模型的性能,所以對prior box要有所選擇。這一步是在src/caffe/utlis/bbox_util.cpp  MineHardExamples 函數裏完成的,我沒細看= =

EncodeLocPrediction&& EncodeConfPrediction

因爲我們對prior box是有選擇的,所以數據的形狀在這裏已經被打亂了,沒辦法直接在後面連接一個lossCaffe等框架需要每一層的輸入是四維張量),所以需要我們把選出來的數據重新整理一下,這一步是在 src/caffe/utlis/bbox_util.cpp  EncodeLocPrediction  EncodeConfPrediction 兩個函數裏完成的。

訓練

Wei Liu等人在這裏的實現方法是在multibox_loss_layer裏又實例化了兩個loss_layer,前向傳播的時候需要先經過前面三步,然後把數據手動餵給loss,反向傳播的時候也需要手動把殘差從loss取出來寫回給前面的卷積層。

SSD的特殊之處主要體現在以下3點:

(1)多尺度的特徵圖檢測(Multi-scale),如SSD同時使用了上圖所示的8*8的特徵圖和4*4特徵圖。

(2)相比於YOLO,作者使用的是卷積層來代替了YOLO的全連接層做預測。(如下圖所示)

(3)SSD使用了默認的邊界框+(1,2/1,3/1,1/2,1/3)6個框來做檢測(aspectratios)

在訓練時,本文的 SSD 與那些用 region proposals + pooling 方法的區別是,SSD 訓練圖像中的 groundtruth 需要賦予到那些固定輸出的 boxes 上。在前面也已經提到了,SSD 輸出的是事先定義好的,一系列固定大小的 bounding boxes

如下圖中,狗狗的 groundtruth 是紅色的 bounding boxes,但進行 label 標註的時候,要將紅色的 groundtruth box 賦予圖(c)中一系列固定輸出的 boxes 中的一個,即圖(c)中的紅色虛線框。 

事實上,文章中指出,像這樣定義的 groundtruth boxes 不止在本文中用到。在 YOLO 中,在 FasterR-CNN中的 region proposal階段,以及在 MultiBox 中,都用到了。

當這種將訓練圖像中的 groundtruth 與固定輸出的 boxes 對應之後,就可以 end-to-end 的進行 loss function 的計算以及 back-propagation 的計算更新了。

訓練中會遇到一些問題:

  • 選擇一系列 default boxes
  • 選擇上文中提到的 scales 的問題
  • hard negative mining
  • 數據增廣的策略

下面會談本文的解決這些問題的方式,分爲以下下面的幾個部分。 

Matching strategy

如何將 groundtruth boxes default boxes 進行配對,以組成 label 呢?

在開始的時候,用 MultiBox 中的 best jaccard overlap 來匹配每一個 ground truth box default box,這樣就能保證每一個 groundtruth box與唯一的一個 default box 對應起來。

但是又不同於 MultiBox ,本文之後又將 default box 與任何的 groundtruth box 配對,只要兩者之間的jaccard overlap 大於一個閾值,這裏本文的閾值爲 0.5 

Training objective

SSD 訓練的目標函數(training objective)源自於 MultiBox 的目標函數,但是本文將其拓展,使其可以處理多個目標類別。用 xpij=1 表示  i  default box  類別 p   j  ground truth box 相匹配,否則若不匹配的話,則 xpij=0

根據上面的匹配策略,一定有 ixpij≥1,意味着對於  j  ground truth box,有可能有多個 default box與其相匹配。

總的目標損失函數(objective loss function)就由 localization lossloc  confidence lossconf 的加權求和: 

L(x,c,l,g)=1N(Lconf(x,c)+αLloc(x,l,g))

其中:

  • N 是與 ground truth box 相匹配的 default boxes 個數
  • localization lossloc 是 Fast R-CNN Smooth L1 Loss,用在 predict boxl 與 ground truth boxg 參數(即中心座標位置,width、height)中,迴歸 bounding boxes 的中心位置,以及 width、height
  • confidence lossconf 是 Softmax Loss,輸入爲每一類的置信度 c
  • 權重項 α,設置爲 1

·        Choosing scales and aspect ratios fordefault boxes

·        大部分 CNN 網絡在越深的層,feature map 的尺寸(size)會越來越小。這樣做不僅僅是爲了減少計算與內存的需求,還有個好處就是,最後提取的 feature map 就會有某種程度上的平移與尺度不變性。

·        同時爲了處理不同尺度的物體,一些文章,如 ICLR 2014, Overfeat: Integratedrecognition, localization and detection using convolutional networks,還有 ECCV2014, Spatial pyramid pooling in deep convolutional networks for visualrecognition,他們將圖像轉換成不同的尺度,將這些圖像獨立的通過 CNN 網絡處理,再將這些不同尺度的圖像結果進行綜合。

·        但是其實,如果使用同一個網絡中的、不同層上的 feature maps,也可以達到相同的效果同時在所有物體尺度中共享參數

·        之前的工作,如 CVPR 2015, Fully convolutionalnetworks for semantic segmentation,還有 CVPR 2015, Hypercolumns forobject segmentation and fine-grained localization 就用了 CNN 前面的 layers,來提高圖像分割的效果,因爲越底層的 layers,保留的圖像細節越多。文章 ICLR 2016, ParseNet: Lookingwider to see better 也證明了以上的想法是可行的。

·        因此,本文同時使用 lower feature mapsupper feature maps predict detections。下圖展示了本文中使用的兩種不同尺度的 feature map8×8 feature map,以及 4×4  feature map 

一般來說,一個 CNN 網絡中不同的 layers 有着不同尺寸的感受野(receptive fields。這裏的感受野,指的是輸出的 feature map 上的一個節點,其對應輸入圖像上尺寸的大小

所幸的是,SSD 結構中,default boxes 不必要與每一層 layer receptive fields 對應。本文的設計中,feature map 中特定的位置,來負責圖像中特定的區域,以及物體特定的尺寸。加入我們用 m  feature maps 來做 predictions,每一個 feature map default box 的尺寸大小計算如下: 

sk=smin+smaxsminm−1(k−1),          k[1,m]


其中,smin 取值 0.2smax 取值 0.95,意味着最低層的尺度是 0.2,最高層的尺度是 0.95,再用不同 aspect ratio default boxes,用 ar 來表示:ar={1,2,3,12,13},則每一個 default boxes widthheight 就可以計算出來: 

wak=skar−−√hak=sk/ar−−√


對於 aspect ratio 1 時,本文還增加了一個 default box,這個 box scale  sk=sksk+1−−−−−√。所以最終,在每個 feature map location 上,有 6 default boxes

每一個 default box 的中心,設置爲:(i+0.5|fk|,j+0.5|fk|),其中,|fk| 是第 k  feature map 的大小,同時,i,j[0,|fk|)

在結合 feature maps 上,所有不同尺度、不同 aspect ratios default boxes,它們預測的 predictions 之後。可以想見,我們有許多個 predictions,包含了物體的不同尺寸、形狀。如下圖,狗狗的 ground truth box  4×4 feature map 中的紅色 box 吻合,所以其餘的 boxes 都看作負樣本。 

Hard negativemining

在生成一系列的 predictions 之後,會產生很多個符合 ground truth box predictions boxes,但同時,不符合 ground truth boxes 也很多,而且這個 negative boxes,遠多於 positive boxes。這會造成 negative boxespositive boxes 之間的不均衡。訓練時難以收斂。

因此,本文采取,先將每一個物體位置上對應 predictionsdefault boxes)是 negative boxes 進行排序,按照 default boxes confidence 的大小。選擇最高的幾個,保證最後 negativespositives 的比例在 3:1

本文通過實驗發現,這樣的比例可以更快的優化,訓練也更穩定。 

 

Model

SSD 是基於一個前向傳播 CNN 網絡,產生一系列 固定大小(fixed-size  bounding boxes,以及每一個 box 中包含物體實例的可能性,即 score。之後,進行一個 非極大值抑制(Non-maximum suppression 得到最終的 predictions

 

SSD模型的最開始部分,本文稱作 base network,是用於圖像分類的標準架構。在 base network 之後,本文添加了額外輔助的網絡結構:

·        Multi-scalefeature maps for detection 
在基礎網絡結構後,添加了額外的卷積層,這些卷積層的大小是逐層遞減的,可以在多尺度下進行 predictions

·        Convolutionalpredictors for detection 
每一個添加的特徵層(或者在基礎網絡結構中的特徵層),可以使用一系列 convolutional filters,去產生一系列固定大小的 predictions,具體見 Fig.2。對於一個大小爲 m×n,具有 p 通道的特徵層,使用的convolutional filters 就是 3×3×p  kernels。產生的 predictions,要麼就是歸屬類別的一個得分,要麼就是相對於 default box coordinate shape offsets 
在每一個 m×n 的特徵圖位置上,使用上面的 3×3  kernel,會產生一個輸出值。boundingbox offset 值是輸出的 default box 與此時 feature map location 之間的相對距離(YOLO 架構則是用一個全連接層來代替這裏的卷積層)。

·        Defaultboxes and aspect ratios 
每一個 box 相對於與其對應的feature map cell 的位置是固定的。在每一個 feature map cell 中,我們要 predict 得到的 box  default box 之間的 offsets,以及每一個 box 中包含物體的 score(每一個類別概率都要計算出)。 
因此,對於一個位置上的 k boxes 中的每一個 box,我們需要計算出 c 個類,每一個類的score,還有這個 box 相對於 它的默認 box  4 個偏移值(offsets)。於是,在 featuremap 中的每一個feature map cell 上,就需要有 (c+4k  filters。對於一張 m×n 大小的 feature map,即會產生 (c+4k×m×n 個輸出結果。

這裏的 default box 很類似於 FasterR-CNN 中的 Anchor boxes,關於這裏的 Anchor boxes,詳細的參見原論文。但是又不同於 Faster R-CNN 中的,本文中的 Anchor boxes 用在了不同分辨率的 feature maps 上。

Experimental Results

Base network and hole filling algorithm

本文的 Base network 是基於 ICLR 2015, VGG16 來做的,在 ILSVRC CLS-LOC 數據集上進行了預訓練。

 ICLR 2015, DeepLab-LargeFOV 的工作類似,本文將 VGG 中的 FC6 layerFC7 layer 轉成爲卷積層,並從模型的 FC6FC7 上的參數,進行採樣得到這兩個卷積層的 parameters

還將 Pool5 layer 的參數,從 2×2−s2 轉變成 3×3−s1,外加一個 pad1),如下圖: 


但是這樣變化後,會改變感受野(receptive field)的大小。因此,採用了 atrous algorithm 的技術,這裏所謂的 atrousalgorithm,我查閱了資料,就是 holefilling algorithm(孔填充算法)

DeepLab 的主頁上:http://liangchiehchen.com/projects/DeepLab.html,有一張如下的圖: 

博客 1http://www.cnblogs.com/jianyingzhou/p/5386222.html

最早用的就是 deeplab 的文章了,Semantic Image Segmentation with Deep Convolutional Nets and FullyConnected CRFS 這篇文章和 fcn 不同的是,在最後產生 score map 時,不是進行upsampling,而是採用了 hole algorithm,就是在 pool4 pool 5層,步長由 2 變成 1,必然輸出的 score map 變大了,但是 receptive field 也變小了,爲了不降低 receptive field,怎麼做呢?利用 hole algorithm,將卷積 weights 膨脹擴大,即原來卷積核是 3x3,膨脹後,可能變成 7x7 了,這樣 receptive field 變大了,而 score map 也很大,即輸出變成 dense(密集)的了。

這麼做的好處是,輸出的 scoremap 變大了,即是 dense 的輸出了,而且 receptive field 不會變小,而且可以變大。這對做分割、檢測等工作非常重要。

 

keras卷積補零相關的border_mode的選擇以及padding的操作

1、 keras卷積操作中border_mode的實現

總結:如果卷積的方式選擇爲same,那麼卷積操作的輸入和輸出尺寸會保持一致。如果選擇valid,那捲積過後,尺寸會變小。

 代碼解讀

num_priors = 6

x =Dense(num_priors * 4, name='pool6_mbox_loc_flat')(net['pool6'])

即爲x= Dense(24,name='pool6_mbox_loc_flat')(net['pool6'])

24爲該層輸出維度,模型中非首層的全連接層其輸入維度可以自動推斷,在此處爲首層全連接層

num_classes=21

name ='pool6_mbox_conf_flat'

x =Dense(num_priors * num_classes, name=name)(net['pool6'])

即爲:

num_classes=21

name ='pool6_mbox_conf_flat'

x = Dense(126,name=name)(net['pool6'])

 

 

Flatten

keras.layers.core.Flatten()

Flatten層用來將輸入壓平,即把多維的輸入一維化,常用在從卷積層到全連接層的過渡。Flatten不影響batch的大小。

例子

model= Sequential()

model.add(Convolution2D(64, 3, 3,

            border_mode='same',

            input_shape=(3, 32, 32)))

# now: model.output_shape == (None, 64, 32, 32)

 

model.add(Flatten())

# now: model.output_shape == (None, 65536)


Reshape

keras.layers.core.Reshape(target_shape)

Reshape層用來將輸入shape轉換爲特定的shape

參數

·        target_shape:目標shape,爲整數的tuple,不包含樣本數目的維度(batch大小)

輸入shape

任意,但輸入的shape必須固定。當使用該層爲模型首層時,需要指定input_shape參數

輸出shape

(batch_size,)+target_shape

例子

# as first layer in a Sequential model

model= Sequential()

model.add(Reshape((3, 4), input_shape=(12,)))

# now: model.output_shape == (None, 3, 4)

# note: `None` is the batch dimension

 

# as intermediate layer in a Sequential model

model.add(Reshape((6, 2)))

# now: model.output_shape == (None, 6, 2)

 

# also supports shape inference using `-1` as dimension

model.add(Reshape((-1, 2, 2)))

# now: model.output_shape == (None, 3, 2, 2)

數據增強

主要函數:ImageDataGenerator 實現了大多數上文中提到的圖像幾何變換方法.

·        rotation_range: 旋轉範圍, 隨機旋轉(0-180);

·        width_shift and height_shift: 隨機沿着水平或者垂直方向,以圖像的長寬小部分百分比爲變化範圍進行平移;

·        rescale: 對圖像按照指定的尺度因子, 進行放大或縮小, 設置值在0 - 1之間,通常爲1 / 255;

·        shear_range: 水平或垂直投影變換參考這裏 https://keras.io/preprocessing/image/

·        zoom_range: 按比例隨機縮放圖像尺寸;

·        horizontal_flip: 水平翻轉圖像;

·        fill_mode: 填充像素, 出現在旋轉或平移之後.

 

Input=imag  ->output:爲Box coordinate(4 numbers)這是卷積神經網絡預測的

                     Correct output (4 numbers)

兩者比較,得出Loss爲歐氏距離去算差異值

有準確的label值,groundtruth是給定的標籤,它有(X,Y,W,H).使得卷積神經網絡預測出的框不斷擬合給定輸入,我們做的事,就是不斷減小loss值。

SGD反向傳播,不斷改變參數,直到最後,神經網絡預測的框非常接近groudtruth的值。

這樣使得框能準確框。

以上過程叫做location(迴歸)的訓練過程

 

Classification和

最終的final conv feature map要利用到高維特徵,把它給到兩個模塊上

一個是用於class scores ,概率

一個是Box coordinate,座標

 

網絡訓練時,分類用softmax計算loss

計算座標loss用歐氏距離

 

Regression head(迴歸模塊)加在哪裏?

1種加在最後一,積之後,VGG

一種加在全連接層之後,R-CNN

實際試一下,進行對比,才知道那個位置最合適。

Sliding window(滑動窗口)

不斷滑動窗口,來進行擬合

Network input爲3*221*221,滑動擬合Largerimage爲3*257*257

Scale變換之後,相當於金字塔

Region proposal(區域建議)

可以用selective search進行先框出一部分,即紋理相同的框起來,進行合併,框出一部分典型的框,對於R-CNN一幅圖可以框出2000個框,對固化的特徵進行分類。

R-CNN將最後一層改變了,將池化層最後獲取的特徵固化到磁盤上

R-CNN訓練,用SVM訓練分類器

FastRCNN改進:實現了權重共享,缺點:找框太費時間了

FasterRCNN改進主要在test上時間的提升,在卷積之後找框,採用Region proposal network(RPN)的方法,所有的訓練分類都是在卷積上面完成的。

最大的改進,在測試時對於一個3*3大小的滑動框,可以生成9個anchor(候選框),在卷積之後提取框了之後進行分類或者回歸。

 

不管是任何時候的機器學習,它的特徵圖大小要一樣,採用Rol pooling將9個框弄成一樣大小的。

Data augmentation

Horizon flips水平翻轉、Random crops/scales(隨機裁剪、縮放)、translation(平移)、rotation(角度變換,對整張圖片進行進行小角度的旋轉)、stretching、shearing

在做數據增強時,所有的方法一起進行,隨機進行組合 ,使得數據沒有特徵可循

數據量大約是原來的10倍

Transfer learning

當時數據量達不到要求時,把別人訓練好的模型拿過來借用一下。

 

發佈了5 篇原創文章 · 獲贊 27 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章