在很多模型中都会有一些 1 ∗ 1 1*1 1∗1的卷积层,打眼一看感觉这些layer很鸡肋,不知道放在模型里能起到什么作用。但深入理解一下就能发现,1*1的卷积是非常有用的,可以很灵活地控制特征图的深度,并能起到减少参数量的作用。
本文就基于个人粗浅的理解,简单讨论一下1*1卷积的作用。
1. 升维降维,实现跨通道的信息整合
feature map和1*1的卷积核做卷积时,只需要考虑当前像素即可,并不需要考虑周围的像素值。因此第一个作用主要是可以用来调节feature map的通道数,对不同通道上的像素点进行线性组合,即可实现feature map的升维或降维功能,这也是通道见信息的交互和整合过程。
例如现在的feature map维度是(48, 28, 28),48表示channel,28表示长和宽。如果给定一个1*1的卷积层,输入channel=48,出的channel=32,那么就可以对特征图实现从48维到32维的降维操作。
同样地,只要输出channel大于48,就可以实现升维操作。
2. 减少模型参数量
减少模型参数这一想法最早应该是在GoogleNet中提出的,假设给定如下两个Inception模块:
如上图,现在蓝色方框中,左侧是 3 ∗ 3 3*3 3∗3的卷积,而右侧是 1 ∗ 1 1*1 1∗1和一个 3 ∗ 3 3*3 3∗3的卷积。两者的功能是一样的,即得到的输出维度相同。现在要计算两者的参数量,直觉上来说,单个 3 ∗ 3 3*3 3∗3的卷积参数似乎较少,但事实真的如此吗?
我们假设Previous Layer得到结果的维度是(96, 28, 28),即这个Inception模块的输入是96通道,长宽均为28的feature map,卷积后输出通道为48。假设经过左侧和右侧模块的方框所需要的计算参数分别为p1,p2,则p1和p2的计算公式如下:
p1 = 96 ∗ 3 ∗ 3 ∗ 48 = 41472 96*3*3*48=41472 96∗3∗3∗48=41472
右图中第一个 1 ∗ 1 1*1 1∗1卷积可以先将原始输入降维,假设这里降到32维,则:
p2 = 96 ∗ 1 ∗ 1 ∗ 32 + 32 ∗ 3 ∗ 3 ∗ 48 = 16896 96*1*1*32+32*3*3*48=16896 96∗1∗1∗32+32∗3∗3∗48=16896
注:卷积核的通道数与输入的feature map一致,而卷积核的个数与输出channel一致。
我们惊奇的发现,反而是第二种采用了 1 ∗ 1 1*1 1∗1和 3 ∗ 3 3*3 3∗3两次卷积的结构,拥有更少的训练参数。由此可见,虽然加入了这额外的 1 ∗ 1 1*1 1∗1的卷积层,但竟然可以减少训练的参数。
Resnet中的残差模块使用
1
∗
1
1*1
1∗1卷积核意义也是如此:
假设输入feature map的维度是(256, 28, 28),左侧和右侧模块的参数量分别是p1和p2,那么p1和p2的计算值分别如下(为了追求两者输入输出的一致性,需要把左侧图的64都改为256,且中间只有一层
3
∗
3
∗
256
3*3*256
3∗3∗256的卷积层):
p1 = 256 ∗ 3 ∗ 3 ∗ 256 = 589824 256*3*3*256=589824 256∗3∗3∗256=589824
p1 = 256 ∗ 1 ∗ 1 ∗ 64 + 64 ∗ 3 ∗ 3 ∗ 64 + 64 ∗ 1 ∗ 1 ∗ 256 = 69632 256*1*1*64+64*3*3*64+64*1*1*256=69632 256∗1∗1∗64+64∗3∗3∗64+64∗1∗1∗256=69632
可见采用了 1 ∗ 1 1*1 1∗1卷积后的参数量会减少很多,我觉得这主要是 1 ∗ 1 1*1 1∗1卷积核可以先进行降维,降维之后需要的 3 ∗ 3 3*3 3∗3的卷积核数目就变少了。而真正占用参数量的是 3 ∗ 3 3*3 3∗3卷积核,1*1$卷积核的参数量其实非常少,所以引入了 1 ∗ 1 1*1 1∗1卷积核来减少训练参数。