深度学习的实践层面

深度学习的实践层面

设计机器学习应用

  1. 在训练神经网络时,超参数选择是一个高度迭代的过程。我们通常从一个初步的模型框架开始,进行编码、运行和测试,通过不断调整优化模型。

    数据集一般划分为三部分:训练集、验证集和测试集。常见的比例是60%用于训练,20%用于验证,20%用于测试。然而,当数据量非常大时,验证集和测试集的比例会相应减小。验证集的目的是帮助选择最优模型,而测试集用于评估最终模型的泛化能力。对于百万级数据集,验证集和测试集可以相对较小,通常验证集选取1万条数据,测试集选取1000条数据即可。

    在某些情况下,尤其是数据量巨大时,可以不设置独立的测试集,使用验证集同时承担模型选择和性能评估的功能。不过,这样可能会导致一定的偏差,尤其是验证集数据被过度拟合时。如果项目不需要无偏评估,或者模型较为简单,不容易出现过拟合,那么可以不设置独立的测试集,将验证集视为“训练验证集”。

  2. 在深度学习中,一个常见问题是训练集和测试集的分布不一致。例如,训练集可能来自高质量的网络猫咪图片,而验证集和测试集则来自用户上传的手机拍摄图片。由于两者在分辨率和质量上的差异,这种分布不一致可能导致模型在测试时性能下降。

    因此,确保验证集和测试集的分布相似至关重要。只有当它们来自相同的分布时,验证集才能有效评估模型的表现,进而帮助优化模型。如果两者分布不匹配,可能导致评估偏差,影响模型的泛化能力。

  3. 在机器学习模型的训练中,偏差和方差是两个关键的评估指标,可以帮助理解模型的拟合情况。

    假定有一个二维数据集与可视化拟合模型:

    https://cdn.acwing.com/media/article/image/2024/11/15/181746_cfe93bd2a3-bias.png

    第一张图不能很好的拟合数据,属于高偏差、欠拟合现象,这种接近线性的分类器数据拟合度低。

    第三张图片过度拟合数据,属于高方差、过拟合现象。曲线或高次函数的灵活性太高以致拟合了错误样本和活跃数据。

    在二维数据集中,可以绘制数据来可视化偏差与方差。高维数据无法可视化边界,但可以通过部分指标来展现。通过查看训练集误差和验证集误差,我们便可以诊断算法。

    • 偏差与欠拟合:高偏差意味着模型没有很好地拟合训练数据,通常表现为训练集和验证集误差都很高。例如,训练集误差为15%,验证集误差为16%,说明模型欠拟合,偏差较高,但方差较小。
    • 方差与过拟合:高方差则意味着模型过于复杂,过拟合了训练数据中的噪声和异常值。例如,训练集误差为1%,验证集误差为11%,表示模型在训练集上表现很好,但在验证集上泛化性能差,方差较高。
    • 偏差与方差同时高:如果训练集误差和验证集误差都很高,比如训练集误差为15%,验证集误差为30%,这通常表明模型在训练数据和验证数据上都未能充分学习,偏差和方差都较高。高维数据中,部分区域可能存在高偏差或高方差,这时很难通过简单的可视化来识别。
    • 低偏差与低方差:理想情况下,训练集和验证集的误差都较低。例如,训练集误差为0.5%,验证集误差为1%,表示模型既能准确拟合训练数据,也具有较好的泛化能力。

    贝叶斯误差是指在给定数据和任务下,任何模型都无法超越的最小误差,通常反映了数据本身的噪声或内在不确定性。例如,在猫狗分类任务中,假设贝叶斯误差为0%,表示模型理论上可以达到完美分类。然而,如果贝叶斯误差为15%,那么即使训练集误差为15%,这也说明偏差不高。

    当数据本身非常复杂或噪声较多时,即使是人类或系统也难以准确识别。这时,最优误差(贝叶斯误差)会较高,我们的分析需要根据具体情况调整,避免过度拟合或过度偏向理论最优。

  4. 在神经网络的训练过程中,需要先识别模型的主要问题是偏差还是方差,并选择相应的策略进行优化。高偏差模型无法很好拟合训练集(欠拟合),高方差训练集表现理想,但验证集表现不佳(过拟合)。

    解决高偏差问题:

    • 使用更大的网络(增加隐藏层或隐藏单元);
    • 延长训练时间;
    • 尝试更先进的优化算法;
    • 测试不同的网络架构(可能有效也可能无效)。

    解决高方差问题:

    • 增加训练数据;
    • 应用正则化(如L1、L2正则化或Dropout);
    • 寻找能减少方差的网络架构(有时可以同时优化偏差和方差)。

    同时优化偏差和方差:

    • 现代深度学习得益于大数据和更强的计算能力,可以更好地同时减少偏差和方差,而无需严格权衡两者。
    • 增大网络规模往往能降低偏差,增加数据或适度正则化可有效减少方差,关键在于不断尝试不同的网络架构和优化策略,找到能够降低偏差与方差的平衡点。

正则化

  1. 在逻辑回归模型中,为了防止过拟合,我们可以在代价函数中加入正则化项。正则化项限制了参数的大小,从而控制模型的复杂度,提升泛化能力。

    L2正则化:

    \[J(\omega,b)=\frac{1}{m}\sum_{i=1}^{m}L(\hat{y}^{(i)},y^{(i)})+\frac{\lambda}{2m}||\omega||^2_2 \]

    其中:

    • \(L(\hat{y}^{(i)}, y^{(i)})\):模型的基础损失函数(如逻辑回归的交叉熵损失)。
    • \(||\omega||_2^2=\omega^T \omega= \sum_{j=1}^n \omega_j^2\):参数向量 \(\omega\) 的欧几里得范数的平方。
    • \(\lambda\):正则化强度的超参数,通过控制正则化项的权重来调节模型的复杂度。

    L2正则化的效果是对所有参数施加平方惩罚,使得较大的参数减小,但不直接使其变为零。

    L1正则化:

    \[J(\omega,b)=\frac{1}{m}\sum_{i=1}^{m}L(\hat{y}^{(i)},y^{(i)})+\frac{\lambda}{2m}||\omega||_1 \]

    其中:

    • \(||\omega||1 = \sum{j=1}^n |\omega_j|\):参数向量 \(\omega\) 的L1范数,计算所有参数绝对值的总和。

    L1正则化的效果是鼓励参数稀疏化(即许多参数被压缩到0),这使其非常适合特征选择任务。

    正则化参数 \(\lambda\)
    \(\lambda\) 是权衡正则化项与原始损失项的重要超参数,通常通过交叉验证来选择合适的值。

    • 较大的 \(\lambda\) 会使模型偏向更简单,减少过拟合,但可能导致欠拟合。
    • 较小的 \(\lambda\) 则会允许更复杂的模型,但可能会过拟合训练数据。

    在深度神经网络中,正则化同样可以帮助防止过拟合。对整个网络参数施加正则化后,代价函数变为:

    \[J(\omega^{[1]},b^{[1]},...,\omega^{[L]},b^{[L]}) = \frac{1}{m}\sum_{i=1}^{m}L(\hat{y}^{(i)},y^{(i)})+\frac{\lambda}{2m}\sum_{l=1}^L||\omega^{[l]}||_F^2 \]

    对于神经网络中的权重矩阵 \(\omega^{[l]} \in \mathbb{R}^{n^{[l]} \times n^{[l-1]}}\),其弗罗贝尼乌斯范数的平方定义为:

    \[||\omega^{[l]}||_F^2=\sum_{i=1}^{n^{[l]}} \sum_{j=1}^{n^{[l-1]}}(\omega_{ij}^{[l]})^2 \]

    即矩阵中所有元素的平方和。加入正则化后,权重更新的公式为:

    \[d\omega^{[l]}=\text{backpropagation}+\frac{\lambda}{m}\omega^{[l]} \\ \omega^{[l]}=\omega^{[l]}-\alpha d\omega^{[l]} \\= \omega^{[l]}-\alpha \cdot \text{backpropagation}-\frac{\alpha \lambda}{m}\omega^{[l]} \\ =(1-\frac{\alpha \lambda}{m})\omega^{[l]} -\alpha \cdot \text{backpropagation} \]

    正则化会让权重在每次更新时乘以一个小于1的系数 \(1 - \frac{\alpha \lambda}{m}\),逐步减小权重的大小。因此,L2正则化也被称为权重衰减(Weight Decay)

  2. 在神经网络中,如果正则化参数 \(\lambda\) 很大,那么权重 \(\omega\) 会被压缩为接近0的值,神经网络的隐藏单元的作用变小,网络趋向于简单化。网络表现类似逻辑回归模型,进入高偏差(欠拟合)状态。那么就会存在适当的正则化参数 \(\lambda\) 能使模型在偏差和方差之间达到中间平衡状态。

    随着正则化参数 \(\lambda\) 的增大,权重 \(\omega\) 也会逐渐减小,那么 \(z=\omega \cdot x+b\) 也会很小。激活函数(例如tanh)的取值会落入接近线性的区域,网络整体表现为线性函数。线性网络更简单,不容易拟合数据的复杂非线性特征,因此减少了过拟合。

    在训练模型时,可以绘制代价函数—迭代轮数图来展示效果,在添加正则化后,要用增加了惩罚项的代价函数进行梯度下降,否则可能会导致代价函数不单调下降。

  3. Dropout 是一种有效的正则化技术,主要用于防止神经网络的过拟合。其核心思想是在训练过程中,通过随机“丢弃”神经网络中的部分节点(使其激活值为 0),防止模型过度依赖某些节点或特征。这样,每次训练时使用的网络结构是不同的,从而减少了模型对特定节点的依赖,增强了网络的泛化能力。
    在训练过程中,对于每个训练样本,Dropout 会根据设定的概率随机选择并丢弃神经网络中的某些节点。丢弃的节点在当前训练步骤中不会参与前向传播和反向传播,从而降低了网络的复杂度并减少过拟合的风险。对于同样的神经网络,不同的训练样本,失活的隐藏单元也不同。

    反向随机失活(Inverted dropout)是 Dropout 的常用实现方法。在训练阶段,随机丢弃部分节点,为了补偿丢弃节点对期望值的影响,训练阶段会将激活值按保留概率 keep-prob 进行缩放。在测试阶段不再进行 Dropout,而是使用完整的网络进行预测。

    训练阶段

    • 对于每一层的每个节点,根据设定的保留概率 keep-prob 决定该节点是否被保留。

    • 通过生成一个随机数矩阵 \(d^{[l]}\),每个节点都有一个 0 到 1 之间的随机值,如果该值小于 keep-prob,则该节点被保留;如果大于 keep-prob,则该节点被丢弃。

      d3 = np.random.rand(a3.shape[0],a3.shape[1])

      d3 = (d3 < keep_prob).astype(int)

    • 将生成的 dropout 向量 \(d^{[l]}\) 与当前层的激活值 \(a^{[l]}\) 相乘。被丢弃的节点会变为 0,保留的节点保持原值。

      a3 = np.multiply(d3, a3)

    • 由于在训练过程中每一层的某些节点被丢弃,激活值的期望会发生变化。例如,如果 keep-prob 为 0.8,则大约 20% 的节点会被丢弃。为了保证训练过程中每层的激活值的期望一致,我们需要对每层的激活值进行缩放,即将激活值除以 keep-prob,确保期望值保持不变。

      a3 = a3 / keep_prob

    • 反向传播仍然按正常方式进行,只不过丢弃的节点不参与梯度更新。

      da2 = np.multiply(da2, d2)

      da2 = da2 / keep_prob

    测试阶段

    • 在测试阶段,不再执行 Dropout 操作。整个网络的所有节点都会参与前向传播和预测计算。此时,我们使用完整的网络结构,不再丢弃任何节点。
  4. Dropout是一种通过随机移除神经网络中的单元或连接来实现正则化的技术。这种随机性使网络在训练过程中降低了对特定特征的依赖性,从而增强了模型的泛化能力。与此同时,Dropout在一定程度上具有类似于L2正则化的效果,它通过收缩权重的平方范数,防止权重过大,从而有效抑制过拟合。此外,Dropout的随机性使其在具有不同输入范围的场景中表现更为优异。

    为了更精细地控制正则化强度,Dropout允许为不同层设置不同的Keep-prob。过拟合程度较低的层可以设置较高的Keep-prob值,从而减少Dropout的强度;而对于参数多、容易过拟合的层,Keep-prob值应设置得较低以加强正则化。对于输入层和输出层,通常会选择接近1的Keep-prob值,因为随机删除输入特征可能对模型性能产生负面影响,且输出层特征数量较少,更容易受到特征删除的影响。

    在实际应用中,Dropout特别适合于计算机视觉领域。这是因为该领域通常面临大规模高维数据,而数据不足和过拟合是常见问题。通过随机化特征选择,Dropout可以显著提高计算机视觉模型的性能,使其成为这一领域的默认选择之一。

    然而,Dropout也存在一些局限性。例如,由于每次迭代中随机移除的单元不同,导致代价函数 \(J\) 的定义不再明确。代价函数的变化不再单调,难以直观地评估梯度下降的性能。因此,在调试过程中,建议暂时关闭Dropout(将Keep-prob设置为1),以确保模型的梯度下降过程正常无误,调试完成后再重新启用Dropout。

  5. 数据扩增可以有效减少神经网络中过拟合问题。对于图片分类任务,可以通过一系列图像变换操作来扩大数据集,例如水平翻转、随机裁剪、旋转、放大或扭曲图片等。这些操作能够生成额外的训练样本,增加数据多样性。

    需要注意的是,数据扩增操作应保持原始任务的语义不变。例如,水平翻转后的猫咪图片依然是猫,而垂直翻转可能导致语义错误。此外,对于不同的任务,数据扩增的策略可以有所调整。例如,在光学字符识别中,可以通过轻微旋转、扭曲字符的形状来扩充数据,生成的样本仍然保持原有的字符特征。实际操作中,变形程度不宜过大,以免影响模型对原始任务的学习能力。

  6. 在训练的过程中,我们可以绘制训练误差以及验证误差。随着模型的迭代,训练误差和代价函数会随着训练迭代单调下降,但验证误差会先下降,随后在过拟合阶段开始上升。通过早停(early stopping)机制,可以选择在验证误差最低点停止训练,从而避免过度拟合。

    https://cdn.acwing.com/media/article/image/2024/11/19/181746_7819f157a6-early.png

    早停的作用类似L2正则化,它限制了参数 \(\omega\) 的增长。在训练初期,参数 \(\omega\) 的值较小(随机初始化为较小值)。随着训练迭代, \(\omega\) 的值逐渐变大。早停会在验证集误差最低点停止训练,使得 \(\omega\) 的弗罗贝尼乌斯范数( \(||w||_F\) )保持在中等水平,防止权重过大导致过拟合。

    早停只需运行梯度下降过程即可找到合适的权重值,无需对正则化参数 \(\lambda\) 进行繁琐的超参数搜索。也不需要尝试多组正则化参数,只通过监控验证误差即可实现正则化效果。

    但是早停也存在一些缺点。它同时解决了两个问题:优化代价函数 \(J\) 和防止过拟合,这导致优化和正则化两个任务无法独立处理,增加了问题复杂性。同时,提早停止训练过程可能导致代价函数 \(J\) 未达到全局最优值。

  7. 在测试期间,正则化参数不一定必须设置为0,以避免得到随机结果。因为正则化参数影响权重在训练期间(即反向传播期间)的变化方式,在前向传播期间(即进行测试预测时)没有影响。

  8. 在一次实验中,决定不使用测试集,而仅使用验证集。在这种情况下,他可能对验证集过拟合。在没有单独测试集的情况下,可能会使用验证集反复调整模型。这可能会导致在验证集上过拟合,因为模型参数和超参数是专门为在验证集上表现良好而选择的。

    模型的偏差或者方差都可以在验证集上计算,测试集也不是在所有情况下都必须的。

设置优化问题

  1. 输入归一化是一种通过调整输入数据分布来加速神经网络训练的技术,其核心是将特征值调整为均值为0、标准差为1的标准正态分布。这种归一化方式可以显著提高梯度下降的效率,减少训练时间,并提升模型的稳定性。归一化的具体步骤如下:

    \[\mu = \frac{1}{m}\sum_{i=1}^{m}x^{(i)} \\ \sigma^2=\frac{1}{m}\sum_{i=1}^{m}(x^{(i)}-\mu)^2 \\ x_{norm}=\frac{x-\mu}{\sigma} \]

    通过这种方法,可以将每个输入特征调整为一个标准化的范围,从而减少特征间的数值差异。

    在训练集上计算得到的均值 \(\mu\)\(\sigma\) 必须保存,并用于对测试集和新数据进行归一化。这是为了确保训练数据和测试数据在同一尺度上进行模型预测,避免数据分布不一致的问题。

    归一化需要对每个输入特征单独进行,而不是对所有特征整体归一化。

    如果输入特征未归一化,各特征的取值范围可能差异较大,导致代价函数表现为狭长的斜面。在这种情况下,梯度下降需要迭代多次才能找到最优值。归一化后,代价函数更接近对称圆形,可以使梯度下降更快地找到最优值,并允许使用更大的学习率。

    https://cdn.acwing.com/media/article/image/2024/11/19/181746_6bb51d6ea6-norm.png

  2. 在神经网络中,假设使用线性激活函数 \(g(z)=z\) 并且忽略偏置项,那么网络输出为:

    \[\hat{y}=\omega^{L}\omega^{L-1}...\omega^{[2]}\omega^{[1]}x \]

    梯度爆炸:假设每个权重矩阵都等于 \(\omega^{[l]} = \begin{bmatrix} 1.5 & 0 \\0 & 1.5 \\\end{bmatrix}\),那么有 \(y= \begin{bmatrix} 1.5 & 0 \\ 0 & 1.5 \\\end{bmatrix}^{(L)}x\),随着层数 \(L\) 的增加,激活值和梯度值会以指数形式增长到非常大的值,导致梯度下降算法无法有效更新权重。

    梯度爆炸会导致权重更新过大,模型无法收敛。

    梯度消失:假设每个权重矩阵都等于 \(\omega^{[l]} = \begin{bmatrix} 0.5 & 0 \\0 & 0.5 \\\end{bmatrix}\),那么有 \(y= \begin{bmatrix} 0.5 & 0 \\ 0 & 0.5 \\\end{bmatrix}^{(L)}x\),随着层数 \(L\) 的增加,激活值和梯度值会以指数形式减小到接近0,导致模型难以学习。

    梯度消失会导致权重更新非常缓慢,模型学习速度显著下降。

    在层数较多(例如 \(L = 150\) )的情况下,这两个问题尤为显著,限制了深度神经网络的有效训练。

  3. 通过合理选择神经网络的参数初始化方式,可以有效缓解梯度消失与梯度爆炸问题。这种方法通过控制权重初始值的范围,使得每层神经元的激活值在正向传播和反向传播过程中保持稳定,从而提升深度网络的训练效率。

    假设忽略偏置项 \(b\),神经网络中的激活值可以表示为 \(z = w_{1}x_{1} + w_{2}x_{2} + \ldots +w_{n}x_{n}\)。当神经元的输入特征数量 \(n\) 较大时,权重 \(\omega\) 的值若未控制好,会导致梯度消失与梯度爆炸的问题。

    为使激活值 \(z\) 的范围适中,可通过调整权重初始化值的范围来稳定网络的前向传播与梯度传播。直观上,当 \(n\) 较大时,每个权重 \(\omega_i\) 应该较小,以避免激活值的过大或过小。

    常见的权重初始化方法:

    • 均匀初始化

      将权重 \(\omega_i\) 的值初始化为

      \[\omega_i=\frac{1}{n} \]

      其中 \(n\) 是神经元的输入特征数量。这种方法简单直观,适用于浅层网络,但在深度网络中效果有限。

    • Xavier初始化
      Xavier 初始化适用于Sigmoid和Tanh激活函数,目的是让每层输出的方差尽可能一致。

      \[ w^{[l]} = np.random.randn( \text{shape})*\sqrt{\frac{1}{n^{[l-1]}}} \]

      通过该公式,权重的初始值服从一个方差为 \(\frac{1}{n^{[l-1]}}\) 的正态分布,防止激活值在层与层之间扩展或缩小。

    • He初始化
      He 初始化适用于ReLU或Leaky ReLU激活函数,专为解决梯度消失问题设计。

      \[ w^{[l]} = np.random.randn( \text{shape})*\sqrt{\frac{2}{n^{[l-1]}}} \]

      相较于 Xavier 初始化,这里用 \(\sqrt{\frac{2}{n^{[l-1]}}}\) 替代 \(\sqrt{\frac{1}{n^{[l-1]}}}\),以适应 ReLU 激活函数的不对称性(ReLU 的输出非负)。

    • Yoshua初始化
      Yoshua 初始化是 Xavier 初始化的变种,适用于 Tanh 激活函数,旨在结合前一层和当前层的神经元数量。通过综合考虑前后两层神经元的数量,进一步优化权重初始化的方差。

      \[ w^{[l]} = np.random.randn( \text{shape})* \sqrt{\frac{2}{n^{[l-1]} + n^{\left[l\right]}}} \]

  4. 梯度检验是一种用于验证反向传播算法正确性的方法。它通过数值近似的方式计算代价函数的梯度,并将其与反向传播计算得到的梯度进行比较,来检查实现中的潜在错误。

    首先,将神经网络的所有参数(如 \(\omega^{[1]}, b^{[1]}, \omega^{[2]}, b^{[2]}\) 等)转换为一个大的向量 \(\theta\) 。然后将反向传播计算的所有梯度( \(d\omega^{[1]}, db^{[1]}, d\omega^{[2]}, db^{[2]}\) 等)也转换为一个大的向量 \(d\theta\) ,使其维度与 \(\theta\)一致。

    对每个 \(\theta_i\) 计算一个近似梯度值 \(d\theta_{\text{approx}}[i]\)

    \[ d\theta_{\text{approx}}\left[i \right] = \frac{J\left( \theta_{1},\theta_{2},\ldots,\theta_{i} + \varepsilon,\ldots \right) - J\left( \theta_{1},\theta_{2},\ldots,\theta_{i} - \varepsilon,\ldots \right)}{2\varepsilon} \]

    其中, \(\varepsilon\) 是一个非常小的值(通常取 \(10^{-7}\) ), \(J\) 是代价函数。

    比较 \(d\theta_{\text{approx}}\)\(d\theta\) 是否接近,使用欧几里得距离( \(||d\theta_{\text{approx}} - d\theta||_2\) )衡量它们之间的误差。归一化距离公式:

    \[ \text{distance} = \frac{{||d\theta_{\text{approx}} - d\theta||}_2}{||d\theta_{\text{approx}}||_2 + ||d\theta||_2} \]

    比较结果:

    • \(< 10^{-7}\) :非常好,梯度正确。
    • \(10^{-7}\)\(10^{-5}\) :可能正确,但需检查每个元素是否过大。
    • \(> 10^{-3}\):很可能存在错误,需要仔细检查代码。

    如果误差过大,逐步检查每个参数 \(\theta_i\) 的近似梯度值和反向传播的梯度值,定位可能的错误。

  5. 梯度检验只适用于调试阶段,在训练过程中,不要使用梯度检验,因为计算 \(d\theta_{\text{approx}}[i]\) 的过程非常耗时。梯度检验仅用于确认反向传播的实现是否正确。在确认无误后,应关闭梯度检验,以提高训练效率。

    如果梯度检验失败,需逐项检查 \(d\theta_{\text{approx}}[i]\)\(d\theta[i]\) ,找出哪些元素差异较大。定位差异较大的参数可能会帮助发现潜在的bug。例如,如果某一层的 \(d\omega\)\(db\) 差异较大,可以专注检查该层的梯度计算逻辑。
    如果使用正则化(如L2正则化),梯度检验时必须确保代价函数 \(J\) 包含正则化项。计算梯度时, \(d\theta\) 需要同时考虑代价函数的主项和正则化项的贡献,以保持一致性。

    由于 Dropout 在每次前向传播中随机舍弃部分神经元,其动态特性会导致梯度检验的结果不稳定。调试过程中建议关闭 Dropout,或将 Dropout 的保留概率(keepprob)设置为 1.0,以禁用 Dropout。在禁用 Dropout 的情况下,确保反向传播逻辑正确后,再重新启用 Dropout。

    梯度检验通常在参数较小时(如随机初始化时)更为可靠,因为此时梯度下降的实现可能更准确。随着训练的进行, \(\omega\)\(b\) 可能增大,数值梯度的近似值可能会变得不再精确。如果需要,可以在训练一段时间后再次运行梯度检验,确保参数较大时反向传播仍然准确。

posted @ 2024-11-19 23:26  钰见梵星  阅读(2)  评论(0编辑  收藏  举报