卷積神經網路感受野的計算
學習RCNN系列論文時, 出現了感受野(receptive field)的名詞, 感受野的尺寸大小是如何計算的,在網上沒有搜到特別詳細的介紹, 為了加深印象,記錄下自己對這一感念的理解,希望對理解基於CNN的物體檢測過程有所幫助。
1感受野的概念
在卷積神經網路中,感受野的定義是 卷積神經網路每一層輸出的特徵圖(feature map)上的畫素點在原始影象上對映的區域大小。
RCNN論文中有一段描述,Alexnet網路pool5輸出的特徵圖上的畫素在輸入影象上有很大的感受野(have very large receptive fields (195 × 195 pixels))和步長(strides (32×32 pixels)), 這兩個變數的數值是如何得出的呢?
2感受野大小的計算
感受野計算時有下面的幾個情況需要說明:
(1)第一層卷積層的輸出特徵影象素的感受野的大小等於濾波器的大小
(2)深層卷積層的感受野大小和它之前所有層的濾波器大小和步長有關係
(3)計算感受野大小時,忽略了影象邊緣的影響,即不考慮padding的大小,關於這個疑惑大家可以閱讀一下參考文章2的解答進行理解
這裡的每一個卷積層還有一個strides的概念,這個strides是之前所有層stride的乘積。
即strides(i) =stride(1) *stride(2) * ...*stride(i-1)
關於感受野大小的計算採用top to down的方式, 即先計算最深層在前一層上的感受野,然後逐漸傳遞到第一層,使用的公式可以表示如下:
RF = 1 #待計算的feature map上的感受野大小
for layer in (top layer To down layer):
RF = ((RF -1)* stride) + fsize
stride 表示卷積的步長; fsize表示卷積層濾波器的大小
用python實現了計算VGG16網路每層輸出feature map的感受野大小,實現程式碼:
#!/usr/bin/env python net = {'net': [[3, 1, 1], [3, 1, 1], [2, 2, 0], [3, 1, 1], [3, 1, 1], [2, 2, 0], [3, 1, 1], [3, 1, 1], [3, 1, 1], [2, 2, 0], [3, 1, 1], [3, 1, 1], [3, 1, 1], [2, 2, 0], [3, 1, 1], [3, 1, 1], [3, 1, 1], [2, 2, 0]], 'name': ['conv1_1', 'conv1_2', 'pool1', 'conv2_1', 'conv2_2', 'pool2', 'conv3_1', 'conv3_2', 'conv3_3', 'pool3', 'conv4_1', 'conv4_2', 'conv4_3', 'pool4', 'conv5_1', 'conv5_2', 'conv5_3', 'pool5']} imsize = 224 def outFromIn(isz, net, layernum): totstride = 1 # 這個是當前層與前面層步長的累積 insize = isz for layer in range(layernum): fsize, stride, pad = net[layer] outsize = (insize - fsize + 2 * pad) / stride + 1 insize = outsize totstride = totstride * stride return outsize, totstride def inFromOut(net, layernum): RF = 1 # 最後一層相對前一層的感受野是1 for layer in reversed(range(layernum)): # 從最後一層往前數 t = RF fsize, stride, pad = net[layer] # 得到這一層的fsize,stride,pad RF = ((RF - 1) * stride) + fsize # 最後 # print(t,stride, fsize, RF) return RF if __name__ == '__main__': for i in range(len(net['net'])): # 逐層進行處理 p = outFromIn(imsize, net['net'], i + 1) # 得到當前層的輸出資訊 # print(p[0], p[1]) # if i != 5: # continue rf = inFromOut(net['net'], i + 1) # print(rf, '**') print("Layer Name = %s, Output size = %3d, Stride = % 3d, RF size = %3d" % ( net['name'][i], p[0], p[1], rf))
假如要計算第N層的感受野,總的計算過程就是:從後往前計算,也就是第N層相對前面層的感受野(即第N-1層到第1層)。