卷积层的类参数如下:
torch.nn.Conv2d(in_channels, out_channels, kernel_size, stride=1, padding=0, dilation=1, groups=1, bias=True,padding_mode='zeros')
图1 示例 |
---|
如果我们要实现这样完成图1功能的模块,要怎么搭建?
先看一下卷积层的参数:
① in_channels为卷积层输入通道数(上图为3),out_channels为输出的通道数(上图为64),kernel_size为卷积层的卷积核大小(上图为7),padding为填充的长度(会在input两边每边填padding长度),stride为卷积核移动的步长(上图为2)。
② dilation为空洞卷积的参数,表示卷积核中两两卷积点插入(dilation-1)个空白,默认为1即不插入,如果是3X3卷积核,设置dilation为2,则卷积核大小变为5X5,见下图 。更多详情可见 如何理解空洞卷积(dilated convolution)?
图2 空洞卷积示意 图源1 |
---|
③ groups为分组卷积的参数。作用就是将输入的通道数分为groups组,每个组内与各自的卷积核卷积得到各自的输出,最后将输出合并在一起。
图3 分组卷积示意 图源2 |
---|
用图3来分析,假设卷积核大小为3,如果要从12个channels变成6个channels,卷积层需要6个 12通道3×3大小的卷积核,即该卷积层的权重shape=(6,12,3,3),偏置shape为6(默认bias=True),该层参数量为(out_channels×in_channels×kernel_size[0]×kernel_size[1]+out_channels)=(6×12×3×3+6)。
如果设置groups=3(in_channels和out_channels必须能被groups整除),则一组内有4(in_channels/groups)个channel,而组内需要输出2(out_channels/groups)个输出channel,因此卷积层的参数量为(3×2×4×3×3+6)。
下面是示例代码:
layer=nn.Conv2d(12,6,3,1,groups=1)
for name,x in layer.named_parameters():
print(name,type(x),x.size())
图4 左为groups=1,右为groups=3的卷积层参数 |
---|
顺便提一嘴,卷积层的权重weight形状为(out_channels,in_channels/groups,kernel_size[0],kernel_size[1]),bias形状为(out_channels), 用分组卷积的卷积层的weight参数量是原来卷积层的1/groups 。
根据 图1,不使用空洞卷积(即dilation==1)的情况下,该部分输出的size(76,47)为(304,228)的1/4,又卷积和池化stride=2,因此卷积层要让输入size从(304,228)变成(152,114),池化层要让它从(152,114)变成(76,57).根据卷积计算公式
,可以计算得到卷积层paddng=3,池化层padding=1。下面是搭完整个模块的代码:
至于bias为什么为False,因为后面有批归一化操作。令卷积层输出结果y=wx+b,y作为BatchNorm层的输入x,见图5第3步,分子部分:输入减去输入的均值,偏置消掉了,分母部分:方差不受偏置b的影响。(不懂请自己补充概率论相关知识)
所以卷积层后若加BatchNorm,最好是不设置偏置。
图5 批归一化部分过程
图源:
vdumoulin/conv_arithmetic ↩︎
Group Convolution 分组卷积 ↩︎