卷积操作作为卷积神经网络的核心模块,在其计算过程中必须考虑图像“边缘像素”的卷积方式。查阅资料发现,我们可以采用“卷积之前进行边界填充”或“卷积之后进行边界填充两种方式”,同时边界填充的具体手段包含常量填充、零填充、镜像填充以及重复填充等。
比起使用卷积自带的填充方式,提前填充有更强的功能有更大的自由,更为推荐。
在具体分析各种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一词;填充方式的选择对于图像较小的情况下比较重要,对于尺寸较大的图像来说如何填充影响可能并不大。
参考: