AI-7 现代卷积神经网络

 

conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))

7.1. 深度卷积神经网络(AlexNet)

更多的数据和更高性能的硬件使得深度卷积神经网络在2012年出现突破。

2012年,AlexNet横空出世,首次证明了学习到的特征可以超越手工设计的特征。

AlexNet和LeNet的设计理念非常相似,但也存在显著差异:

结构上的区别:更胖,更深AlexNet比相对较小的LeNet5要深得多。AlexNet由八层组成:五个卷积层、两个全连接隐藏层和一个全连接输出层。

细节上的改进:1AlexNet使用ReLU而不是sigmoid作为其激活函数(ReLU激活函数在正区间的梯度总是1)

       2添加了丢弃法,而非单独使用权重衰减

       3进行了数据增强

在参数个数以及运算量上确实有了很大的增加。

练习

  • 试着增加迭代轮数。对比LeNet的结果有什么不同?为什么?

迭代次数增加到40,精度有所增加。

  • AlexNet对Fashion-MNIST数据集来说可能太复杂了。

    • 尝试简化模型以加快训练速度,同时确保准确性不会显著下降。

    • 设计一个更好的模型,可以直接在28×28图像上工作。

对照组-左1
net = nn.Sequential(
    # 这里使用一个11*11的更大窗口来捕捉对象。
    # 同时,步幅为4,以减少输出的高度和宽度。
    # 另外,输出通道的数目远大于LeNet
    nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    # 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
    nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    # 使用三个连续的卷积层和较小的卷积窗口。
    # 除了最后的卷积层,输出通道的数量进一步增加。
    # 在前两个卷积层之后,汇聚层不用于减少输入的高度和宽度
    nn.Conv2d(256, 256, kernel_size=3, padding=1), nn.ReLU(),
    nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(),
    nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Flatten(),
    # 这里,全连接层的输出数量是LeNet中的好几倍。使用dropout层来减轻过拟合
    nn.Linear(6400, 4096), nn.ReLU(),
    nn.Dropout(p=0.5),
    nn.Linear(4096, 4096), nn.ReLU(),
    nn.Dropout(p=0.5),
    # 最后是输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000
    nn.Linear(4096, 10))
实验组右1-减少了一些层
net = nn.Sequential(
    # 这里使用一个11*11的更大窗口来捕捉对象。
    # 同时,步幅为4,以减少输出的高度和宽度。
    # 另外,输出通道的数目远大于LeNet
    nn.Conv2d(1, 96, kernel_size=11, stride=4, padding=1), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    # 减小卷积窗口,使用填充为2来使得输入与输出的高和宽一致,且增大输出通道数
    nn.Conv2d(96, 256, kernel_size=5, padding=2), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    # 使用三个连续的卷积层和较小的卷积窗口。
    # 除了最后的卷积层,输出通道的数量进一步增加。
    # 在前两个卷积层之后,汇聚层不用于减少输入的高度和宽度
    nn.Conv2d(256, 256, kernel_size=3, padding=1), nn.ReLU(),
    #nn.Conv2d(384, 384, kernel_size=3, padding=1), nn.ReLU(),
    #nn.Conv2d(384, 256, kernel_size=3, padding=1), nn.ReLU(),
    nn.MaxPool2d(kernel_size=3, stride=2),
    nn.Flatten(),
    # 这里,全连接层的输出数量是LeNet中的好几倍。使用dropout层来减轻过拟合
    nn.Linear(6400, 4096), nn.ReLU(),
    nn.Dropout(p=0.5),
    #nn.Linear(4096, 4096), nn.ReLU(),
    #nn.Dropout(p=0.5),
    # 最后是输出层。由于这里使用Fashion-MNIST,所以用类别数为10,而非论文中的1000
    nn.Linear(4096, 10))

看看效果如何? 诶,模型精简之后精度反而提升了!

修改了输入图像适合28*28

  • 修改批量大小,并观察模型精度和GPU显存变化。

            batchsize=128

            batchsize=192

             batchsize=256

            批量增大,效果没变好?

  • 分析了AlexNet的计算性能。

    • 在AlexNet中主要是哪部分占用显存?

     答:全连接层的参数占用大量内存 

    • 在AlexNet中主要是哪部分需要更多的计算?

     答:卷积层需要进行大量的计算

    • 计算结果时显存带宽如何?似乎够用

  • 将dropout和ReLU应用于LeNet-5,效果有提升吗?再试试预处理会怎么样?

    有提升

7.2. 使用块的网络(VGG)

AlexNet的形状不是很规则,不好迁移,而且最后的全连接层开销比较大。

VGG-11使用可复用的卷积块构造网络。不同的VGG模型可通过每个块中卷积层数量和输出通道数量的差异来定义。在VGG论文中,Simonyan和Ziserman尝试了各种架构。

特别是他们发现深层且窄的卷积(即3×3)比较浅层且宽的卷积更有效。 为啥深层且窄的卷积更有效嘞。

经验发现3x3 的卷积层  和 2x2的池化层 效果更好

练习:

  • 打印层的尺寸时,我们只看到8个结果,而不是11个结果。剩余的3层信息去哪了?

conv_arch = ((1, 64), (1, 128), (2, 256), (2, 512), (2, 512))

    答:因为后三个VGG块中,其实分别有尺寸相同两个卷积层。

  • 与AlexNet相比,VGG的计算要慢得多,而且它还需要更多的显存。分析出现这种情况的原因。

    因为VGG中有更多的卷积层,因此需要更多的计算和显存。

  • 尝试将Fashion-MNIST数据集图像的高度和宽度从224改为96。这对实验有什么影响?

  224

    我遇到的问题是,在最后一个池化层前,图像就已经被我收束到1x1了。。。

 

7.3. 网络中的网络(NiN)

 

现在NiN虽然被用的不多,但是其设计理念非常有价值。

LeNet、AlexNet和VGG都有一个共同的设计模式:通过一系列的卷积层与汇聚层来提取空间结构特征;然后通过全连接层对特征的表征进行处理。 AlexNet和VGG对LeNet的改进主要在于如何扩大和加深这两个模块。 或者,可以想象在这个过程的早期使用全连接层。然而,如果使用了全连接层,可能会完全放弃表征的空间结构。 网络中的网络NiN)提供了一个非常简单的解决方案:在每个像素的通道上分别使用多层感知机 (Lin et al., 2013

NiN和AlexNet之间的一个显著区别是NiN完全取消了全连接层。 相反,NiN使用一个NiN块,其输出通道数等于标签类别的数量。最后放一个全局平均汇聚层(global average pooling layer),生成一个对数几率 (logits)。NiN设计的一个优点是,它显著减少了参数量,但是有时会增加训练模型的时间。

练习:

1调整NiN的超参数,以提高分类准确性。

lr, num_epochs, batch_size = 0.1, 10, 128  #这是原来的参数

lr, num_epochs, batch_size = 0.1, 20, 256   #调整批量大小和训练周期后,精度反而下降了

2为什么NiN块中有两个1×1卷积层?删除其中一个,然后观察和分析实验现象。

     对照组(两个1x1卷积层)                   实验组 (只保留一个)

很奇怪,效果反而变好了.....

3计算NiN的资源使用情况。

    1. 参数的数量是多少?

    2. 计算量是多少?

    3. 训练期间需要多少显存?

    4. 预测期间需要多少显存?

由于使用1X1卷积代替全连接,减少了参数量,降低了模型复杂度。

4一次性直接将384×5×5的表示缩减为10×5×5的表示,会存在哪些问题?

  输出通道数减少,会导致显存占用量减小。但也会使得模型精度有所下降。

7.4. 含并行连结的网络(GoogLeNet)

  在GoogLeNet中,基本的卷积块被称为Inception块(Inception block),Inception块由四条并行路径组成。相当于每条路径使用。 前三条路径使用窗口大小为1×13×35×5的卷积层,从不同空间大小中提取信息。每条线路的输出在通道维度上连结,并构成Inception块的输出。

  至于为什么最后那样联结,估计是多次调试之后的经验结论。

练习:

  1. GoogLeNet有一些后续版本。尝试实现并运行它们,然后观察实验结果。这些后续版本包括:

  2. 使用GoogLeNet的最小图像大小是多少?

  3. 将AlexNet、VGG和NiN的模型参数大小与GoogLeNet进行比较。后两个网络架构是如何显著减少模型参数大小的?

 

7.5. 批量规范化

批量规范化(batch normalization) (Ioffe and Szegedy, 2015),这是一种流行且有效的技术,可持续加速深层网络的收敛速度。 再结合在 7.6节中将介绍的残差块,批量规范化使得研究人员能够训练100层以上的网络。

 

原因:

  1应用多层感知机来预测房价的例子( 4.10节)。 使用真实数据时,我们的第一步是标准化输入特征,使其平均值为0,方差为1。 直观地说,这种标准化可以很好地与我们的优化器配合使用,因为它可以将参数的量级进行统一。

  2对于典型的多层感知机或卷积神经网络,训练时中间层中的变量可能具有更广的变化范围:不论是沿着从输入到输出的层,跨同一层中的单元,或是随着时间的推移,模型参数的随着训练更新变幻莫测。 批量规范化的发明者非正式地假设,这些变量分布中的这种偏移可能会阻碍网络的收敛。

  3第三,更深层的网络很复杂,容易过拟合。 这意味着正则化变得更加重要。

我们在下面讨论这两种情况:全连接层和卷积层,他们的批量规范化实现略有不同:

  全连接层:通常,我们将批量规范化层置于全连接层中的仿射变换和激活函数之间。

  卷积层:对于卷积层,我们可以在卷积层之后和非线性激活函数之前应用批量规范化。

和暂退法一样,批量规范化层在训练模式和预测模式下的计算结果也是不一样的。

练习:

1在使用批量规范化之前,我们是否可以从全连接层或卷积层中删除偏置参数?为什么?

   规范化之前不能,因为偏置参数可以帮助模型更好的学习数据。使用批量规范化后可以,因为批量规范的过程就已经有偏置的环节。

2比较LeNet在使用和不使用批量规范化情况下的学习率。

  2.1绘制训练和测试准确度的提高。2.2学习率有多高?

      使用批量规范化              不使用规范化

结果发现,使用批量规范化,比不适用精度会高一些,至于学习率只能说比较平稳的

 

3我们是否需要在每个层中进行批量规范化?

  输出层中不需要做BN,因为softmax会选择最大的一个值作为分类结果,做不做BN都没有影响。

4可以通过批量规范化来替换暂退法吗?行为会如何改变?

  批量规范化关注控制过程变量的大小来实现正则化;暂退法是通过在数据中增加噪声来实现正则化,实现手段不完全相同。

5确定参数betagamma,并观察和分析结果。

6查看高级API中有关BatchNorm的在线文档,以查看其他批量规范化的应用。

  BatchNorm1d — PyTorch 2.0 文档   

7研究思路:可以应用的其他“规范化”转换?可以应用概率积分变换吗?全秩协方差估计可以么?

  差不多学会了再来研究吧..

7.6. 残差网络(ResNet)

如果我们能将新添加的层训练成恒等映射(identity function)f(x)=x,新模型和原模型将同样有效。 同时,由于新模型可能得出更优的解来拟合训练数据集,因此添加层似乎更容易降低训练误差。大概是通过扩大了函数类的容量,从而使其更可能接近最优解。

针对这一问题,何恺明等人提出了残差网络(ResNet) (He et al., 2016)

练习:

1图7.4.1中的Inception块与残差块之间的主要区别是什么?在删除了Inception块中的一些路径之后,它们是如何相互关联的?

    inception块有四个路径,而残差块只有两个路径。且inception是将不同路径的通道数连接,残差块则是加到一起。

2参考ResNet论文 (He et al., 2016)中的表1,以实现不同的变体。

  略

3对于更深层次的网络,ResNet引入了“bottleneck”架构来降低模型复杂性。请试着去实现它。

  使用1x1卷积来减少计算量

 class bottleNeck(nn.Module):
    def __init__(self, input_channels, num_channels,
                 use_1x1conv=False, strides=1):
        super().__init__()
        self.conv1 = nn.Conv2d(input_channels, num_channels,
                                   kernel_size=1, stride=strides)
        self.bn1 = nn.BatchNorm2d(num_channels)
        self.comv2 = nn.Conv2d(input_channels, num_channels,
                                   kernel_size=3,padding = 1, stride=strides)
        self.bn2 = nn.BatchNorm2d(num_channels)
        self.conv3 = nn.Conv2d(input_channels, num_channels,
                                   kernel_size=1, stride=strides)
        self.bn3 = nn.BatchNorm2d(num_channels)
 
    
    def forward(self, X):
        Y = F.relu(self.bn1(self.conv1(X)))
        Y = self.bn2(self.conv2(Y))
        Y = Y.relu(Y)
        Y = conv3(Y)
        return Y

4在ResNet的后续版本中,作者将“卷积层、批量规范化层和激活层”架构更改为“批量规范化层、激活层和卷积层”架构。请尝试做这个改进。详见 (He et al., 2016)中的图1。  

  参考7.7blcok1

5为什么即使函数类是嵌套的,我们仍然要限制增加函数的复杂性呢?
  答:第一是因为复杂的函数会增加拟合的计算要求,第二是增加了过拟合的风险

 

7.7. 稠密连接网络(DenseNet)

借助泰勒展开,稠密层将函数展开为多项。在跨层连接上,不同于ResNet中将输入与输出相加,稠密连接网络(DenseNet)在通道维上连结输入与输出。DenseNet的主要构建模块是稠密块和过渡层。

在稠密快中,使用了ResNet改良版的“批量规范化、激活和卷积”架构。在前向传播中,我们将每个卷积块的输入和输出在通道维上连结。

而过渡层可以用来控制模型复杂度。 它通过1×1卷积层来减小通道数,并使用步幅为2的平均汇聚层减半高和宽,从而进一步降低模型复杂度。

练习:

1为什么我们在过渡层使用平均汇聚层而不是最大汇聚层?

  因为过度层前输入的信息都应该是对结果有贡献的,过渡层只是为了降低模型复杂度,但不应放弃某些特征。

2DenseNet的优点之一是其模型参数比ResNet小。为什么呢?

  DenseNet比传统的卷积网络所需要的参数更少,因此密集连接带来了特征重用,不需要重新学习冗余的特征图,而且维度拼接的操作,带来了丰富的特征信息,利用更少的卷积就能获得很多的特征图。

3DenseNet一个诟病的问题是内存或显存消耗过多。

3.1真的是这样吗?可以把输入形状换成224×224,来看看实际的显存消耗。3.2有另一种方法来减少显存消耗吗?需要改变框架么?

似乎并非如此,随着输入的增大,显存并没有出现很大改变。

 

posted @ 2023-07-19 11:26  浪矢-CL  阅读(167)  评论(0编辑  收藏  举报