谈谈1×1卷积核的作用
最近在看yolo3,发现对于1×1的卷积核的理解有些遗忘,借此强化一下记忆。
最早我对此有些疑惑,1×1卷积核不会改变高(Height)和宽(Width)(在stride和padding等其他参数为默认状态时), 但**通道数(Channel)**可以随意变化,例如在pytorch中:
情况1,不变,加入了非线性的因素
nn. Conv2d(256, 256, kernel_size=1)
情况2,通道数增加(升维)
nn. Conv2d(256, 512, kernel_size=1)
情况3,通道数下降(降维)
nn. Conv2d(256, 128, kernel_size=1)
总结
可以理解为加入了非线性的一些因素,对通道进行非线性重组,使得不同通道内的信息能够交互(例如从64层缩小到32层),因为卷积运算不同于普通运算。
一般1×1都是用来做bottleneck的,先做1×1缩小,再做3×3放大。经过bottleneck可以有效缩小参数的规模,从而减少计算量,且在降维之后对数据的训练和特征提取将更加有效。
在yolo3中是这样出现的:
def conv2d(filter_in, filter_out, kernel_size): #该函数与本文主要内容无关
pad = (kernel_size - 1) // 2 if kernel_size else 0
return nn.Sequential(OrderedDict([
("conv", nn.Conv2d(filter_in, filter_out, kernel_size=kernel_size, stride=1, padding=pad, bias=False)),
("bn", nn.BatchNorm2d(filter_out)),
("relu", nn.LeakyReLU(0.1)),
]))
# 例如:in_filters = 1024, filters_list = [512, 1024], out_filters = 75
def make_last_layers(filters_list, in_filters, out_filter):
m = nn.ModuleList([
# 通过来来回回的自定义conv2d函数缩小参数规模
conv2d(in_filters, filters_list[0], 1), #先缩小,1*1的卷积核
conv2d(filters_list[0], filters_list[1], 3), #再放大,3*3的卷积核
conv2d(filters_list[1], filters_list[0], 1), #先缩小,1*1的卷积核
conv2d(filters_list[0], filters_list[1], 3), #再放大,3*3的卷积核
conv2d(filters_list[1], filters_list[0], 1), #最后缩小,1*1的卷积核(达到通道数为512的目标)
conv2d(filters_list[0], filters_list[1], 3),
nn.Conv2d(filters_list[1], out_filter, kernel_size=1,
stride=1, padding=0, bias=True)
])
return m
(yolo3代码引用自https://blog.csdn.net/weixin_44791964/article/details/105310627)