NIN论文翻译及解读

文章目录

    • 1、MLPCONV结构
    • 2、Global Average Pooling(GAP)
    • 3、NIN网络结构
    • NIN论文解读及个人理解
    • NIN网络的代码实现(pytorch)
      • 1、NIN块实现
      • 2、GAP层实现
      • 3、NIN总网络实现
    • 引用文章

论文链接:https://arxiv.org/pdf/1312.4400.pdf

摘要:我们提出了一种新式深度网络结构称之为NIN,增强模型对感受野内局部块的辨别力。 传统的卷积层使用线性过滤器后跟非线性激活函数来扫描输入。 与之相反的是我们构建更加复杂结构的微神经网络来使得感受野内的数据抽象化。 我们使用多层感知器来实例化微神经网络,这是一种强大的函数逼近器。 特征图是通过以与 CNN 类似的方式在输入上滑动微网络获得的,然后将特征图送入下一层。 深度 NIN 可以通过堆叠多个上述结构来实现。 通过微网络增强的局部建模,我们能够在分类层的特征图上利用全局平均池化,这比传统的全连接层更容易解释并且更不容易过拟合。同时我们展示了 NIN 在 CIFAR-10 和 CIFAR-100 上的最新分类性能,以及在 SVHN 和 MNIST 数据集上的合理性能。

1、MLPCONV结构

NIN中mlpconv结构是将多层感知机MLP和卷积Conv集合在了一起,即传统卷积层之间加MLP层:

NIN论文翻译及解读_第1张图片

mlpconv使用微网络(本文为MLP)将输入局部块映射到输出向量,此时的MLP由具有非线性激活函数的多个全连接层组成,且共享所有局部感受野。

特征图是通过与CNN类似的方式在输入上滑动MLP得到的,然后将特征图输出结果传入到下一层中。

NIN的整个结构就是多个mlpconv层的堆叠.

为什么要使用MLP作为本文微网络?

答:径向基网络和MLP都是通用的函数逼近器,之所以使用MLP有两点原因:①MLP和CNN(使用BP算法训练)结构兼容。②MLP可以是深度模型本身,符合特征重用的特点

2、Global Average Pooling(GAP)

作者想法:在最后一个mlpconv层中为分类任务的每个对应类别生成一个特征图,通过GAP层取每个特征图的空间平均值,将结果向量直接传入到softmax层。(但是传统的做法都是在最后一层卷积层得到的特征图后面跟上FC层)

GAP较FC的优点:
①强制特征图和类别之间的对应关系,更适合卷积结构。
②GAP中没有要优化的参数,减少了参数量,避免了过拟合
③GAP汇总了空间信息,对输入的空间转化更加稳定。
④FC输入的大小必须固定,而GAP对网络输入的图像尺寸没有固定要求。
在使用 GAP 时 feature map 数要等于要分类的类别数,然后再对每一个 feature map 求均值,送到softmax中。

3、NIN网络结构

这篇文章中整个NIN网络包括:三个堆叠的mlpconv层和一个全局平均池化(GAP)层,如下图所示:

NIN论文翻译及解读_第2张图片

1、在三个mlpconv层后跟GAP和目标成本层。

2、可以在mlpconv层中间加入下采样层(与CNN和maxout网络一样)。

3、每个mlpconv层都有一个三层感知机。

4、NIN和微网络中的层数可根据特定任务调整。

NIN论文解读及个人理解

NIN论文翻译及解读_第3张图片

​ 一个卷积和对原图的同一片相同大小区域卷积得到一个数,96个卷积核同样操作得到96个数,将96个数组合成96维向量传入到MLP层输出仍为96,所以:

1、本文实际的NIN块(即mlpconv层)等价于普通卷积后跟两个1×1conv(即mlp层),其中每个卷积操作后面都有ReLU进行非线性激活。

2、mlpconv的作用总结:
①相当于在通道间做特征融合。
②相当于每一层卷积之后加一个激活函数,增加了结构的非线性表达能力。

3、可以将与mlp等价的1×1conv+ReLU灵活运用到其他网络中(如GoogLeNet中的InceptionV1模块),后面的网络运用mlpconv时直接将之转化为1×1conv+ReLU

4、1×1卷积思想:
①可以将1×1卷积看作是全连接层(将通道看成特征维,将宽和高维度上的样本当作是数据样本)
②1×1卷积既可以增加、减少通道数,也可以使通道数量不变化。

5、GAP思想:

① 前面的 mlpconv 层已经能提取出高维的有分类能力的特征了,不需要再多加几层FC层。可以把通道维看做特征维,宽度和长度的维度看做样本。那么 GAP 的本质就是把样本求均值映射到特征,因为最后一层的 feature map 数和类别数相同,那么也就是把样本映射到要分类的类别。

② FC层会综合前面卷积所提取所有的特征,可以把特征理解到更高的维度,来进行判别。也正是因为加上FC层,网络才更容易过拟合,因为FC层的理解力过于强大,它实际上是把所有可能考虑的情况都进行了考虑。怎么进行改进?因为我们前面用 mlpconv 层已经理解到了更高维能够分类的特征,那么最后就可以不用FC层,直接用 GAP 来对每个 feature map 求均值就行,因为模型已经把提取能够分类的特征的任务重心放到了整个模型的前面(mlpconv),后面只用综合前面的结果做出最后的判断就行。

NIN网络的代码实现(pytorch)

NiN块是NiN中的基础块。它由一个卷积层加两个充当全连接层的1×1卷积层(卷积层后跟ReLU)串联而成。其中第一个卷积层的超参数可以自行设置,而第二和第三个卷积层的超参数一般是固定的。

1、NIN块实现

import torch.nn as nn
import torch.nn.functional as F
class NIN_BLOCK(nn.Module):
    def __init__(self, in_channels, out_channels, kernel_size, stride, padding):
        super(NIN_BLOCK, self).__init__()
        self.conv1 = nn.Conv2d(in_channels, out_channels, kernel_size, stride, padding)
        self.conv2 = nn.Conv2d(out_channels, out_channels, kernel_size=1)
        self.conv3 = nn.Conv2d(out_channels, out_channels, kernel_size=1)
    def forward(self, x):
        x = self.conv1(x)
        x = F.relu(x)
        x = self.conv2(x)
        x = F.relu(x)
        x = self.conv3(x)
        return F.relu(x)

2、GAP层实现

第一种实现:

class GlobalAvgPool2d(nn.Module):
    # 全局平均池化层可通过将池化窗口形状设置成输入的高和宽实现
    def __init__(self):
        super(GlobalAvgPool2d, self).__init__()
    def forward(self, x):
        return F.avg_pool2d(x, kernel_size=x.size()[2:])        

第二种实现:

class GlobalAvgPool2d(nn.Module):
	def __init__(self):
        super(GlobalAvgPool2d, self).__init__()
# nn.AdaptiveAvgPool2d(要转化成的大小)
## 如:
# nn.AdaptiveAvgPool2d((6, 6))
## 那么此函数会根据当前来到此处的 feature map 自动求 padding 和 stride,并输出(6,6)大小的 feature map
## 所以,此函数也能用到全卷积中,用来自动调整步长以适应图像不同的输入
		# 全局平均池化,就是如下写法:
		self.GAP = nn.AdaptiveAvgPool2d((1, 1))
	def forward(self, x):
		return self.GAP(x)

3、NIN总网络实现

class NIN(nn.Module):
    def __init__(self):
        super(NIN, self).__init__()
        self.block1 = NIN_BLOCK(3, 96, kernel_size=11, stride=4, padding=0)
        self.maxpool1 = nn.MaxPool2d(kernel_size=3, stride=2)  # 224*224*3 → 55*55*96 由以上两步共同完成
        self.block2 = NIN_BLOCK(96, 256, kernel_size=5, stride=1, padding=2)
        self.maxpool2 = nn.MaxPool2d(kernel_size=3, stride=2)  # 55*55*96 → 27*27*256
        self.block3 = NIN_BLOCK(256, 384, kernel_size=3, stride=1, padding=1)
        self.maxpool3 = nn.MaxPool2d(kernel_size=3, stride=2)  # 27*27*256 → 13*13*384
        self.block4 = NIN_BLOCK(384, 1000, kernel_size=3, stride=1, padding=1)
        self.GAP = GlobalAvgPool2d()
    def forward(self, x):
        x = self.block1(x)
        x = self.maxpool1(x)
        x = self.block2(x)
        x = self.maxpool2(x)
        x = self.block3(x)
        x = self.maxpool3(x)
        x = F.dropout(x, 0.5, training=self.training)
        x = self.block3(x)
        x = self.GAP(x)
        x = x.view(x.shape[0], -1)  # 将四维输出转换为二维输出,即形状为(批量大小,1000)
        return F.softmax(x, dim=1)

引用文章

[1] https://blog.csdn.net/fanzy1234/article/details/86173123
[2] https://tangshusen.me/Dive-into-DL-PyTorch/#/chapter05_CNN/5.8_nin
[3] https://blog.csdn.net/m0_45962052/article/details/104392961

你可能感兴趣的:(CNN,深度学习,计算机视觉,神经网络)