返回介绍

数学基础

统计学习

深度学习

工具

Scala

五、调试策略

发布于 2023-07-17 23:38:23 字数 7159 浏览 0 评论 0 收藏 0

  1. 当一个机器学习系统效果不好时,很难判断效果不好的原因是算法本身,还是算法实现错误。由于各种原因,机器学习系统很难调试

    • 大多数情况下,我们不能提前知道算法的行为

      • 实际上,使用机器学习的出发点是:机器学习会发现一些我们无法发现的有用的行为
      • 如果我们在一个新的分类任务上训练一个神经网络,它达到了 5% 的测试误差。我们无法直接知道:这是期望的结果,还是次优的结果?
    • 大部分机器学习模型有多个自适应的部分

      • 如果某个部分失效了,那么其他部分仍然可以自适应这种状况,并获得大致可接受的性能
      • 比如在多层神经网络中,假设我们在梯度下降中对偏置更新时犯了一个错误 $ MathJax-Element-20 $ (错误原因:没有使用梯度。其中 $ MathJax-Element-21 $ 为学习率)。这个错误导致偏置在学习过程中不断减小。但是只是检查模型输出的话,这个错误并不是显而易见的。因为权重 $ MathJax-Element-44 $ 可以自适应的补偿偏置 $ MathJax-Element-23 $ 的错误
  2. 大部分神经网络的调试策略都是解决上述两个难点的一个或者两个

    • 我们可以设计一种足够简单的情况,能够提前得到正确结果,判断模型预测是否与之相符
    • 我们可以设计一个测试(类似于 UnitTest),独立检查神经网络实现的各个部分
  3. 一些重要的调试方法如下:

    • 可视化计算中模型的行为:直接观察机器学习模型运行机器任务,有助于确定其达到的量化性能数据是否看上去合理

      • 仅仅评估模型性能可能是最具破坏性的错误之一,因为它会使你在系统出问题时误以为系统运行良好
    • 可视化那些最严重的错误:大多数模型能够输出运行任务时的某种置信度(如基于softmax函数输出层的分类器给每个类分配了一个概率)。如果某个样本被错误的分类,而且其分类置信度很低,那么可以检查这些样本的问题

    • 根据训练和测试误差检测软件:通常我们很难确定底层软件是否正确实现,而测试和训练误差提供了一些线索

      • 如果训练误差较低,而测试误差较高,那么很可能是由于算法过拟合。也有可能是软件错误,导致测试误差未能正确地度量
      • 如果训练误差和测试误差都很高,那么很难确定是由于软件错误,还是由于算法模型的欠拟合。此时需要进一步测试,如下所述
    • 监控激活函数值和梯度的直方图:可视化激活函数值和梯度的统计量往往是有用的。

      • 隐单元的激活函数值告诉我们:该单元是否饱和,或者它们饱和的频率如何(如多久关闭一次,是否永远关闭,以及采用双曲正切单元时饱和的程度)
      • 梯度的统计量告诉我们:梯度是否快速的增长或者快速的消失
      • 参数的梯度的量级和参数的量级也有意义:我们希望参数在一个小批量更新中变化的幅度是参数量值的 1% 这样的级别(而不是 50% 或者 0.0001%,这两者要么导致参数移动太快,要么太慢)
      • 如果数据是稀疏的(如自然语言),则有些参数可能是很少更新的,检测时需要注意
  4. 许多深度学习算法为每一步的结果产生了某种保证。其中包括:

    • 目标函数值确保在算法的迭代步中不会增加

    • 某些变量的导数在算法的每一步中都是 0

    • 所有变量的梯度在收敛时,会变为 0

      由于计算机存储浮点数的舍入误差,这些条件可能会有误差

    如果违反了这些保证,那么一定是软件错误

5.1 梯度检查

  1. 比较反向传播导数和数值导数:如果我们正在使用一个软件框架或者库,那么必须定义 bprop方法,常见的错误原因是未能正确的实现梯度表达。验证该错误的一个方法是:比较实现的自动求导和通过有限差分计算的导数

    $ \frac{df(x)}{dx}=\frac{f(x+h)-f(x)}{h} $

    或者采用中心差分法:

    $ \frac{df(x)}{dx}=\frac{f(x+h)-f(x-h)}{2h} $

    其中 $ MathJax-Element-24 $ 必须足够大,从而确保不会由于有限精度问题产生舍入误差

    • 如果梯度是雅克比矩阵(输出为向量,输入也是向量),则我们可以多次使用有限差分法来评估所有的偏导数

    • 通常推荐使用中心差分法,因为根据泰勒展开,有:

      $ \frac{f(x+h)-f(x)}{h}=f^\prime(x)+O(h)\\ \frac{f(x+h)-f(x-h)}{2h}=f^\prime(x)+O(h^2) $

      使用中心差分法的误差更小。

  2. 理论上进行梯度检查很简单,就是把解析的梯度和数值计算的梯度进行比较。但是实际操作过程中,这个过程复杂且容易出错。

  3. 使用中心化公式来计算数值梯度。

    通常我们计算数值梯度时,采用:

    $ \frac{df(x)}{dx}=\frac{f(x+h)-f(x)}{h} $

    其中 $ MathJax-Element-39 $ 为一个很小的数字,在实践过程中近似为 $ MathJax-Element-26 $ 。但是实践中证明,使用中心化公式效果更好:

    $ \frac{df(x)}{dx}=\frac{f(x+h)-f(x-h)}{2h} $
    • 缺点:在检查梯度的每个维度时,需要计算两次损失函数
    • 优点:梯度的数值求解结果会准确的多。中心化公式的近似误差为 $ MathJax-Element-27 $ ,而前一个公式的近似误差为 $ MathJax-Element-28 $
  4. 使用相对误差来比较。对于数值梯度 $ MathJax-Element-29 $ 和解析梯度 $ MathJax-Element-30 $ ,通常都是比较其相对误差而不是绝对误差来判断数值计算得到的梯度是否正确:

    $ s=\frac{|f_a^\prime-f_n^\prime|}{\max(|f_a^\prime|,|f_n^\prime|)} $
    • 如果相对误差 $ MathJax-Element-31 $ ,则通常意味着求解梯度可能出错
    • 如果相对误差 $ MathJax-Element-32 $ ,则对于有不可导点的目标函数时OK的,但是对于使用了tanh/softmax的目标函数,还是有点高
    • 如果相对误差 $ MathJax-Element-33 $ ,则求解梯度结果正确
    • 因为网络越深,相对误差就越高。因此对于一个 10 层网络的输入数据做梯度检查,那么 $ MathJax-Element-35 $ 的相对误差可能就OK了,因为误差一直在累积
  5. 使用双精度类型。当使用单精度浮点数来进行梯度检查时,即使梯度计算过程正确,相对误差也会很高(如 $ MathJax-Element-35 $ )

  6. 梯度检查时,一个导致不准确的原因是:不可导点。

    • 不可导点是目标函数不可导的部分,由于 relu 等函数的引入导致。

    • 解决方法是:使用更少的数据点。

      • 因为数据点越少,不可导点就越少,所以在计算有限差值近似时,横跨不可导点的几率就越小。
      • 另外如果你的梯度检查对 2-3 个数据点都有效,那么基本上对于整个 batch 数据进行梯度检查也没有问题。所以用少量的数据点,能让梯度检查更迅速有效
  7. 谨慎设置步长 $ MathJax-Element-39 $

    • 并不是 $ MathJax-Element-39 $ 越小越好。因为当 $ MathJax-Element-39 $ 特别小时,可能会遇到数值精度问题。如果梯度检查不通过,可以尝试将 $ MathJax-Element-39 $ 调到 $ MathJax-Element-40 $ 或者 $ MathJax-Element-41 $
  8. 建议让网络预热一小段时间,等到损失函数开始下降之后在进行梯度检查

    • 第一次迭代就开始梯度检查的危险在于:此时可能处于不正常的边界情况,从而掩盖了梯度没有正确实现的事实。因为梯度检查是在参数空间中的一个特定的、单独的点上进行的。即使在该点上检查成功,也不能保证梯度实现是正确的。
  9. 不要让正则化吞没数据

    • 通常损失函数为:数据损失+正则化损失之和。某些情况下,损失函数的梯度主要来源于正则化部分,此时就会掩盖掉数据损失梯度的不正确实现
    • 建议先关掉正则化对数据损失做单独检查,然后对正则化做单独检查
  10. 关闭 dropout 和数据 augmentation

    • 梯度检查时,关闭网络中任何不确定的效果的操作,如随机 dropout,随机数据扩展。不然它们会在计算数值梯度时导致巨大误差
  11. 检查少量的维度。由于梯度可以有上百万的参数,此时只能检查其中一些维度然后假设其他维度是正确的

    • 确保在所有不同的参数中都抽取一部分来梯度检查。比如 $ MathJax-Element-42 $ 这些权重矩阵中,每个矩阵抽取一部分来检查。
    • 不要将所有参数拼接成一个巨大的向量,然后从这个向量中随机抽取一些维度来检查
  12. 只有在调试过程中进行梯度检验。不要在训练过程中执行梯度检验,因为非常耗计算资源。

5.2 学习过程检查

  1. 拟合极小的数据集:

    当训练集上有很大的误差时,我们需要确定问题是欠拟合,还是软件错误。尝试对一个小数据子集进行训练,然后确保能达到 0 的损失值。

    • 通常即使是极小模型也能保证很好的拟合一个足够小的数据集。如只有一个样本的分类数据,它可以通过正确设置输出层的偏置来拟合
    • 如果分类器不能正确标定一个单样本组成的训练集、自编码器无法成功再现一个单独的样本、生成模型无法一致的生成一个单独的样本,那么很有可能是由于软件错误
    • 这种测试可以推广到少量样本的小数据集上,不一定是只有一个样本的数据集
    • 进行这个训练时,最好让正则化强度为0,不然它会阻止得到0的损失
    • 如果不能通过这个检验,那么训练过程有问题。此时进行整个数据集的训练是没有意义的;如果能通过这个检验,那么也不保证训练过程没问题
  2. 在训练神经网络时,应该跟踪多个重要数值

    • 这些数值输出的图表是观察训练进程的一个窗口,是直观理解不同超参数设置效果的工具

    • 通常 $ MathJax-Element-60 $ 轴都是以周期 epoch 为单位,它衡量了训练中每个样本数据都被观察过次数的期望

      • 一个周期表示每个样本数据都被观察过了一次
      • 不要使用迭代次数。因为迭代次数与数据的 batch size 有关。而 batch size 可以任意设置
  3. 第一个要跟踪的数值就是损失函数

    training_loss

    从左图中可见:

    • 过低的学习率(蓝色曲线)导致算法的损失函数下降近似线性的
    • 稍高一些的学习率(红色曲线) 会导致算法的损失函数看起来呈几何指数下降
    • 更高一些的学习率(绿色曲线)会让损失函数下降的更快,但是它使得损失函数停留在一个较高的水平位
    • 异常高的学习率(黄色曲线)会让损失函数上升

    从右图可见:

    • 损失函数值曲线看起来比较合理,但是 batch size 可能有点小。因为损失值的噪音很大
    • 损失值的震荡程度和 batch size 有关。当 batch size=1 时,震荡会相对较大;而 batch size 为整个数据集大小时,震荡最小。因为每个梯度更新都是单调的优化损失函数
  4. 在训练分类器时,第二个要跟踪的就是验证集和训练集的准确率。从该图标可以获知模型过拟合的程度

    training_loss2

    • 训练集准确率和验证集准确率之间的空隙指明了模型过拟合的程
    • 蓝色的验证集曲线相对于训练集,验证集的准确率低了很多。这说明模型有很强的过拟合。此时应该增大正则化强度或者收集更多的数据
    • 绿色的验证集曲线和训练集曲线如影随形,说明你的模型容量还不够大,发生了欠拟合。此时应该通过增加参数数量让模型更大一些。
  5. 另一个应该跟踪的数值是:权重更新的相对值

    假设权重为 $ MathJax-Element-44 $ ,更新的增量为 $ MathJax-Element-45 $ 。 $ MathJax-Element-46 $ 为学习率。那么权重更新的相对值为:

    $ s=\frac{||\Delta \mathbf W||_F}{||\mathbf W||_F} $
    • 这里的梯度是一个更新的梯度。如果多个 batch ,则每个 batch 更新一次就计算一次
    • 这个比例 $ MathJax-Element-59 $ 应该在 $ MathJax-Element-48 $ 左右。如果更低,说明学习率可能太小;如果更高,说明学习率可能太高
  6. 一个不正确的初始化可能让学习过程变慢,甚至停止。这个问题可以比较简单的诊断出来:

    • 输出网络中所有层的激活数据和梯度分布的柱状图
    • 如果看到任何奇怪的分布,都不是好兆头。如;对于使用 tanh 的神经元,我们应该看到激活数据的值在整个 [-1,1] 区间都有分布。如果看到神经元的输出都是0,或者都在饱和部分,那么就有问题
  7. 如果数据是图像像素数据,那么把第一层特征可视化会有帮助:

    training_img

    • 左图的特征充满了噪音,这暗示网络可能出现问题:网络没有收敛 、学习率设置不当、正则化惩罚的权重过低
    • 右图特征不错,平滑、干净、种类繁多。说明训练过程良好

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。
列表为空,暂无数据
    我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
    原文