1. 程式人生 > >計算機視覺中upsampling(上取樣)的三種方式

計算機視覺中upsampling(上取樣)的三種方式

版權宣告:新建了專注於語義分割的QQ群704803384,歡迎交流!!!    https://blog.csdn.net/u014451076/article/details/79156967
bilinear
雙線性插值是目前在語義分割中用的比較多的一種方式,比如FCN中就是用的這種方法。 
這種方法特點是不需要進行學習,執行速度快,操作簡單。只需要設定好固定的引數值即可,設定的引數就是中心值需要乘以的係數。 
一個簡單的例子可以參考如下(來自網際網路): 

具體的實現方式,可以直接參考fcn.berkerlyvision.org中的surgery.py如下:

def upsample_filt(size):
    """
    Make a 2D bilinear kernel suitable for upsampling of the given (h, w) size.
    """
    factor = (size + 1) // 2
    if size % 2 == 1:
        center = factor - 1
    else:
        center = factor - 0.5
    og = np.ogrid[:size, :size]
    return (1 - abs(og[0] - center) / factor) * \
           (1 - abs(og[1] - center) / factor)
1
2
3
4
5
6
7
8
9
10
11
12
如果看了上面的簡單例項和具體程式碼還不會使用bilinear,就看最後一個例子,這裡以FCN舉例, 
在FCN的berkerly官方caffe實現,以voc-fcn32/train.prototxt舉例,bilinear部分程式碼如下:

layer {
  name: "score_fr"
  type: "Convolution"
  bottom: "fc7"
  top: "score_fr"
  param {
    lr_mult: 1
    decay_mult: 1
  }
  param {
    lr_mult: 2
    decay_mult: 0
  }
  convolution_param {
    num_output: 21
    pad: 0
    kernel_size: 1
  }
}
layer {
  name: "upscore"
  type: "Deconvolution"
  bottom: "score_fr"
  top: "upscore"
  param {
    lr_mult: 0
  }
  convolution_param {
    num_output: 21
    bias_term: false
    kernel_size: 64
    stride: 32
  }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
其中,upscore層使用surgery.py中的upsample_filt函式進行實現(本文第一段程式碼),相當於設定引數type: ‘bilinear’,這個很容易實現。通過測試可以發現,在forward-propagation過程中,score_fr層的blob shape是[1, 21, 16, 16],經過bilinear後變為[1, 21, 544, 544]。依照程式碼簡單分析就可以發現bilinear的具體計算流程如下: 
(1) 64%2 == 0,所以center的座標為(31.5, 31.5),note在python中下標從0開始 
(2) 計算出一個64x64的矩陣,每個位置根據程式碼所示填數,其實就是線性規則 
(3) 二維來看,將score_fr層的16x16的每一個位置的座標放在31.5位置,也就是在相鄰元素之間插入32個位置,周邊補充32個位置,不同元素對插入的不同值有影響,則相互疊加,最後將原來的16x16的元素移除,也就形成了32x17 = 544,也就是具體upscore層算出來的值 
放點東西,形象表示一下: 
32個元素 [16x16中的(0,0)元素] 32個元素 [16x16中的(0,1)元素] 32個元素 … 
其中,中括號中的元素不可見

Deconvolution
Deconvolution是目前爭議比較多的方法,主要是名字上的爭議,由於實現上採用轉置卷積核的方法,所以有人說應該叫(transposed convolution),但是思想上是為了還原原有特徵圖,類似消除原有卷積的某種效果,所以叫反捲積(deconvolution). Caffe中叫deconvolution,這裡就繼續沿用這個名字. 
要理解deconv,要先了解conv的具體是實現方式,在實現過程中,為了使卷積運算更快的執行,通常轉化為矩陣乘法進行處理(因為矩陣乘法有一些加速計算庫)。卷積計算通常的兩種實現方式是:在caffe中使用im2col的方法,在其他的地方使用toeplitz matrix(託普利茲矩陣)進行實現。 
具體例子參看知乎https://www.zhihu.com/question/43609045?sort=created 
為了更容易地實現deconvolution,直接使deconv的前向傳播模擬conv的反向傳播,當然,這裡只是為了保證尺寸大小互逆,並不能保證值的還原。具體思路可以參考這篇部落格http://blog.csdn.net/zsz_shsf/article/details/53201669。 
做幾個小例子幫助理解: 
(1) 關於第一節中bilinear的在caffe中使用deconvolution進行實現,上節的bilinear論述過程中使用固定值計算的方法,本節從deconv視覺化計算的角度進行理解,https://github.com/vdumoulin/conv_arithmetic 
63個元素 [16x16中的(0,0)元素] 31個元素 [16x16中的(0,1)元素] 31個元素 
其中,中括號中的元素可見 
對以上過程進行卷積運算,注意這裡stride 使用1, 最終輸出大小為(63+32x15+64-64)/1 + 1 = 544 
這裡可以腦補一下計算過程,相當於第一節中的手算疊加 
(2) 對bilinear使用轉置運算進行實現,先將64x64的卷積核轉化為toeplitz matrix,然後轉置,得到544x544,256的矩陣,然後將score_fr轉化為1, 256的矩陣,兩者矩陣乘法,得到544x544的最終結果,具體過程腦補吧

unpooling
也就是反池化,不需要學習,用的不是太多,參考論文Visualizing and Understanding Convolutional Networks,還有SegNet和DeconvNet 
簡單原理:在池化過程中,記錄下max-pooling在對應kernel中的座標,在反池化過程中,將一個元素根據kernel進行放大,根據之前的座標將元素填寫進去,其他位置補0 
實現程式碼可以看SegNet的實現

end
簡單捋了一遍,幫助理解
--------------------- 
作者:明天去哪 
來源:CSDN 
原文:https://blog.csdn.net/u014451076/article/details/79156967 
版權宣告:本文為博主原創文章,轉載請附上博文連結!