conv2d的输入_PyTorch Conv2d中的四种填充模式解析

本文首发自【简书】用户【西北小生_】的博客,未经允许,禁止转载!

PyTorch二维卷积函数 torch.nn.Conv2d() 有一个“padding_mode”的参数,可选项有4种:'zeros', 'reflect',

'replicate' or 'circular',其默认选项为'zeros',也就是零填充。这四种填充方式到底是怎么回事呢?

padding_mode (string, optional): `'zeros'`, `'reflect'`,

`'replicate'` or `'circular'`. Default: `'zeros'`

为了直观的观察这4种填充方式,我们定义一个1*1卷积,并将卷积核权重设置为1,这样在进行不同填充方式的卷积计算后,我们即可得到填充后的矩阵。本例中我们生成一个由1~16组成的4*4矩阵,对其进行不同填充方式的卷积计算。

# 定义一个由1~16组成的高和宽维度为4*4的矩阵作为卷积输入,由于2维卷积只能处理4维的输入,故增加两个维度

In [51]: x = torch.nn.Parameter(torch.reshape(torch.range(1,16),(1,1,4,4)))

# 查看定义的输入

In [52]: x

Out[52]:

Parameter containing:

tensor([[[[ 1., 2., 3., 4.],

[ 5., 6., 7., 8.],

[ 9., 10., 11., 12.],

[13., 14., 15., 16.]]]], requires_grad=True)

1.'zeros'

'zeros'就是最常见的零填充,即在矩阵的高、宽两个维度上用0进行填充,填充时将在一个维度的两边都进行填充。

# 定义一个1*1卷积,设置填充模式为'zeros',在高和宽维度上两边各填充1个单位

In [53]: conv_zeros = torch.nn.Conv2d(1,1,1,1,padding=1,padding_mode='zeros',bias=False)

# 查看定义的卷积

In [54]: conv_zeros

Out[54]: Conv2d(1, 1, kernel_size=(1, 1), stride=(1, 1), padding=(1, 1), bias=False)

# 将卷积核的权重设置为1,这样可使卷积后的输出即为填充后的输入矩阵

In [55]: conv_zeros.weight = torch.nn.Parameter(torch.ones(1,1,1,1))

# 查看卷积核权重

In [56]: conv_zeros.weight

Out[56]:

Parameter containing:

tensor([[[[1.]]]], requires_grad=True)

# 进行卷积计算,并输出结果

In [57]: conv_zeros(x)

Out[57]:

tensor([[[[ 0., 0., 0., 0., 0., 0.],

[ 0., 1., 2., 3., 4., 0.],

[ 0., 5., 6., 7., 8., 0.],

[ 0., 9., 10., 11., 12., 0.],

[ 0., 13., 14., 15., 16., 0.],

[ 0., 0., 0., 0., 0., 0.]]]], grad_fn=)

2.'reflect'

'reflect'是以矩阵边缘为对称轴,将矩阵中的元素对称的填充到最外围。

# 定义一个1*1卷积,设置填充模式为'reflect',在高和宽维度上两边各填充1个单位

In [58]: conv_reflect = torch.nn.Conv2d(1,1,1,1,padding=1,padding_mode='reflect',bias=False)

# 将卷积核的权重设置为1,这样可使卷积后的输出即为填充后的输入矩阵

In [59]: conv_reflect.weight = torch.nn.Parameter(torch.ones(1,1,1,1))

# 进行卷积计算,并输出结果

In [60]: conv_reflect(x)

Out[60]:

tensor([[[[ 6., 5., 6., 7., 8., 7.],

[ 2., 1., 2., 3., 4., 3.],

[ 6., 5., 6., 7., 8., 7.],

[10., 9., 10., 11., 12., 11.],

[14., 13., 14., 15., 16., 15.],

[10., 9., 10., 11., 12., 11.]]]], grad_fn=)

3.'replicate'

'replicate'将矩阵的边缘复制并填充到矩阵的外围。

# 定义一个1*1卷积,设置填充模式为'replicate',在高和宽维度上两边各填充1个单位

In [61]: conv_reflect = torch.nn.Conv2d(1,1,1,1,padding=1,padding_mode='replicate',bias=False)

# 将卷积核的权重设置为1,这样可使卷积后的输出即为填充后的输入矩阵

In [62]: conv_reflect.weight = torch.nn.Parameter(torch.ones(1,1,1,1))

# 进行卷积计算,并输出结果

In [63]: conv_replicate(x)

Out[63]:

tensor([[[[ 1., 1., 2., 3., 4., 4.],

[ 1., 1., 2., 3., 4., 4.],

[ 5., 5., 6., 7., 8., 8.],

[ 9., 9., 10., 11., 12., 12.],

[13., 13., 14., 15., 16., 16.],

[13., 13., 14., 15., 16., 16.]]]], grad_fn=)

4.'circular'

顾名思义,'circular'就是循环的进行填充,怎么循环的呢?先看例子:

# 定义一个1*1卷积,设置填充模式为'circular',在高和宽维度上两边各填充1个单位

In [64]: conv_reflect = torch.nn.Conv2d(1,1,1,1,padding=1,padding_mode='circular',bias=False)

# 将卷积核的权重设置为1,这样可使卷积后的输出即为填充后的输入矩阵

In [65]: conv_reflect.weight = torch.nn.Parameter(torch.ones(1,1,1,1))

# 进行卷积计算,并输出结果

In [66]: conv_circular(x)

Out[66]:

tensor([[[[16., 13., 14., 15., 16., 13.],

[ 4., 1., 2., 3., 4., 1.],

[ 8., 5., 6., 7., 8., 5.],

[12., 9., 10., 11., 12., 9.],

[16., 13., 14., 15., 16., 13.],

[ 4., 1., 2., 3., 4., 1.]]]], grad_fn=)

如果将输入矩阵从左到右,从上到下进行无限的重复延伸,即为下面这种形式:

tensor([[[[ 1., 2., 3., 4., 1., 2., 3., 4., 1., 2., 3., 4.],

[ 5., 6., 7., 8., 5., 6., 7., 8., 5., 6., 7., 8.],

[ 9., 10., 11., 12., 9., 10., 11., 12., 9., 10., 11., 12.],

[13., 14., 15., 16., 13., 14., 15., 16., 13., 14., 15., 16.],

[ 1., 2., 3., 4., 1., 2., 3., 4., 1., 2., 3., 4.],

[ 5., 6., 7., 8., 5., 6., 7., 8., 5., 6., 7., 8.],

[ 9., 10., 11., 12., 9., 10., 11., 12., 9., 10., 11., 12.],

[13., 14., 15., 16., 13., 14., 15., 16., 13., 14., 15., 16.],

[ 1., 2., 3., 4., 1., 2., 3., 4., 1., 2., 3., 4.],

[ 5., 6., 7., 8., 5., 6., 7., 8., 5., 6., 7., 8.],

[ 9., 10., 11., 12., 9., 10., 11., 12., 9., 10., 11., 12.],

[13., 14., 15., 16., 13., 14., 15., 16., 13., 14., 15., 16.]]]])

image.png

看出来了吗?如果无限延伸的话这样就是对原始的4*4矩阵的循环,上面的矩阵就是在高和宽维度上都填充4个单位的结果,如果只填充1个单位,那就只截取填充一个单位后的矩阵:

image.png

这就是例子中只填充1个单位的结果。

你可能感兴趣的:(conv2d的输入)