卷積操作作為卷積神經網絡的核心模塊,在其計算過程中必須考慮圖像「邊緣像素」的卷積方式。查閱資料發現,我們可以採用「卷積之前進行邊界填充」或「卷積之後進行邊界填充兩種方式」,同時邊界填充的具體手段包含常量填充、零填充、鏡像填充以及重複填充等。
在具體分析各種Pad之前,先創建一個2dTensor用於測試後面的填充操作:
x = torch.Tensor([[1, 2], [3, 4]])
創建的Tensor數值分別1、2、3、4:
1、零填充ZeroPad2d
我們最常用的是nn.ZeroPad2d,也就是對Tensor使用0進行邊界填充,我們可以指定tensor的四個方向上的填充數,比如左邊添加1dim、右邊添加2dim、上邊添加3dim、下邊添加4dim,即指定paddin參數為(1,2,3,4),如下:
pad = nn.ZeroPad2d(padding=(1, 2, 3, 4))
y = pad(x)
得到的y是x在四個方向上按照(1,2,3,4)進行的補零操作,如下圖:
2、常數填充ConstantPad2d
零填充是常數填充的一個特例,常數填充nn.ConstantPad2d()需要我們指定填充所用的常數值value核填充數padding,這裡選擇四個方向上均填充為1dim,即padding為(1,1,1,1),代碼如下:
pad = nn.ConstantPad2d(padding=(1, 1, 1, 1), value=666)
y = pad(x)
得到的y在四周分別用666進行填充:
3、鏡像填充ReflectionPad2d
鏡像填充的方式相比於前面使用固定數值進行填充,有可能獲得更好的卷積結果。鏡像填充封裝在nn.ReflectionPad2d中,其填充方式為新的dim值使用反方向的最下邊元素的值,代碼如下:
pad = nn.ReflectionPad2d(padding=(1, 1, 1, 1))
y = pad(x)
從下圖結果可以看出第一行第一列的4是原來右下角的4,第一行第二列的3原來左下角的3:
4、重複填充ReplicationPad2d
重複填充即重複圖像的邊緣像素值,將新的邊界像素值用邊緣像素值擴展,封裝於nn.ReplicationPad2d()中,同樣可以指定4個方向的填充數量:
pad = nn.ReplicationPad2d(padding=(1, 1, 1, 1))
y = pad(x)
從下圖得到的結果可以看出,填充後邊界像素值是原來的1、2、3、4的複製:
總結:
對於pytorch是在卷積之前還是卷積之後進行padding這個問題,根據【1】中所述,應該是卷積之前進行的填充;上文中dim並不是維度的意思,自己沒有找到合適的詞描述添加的「行或列」,就用了dim一詞;填充方式的選擇對於圖像較小的情況下比較重要,對於尺寸較大的圖像來說如何填充影響可能並不大。
參考:
【1】https://discuss.pytorch.org/t/difference-between-padding-then-convolution-or-convolution-with-padding/33790