pytorch 卷积层 padding_mode=‘circular’ 的小 bug

今天在写conv2d卷积的时候发现一个小问题,当我的2D卷积层定义为

nn.Conv2d(self.input_channels,self.hidden_channels, 
self.input_kernel_size, self.input_stride,
self.input_padding, bias=True, padding_mode='circular'))

时,当我的输入shape=(1,2,128,128),输入channel=2,hidden_channel=8,kernel_size=4,stride=2,padding=1时,经过卷积之后我的输出shape=(1,8,63,63),这样官方给的卷积size计算公式不符。输出大小=(输入大小-卷积核大小+2*padding)/步长+1,,out_size = (input_size - K + 2P)/ S +1。

最后发现是padding_mode设定为‘circular’是会出现问题,当使用其他padding_mode('zeros', 'reflect', 'replicate')方式时,会正常计算。而源码中没对这个问题进行解释。

conv2d父类_ConvNd部分:

conv2d源码部分:

因此使用'circular' 模式时需要注意,可能会出现后续处理shape不匹配问题。

import torch
import torch.nn as nn

x = torch.ones((1, 1, 32, 32))
print(x.shape)
conv_zeros = nn.Conv2d(in_channels=1, out_channels=8, kernel_size=4, 
                        stride=2, padding=1, bias=True,)
out1 = conv_zeros(x)
print('默认zeros卷积后的shape= ', out1.shape)
conv_reflect = nn.Conv2d(in_channels=1, out_channels=8, kernel_size=4, 
                        stride=2, padding=1, bias=True, padding_mode='reflect')
out2 = conv_reflect(x)
print('reflect卷积后的shape= ', out2.shape)
conv_replicate = nn.Conv2d(in_channels=1, out_channels=8, kernel_size=4, 
                        stride=2, padding=1, bias=True, padding_mode='replicate')
out3 = conv_replicate(x)
print('replicate卷积后的shape= ', out3.shape)
conv_circular = nn.Conv2d(in_channels=1, out_channels=8, kernel_size=4, 
                        stride=2, padding=1, bias=True, padding_mode='circular')
out4 = conv_circular(x)
print('circular卷积后的shape= ', out4.shape)


# 输出
# torch.Size([1, 1, 32, 32])
# 默认zeros卷积后的shape=  torch.Size([1, 8, 16, 16])
# reflect卷积后的shape=  torch.Size([1, 8, 16, 16])
# replicate卷积后的shape=  torch.Size([1, 8, 16, 16])
# circular卷积后的shape=  torch.Size([1, 8, 15, 15])

conv_circular = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=4, stride=2, padding=1, bias=True, padding_mode='circular')
out4 = conv_circular(x)
print('circular卷积后', out4[0, 0].shape)
# circular卷积后 torch.Size([15, 15])

假设我们对原始输入只扩充两个位置(1,0,1,0),最终会得到与padding_mode='circular' 一样的结果,因此可以断定,当启用这个模式时,其填充方式是1*padding,而不是2*padding。

import torch
import torch.nn as nn
import torch.nn.functional as F

x = torch.ones((1, 1, 32, 32))
padded_tensor = F.pad(x, pad=(1, 0, 1, 0), mode='constant', value=0)
print(padded_tensor.shape)  # torch.Size([1, 1, 33, 33])

conv = nn.Conv2d(in_channels=1, out_channels=1, kernel_size=4, stride=2)
out = conv(padded_tensor)
print('circular卷积后', out.shape)  # 卷积后 torch.Size([1, 1, 15, 15])


因此可以得出结论,padding_mode 的默认'zeros' 模式(及replicate,reflect)是在两边各扩展 一块 size 为 padding 的0,一共 填充了 size 为 2*padding 的数据 ,也就是假设原来是128*128,填充之后是130*130;

而 'circular' 模式是将 padding/2,再在两边填充数据,一共填充了 size 为 padding 的数据,也就是shape为129*129。

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值