標籤:

圖像語義分割入門+FCN/U-Net網路解析

圖像語義分割(Semantic Segmentation)是圖像處理和是機器視覺技術中關於圖像理解的重要一環,也是 AI 領域中一個重要的分支。語義分割即是對圖像中每一個像素點進行分類,確定每個點的類別(如屬於背景、人或車等),從而進行區域劃分。目前,語義分割已經被廣泛應用於自動駕駛、無人機落點判定等場景中。

圖1 自動駕駛中的圖像語義分割

而截止目前,CNN已經在圖像分類分方面取得了巨大的成就,湧現出如VGG和Resnet等網路結構,並在ImageNet中取得了好成績。CNN的強大之處在於它的多層結構能自動學習特徵,並且可以學習到多個層次的特徵:

  1. 較淺的卷積層感知域較小,學習到一些局部區域的特徵;
  2. 較深的卷積層具有較大的感知域,能夠學習到更加抽象一些的特徵。

這些抽象特徵對物體的大小、位置和方向等敏感性更低,從而有助於分類性能的提高。這些抽象的特徵對分類很有幫助,可以很好地判斷出一幅圖像中包含什麼類別的物體。圖像分類是圖像級別的!

圖2 圖像分類

與分類不同的是,語義分割需要判斷圖像每個像素點的類別,進行精確分割。圖像語義分割是像素級別的!但是由於CNN在進行convolution和pooling過程中丟失了圖像細節,即feature map size逐漸變小,所以不能很好地指出物體的具體輪廓、指出每個像素具體屬於哪個物體,無法做到精確的分割。

針對這個問題,Jonathan Long等人提出了Fully Convolutional Networks(FCN)用於圖像語義分割。自從提出後,FCN已經成為語義分割的基本框架,後續演算法其實都是在這個框架中改進而來。

FCN論文地址:FCN paper

FCN原作代碼:FCN github

1 FCN改變了什麼?

對於一般的分類CNN網路,如VGG和Resnet,都會在網路的最後加入一些全連接層,經過softmax後就可以獲得類別概率信息。但是這個概率信息是1維的,即只能標識整個圖片的類別,不能標識每個像素點的類別,所以這種全連接方法不適用於圖像分割。

圖3 全連接層

而FCN提出可以把後面幾個全連接都換成卷積,這樣就可以獲得一張2維的feature map,後接softmax獲得每個像素點的分類信息,從而解決了分割問題,如圖4。

圖4

2 FCN結構

整個FCN網路基本原理如圖5(只是原理示意圖)

  1. image經過多個conv和+一個max pooling變為pool1 feature,寬高變為1/2
  2. pool1 feature再經過多個conv+一個max pooling變為pool2 feature,寬高變為1/4
  3. pool2 feature再經過多個conv+一個max pooling變為pool3 feature,寬高變為1/8
  4. ......
  5. 直到pool5 feature,寬高變為1/32。

圖5 FCN網路結構示意圖

那麼:

  1. 對於FCN-32s,直接對pool5 feature進行32倍上採樣獲得32x upsampled feature,再對32x upsampled feature每個點做softmax prediction獲得32x upsampled feature prediction(即分割圖)。
  2. 對於FCN-16s,首先對pool5 feature進行2倍上採樣獲得2x upsampled feature,再把pool4 feature和2x upsampled feature逐點相加,然後對相加的feature進行16倍上採樣,並softmax prediction,獲得16x upsampled feature prediction。
  3. 對於FCN-8s,首先進行pool4+2x upsampled feature逐點相加,然後又進行pool3+2x upsampled逐點相加,即進行更多次特徵融合。具體過程與16s類似,不再贅述。

作者在原文種給出3種網路結果對比,明顯可以看出效果:FCN-32s < FCN-16s < FCN-8s,即使用多層feature融合有利於提高分割準確性

圖6

3 什麼是上採樣?

說了半天,到底什麼是上採樣?

實際上,上採樣(upsampling)一般包括2種方式:

  1. Resize,如雙線性插值直接縮放,類似於圖像縮放(這種方法在原文中提到)
  2. Deconvolution,也叫Transposed Convolution

什麼是Resize就不多說了,這裡解釋一下Deconvolution。

對於一般卷積,輸入藍色4x4矩陣,卷積核大小3x3。當設置卷積參數pad=0,stride=1時,卷積輸出綠色2x2矩陣,如圖6。

圖6 Convolution forward示意圖

而對於反卷積,相當於把普通卷積反過來,輸入藍色2x2矩陣,卷積核大小還是3x3。當設置反卷積參數pad=0,stride=1時輸出綠色4x4矩陣,如圖7,這相當於完全將圖4倒過來(其他更多卷積示意圖點這裡)。

圖7 Deconvolution forward示意圖

傳統的網路是subsampling的,對應的輸出尺寸會降低;upsampling的意義在於將小尺寸的高維度feature map恢復回去,以便做pixelwise prediction,獲得每個點的分類信息。

圖8 Subsampling vs Upsampling

上採樣在FCN網路中的作用如圖8,明顯可以看到經過上採樣後恢復了較大的pixelwise feature map(其中最後一個層21-dim是因為PACSAL數據集有20個類別+Background)。這其實相當於一個Encode-Decode的過程。

具體的FCN網路結構,可以在FCN Github中查到,可以使用Netscope查看網路結構。這裡解釋裡面的難點:

  • 為了解決圖像過小後 1/32 下採樣後輸出feature map太小情況,FCN原作者在第一個卷積層conv1_1加入pad=100。

layer { name: "conv1_1" type: "Convolution" bottom: "data" top: "conv1_1" param { lr_mult: 1 decay_mult: 1 } param { lr_mult: 2 decay_mult: 0 } convolution_param { num_output: 64 pad: 100 kernel_size: 3 stride: 1 }}

考慮如果不在conv1_1加入pad=100,會發生什麼?

假設輸入圖像高度為h。由於VGG中縮小輸出feature map只在pooling層,經過每個pooling後輸出高度變為:

pool1: h^1=(h-2)/2+1=h/2

pool2: h^2=(h^1-2)/2+1=h/2^2

......

pool5: h^5=(h^4-2)/2+1=h/2^5

很明顯,feature map的尺寸縮小了32倍,接下來是fc6卷積層:

layer { name: "fc6" type: "Convolution" bottom: "pool5" top: "fc6" param { lr_mult: 1 decay_mult: 1 } param { lr_mult: 2 decay_mult: 0 } convolution_param { num_output: 4096 pad: 0 kernel_size: 7 stride: 1 }}

fc6: h^6=(h^5-7)/1+1=(h-192)/2^5

如果不在conv1_1加入pad=100,那麼對於小於192x192的輸入圖像,在反卷積恢復尺寸前已經feature map size = 0!所以在conv1_1添加pad=100的方法,解決輸入圖像大小的問題(但是實際也引入很大的雜訊)。

  • 由於FCN在conv1_1加入pad=100,同時fc6卷積層也會改變feature map尺寸,那麼真實的網路就不可能像原理圖3那樣「完美1/2」。

那麼在特徵融合的時候,如何保證逐點相加的feature map是一樣大的呢?這就要引入crop層了。以fcn-8s score_pool4c為例:

layer { name: "score_pool4c" type: "Crop" bottom: "score_pool4" # 需要裁切的blob bottom: "upscore2" # 用於指示裁切尺寸的blob,和輸出blob一樣大 top: "score_pool4c" # 輸出blob crop_param { axis: 2 offset: 5 }}

在caffe中,存儲數據的方式為:caffe blob = [num, channel, height, width]

  1. 而score_pool4c設置了axis=2,相當於從第2維(index start from 0!)往後開始裁剪,即裁剪height和width兩個維度,同時不改變num和channel緯度
  2. 同時設置crop在height和width緯度的開始點為offset=5

不妨定義:

crop_w = upscore2 blob widthcrop_h = upscore2 blob height

相當於score_pool4c層的輸出:

score_pool4c = score_pool4[ :, :, 5:5+crop_h, 5:5+crop_w]

剛好相當於從score_pool4中切出upscore2大小!這樣就可以進行逐點相加的特徵融合了。

4 U-Net

U-Net原作者官網

U-Net是原作者參加ISBI Challenge提出的一種分割網路,能夠適應很小的訓練集(大約30張圖)。U-Net與FCN都是很小的分割網路,既沒有使用空洞卷積,也沒有後接CRF,結構簡單。

圖9 U-Net網路結構圖

整個U-Net網路結構如圖9,類似於一個大大的U字母:首先進行Conv+Pooling下採樣;然後Deconv反卷積進行上採樣,crop之前的低層feature map,進行融合;然後再次上採樣。重複這個過程,直到獲得輸出388x388x2的feature map,最後經過softmax獲得output segment map。總體來說與FCN思路非常類似。

為何要提起U-Net?是因為U-Net採用了與FCN完全不同的特徵融合方式:拼接!

圖10 U-Net concat特徵融合方式

與FCN逐點相加不同,U-Net採用將特徵在channel維度拼接在一起,形成更「厚」的特徵。所以:

語義分割網路在特徵融合時也有2種辦法:

  1. FCN式的逐點相加,對應caffe的EltwiseLayer層
  2. U-Net式的channel維度拼接融合,對應caffe的ConcatLayer層

記得劃重點哦。

5 我的分割實際應用

理論看完了,看看實際效果。使用一組樹木橫截面樣本(約30張)訓練U-Net模型,用於提取樹木年輪。訓練圖片與標記Ground Truth樣式如下:

圖11 年輪圖像與標記

模型在測試集實際分割效果如圖12:

圖12

隨便調了下,效果還不錯。看了上面的例子,是不是感覺圖像語義分割是不是很有用?

(PS:年輪數據版權是別人的,無法開源)

相比其他大型網路,FCN/U-Net還是蠻簡單的,就不多廢話了。

總結一下,CNN圖像語義分割也就基本上是這個套路:

  1. 下採樣+上採樣:Convlution + Deconvlution/Resize
  2. 多尺度特徵融合:特徵逐點相加/特徵channel維度拼接
  3. 獲得像素級別的segement map:對每一個像素點進行softmax判斷類別

作為一篇入門文章,讀完後如果可以理解這3個方面,也就可以了;當然CNN圖像語義分割也算入門了。

Reference:

余俊:FCN學習:Semantic Segmentation

推薦閱讀:

TAG:語義 |