1. 程式人生 > >Fully Convolutional Networks

Fully Convolutional Networks

文章目錄

  1. 基本概念
  2. 網路結構
  3. 全卷積網路
  4. 反捲積層
  5. 跳級(skip)結構
  6. 模型訓練

FCN是深度學習應用在影象分割的代表作, 是一種端到端(end to end)的影象分割方法, 讓網路做畫素級別的預測直接得出label map, 下面我們來看看FCN是如何做到畫素級別的分類的

論文 : Fully Convolutional Networks for Semantic Segmentation

FCN程式碼及模型

FCN模型結構

基本概念

影象分割以的分類:

  • semantic segmentation

     - 只標記語義, 也就是說只分割出這個類來

  • instance segmentation - 標記例項和語義, 不僅要分割出這個類, 而且要分割出這個人是誰, 也就是具體的例項

網路結構

FCN對影象進行畫素級的分類,從而解決了語義級別的影象分割(semantic segmentation)問題。與經典的CNN在卷積層之後使用全連線層得到固定長度的特徵向量進行分類(全聯接層+softmax輸出)不同,FCN可以接受任意尺寸的輸入影象,採用反捲積層對最後一個卷積層的feature map進行上取樣, 使它恢復到輸入影象相同的尺寸,從而可以對每個畫素都產生了一個預測, 同時保留了原始輸入影象中的空間資訊, 最後在上取樣的特徵圖上進行逐畫素分類。

  • 上圖是語義分割所採用的全卷積網路(FCN)的結構示意圖

全卷積網路

通常CNN網路在卷積層之後會接上若干個全連線層, 將卷積層產生的特徵圖(feature map)對映成一個固定長度的特徵向量。以AlexNet為代表的經典CNN結構適合於影象級的分類和迴歸任務,因為它們最後都得到整個輸入影象的一個概率向量,比如AlexNet的ImageNet模型輸出一個1000維的向量表示輸入影象屬於每一類的概率(softmax歸一化)。

如圖所示,

  • 在CNN中, 貓的圖片輸入到AlexNet, 得到一個長為1000的輸出向量, 表示輸入影象屬於每一類的概率, 其中在“tabby cat”這一類統計概率最高, 用來做分類任務

  • FCN與CNN的區別在於把於CNN最後的全連線層轉換成卷積層,輸出的是一張已經Label好的圖片, 而這個圖片就可以做語義分割

CNN的強大之處在於它的多層結構能自動學習特徵,並且可以學習到多個層次的特徵:

  • 較淺的卷積層感知域較小,學習到一些區域性區域的特徵

  • 較深的卷積層具有較大的感知域,能夠學習到更加抽象一些的特徵

高層的抽象特徵對物體的大小、位置和方向等敏感性更低,從而有助於識別效能的提高, 所以我們常常可以將卷積層看作是特徵提取器

為什麼CNN對畫素級別的分類很難?

  1. 儲存開銷很大。例如對每個畫素使用的影象塊的大小為15x15,然後不斷滑動視窗,每次滑動的視窗給CNN進行判別分類,因此則所需的儲存空間根據滑動視窗的次數和大小急劇上升。
  2. 計算效率低下。相鄰的畫素塊基本上是重複的,針對每個畫素塊逐個計算卷積,這種計算也有很大程度上的重複。
  3. 畫素塊大小的限制了感知區域的大小。通常畫素塊的大小比整幅影象的大小小很多,只能提取一些區域性的特徵,從而導致分類的效能受到限制。

下面我們看一下是如何將全連線層全卷積層的相互轉化:

全連線層和卷積層之間唯一的不同就是卷積層中的神經元只與輸入資料中的一個區域性區域連線,並且在卷積列中的神經元共享引數。然而在兩類層中,神經元都是計算點積,所以它們的函式形式是一樣的。因此,將此兩者相互轉化是可能的:

  1. 對於任一個卷積層,都存在一個能實現和它一樣的前向傳播函式的全連線層。權重矩陣是一個巨大的矩陣,除了某些特定塊,其餘部分都是零。而在其中大部分塊中,元素都是相等的。

  2. 任何全連線層都可以被轉化為卷積層。比如VGG16中第一個全連線層是25088∗409625088∗4096的資料尺寸,將它轉化為512∗7∗7∗4096512∗7∗7∗4096的資料尺寸,即一個K=4096K=4096的全連線層,輸入資料體的尺寸是7∗7∗5127∗7∗512,這個全連線層可以被等效地看做一個F=7,P=0,S=1,K=4096F=7,P=0,S=1,K=4096的卷積層。換句話說,就是將濾波器的尺寸設定為和輸入資料體的尺寸一致7∗77∗7, 這樣輸出就變為1∗1∗40961∗1∗4096, 本質上和全連線層的輸出是一樣的

    • 輸出啟用資料體深度是由卷積核的數目決定的(K=4096)

在兩種變換中,將全連線層轉化為卷積層在實際運用中更加有用。假設一個卷積神經網路的輸入是227x227x3的影象,一系列的卷積層和下采樣層將影象資料變為尺寸為7x7x512的啟用資料體, AlexNet的處理方式為使用了兩個尺寸為4096的全連線層,最後一個有1000個神經元的全連線層用於計算分類評分。我們可以將這3個全連線層中的任意一個轉化為卷積層:

  • 第一個連線區域是[7x7x512]的全連線層,令其濾波器尺寸為F=7,K=4096F=7,K=4096,這樣輸出資料體就為[1x1x4096]
  • 第二個全連線層,令其濾波器尺寸為F=1,K=4096F=1,K=4096,這樣輸出資料體為[1x1x4096]
  • 最後一個全連線層也做類似的,令其F=1,K=1000F=1,K=1000,最終輸出為[1x1x1000]

fcn的輸入圖片為什麼可以是任意大小呢?

首先,我們來看傳統CNN為什麼需要固定輸入圖片大小。

對於CNN,一幅輸入圖片在經過卷積和pooling層時,這些層是不關心圖片大小的。比如對於一個卷積層,outputsize=(inputsize−kernelsize)/stride+1outputsize=(inputsize−kernelsize)/stride+1,它並不關心inputsize多大,對於一個inputsize大小的輸入feature map,滑窗卷積,輸出outputsize大小的feature map即可。pooling層同理。但是在進入全連線層時,feature map(假設大小為n×n)要拉成一條向量,而向量中每個元素(共n×n個)作為一個結點都要與下一個層的所有結點(假設4096個)全連線,這裡的權值個數是4096×n×n,而我們知道神經網路結構一旦確定,它的權值個數都是固定的,所以這個n不能變化,n是conv5的outputsize,所以層層向回看,每個outputsize都要固定,那每個inputsize都要固定,因此輸入圖片大小要固定。

把全連線層的權重W重塑成卷積層的濾波器有什麼好處呢?

這樣的轉化可以在單個向前傳播的過程中, 使得卷積網路在一張更大的輸入圖片上滑動,從而得到多個輸出(可以理解為一個label map)

比如: 我們想讓224×224尺寸的浮窗,以步長為32在384×384的圖片上滑動,把每個經停的位置都帶入卷積網路,最後得到6×6個位置的類別得分, 那麼通過將全連線層轉化為卷積層之後的運算過程為:

  • 如果224×224的輸入圖片經過卷積層和下采樣層之後得到了[7x7x512]的陣列,那麼,384×384的大圖片直接經過同樣的卷積層和下采樣層之後會得到[12x12x512]的陣列, 然後再經過上面由3個全連線層轉化得到的3個卷積層,最終得到[6x6x1000]的輸出((12 – 7)/1 + 1 = 6), 這個結果正是浮窗在原圖經停的6×6個位置的得分

一個確定的CNN網路結構之所以要固定輸入圖片大小,是因為全連線層權值數固定,而該權值數和feature map大小有關, 但是FCN在CNN的基礎上把1000個結點的全連線層改為含有1000個1×1卷積核的卷積層,經過這一層,還是得到二維的feature map,同樣我們也不關心這個feature map大小, 所以對於輸入圖片的size並沒有限制

如下圖所示,FCN將傳統CNN中的全連線層轉化成卷積層,對應CNN網路FCN把最後三層全連線層轉換成為三層卷積層 :


  1. 全連線層轉化為全卷積層 : 在傳統的CNN結構中,前5層是卷積層,第6層和第7層分別是一個長度為4096的一維向量,第8層是長度為1000的一維向量,分別對應1000個不同類別的概率。FCN將這3層表示為卷積層,卷積核的大小 (通道數,寬,高) 分別為 (4096,1,1)、(4096,1,1)、(1000,1,1)。看上去數字上並沒有什麼差別,但是卷積跟全連線是不一樣的概念和計算過程,使用的是之前CNN已經訓練好的權值和偏置,但是不一樣的在於權值和偏置是有自己的範圍,屬於自己的一個卷積核

  2. CNN中輸入的影象大小是統一固定成227x227大小的影象,第一層pooling後為55x55,第二層pooling後圖像大小為27x27,第五層pooling後的影象大小為13x13, 而FCN輸入的影象是H*W大小,第一層pooling後變為原圖大小的1/2,第二層變為原圖大小的1/4,第五層變為原圖大小的1/8,第八層變為原圖大小的1/16

  3. 經過多次卷積和pooling以後,得到的影象越來越小,解析度越來越低。其中影象到H/32∗W/32H/32∗W/32的時候圖片是最小的一層時,所產生圖叫做heatmap熱圖,熱圖就是我們最重要的高維特徵圖,得到高維特徵的heatmap之後就是最重要的一步也是最後的一步對原影象進行upsampling,把影象進行放大幾次到原影象的大小

相較於使用被轉化前的原始卷積神經網路對所有36個位置進行迭代計算優化模型,然後再對36個位置做預測,使用轉化後的卷積神經網路進行一次前向傳播計算要高效得多,因為36次計算都在共享計算資源。這一技巧在實踐中經常使用,通常將一張影象尺寸變得更大,然後使用變換後的卷積神經網路來對空間上很多不同位置進行評價得到分類評分,然後在求這些分值的平均值。

反捲積層

Upsampling的操作可以看成是反捲積(deconvolutional),卷積運算的引數和CNN的引數一樣是在訓練FCN模型的過程中通過bp演算法學習得到。反捲積層也是卷積層,不關心input大小,滑窗卷積後輸出output。deconv並不是真正的deconvolution(卷積的逆變換),最近比較公認的叫法應該是transposed convolution,deconv的前向傳播就是conv的反向傳播。

  • 反捲積引數: 利用卷積過程filter的轉置(實際上就是水平和豎直方向上翻轉filter)作為計算卷積前的特徵圖
  • 反捲積學習率為00

Ways for Visualizing Convolutional Networks

反捲積的運算如下所示:

藍色是反捲積層的input,綠色是反捲積層的outputFull padding, transposed

Full padding, transposed

  • 上圖中kernelsize=3,stride=1,padding=2kernelsize=3,stride=1,padding=2的反捲積,input是2×2, output是4×4

Zero padding, non-unit strides, transposed

  • 上圖中kernelsize=3,stride=2,padding=1kernelsize=3,stride=2,padding=1的反捲積,input feature map是3×3, 轉化後是5×5, output是5×5

注意: :

A guide to convolution arithmetic for deep learning

怎麼使反捲積的output大小和輸入圖片大小一致,從而得到pixel level prediction?

FCN裡面全部都是卷積層(pooling也看成卷積),卷積層不關心input的大小,inputsize和outputsize之間存線上性關係。
假設圖片輸入為[n×n]大小,第一個卷積層輸出map就為conv1out.size=(n−kernelsize)/stride+1conv1out.size=(n−kernelsize)/stride+1, 記做conv1out.size=f(n)conv1out.size=f(n), 依次類推,conv5out.size=f(conv5in.size)=f(…f(n))conv5out.size=f(conv5in.size)=f(…f(n)), 反捲積是要使n=f′(conv5out.size)n=f′(conv5out.size)成立,要確定f′f′,就需要設定deconvolution層的kernelsize,stride,padding,計算方法如下:

1
2
3
4
5
6
7
8
9
10
11
layer {
 name: "upsample", type: "Deconvolution"
 bottom: "{{bottom_name}}" top: "{{top_name}}"
 convolution_param {
 kernel_size: {{2 * factor - factor % 2}} stride: {{factor}}
 num_output: {{C}} group: {{C}}
 pad: {{ceil((factor - 1) / 2.)}}
 weight_filler: { type: "bilinear" } bias_term: false
 }
 param { lr_mult: 0 decay_mult: 0 }
}
  • factor是指反捲積之前的所有卷積pooling層的累積取樣步長,卷積層使feature map變小,是因為stride,卷積操作造成的影響一般通過padding來消除,因此,累積取樣步長factor就等於反捲積之前所有層的stride的乘積

跳級(skip)結構

對CNN的結果做處理,得到了dense prediction,而作者在試驗中發現,得到的分割結果比較粗糙,所以考慮加入更多前層的細節資訊,也就是把倒數第幾層的輸出和最後的輸出做一個fusion,實際上也就是加和:

實驗表明,這樣的分割結果更細緻更準確。在逐層fusion的過程中,做到第三行再往下,結果又會變差,所以作者做到這裡就停了。

模型訓練

  • 用AlexNet,VGG16或者GoogleNet訓練好的模型做初始化,在這個基礎上做fine-tuning,全部都fine-tuning,只需在末尾加上upsampling,引數的學習還是利用CNN本身的反向傳播原理

  • 採用whole image做訓練,不進行patchwise sampling。實驗證明直接用全圖已經很effective and efficient

  • 對class score的卷積層做全零初始化。隨機初始化在效能和收斂上沒有優勢

FCN例子: 輸入可為任意尺寸影象彩色影象;輸出與輸入尺寸相同,深度為:20類目標+背景=21,模型基於AlexNet

  • 藍色:卷積層
  • 綠色:Max Pooling層
  • 黃色: 求和運算, 使用逐資料相加,把三個不同深度的預測結果進行融合:較淺的結果更為精細,較深的結果更為魯棒
  • 灰色: 裁剪, 在融合之前,使用裁剪層統一兩者大小, 最後裁剪成和輸入相同尺寸輸出
  • 對於不同尺寸的輸入影象,各層資料的尺寸(height,width)相應變化,深度(channel)不變

  • 全卷積層部分進行特徵提取, 提取卷積層(3個藍色層)的輸出來作為預測21個類別的特徵

  • 圖中虛線內是反捲積層的運算, 反捲積層(3個橙色層)可以把輸入資料尺寸放大。和卷積層一樣,升取樣的具體引數經過訓練確定

  1. 以經典的AlexNet分類網路為初始化。最後兩級是全連線(紅色),引數棄去不用

  2. 從特徵小圖(16∗16∗409616∗16∗4096)預測分割小圖(16∗16∗2116∗16∗21),之後直接升取樣為大圖。

    • 反捲積(橙色)的步長為32,這個網路稱為FCN-32s
  3. 升取樣分為兩次完成(橙色×2), 在第二次升取樣前,把第4個pooling層(綠色)的預測結果(藍色)融合進來。使用跳級結構提升精確性

    • 第二次反捲積步長為16,這個網路稱為FCN-16s
  4. 升取樣分為三次完成(橙色×3), 進一步融合了第3個pooling層的預測結果

    • 第三次反捲積步長為8,記為FCN-8s。

其他引數:

  • minibatch:20張圖片

  • learning rate:0.001

  • 初始化:分類網路之外的卷積層引數初始化為0

  • 反捲積引數初始化為bilinear插值。最後一層反捲積固定位bilinear插值不做學習

總體來說,本文的邏輯如下:

  • 想要精確預測每個畫素的分割結果

  • 必須經歷從大到小,再從小到大的兩個過程

  • 在升取樣過程中,分階段增大比一步到位效果更好

  • 在升取樣的每個階段,使用降取樣對應層的特徵進行輔助

缺點:

  1. 得到的結果還是不夠精細。進行8倍上取樣雖然比32倍的效果好了很多,但是上取樣的結果還是比較模糊和平滑,對影象中的細節不敏感

  2. 對各個畫素進行分類,沒有充分考慮畫素與畫素之間的關係。忽略了在通常的基於畫素分類的分割方法中使用的空間規整(spatial regularization)步驟,缺乏空間一致性

論文筆記《Fully Convolutional Networks for Semantic Segmentation》

全卷積網路 FCN 詳解