🎨
Bible-DeepLearning
  • Introduction
  • 第6章 深度前馈网络
    • 6.1 例子:学习XOR
    • 6.2 基于梯度的学习
      • 6.2.1 代价函数
        • 6.2.1.1 使用最大似然学习条件分布
        • 6.2.1.2 学习条件统计量
      • 6.2.2 输出单元
        • 6.2.2.1 用于高斯输出分布的线性神单元
        • 6.2.2.2 用于Bernoulli输出分布的sigmoid单元
        • 6.2.2.3 用于Multinoulli输出分布的softmax单元
    • 6.3 隐藏单元
      • 6.3.1 ReLU及其扩展
      • 6.3.2 logistic sigmoid与双曲正切函数
      • 6.3.3 其他隐藏单元
      • 李宏毅补充 SELU
    • 6.4 架构设计
    • 6.5 反向传播和其他的微分算法
      • 6.5.1 计算图
      • 6.5.2 微积分中的链式法则
      • 6.5.3 递归地使用链式法则来实现反向传播
      • 6.5.4 全连接MLP中的反向传播计算
      • 6.5.5 符号到符号的导数
      • 6.5.6 一般化的反向传播
      • 6.5.7 实例:用于MLP 训练的反向传播
      • 6.5.8 复杂化
  • 第7章 深度学习中的正则化
    • 7.1 参数范数惩罚
      • 7.1.1 L2参数正则化
      • 7.1.2 L1参数正则化
    • 7.2 作为约束的范数惩罚
    • 7.3 正则化和欠约束问题
    • 7.4 数据集增强
    • 7.5 噪声鲁棒性
    • 7.6 半监督学习
    • 7.7 多任务学习
    • 7.8 提前终止
    • 7.9 参数绑定和参数共享
    • 7.10 稀疏表示
    • 7.11 Bagging 和其他集成方法
    • 7.12 Dropout
    • 7.13 对抗训练
    • 7.14 切面距离、正切传播和流形正切分类器
    • Ag补充 一些能用于提升比赛成绩的方法
  • 第8章 深度模型中的优化
    • 8.1 学习和纯优化有什么不同
      • 8.1.1 经验风险最小化
      • 8.1.2 代理损失函数和提前终止
      • 8.1.3 批量算法和小批量算法
    • 8.2 神经网络优化中的挑战
      • 8.2.1 病态
      • 8.2.2 局部极小值
      • 8.2.3 8.2.3 高原、鞍点和其他平坦区域
      • 8.2.4 悬崖和梯度爆炸
      • 8.2.5 长期依赖
      • 8.2.6 非精确梯度
    • 8.3 基本算法
      • 8.3.1 随机梯度下降
      • 8.3.2 动量
      • 8.3.3 Nesterov 动量
    • 8.4 参数初始化策略
    • 8.5 自适应学习率算法
      • 8.5.1 AdaGrad
      • 8.5.2 RMSProp
      • 8.5.3 Adam
      • 8.5.4 选择正确的优化算法
    • 8.6 二阶近似方法
      • 8.6.1 牛顿法
      • 8.6.2 共轭梯度
      • 8.6.3 BFGS
    • 8.7 优化策略和元算法
      • 8.7.1 批标准化
      • 8.7.2 坐标下降
      • 8.7.3 Polyak 平均
      • 8.7.4 监督预训练
      • 8.7.5 设计有助于优化的模型
  • 第9章 卷积网络
    • 9.1 卷积运算
    • 9.2 动机
    • 9.3 池化
    • 9.4 卷积与池化作为一种无限强的先验
    • 9.5 基本卷积函数的变体
    • 9.6 结构化输出
    • 9.7 数据类型
  • 第10章 序列建模:循环和递归网络
    • 10.1 展开计算图
    • 10.2 循环神经网络
      • 10.2.1 导师驱动过程和输出循环网络
      • 10.2.2 计算循环神经网络的梯度
      • 10.2.3 作为有向图模型的循环网络
      • 10.2.4 基于上下文的RNN序列建模
    • 10.3 双向RNN
    • 10.4 基于编码 - 解码的序列到序列架构
    • 10.5 深度循环网络
    • 10.6 递归神经网络
    • 10.7 长期依赖的挑战
    • 10.9 渗漏单元和其他多时间尺度的策略
    • 10.10 长短期记忆和其他门控RNN
      • 10.10.1 LSTM
      • 10.10.2 其他门控RNN
    • 10.11 优化长期依赖
      • 10.11.1 梯度截断
      • 10.11.2 引导信息流的正则化
    • 10.12 外显记忆
  • 第11章 实践方法论
    • 11.1 性能度量
    • 11.2 默认的基准模型
    • 11.3 决定是否收集更多数据
    • 11.4 选择超参数
      • 11.4.1 手动选择超参数
      • 11.4.3 网络搜索
      • 11.4.4 随机搜索
    • 11.5 调试策略
Powered by GitBook
On this page

Was this helpful?

  1. 第11章 实践方法论

11.5 调试策略

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

在大多数情况下,我们不能提前知道算法的行为。 事实上,使用机器学习的整个出发点是,它会发现一些我们自己无法发现的有用行为。 如果我们在一个\emph{新}的分类任务上训练一个神经网络,它达到$5\%$的测试误差,我们没法直接知道这是期望的结果,还是次优的结果。

另一个难点是,大部分机器学习模型有多个自适应的部分。 如果一个部分失效了,其他部分仍然可以自适应,并获得大致可接受的性能。 例如,假设我们正在训练多层神经网络,其中参数为权重$W$和偏置 $b$。 进一步假设,我们单独手动实现了每个参数的梯度下降规则。 而我们在偏置更新时犯了一个错误:

b←b−α,\begin{aligned} b \leftarrow b - \alpha, \end{aligned}b←b−α,​

其中$\alpha$是学习率。 这个错误更新没有使用梯度。 它会导致偏置在整个学习中不断变为负值,对于一个学习算法来说这显然是错误的。 然而只是检查模型输出的话,该错误可能并不是显而易见的。 根据输入的分布,权重可能可以自适应地补偿负的偏置。

大部分神经网络的调试策略都是解决这两个难题的一个或两个。 我们可以设计一种足够简单的情况,能够提前得到正确结果,判断模型预测是否与之相符;我们也可以设计一个测试,独立检查神经网络实现的各个部分。

一些重要的调试检测如下所列。

\emph{可视化计算中模型的行为}:%?? in action 当训练模型检测图像中的对象时,查看一些模型检测到部分重叠的图像。 在训练语音生成模型时,试听一些生成的语音样本。 这似乎是显而易见的,但在实际中很容易只注意量化性能度量,如准确率或对数似然。 直接观察机器学习模型运行其任务,有助于确定其达到的量化性能数据是否看上去合理。 错误评估模型性能可能是最具破坏性的错误之一,因为它们会使你在系统出问题时误以为系统运行良好。

\emph{可视化最严重的错误}: 大多数模型能够输出运行任务时的某种置信度量。 例如,基于\,softmax函数\,输出层的分类器给每个类分配一个概率。 因此,分配给最有可能的类的概率给出了模型在其分类决定上的置信估计值。 通常,相比于正确预测的概率最大似然训练会略有高估。 但是由于实际上模型的较小概率指示结果对应着正确的标签的可能也较小,因此它们在一定意义上还是有些用的。 通过查看训练集中很难正确建模的样本,通常可以发现该数据预处理或者标记方式的问题。 例如,街景转录系统原本有个问题是,地址号码检测系统会将图像裁剪得过于紧密,而省略掉了一些数字。 然后转录网络会给这些图像的正确答案分配非常低的概率。 将图像排序,确定置信度最高的错误,显示系统的裁剪有问题。 修改检测系统裁剪更宽的图像,使整个系统获得了更好的性能,即便转录网络需要能够处理地址号码中位置和范围更大变化的情况。

\emph{根据训练和测试误差检测软件}: 我们往往很难确定底层软件是否是正确实现。 训练和测试误差能够提供一些线索。 如果训练误差较低,但是测试误差较高,那么很有可能训练过程是在正常运行,但模型由于算法原因过拟合了。 另一种可能是,测试误差没有被正确地度量,可能是由于训练后保存模型再重载去度量测试集时出现问题,或者是因为测试数据和训练数据预处理的方式不同。 如果训练和测试误差都很高,那么很难确定是软件错误,还是由于算法原因模型欠拟合。 这种情况需要进一步的测试,如下面所述。

\emph{拟合极小的数据集}: 当训练集上有很大的误差时,我们需要确定问题是真正的欠拟合,还是软件错误。 通常,即使是小模型也可以保证很好地拟合一个足够小的数据集。 例如,只有一个样本的分类数据可以通过正确设置输出层的偏置来拟合。 通常,如果不能训练一个分类器来正确标注一个单独的样本,或不能训练一个自编码器来成功地精准再现一个单独的样本,或不能训练一个生成模型来一致地生成一个单独的样本,那么很有可能是由于软件错误阻止训练集上的成功优化。 此测试可以扩展到只有少量样本的小数据集上。

\emph{比较反向传播导数和数值导数}: 如果读者正在使用一个需要实现梯度计算的软件框架,或者在添加一个新操作到求导库中,必须定义它的\texttt{bprop}方法,那么常见的错误原因是没能正确地实现梯度表达。 验证这些求导正确性的一种方法是比较实现的自动求导和通过有限差分(finite difference)计算的导数。 因为

f′(x)=lim⁡ϵ→0f(x+ϵ)−f(x)ϵ,\begin{aligned} f'(x) = \lim_{\epsilon \to 0} \frac{f(x+\epsilon) - f(x)}{\epsilon}, \end{aligned}f′(x)=ϵ→0lim​ϵf(x+ϵ)−f(x)​,​

我们可以使用小的、有限的$\epsilon$近似导数:

f′(x)≈f(x+ϵ)−f(x)ϵ.\begin{aligned} f'(x) \approx \frac{f(x+\epsilon) - f(x)}{\epsilon}. \end{aligned}f′(x)≈ϵf(x+ϵ)−f(x)​.​

我们可以使用中心差分(centered difference)提高近似的准确率:

f′(x)≈f(x+12ϵ)−f(x−12ϵ)ϵ.\begin{aligned} f'(x) \approx \frac{ f(x+\frac{1}{2}\epsilon) - f(x-\frac{1}{2}\epsilon) }{\epsilon}. \end{aligned}f′(x)≈ϵf(x+21​ϵ)−f(x−21​ϵ)​.​

扰动大小$\epsilon$必须足够大,以确保该扰动不会由于数值计算的有限精度问题产生舍入误差。

[success] from Ag 有限差分 = 单边误差 中心差分 = 双边误差 双边误差比单元误差更准确 基于双边误差计算参数$\theta$的导数 (1)把所有参数W、b合成一个大的向量$\theta$ (2)所有参数的导数dW、db也看成是一个大的向量$d\theta$ (3)$d\theta[i]{appro} \approx \frac{J(\theta_1, \theta_2, \cdots, \theta_i+\epsilon,\cdots) - J(\theta_1, \theta_2, \cdots, \theta_i-\epsilon,\cdots)}{2\epsilon}$ (4)比较$d\theta[i]{appro}$和$d\theta[i]$,比较方法为计算以下公式与一个threshold

∣∣dθ[i]appro−dθ[i]∣∣2∣∣θ[i]appro∣∣2+∣∣θ[i]∣∣2\frac{||d\theta[i]_{appro}-d\theta[i]||_2}{||\theta[i]_{appro}||_2 + ||\theta[i]||_2}∣∣θ[i]appro​∣∣2​+∣∣θ[i]∣∣2​∣∣dθ[i]appro​−dθ[i]∣∣2​​

使用双边误差计算导数的注意事项 这种计算$d\theta$的方式很慢,仅用于debug,不用于训练 如果check过高,先检查是哪个参数(W还是b,哪个index)引起的。 计算时不要忘记正则化项 debug时不要开启dropout

通常,我们会测试向量值函数$g:\Bbb R^m \to \Bbb R^n$的梯度或\,Jacobian\,矩阵。 令人遗憾的是,有限差分只允许我们每次计算一个导数。 我们可以使用有限差分 $mn$次评估$g$的所有偏导数,也可以将该测试应用于一个新函数(在函数$g$的输入输出都加上随机投影)。%?? 后面这句好像不对? g的输入输出都使用随机投影的

[warning] 在函数$g$的输入输出都加上随机投影是什么意思?

例如,我们可以将导数实现的测试用于函数$f(x) = u^T g(v x)$,其中$u$和$v$是随机向量。%?? 这句也不对 正确计算$f'(x)$要求能够正确地通过$g$反向传播,但是使用有限差分能够高效地计算,因为$f$只有一个输入和一个输出。 通常,一个好的方法是在多个$u$值和$v$值上重复这个测试,可以减少测试忽略了垂直于随机投影的错误的几率。%?? 很难

[warning] 看不懂?

如果我们可以在复数上进行数值计算,那么使用复数作为函数的输入会有非常高效的数值方法估算梯度{cite?}。 该方法基于如下观察 \begin{aligned} f(x + i\epsilon) &= f(x) + i\epsilon f'(x) + O(\epsilon^2) ,\ \text{real}( f(x+i\epsilon) ) &= f(x) + O(\epsilon^2), \quad \text{image}( \frac{f(x+i\epsilon)}{ \epsilon } ) = f'(x) + O(\epsilon^2), \end{aligned} 其中$i=\sqrt{-1}$。 和上面的实值情况不同,这里不存在消除影响,因为我们对$f$在不同点上计算差分。 因此我们可以使用很小的$\epsilon$,比如$\epsilon = 10^{-150}$,其中误差$O(\epsilon^2)$对所有实用目标都是微不足道的。

\emph{监控激活函数值和梯度的直方图}: 可视化神经网络在大量训练迭代后(也许是一个轮)收集到的激活函数值和梯度的统计量往往是有用的。 隐藏单元的预激活值可以告诉我们该单元是否饱和,或者它们饱和的频率如何。 例如,对于整流器,它们多久关一次?是否有单元一直关闭? 对于双曲正切单元而言,预激活绝对值的平均值可以告诉我们该单元的饱和程度。 在深度网络中,传播梯度的快速增长或快速消失,可能会阻碍优化过程。 最后,比较参数梯度和参数的量级也是有帮助的。 正如{cite?}所建议的,我们希望参数在一个小批量更新中变化的幅度是参数量值$1\%$这样的级别,而不是$50\%$或者$0.001\%$(这会导致参数移动得太慢)。 也有可能是某些参数以良好的步长移动,而另一些停滞。 如果数据是稀疏的(比如自然语言),有些参数可能很少更新,检测它们变化时应该记住这一点。

最后,许多深度学习算法为每一步产生的结果提供了某种保证。 例如,在第三部分,我们将看到一些使用代数解决优化问题的近似推断算法。 通常,这些可以通过测试它们的每个保证来调试。 某些优化算法提供的保证包括,目标函数值在算法的迭代步中不会增加,某些变量的导数在算法的每一步中都是零,所有变量的梯度在收敛时会变为零。 通常,由于舍入误差,这些条件不会在数字计算机上完全成立,因此调试测试应该包含一些容差参数。

Previous11.4.4 随机搜索

Last updated 5 years ago

Was this helpful?