Advertisement

How to Train Your Deep Residual Neural Networks

阅读量:

作者:禅与计算机程序设计艺术

1.简介

深度残差网络(ResNets)是一种复杂的深层神经网络架构,在2015年的ImageNet图像分类任务中展现了卓越的表现。随着深度学习技术的迅速发展以及各公司加大了对该领域的投资,越来越多的研究者开始深入研究与优化ResNets的关键要素及其架构设计与训练策略。本文将深入探讨如何有效训练ResNets模型,并归纳总结当前研究的主要进展及其面临的挑战

2. 基本概念术语说明

2.1 深度学习

深度机器学习体系中的一种核心技术是深度学习(Deep Learning)。这种技术能够使计算机系统具备类似人类的高级认知能力。它是建立在数据驱动的基础之上,并依赖于多层神经网络架构来解析和解决复杂的任务。这种技术的关键在于从大量数据中提取出有价值的信息特征,并将这些信息转化为可被系统理解和应用的具体内容。这样做的结果就是让计算机系统能够从中自主地做出决策或预测判断。这种体系主要包括两个主要分支:一个是卷积神经网络(CNN),另一个是循环神经网络(RNN)。

自动化的特征工程:在深度学习框架中作为第一步实现自动化的特征工程任务,在该过程中需要将原始数据转换为适合模型训练使用的标准格式。这一技术主要涉及计算机视觉、自然语言处理等多个领域的前沿算法和技术实现。
该技术的核心目标是提升模型性能。

在模型训练过程中, 深度学习架构通常包含多个层次结构, 每个层次都可被视为一种带有非线性转换功能的模块. 各层次单元相互作用形成一个复杂而强大的整体架构, 其目的是使模型能够有效地学习和优化各个层次参数. 实现这一目标通常需要充足的数据量、强大的计算能力以及合理的超参数设置.

深度学习模型不仅具备学习复杂特征的能力,并且可以通过其内部参数共享机制来提取更高层次的特征。具体而言,在某一个特定的特征上,在不同层中可能共享相同的权重参数,从而能够充分利用训练好的模型来提取更加抽象和高层次的特征。

2.2 残差块(Residual Block)

残差块单元是ResNet网络的核心模块。它由两个尺寸一致的卷积层组成,在前向通道中首先提取关键特征信息;而后通过直接连接前向通道中的特征图实现跳跃式传递。其优势在于能够有效保持局部细节信息,并避免梯度消失或爆炸的问题;因此在现代深度学习模型中得到了广泛应用。下面是它的结构示意图

其中:

  • 输入变量为x
  • 卷积操作的输出由函数F(x)表示
  • 批量归一化层定义为\mathrm{BN}(x)
  • 可学习的缩放因子和偏置参数分别为\gamma\beta
  • 可学习的卷积核和偏置参数分别为Wb
  • 残差连接中的表达式为h_{i+1} = y + x
  • 残差项r = F(x) - x(residual item)

2.3 ResNets网络结构

该网络架构是深度残差网络(ResNets)的关键组件。其由一系列叠加的残差模块构成。各个残差模块之间可通过快捷连接的方式轻松扩展通道数量。以下是该架构的详细图解:

其中:

  • 基于n个不同设计的模块化残差块构建网络结构,在第i个模块中包含n_i个子模块;
    • 每个子模块均由两个相同的3×3卷积操作组成,在第一个卷积操作中提取输入信号的主要特征信息;
    • 第二个卷积操作通过直接跳跃连接将特征信号快速传递到后续处理环节;
    • 最后一步操作包括一个全局平均池化过程以及随后的全连接计算步骤。

ResNets体系一般包含两种主要架构,即残差网络(ResNet)和深度残差网络(DenseNet)。

2.4 ResNets训练方法

ResNets的训练过程涉及随机参数初始化、采用小批量随机梯度下降算法、运用动量梯度下降法、采用权重衰减技术以及应用提前终止策略等方法。

(1)随机初始化

ResNets在初始阶段通常会选择较高的学习率设置,并且常通过零均值高斯分布进行参数的随机初始化以加速训练过程。由于深度学习模型具有较强的泛化能力可能会导致过拟合现象,在初始化阶段建议选择较低的学习率设置以降低过拟合的风险。

(2)mini-batch SGD

ResNets通常采用小批量随机梯度下降( mini-batch gradient descent)的方式进行训练。在每一个迭代周期内,将整个数据集划分为多个小批量子集,并对每个子集分别运用传统的梯度下降算法来更新模型参数。

(3)动量法

该方法属于优化算法家族中的重要成员,在机器学习领域具有广泛的应用价值。其基本思路是沿迭代过程中的历史梯度方向确定下一步的方向,并在这一过程中动态调节步长系数以实现加速效果。借助于动量项的帮助,在一定程度上可以有效规避陷入局部最优的风险,并加快收敛速度。

(4)权值衰减

权重衰减(Weight Decay)是一种正则化手段,在机器学习中被广泛应用于防止模型过拟合。在每一次迭代过程中,更新后的参数θt相较于上一轮的参数θ{t-1}有所下降。通过这种方式能够有效抑制模型的复杂度。为了实现这一效果,在优化过程中通常会在目标函数中添加一个L₂范数惩罚项。

(5)early stopping策略

该方法指在验证集指标未持续提升的情况下提前终止训练以避免过拟合这一现象。其核心在于持续观察验证集的表现并及时采取措施当提升停滞时停止训练。

(6)Dropout

这是一个广泛应用于深度学习的强大技巧,在提升模型泛化能力方面发挥着关键作用。
在每一次前向传播过程中,在输入数据经过线性变换后会自动引入噪声干扰以降低对特定特征的过度依赖。
这种做法不仅能够缓解梯度消失问题还能帮助优化优化过程。
此外它还能通过抑制深层特征对深层表示的影响从而实现更加鲁棒的学习过程。

2.5 ResNets训练技巧

不只采用传统的训练方法和技巧外

(1)用更小的学习率

在训练初期阶段时,采用较高的学习率可能会使模型出现欠拟合现象.因此建议首先利用较高的学习率对模型参数进行微调训练;随后逐步过渡至较低的学习率以提升训练效率.

(2)初始权值不太重要

对于ResNets模型性能而言,并非初始权重占据主导地位。在训练过程中,关注参数优化而非初设权重更为关键。由此可知,在实际应用中可采用随机初设权重的方式替代人工设计的架构。

(3)数据增强

一种基于数据的增强技术(data augmentation),旨在扩展训练数据集的规模。该技术通过模拟真实的数据分布来提升模型的鲁棒性。主要分为两大类:

  • 在训练过程中, 采用数据增强技术生成新样本, 并将其纳入到训练集中。
  • 在测试阶段中, 仅基于原始数据集中的样本对模型性能进行评估。

(4)Label Smoothing

Label Smoothing是一种用于调整分类器输出的技术手段,在深度学习中被广泛应用于提升模型性能。通过将真实标签进行平滑处理后得到新的目标值分布,在训练过程中能够有效减少过拟合风险。

(5)Batch Normalization

Batch Normalization是一种广泛应用的技术手段,在提升深度神经网络的训练速度与准确性方面发挥了重要作用。通过向输入数据注入白噪声处理,Batch Normalization能够使模型的激活值趋于稳定。

(6)预训练模型

已有预先经过培训的机器学习模型即为"预 trained model"。
采用现有预 training技术能够大幅缩短学习所需的时间,并简化了机器 learning 系统的构建与优化过程。
通过从现有数据中提取关键 feature 信息,并将其应用于新 task 的学习过程中的 fine-tuning 阶段(细调优化),机器 learning 系统能够进一步提升其 performance 和 accuracy。

3. 核心算法原理和具体操作步骤

3.1 参数初始化

在训练ResNet网络模型时,常见采用Xavier初始化法(即Glorot 初始化)或He 初始化法(即Kaiming 初始化)来对模型参数进行初始化。

Xavier初始化是一种较为常见的初始化方案,在各层神经网络中采用不同的权重矩阵以实现网络参数的有效分布。假设输入向量的维度为 D_i ,输出向量的维度为 D_o ,则

He初始化是一种基于激活函数为ReLU特点而设计的初始化方法。该方法旨在保证输入信号在经过激活后的方差与原始输入保持一致

两种初始化方法的优缺点如下表所示:

方法 优点 缺点
Xavier 初始化 提升梯度传播,防止死亡梯度 需要指定输入输出维度
He 初始化 不需要指定输入输出维度 更脆弱的初始化方案,容易产生“裂纹”

3.2 批量归一化

批量归一化(Batch Normalization)是一种正则化方法,在处理输入数据时施加白噪声处理,从而使得模型的激活值趋于稳定。当将其与激活函数结合使用时,在网络中发挥出以下功能:1) 有助于提升训练效率;2) 免缓梯度消失现象;3) 提升模型泛化性能;4) 加速收敛速度。

缓解训练过程中的梯度消失或爆炸问题:Batch Normalization通过将输入数据进行归一化处理,使各层输入数据的分布趋于稳定,并有效抑制训练过程中可能出现的梯度消失或爆炸现象。

提升训练效率:Batch Normalization通过降低计算过程中的不稳定性,在各层的前向传播过程中实现更为平稳的状态转移,从而显著提升训练效率。

在规范化模型中采用Batch Normalization时,其机制是将输入数据的不同尺寸值转换至同一数值区间,并以此确保模型在处理这些数据时保持方差的一致性。

Batch Normalization的具体操作步骤如下:

对于网络中的每一层(除输入层和输出层),同时计算其输入变量x_i和对应的输出变量y_i
对输入变量x_i执行均值\mu=0、标准差\sigma=1的归一化处理。
利用全连接层进行操作以确定Batch Normalization算法中的归一化参数\gamma和偏移量\beta
将输入变量x_i经过乘法运算后加上偏移量\beta_i
对中间结果变量进行均值\mu=0, 标准差\sigma=1"的归一化处理。
更新归一化参数$\gamma_i=\gamma,\beta_j=\beta"。

Batch Normalization在实际应用中也有一些注意事项,比如:

  1. 是否有必要在每一层都应用Batch Normalization?实际上,在内部的各隐藏层中才有必要这样做。
  2. 是否有理由认为Batch Normalization的参数应逐级调整?论文中指出无需进行这样的调整。

3.3 残差连接

残差连接(Residual Connection)是一种训练方法,在深度学习中被广泛应用于提升模型性能。它通过引入跳跃连接来改善网络训练过程中的优化效果。具体而言,在传统的前馈神经网络中,在每一层之间添加一个跳跃连接能够帮助缓解梯度消失或爆炸的问题。该技术的基本思路是将各层之间的残差信号直接传递给下一层以促进信息的有效流动和误差的反向传播效率的提升。具体实施步骤包括以下几点:首先在输入数据经过若干层变换后引入一个跳跃连接将其原始输入与变换后的特征进行叠加运算;其次通过这种叠加操作使得网络在优化过程中能够更好地捕捉特征间的差异并加速收敛速度;最后通过这种方式能够有效避免传统前馈网络在深层学习中常见的梯度消失或爆炸现象从而提升模型的整体性能表现

对于网络中的每一层(除输入层和输出层),计算该层的输入变量x_i及其对应的输出变量y_i
针对每个节点k∈N_{in}^l∪N_{out}^l}

  • 首先检查当前输入$x_k是否与对应的输出值之间存在关联关系;
  • 若发现存在这样的关联关系,则将它们直接相加;
  • 否则,在后续计算中将这些特征视为独立维度并进行处理。
    在每一步操作后:
  • 如果存在上述关联关系,则将当前预测值与实际观测值进行比较;
  • 否则,在后续步骤中维持原始预测结果。

残差连接的好处如下:

  1. 该方法能够更可靠地存储局部信息,并避免数据泄露。
  2. 该算法旨在降低运算负担的同时优化资源利用。
  3. 支持快速而高效的网络训练过程。

3.4 滑动窗口与空间金字塔池化

滑动窗口机制与空间金字塔池化(Spatial Pyramid Pooling)中包含了两项关键的技术手段,在增强模型的感受野能力的同时也降低了计算开销。

滑动window是一种用于处理image data的技术;通过限定window size为3×3来遍历整个image区域,并在每次滑动window时执行相关操作。在ResNet网络结构中使用了滑动窗技术来extract local feature information;同时配合空间金字塔池化方法被used for extract global feature information。

空间金字塔池化利用不同尺度的池化操作提取出多级特征,并将这些特征整合起来作为系统的最终输出。空间金字塔池化的具体操作步骤如下:

  1. 将输入图像分割为若干不同尺寸的子图。
  2. 对于每一个子图而言,在其上分别采用最大池化方法或平均池化方法提取特征。
  3. 将各个子图提取到的特征进行融合处理后整合在一起作为最终输出的结果。

滑动窗口与空间金字塔池化的好处如下:

  1. 可以提升模型的感受野。
  2. 减少计算量。
  3. 可以帮助模型融合不同尺度的特征。

4. 具体代码实例和解释说明

让我们以MNIST数据集为例具体说明如何利用TensorFlow构建一个ResNet网络 假设使用一台配备GPU的电脑 请查看以下详细的代码实例

Here's an example using the MNIST dataset to illustrate how to implement a ResNet model using TensorFlow. Assuming a computer equipped with a GPU, please refer to the following detailed code example for implementation guidance.

复制代码
    import tensorflow as tf
    
    # define the input and output of the network
    inputs = tf.keras.layers.Input(shape=(28, 28))
    outputs = tf.keras.layers.Flatten()(inputs)
    outputs = tf.keras.layers.Dense(units=256)(outputs)
    outputs = tf.keras.layers.Activation("relu")(outputs)
    outputs = tf.keras.layers.Dense(units=10)(outputs)
    outputs = tf.keras.layers.Softmax()(outputs)
    model = tf.keras.models.Model(inputs=inputs, outputs=outputs)
    
    # set the optimizer and loss function for training the model
    optimizer = tf.keras.optimizers.SGD()
    loss_func = tf.keras.losses.CategoricalCrossentropy()
    
    # compile the model with the specified optimizer and loss function
    model.compile(optimizer=optimizer,
              loss=loss_func,
              metrics=["accuracy"])
    
    # load MNIST dataset and split it into training set and validation set
    mnist = tf.keras.datasets.mnist
    (train_images, train_labels), (test_images, test_labels) = mnist.load_data()
    train_images = train_images / 255.0
    test_images = test_images / 255.0
    train_images = np.expand_dims(train_images, axis=-1) # add channel dimension
    test_images = np.expand_dims(test_images, axis=-1) # add channel dimension
    train_images = tf.convert_to_tensor(train_images, dtype=tf.float32)
    train_labels = tf.keras.utils.to_categorical(train_labels, num_classes=10)
    train_labels = tf.convert_to_tensor(train_labels, dtype=tf.float32)
    val_images = tf.slice(train_images, [0,0], [50000, -1])
    val_labels = tf.slice(train_labels, [0,0], [50000, -1])
    train_images = tf.slice(train_images, [50000,0], [-1,-1])
    train_labels = tf.slice(train_labels, [50000,0], [-1,-1])
    
    # train the model using mini-batch SGD and early stopping policy
    history = model.fit(train_images,
                    train_labels,
                    batch_size=64,
                    epochs=10,
                    validation_data=(val_images, val_labels),
                    callbacks=[tf.keras.callbacks.EarlyStopping()])
    
    # evaluate the performance on test set
    test_loss, test_acc = model.evaluate(test_images, test_labels, verbose=2)
    print("Test accuracy:", test_acc)
    
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
      
    
    代码解读

在这个示例代码中,首先构建了一个较为基础的神经网络架构:包含一层输入层、一层扁平化层、一层全连接层以及一层 softmax 输出层。随后配置了优化算法(随机梯度下降SGD)以及损失函数(分类交叉熵Categorical Crossentropy)。接着导入并划分MNIST数据集,并将其划分为训练集与验证集两部分。接着配置训练参数并对模型进行了编译操作。随后采用了批量大小为64的小批量梯度下降方法来进行训练,并设置了早停策略以防止过拟合现象的发生。整个过程总共进行了10轮次的迭代训练工作之后,在测试阶段计算并输出了模型在测试集上的准确率指标值

这个示例代码仅包含一个小型ResNet模型,并未全面体现所有ResNets的特点。它主要作为初步认识该网络架构的一个参考。如需更深入的ResNets实现细节,请访问作者提供的GitHub仓库:https://github.com/tensorflow/models/tree/master/official/resnet

全部评论 (0)

还没有任何评论哟~