NIN(Network in Network)
正如它的名字所示,代表着网络中的网络。
它发表于2013年,入选国际学习表征会议ICLR 2014
优秀论文,其通过少量参数的深度学习模型轻松击败了AlexNet;
这也对我们电脑配置不高的人来说,算是一个特别友好的模型,不需要太大显存量就可训练一个较好的模型。
1.那为啥它的模型参数量少呢?
其实是因为它最后没有全连接层,大家应该知道,全连接层的参数量会特别大,训练时会耗费很大时间在全连接层上面,这些参数也会占用很多内存,让你本来就少的可怜的内存雪上加霜。
2.那它拿啥来取代全连接层呢?
它最后用到了一个全局平均池化(Global Average Pooling,GAP),会把所有特征图都变成1*1的,就是一个值,这不就能代表全连接层里边的一个神经元了么。
全局平均池化
和大家所熟知的池化操作一样,只不过它是把池化核的大小变的特征图大小相等,直接对所有值取平均值,得到这个平均值,作为输出。(这是不是一个很简单的操作呀)
就如上图所示,有几个特征图就得到几个输出值。
这样操作同时还有另一个好处,就是不用考虑输入的特征图有多大,到这里都不用计算特征图大小(如果我们使用全连接层,或者普通池化啥的,咱们是不是得往那个函数里边输特征图大小或者神经元个数,这得咱们计算吧,而且还对最初输入的图片大小有限制),可以直接经过这个函数得到输出值。
3.难道仅仅是因为参数量少了,它就可以达到这么好的效果吗?
当然不止这些啦!
它还有一个神奇的模块,叫MLP卷积(可不是感知机哦!)
MLP卷积
其实它就是一个1*1的卷积,就是叫了个高级的名字。
下面我们就说说这个1×1卷积到底有什么神奇的地方,可以让这个模型一下子跃到这么高的地位。
①参数量少,可以用来改变通道数
这个很明显,1×1的卷积核中的参数量是和特征图的通道数相等的,用它来改变通道数,相比那些大卷积核来说,是个不错的选择。
②可以增强模型的非线性拟合能力
大家要注意啊,每一个卷积操作后边,都会跟一个激活函数,多加几个1×1卷积,那不就意味着多增加了激活函数么,这不就提高了非线性拟合的能力。
大家可能会想,那用别的卷积核也行呀!相比1×1卷积,别的卷积核不是参数量大么,所以这又就显现出了它的第一条优势。
所以,该模型就多次使用到了1×1卷积,即很好的进行了通道信息的融合,又增强了非线性的拟合能力,这不是一举两得的事么。
NIN的pytorch实现
此处我是来做102分类任务的,所以到最后大家可以看到最后一个1×1卷积,输出通道为102。
class NIN(nn.Module):
def __init__(self):
super().__init__()
#每个Sequential里的计算量得一致,或相差不多,才能将GPU的利用率达到90%以上
#in:512*512*3
self.seq1 = nn.Sequential(
nn.Conv2d(3,96,11,4), #输入通道,输出通道,核大小,步长
nn.BatchNorm2d(96),
nn.ReLU(),
#in:96*125*125
nn.Conv2d(96,96,1), #计算量:96*125*125*96
nn.BatchNorm2d(96),
nn.ReLU(),
nn.Conv2d(96,96,1),
nn.BatchNorm2d(96),
nn.ReLU(),
nn.MaxPool2d(3,2)
)
#in:96*62*62
self.seq2 = nn.Sequential(
nn.Conv2d(96,192,5,1,0),
nn.BatchNorm2d(192),
nn.ReLU(),
#in:192*62*62
nn.Conv2d(192,192,1), #计算量:192*62*62*192
nn.BatchNorm2d(192),
nn.ReLU(),
nn.Conv2d(192,192,1),
nn.BatchNorm2d(192),
nn.ReLU(),
nn.MaxPool2d(3,2,0)
)
#in:192*31*31
self.seq3 = nn.Sequential(
nn.Conv2d(192,384,3,1,0),
nn.BatchNorm2d(384),
nn.ReLU(),
#in:384*31*31
nn.Conv2d(384,384,1), #计算量:384*31*31*384
nn.BatchNorm2d(384),
nn.ReLU(),
nn.Conv2d(384,384,1),
nn.BatchNorm2d(384),
nn.ReLU(),
nn.MaxPool2d(3,2)
)
#in:384*15*15
self.seq4 = nn.Sequential(
nn.Conv2d(384,768,3,1,0),
nn.BatchNorm2d(768),
nn.ReLU(),
#in:768*15*15
nn.Conv2d(768,768,1), #计算量:768*15*15*768
nn.BatchNorm2d(768),
nn.ReLU(),
nn.Conv2d(768,102,1), #做102分类,将输出特征层变为102
nn.BatchNorm2d(102),
nn.ReLU()
)
#全局平均池化
self.p = nn.AdaptiveAvgPool2d((1,1))
def forward(self, x):
x = self.seq1(x)
x = self.seq2(x)
x = self.seq3(x)
x = self.seq4(x)
x = self.p(x)
x = x.view(len(x),-1)
return x
这里每个卷积的输出通道数,包括BN层,可能和原论文有出入,大家可以根据自己所做任务的实际情况更改。
希望可以帮助到大家,可以在评论区交流哦!