上一篇请移步【动手学深度学习PyTorch版】18 使用块的网络 VGG_水w的博客-CSDN博客

目录

一、网络中的网络 NiN

1.1 NiN

◼ 全连接层的问题

◼ 大量的参数会带来很多问题

◼ NiN

◼ NiN块

◼ NiN架构

◼ 全局的平均池化层在设计上是不是很关键,所带来的影响有哪些?

1.2 VGG net 和 NiN net

1.3 总结

二、 NiN网络(使用自定义)


一、网络中的网络 NiN

1.1 NiN

这个网络现在用的不多,但是它所提出的很多重要的概念在之后的很多网络中都会被用到。

◼ 全连接层的问题

在AlexNet和VGG的最后面都使用了两个比较大的全连接层,最后再通过一个全连接层作为输出(全连接层比较占用网络参数空间,整个网络的绝大多数参数都集中在全连接层),最重要的问题是会带来过拟合。

假设使用卷积层的话,参数的个数等于输入的通道数(Ci) * 输出的通道数(Co) * 卷积窗口的高度(k) * 卷积窗口的宽度(k)。

但是如果使用全连接层的话,它的参数个数就等于整个输入的像素(也就是输入通道数) * 输入的高 * 输入的宽 * 输出中所有的像素(也就是输出通道数)。

在卷积层的最后一层的输出并没有变成 1 * 1,很多情况下就是 7 * 7,这样的话其实对于全连接层来说输入的像素还是比较多的。

另外,如果使用全连接层,可能会完全放弃表征的空间结构。

  • LeNet中,16X5X5X120:16是最后一个卷积层的输出通道数,5 * 5表示经过卷积操作之后最终输出压缩成了5 * 5的大小,120是输出的隐藏层的大小(下一个全连接层的输入通道数)。
  • AlexNet中,256X5X5X4096:最后一个卷积层的输出通道数是256,4096是输出的隐藏层的大小(下一个全连接层的输入通道数)。
  • VGG最后一个卷积层的输出通道数变成了512,经过多次卷积操作之后最终输出的大小也只压缩到了7 * 7,因此它所占用的内存量确实是比较大的,差不多占用700M左右的内存,其中绝大部分参数都集中在卷积层之后的第一个全连接层。

◼ 大量的参数会带来很多问题

  • 占用大量的内存;
  • 占用很多的计算带宽(一个很大的矩阵乘法不受限于计算,而是几乎是受限于不断访问内存所带来的限制);
  • 很容易过拟合(某一层的参数过多很容易导致模型收敛特别快,反过来讲,就需要使用大量的正则化避免该层学到所有的东西);

◼ NiN

为了解决这些问题,就提出了NiN。

NiN的思想是:完全不要全连接层。

比如2021年由谷歌提出的MLP-Mixer,提出MLP又能够替代CNN了,但是实际上它和NiN是一个东西,与NiN当年的思想是一样的,只是NiN是认为全连接层不是很好,所以就用卷积层来替代全连接层,不要全连接层。而MLP-Mixer认为卷积层不行,我还是得用我的全连接层,所以实际上是一个东西。

在每个像素的通道上分别使用多层感知机,也就是在每个像素位置(针对每个高度和宽度)应用一个全连接层。

这样将权重连接到了每个空间位置,可以将其视为1 * 1的卷积层,或者看作在每个像素位置上独立作用的全连接层,从另一个角度讲,就是将空间维度中的每个像素视为单个样本,将通道维度视为不同特征。

◼ NiN块

NiN中最重要的概念叫做NiN块(VGG之后的网络基本上都有自己的局部的卷积神经网络架构,也就是块状结构)。

NiN块的结构如下图所示:

回顾:卷积层的输入和输出由四维张量组成,张量的每个轴分别对应样本、通道、高度和宽度;全连接层的输入和输出通常是分别对应于样本和特征的二维张量。

NiN块由一个卷积层和两个全连接层(实际上是窗口大小为1 * 1、步幅为1、无填充的卷积层)组成(因为1 * 1的卷积层等价于全连接层,所以这里使用的是1 * 1的卷积层;步幅为1,无填充,所以卷积层输出的形状和输入的形状是一样的,也就是不会改变输入的形状,同时也不会改变通道数)。

NiN块中两个1 * 1的卷积层其实是起到了全连接层的作用,这两个卷积层充当了带有ReLu激活函数的逐像素全连接层。

1 * 1的卷积运算如下图所示,

NiN块可以认为是一个简单的神经网络:一个卷积层+两个全连接层。唯一的不同是这里的全连接层是对每一个像素做全连接,对于每个输入的每个像素的权重都是一样的,不会根据输入的具体情况发生变化,所以可以认为是按照输入的每个像素逐一做全连接

◼ NiN架构

  • 没有全连接层;
  • 交替使用NiN块和步幅为2的最大池化层(最大池化层的作用的就是高宽减半),逐步减小高宽(输出的尺寸)和增大通道数;
  • 最后使用全局平均池化层得到输出(全局平均池化层:该池化层的高宽等于输入的高宽,等价于对每一个通道取平均值,作为这个类别的预测,再通过softmax就能得到每个类别的概率了),其输入通道数是标签类别数,最后不需要使用全连接层,也是一个比较极端的设计;

◼ 全局的平均池化层在设计上是不是很关键,所带来的影响有哪些?

每次卷积的后面都能够加全局最大池化层,它唯一的作用是将卷积输出feature的高宽压缩成为1 * 1,通道数不变,它的主要效果是将输入变小了,而且它没有可学习的参数。加入全局池化层可以让计算变得更简单,但是它最主要的好处是降低了模型的复杂度,加入全局平均池化层同时也会提升模型的泛化性能,提高模型的精度。

坏处就是模型的收敛变慢了(绝大部分情况下在考虑模型时,模型的精度优先于模型的收敛速度) 。

1.2 VGG net 和 NiN net

VGG块由多个卷积层和一个最大池化层组成;NiN块由一个卷积层和两个当做全连接层用的1 * 1的卷积层。

VGG网络由四个VGG块和两个大的全连接层,最后通过一个输出通道数为1000的全连接层得到1000类。

NiN网络由一个NiN块和一个步幅为2、3 * 3的最大池化层不断重复,如果将最后重复部分的NiN块的通道数设置为标签类别的数量的话,则最后就可以用全局平均池化层(global average pooling layer)代替全连接层来得到输出(一个对数几率(logits)),也就是对每个类的预测(这里说NiN网络是由一个NiN块和一个最大池化层不断重复堆叠组成的,为什么上图中NiN网络里每个最大池化层都是一样的,而每个NiN块都长得不一样?NiN块中第一层的卷积窗口形状通常是由用户设置,随后的卷积窗口形状固定为1 * 1,这里应该是受到AlexNet的启发,使用了窗口形状为11 * 11、5 * 5、3 * 3的卷积层,输出通道数与AlexNet中相同)。

第一个NiN块的第一个卷积层的步幅为什么是4?通过长为4的步幅的卷积操作使得输出的尺寸大幅度减小。

NiN完全取消了全连接层,这样做的好处是减少了模型所需参数的数量,但是在实践中,这种设计有时会增加模型的训练时间。

1.3 总结

(1)NiN的核心思想是NiN块,NiN块是一个卷积层加上两个1 * 1的卷积层作为全连接层来使用(也就是说对每个像素增加了非线性,或者说对每个像素的通道数做了全连接层,而且是非线性的,因为有两层)。

(2)NiN使用全局平均池化层(GAP)(通道数量为所需的输出数量)来替代VGG和AlexNet中的全连接层(全局全连接层因为比较大,所以也不需要学一个比较大的全连接层),这样做的好处是不容易过拟合,有更少的参数数量

① 在全局平均池化层(GAP)被提出之前,常用的方式是将feature map直接拉平成一维向量,但是GAP不同,是将每个通道的二维图像做平均,最后也就是每个通道对应一个均值。

② 假设卷积层的最后输出是h × w × d 的三维特征图,具体大小为6 × 6 × 3,经过GAP转换后,变成了大小为 1 × 1 × 3 的输出值,也就是每一层 h × w 会被平均化成一个值,如下图所示。

③ GPA优势:

  1. 抑制过拟合。直接拉平做全连接层的方式依然保留了大量的空间信息,假设feature map是32个通道的10 * 10图像,那么拉平就得到了32 * 10 * 10的向量,如果是最后一层是对应两类标签,那么这一层就需要3200 * 2的权重矩阵,而GAP不同,将空间上的信息直接用均值代替,32个通道GAP之后得到的向量都是32的向量,那么最后一层只需要32 * 2的权重矩阵。相比之下GAP网络参数会更少,而全连接更容易在大量保留下来的空间信息上面过拟合。

  2. 输入尺寸更加灵活。在第1点的举例里面可以看到feature map经过GAP后的神经网络参数不再与输入图像尺寸的大小有关,也就是输入图像的长宽可以不固定。

整体来讲,NiN的架构比较简单,就是NiN块和最大池化层的重复堆叠,直到最后的全局平均池化层,因为完全放弃了全连接层,所以它的参数个数大大减少了,使得参数的总量与类别数的多少无关。

NiN的设计影响了许多后续卷积神经网络的设计。

二、 NiN网络(使用自定义)

import torch
from torch import nn
from d2l import torch as d2ldef nin_block(in_channels, out_channels, kernel_size, strides, padding):"""NiN的block块参数:输入通道数in_channels,要求输出的通道数out_channels,第一个卷积层kernel的大小、步幅、填充"""return nn.Sequential(nn.Conv2d(in_channels, out_channels, kernel_size, strides,padding),# 1X1卷积层:不改变通道数,输入通道数和输出通道数都是同一个数nn.ReLU(), nn.Conv2d(out_channels, out_channels, kernel_size=1),nn.ReLU(), nn.Conv2d(out_channels, out_channels, kernel_size=1),nn.ReLU())
"""NiN的模型"""
## 1. 其实就是把AlexNet的第1个卷积层搬过来,在后面加了2个1X1卷积层和MaxPool2d
net = nn.Sequential(nin_block(1,96,kernel_size=11,strides=4,padding=0),   # NiN的block块:输入通道数1(灰度图)nn.MaxPool2d(3,stride=2),   # 高宽减半## 2. 其实就是把AlexNet的第2个卷积层搬过来,在后面加了2个1X1卷积层和MaxPool2dnin_block(96,256,kernel_size=5,strides=1,padding=2), nn.MaxPool2d(3,stride=2),## 3. nin_block(256,384,kernel_size=3,strides=1,padding=1), nn.MaxPool2d(3,stride=2),nn.Dropout(0.5),## 4. 最后一个NiN块:把通道数降到10(类别个数),nin_block(384,10,kernel_size=3,strides=1,padding=1), nn.AdaptiveAvgPool2d((1,1)),   # 全局平均池化层:高宽都会变成1nn.Flatten())   # 把最后两个维度消掉# 查看每个块的输出形状
X = torch.rand(size=(1,1,224,224))
for layer in net:X = layer(X)print(layer.__class__.__name__, 'output shape:\t', X.shape)

(1)我们可以看到,第一个NiN bolck,由于用的是AexNet的第一个卷积层,stride=4比较大,直接变成了54X54,让计算量比较小了。

(2)第二个NiN bolck的输出是256,通道数从96涨到了256,由于第一个NiN bolck使用了stride=2,所以从54变成了26。

接下来,又用了一个最大池化层,不改变通道数,但是使得高宽减半,变成了12。

(3)同样的道理,第三个NiN bolck的输出通道数把256增加到了384,高宽不变。

接下来,又用了一个最大池化层,不改变通道数,但是使得高宽减半,变成了5。

这个地方使用Dropout。

(4)然后,再加了一个NiN bolck,从384把通道数降到10(我要的类别个数),

最后,全局的平均池化层,对5X5,对每一个通道不管是多大都拿出平均值,高宽就变成1X1。

(5)Flatten把最后两个维度消掉。

(6)总结:将批量大小为1,维度是1X224X224的输入,变成了一个长为10的向量,此处的10就是我要的类别个数。

核心思想是第一个卷积层使用长为4的步幅减小,接下来通过最大池化层来每次减半,最后使用局的平均池化层,高宽把5X5变成1X1。

调用之前实现的函数做训练,

# 训练模型
lr, num_epochs, batch_size = 0.1, 10, 128
train_iter, test_iter = d2l.load_data_fashion_mnist(batch_size, resize=224)
d2l.train_ch6(net, train_iter, test_iter, num_epochs, lr, d2l.try_gpu())

训练效果与我们之前的用的参数是一样的,迭代10次,批量大小为128,学习率为0.1。数据集还是使用fashion_mnist。

可以看到,其实精度也不是很高,训练速度是3232。

对比之前的AlexNet,速度也没有高太多,这是因为加入了大量的1X1的卷积层,计算量变多了。

【动手学深度学习PyTorch版】19 网络中的网络 NiN相关推荐

  1. 【动手学深度学习PyTorch版】12 卷积层

    上一篇移步[动手学深度学习PyTorch版]11 使用GPU_水w的博客-CSDN博客 目录 一.卷积层 1.1从全连接到卷积 ◼ 回顾单隐藏层MLP ◼ Waldo在哪里? ◼ 原则1-平移不变性 ...

  2. 伯禹公益AI《动手学深度学习PyTorch版》Task 03 学习笔记

    伯禹公益AI<动手学深度学习PyTorch版>Task 03 学习笔记 Task 03:过拟合.欠拟合及其解决方案:梯度消失.梯度爆炸:循环神经网络进阶 微信昵称:WarmIce 过拟合. ...

  3. 伯禹公益AI《动手学深度学习PyTorch版》Task 05 学习笔记

    伯禹公益AI<动手学深度学习PyTorch版>Task 05 学习笔记 Task 05:卷积神经网络基础:LeNet:卷积神经网络进阶 微信昵称:WarmIce 昨天打了一天的<大革 ...

  4. 伯禹公益AI《动手学深度学习PyTorch版》Task 06 学习笔记

    伯禹公益AI<动手学深度学习PyTorch版>Task 06 学习笔记 Task 06:批量归一化和残差网络:凸优化:梯度下降 微信昵称:WarmIce 批量归一化和残差网络 BN和Res ...

  5. 伯禹公益AI《动手学深度学习PyTorch版》Task 04 学习笔记

    伯禹公益AI<动手学深度学习PyTorch版>Task 04 学习笔记 Task 04:机器翻译及相关技术:注意力机制与Seq2seq模型:Transformer 微信昵称:WarmIce ...

  6. 伯禹公益AI《动手学深度学习PyTorch版》Task 07 学习笔记

    伯禹公益AI<动手学深度学习PyTorch版>Task 07 学习笔记 Task 07:优化算法进阶:word2vec:词嵌入进阶 微信昵称:WarmIce 优化算法进阶 emmmm,讲实 ...

  7. 【动手学深度学习PyTorch版】6 权重衰退

    上一篇移步[动手学深度学习PyTorch版]5 模型选择 + 过拟合和欠拟合_水w的博客-CSDN博客 目录 一.权重衰退 1.1 权重衰退 weight decay:处理过拟合的最常见方法(L2_p ...

  8. 【动手学深度学习PyTorch版】27 数据增强

    上一篇请移步[动手学深度学习PyTorch版]23 深度学习硬件CPU 和 GPU_水w的博客-CSDN博客 目录 一.数据增强 1.1 数据增强(主要是关于图像增强) ◼ CES上的真实的故事 ◼ ...

  9. 【动手学深度学习PyTorch版】13 卷积层的填充和步幅

    上一篇移步[动手学深度学习PyTorch版]12 卷积层_水w的博客-CSDN博客 目录 一.卷积层的填充和步幅 1.1 填充 1.2 步幅 1.3 总结 二.代码实现填充和步幅(使用框架) 一.卷积 ...

最新文章

  1. spark uniq 本质上就是单词计数
  2. Linux系统设置定时任务 1
  3. 肝!22款超好用的CLI工具
  4. MySQL中的pid与socket是什么?
  5. 谱聚类、Chameleon聚类、PCCA、SOM、Affinity Propagation
  6. linux正则表达式_Linux 中几个正则表达式的用法
  7. 循环控制体重C语言,减重名医王存川教授告诫:越早控制体重,肥胖导致身体的伤害越小...
  8. 【图像分割】基于matlab模糊聚类算法FCM图像分割【含Matlab源码 084期】
  9. 数学——每日一题7 1.14 利用定积分的定义求极限
  10. Git使用学习(十四、解决分支合并后产生的冲突)
  11. python标准数据类型叮叮叮
  12. Python爬虫 | Python爬虫获取女友图片
  13. Java包的简单理解
  14. 泰坦尼克号生存预测(多种模型实现)python
  15. java.lang.SecurityException: User has not given permission to device UsbDevice
  16. STM32——理解中断与中断配置
  17. 基于Docker容器的DevOps应用方案
  18. Android状态栏微技巧,带你真正理解沉浸式模式
  19. 事业上如何运用“长尾理论”?
  20. Java API操作HDFS

热门文章

  1. 如何把安卓系统刷成linux,废旧Android手机如何改造成Linux服务器?
  2. 制造业企业设备管理,设备管理平台,从信息化到智慧化
  3. tflearn教程_Tensorflow tflearn 编写RCNN
  4. C语言——生命小游戏
  5. asp.net简易留言板
  6. LightCNN核心点解析
  7. [附源码]计算机毕业设计基于springboot的4s店车辆管理系统
  8. euclidea教程_euclidea全攻略_euclidea几何构建全关卡通关攻略_玩游戏网
  9. 想知道美国大学按计算机专业的排名,以及各大学在计算机哪个方面是强项,应该去哪里查找?...
  10. VS2019配置GDAL2教程