\[ \begin{align}\begin{aligned}\newcommand{\ba}{\boldsymbol{a}} \newcommand{\bb}{\boldsymbol{b}} \newcommand{\be}{\boldsymbol{e}} \newcommand{\bq}{\boldsymbol{q}} \newcommand{\bk}{\boldsymbol{k}} \newcommand{\bw}{\boldsymbol{w}} \newcommand{\bx}{\boldsymbol{x}} \newcommand{\by}{\boldsymbol{y}} \newcommand{\bz}{\boldsymbol{z}} \newcommand{\bd}{\boldsymbol{d}} \newcommand{\bv}{\boldsymbol{v}} \newcommand{\bs}{\boldsymbol{s}}\\\newcommand{\btheta}{\boldsymbol{\theta}} \newcommand{\bbeta}{\boldsymbol{\beta}} \newcommand{\bgamma}{\boldsymbol{\gamma}} \newcommand{\bsigma}{\boldsymbol{\sigma}} \newcommand{\md}{\mbox{d}} \newcommand{\bmu}{\boldsymbol{\mu}} \newcommand{\bone}{\boldsymbol{1}} \newcommand{\bzero}{\boldsymbol{0}} \newcommand{\bepsilon}{\boldsymbol{\epsilon}} \newcommand{\bphi}{\boldsymbol{\phi}} \newcommand{\bh}{\boldsymbol{h}} \newcommand{\bc}{\boldsymbol{c}} \newcommand{\br}{\boldsymbol{r}} \newcommand{\bQ}{\boldsymbol{Q}} \newcommand{\bK}{\boldsymbol{K}} \newcommand{\bV}{\boldsymbol{V}} \newcommand{\bSigma}{\boldsymbol{\Sigma}} \newcommand{\bg}{\boldsymbol{g}} \newcommand{\bxi}{\boldsymbol{\xi}} \newcommand{\bvarepsilon}{\boldsymbol{\varepsilon}} \newcommand{\bdelta}{\boldsymbol{\delta}} \newcommand{\bq}{\boldsymbol{q}} \newcommand{\bk}{\boldsymbol{k}} \newcommand{\bJ}{\boldsymbol{J}} \newcommand{\bp}{\boldsymbol{p}} \newcommand{\bi}{\boldsymbol{i}} \newcommand{\bo}{\boldsymbol{o}} \newcommand{\bE}{\boldsymbol{E}} \newcommand{\bH}{\boldsymbol{H}} \newcommand{\bL}{\boldsymbol{L}} \newcommand{\bu}{\boldsymbol{u}} \newcommand{\bLambda}{\boldsymbol{\Lambda}} \newcommand{\trans}{^{\rm\scriptsize T}} \newcommand{\var}{\mathrm{var}}\\\newcommand{\bA}{\boldsymbol{A}} \newcommand{\bB}{\boldsymbol{B}} \newcommand{\bC}{\boldsymbol{C}} \newcommand{\bD}{\boldsymbol{D}} \newcommand{\bG}{\boldsymbol{G}} \newcommand{\bI}{\boldsymbol{I}} \newcommand{\bM}{\boldsymbol{M}} \newcommand{\bP}{\boldsymbol{P}} \newcommand{\bS}{\boldsymbol{S}} \newcommand{\bU}{\boldsymbol{U}} \newcommand{\bW}{\boldsymbol{W}} \newcommand{\bX}{\boldsymbol{X}} \newcommand{\bY}{\boldsymbol{Y}} \newcommand{\bZ}{\boldsymbol{Z}} \newcommand{\cotp}{\textcolor[RGB]{48,209,88}{TP}} \newcommand{\cotn}{\textcolor[RGB]{100,210,255}{TN}} \newcommand{\cofp}{\textcolor[RGB]{94,92,230}{FP}} \newcommand{\cofn}{\textcolor[RGB]{191,90,242}{FN}}\\\newcommand{\numcotp}{\textcolor[RGB]{48,209,88}{50}} \newcommand{\numcotn}{\textcolor[RGB]{100,210,255}{30}} \newcommand{\numcofp}{\textcolor[RGB]{94,92,230}{10}} \newcommand{\numcofn}{\textcolor[RGB]{191,90,242}{10}} \DeclareMathOperator*{\argmin}{arg\,min}\end{aligned}\end{align} \]

实际训练建议#

学习目标与记号#

  1. 准确解释训练前检查、训练过程监控、验证与测试;

  2. 根据公式和张量维度分析故障定位,并识别常见实现错误;

  3. Python 使用相同的数据、参数和随机种子重复运行程序,检查能否得到相近结果;比较不同方法时,在其他条件相同的情况下只改变一个需要研究的因素,并根据实验结果分析该因素可能带来的影响。

  本节沿用统一记号:普通小写字母表示标量,粗体小写字母表示向量,粗体大写字母表示矩阵或高阶张量;层编号写作上标 \([l]\)⁠,样本或时间编号写作下标;转置写作 \(\trans\)⁠。除非另有说明,批量样本按行存放。正文与练习中的程序都应同时检查数值结果和数组维度。本节练习的参考答案见 深度学习实验实践指南答案⁠。

  实际训练应同时遵守 数据划分边界⁠、超参数比较时需要遵守的规则二分类评价原则⁠,而不是只观察训练损失。

  当一个模型“效果不好”时,先定位属于数据、实现、优化还是泛化问题,再决定修改方向。下面是一套可重复使用的检查表。

训练前#

  1. 明确输入、标签、损失函数和评价指标的含义,并手工检查少量样本。

  2. 先划分训练、验证和测试集,再拟合标准化器、词表或缺失值填补规则,防止数据泄漏。

  3. 用很小的数据子集尝试过拟合。如果连几十个样本都无法拟合,优先排查标签、维度、损失与输出层是否匹配,以及梯度是否真的更新参数。

  4. 设置随机种子,保存配置,并确认训练与评估模式能够正确切换。

训练中#

  1. 同时记录训练和验证损失、任务指标、学习率、梯度范数及关键层激活统计。

  2. 遇到 NaN 或无穷值时,检查输入范围、除零、对数的定义域、Softmax/交叉熵实现和学习率;必要时使用梯度裁剪,但不要用裁剪掩盖持续的数值错误。

  3. 训练损失几乎不下降时,先做学习率范围试验,再检查初始化、归一化和梯度流。

  4. 训练很好而验证明显较差时,再考虑数据增强、权重衰减、Dropout、提前停止或减少容量。

训练后#

  1. 从最佳验证检查点加载模型,而不是默认使用最后一轮参数。

  2. 按关键子群或数据条件拆分误差,检查类别不平衡、分布漂移和失败样本。

  3. 若输出被解释为概率,除排序指标外还应检查 概率校准⁠;若部署需要阈值,应在验证集上确定阈值。

  4. 用独立测试集报告最终结果,同时记录推断速度、内存和模型大小等实际约束。

  最有价值的实验往往不是一次加入更多技巧,而是设计两次只在一个关键设置上不同的比较,再根据结果判断哪种原因更可能成立。例如,怀疑过拟合时同时观察训练—验证差距;怀疑学习率过大时保持其他设置不变,只改变学习率,并比较梯度范数和短程训练曲线。这样得到的结果更容易解释,也更能为下一次建模提供参考。

Shiny 交互演示:训练集、验证集与测试集的分工

  交互页面会在训练集上估计每个模型的参数,在验证集上比较多项式次数、惩罚强度和分类阈值,并在方案全部确定后才显示一次测试集结果。候选方案表只包含验证集结果,便于观察测试集为什么不能参与反复选择。

点击打开“二分类评价与超参数选择”交互演示

核心推导与实现核验#

核心关系

\[\text{正确性}\rightarrow\text{可优化性}\rightarrow\text{泛化}\rightarrow\text{效率}.\]

  推导路径。 先在小批量上确认数据、损失和梯度正确,再验证训练损失能下降,然后讨论训练—验证差距,最后才优化吞吐和资源;顺序可减少问题相互遮蔽。

关键条件

  可以先选择少量且容易区分的训练样本,让模型反复学习。正常情况下,模型应当能够几乎完全正确地预测这些样本。如果做不到,应先检查程序实现、输入数据与标签、损失函数以及优化设置是否存在问题,而不是认为模型只是在新数据上的表现不好。通过这项检查只能说明训练流程基本能够工作,不能证明模型在新数据上也有良好的预测表现。

数据规模

  训练日志应明确区分三种规模:完成了多少次参数更新、完整遍历了多少轮数据,以及累计处理了多少个样本。比较两条训练曲线时,横轴必须采用同一种计数方式,学习率记录也要对应同一个训练时刻。

常见误区

  只看最终准确率会掩盖 NaN、梯度爆炸、过拟合时间点和类别级错误。

动手检查

  给训练管线依次注入标签错位、学习率过大和评估模式未切换三类故障,确认维度断言、有限性检查、梯度日志和验证曲线能分别暴露第一处异常。

数值稳定性与规模

  每一步先检查输入、损失、梯度与参数是否有限,再写入聚合指标;发生 NaN 时保留首个异常批次和随机状态。多次运行时应保存每一次实验的结果。如果某次实验报错、没有完成训练或得到无法使用的数值,不要直接删掉它后只对其余结果求平均,而应说明失败的次数和原因。正常完成但表现较差的实验仍应计入平均值。

本节小结#

  1. 排错应按正确性、优化、泛化和效率逐层推进。

  2. 让模型反复学习少量训练样本,可以快速检查数据与标签、损失函数、梯度计算和参数更新等环节是否基本正常。

  3. 日志、检查点和环境记录是实验结果的一部分。

综合练习#

  程序题应固定随机种子、写出维度断言并报告运行环境;比较题还应固定数据划分、随机种子集合和训练预算。全部参考答案见 深度学习实验实践指南答案⁠。

  1. 少量训练样本检查。 说明为什么模型应当能够几乎完全正确地预测少量且容易区分的训练样本,以及为什么通过这项检查仍不能证明数据处理、验证过程和模型对新数据的预测表现一定正确。针对这三方面,各举一个“模型通过了这项检查,但相应方面仍然存在问题”的例子。

  2. 更新尺度计算。 某一步训练前参数范数为 \(\lVert\btheta\rVert_2=20\)⁠,梯度范数为 \(\lVert\nabla\mathcal J\rVert_2=5\)⁠,学习率为 \(0.02\)⁠,且没有动量与权重衰减。计算参数更新范数和相对更新量 \(\lVert\Delta\btheta\rVert_2/\lVert\btheta\rVert_2\)⁠;说明该数值应如何与连续多步日志结合使用。

  3. 检查点计算。 四轮训练的验证损失依次为 \(0.80,0.55,0.58,0.62\)⁠,验证准确率依次为 \(0.68,0.76,0.75,0.73\)⁠。若预先规定以验证损失选择检查点,指出最佳轮,计算最后一轮相对最佳轮的损失增量和准确率下降,并解释为什么不能临时改用测试指标选轮。

  4. 运行时间计算。 一次训练处理 200 个批次,共耗时 40 秒;预测阶段预热后,对固定 512 个样本的批量重复预测 100 次,共耗时 2 秒。分别计算处理一个训练批次和完成一次固定批量预测的平均时间,并说明为什么预热、同步和重复计时必须保持一致。

  5. 统一检查器实现。 编写训练检查器,验证输入范围、标签集合、损失和梯度是否有限,记录梯度范数、参数相对更新量、学习率与当前最佳验证检查点;发现首个异常时保存批次编号和随机状态。

  6. 故障注入测试。 分别注入标签错位、学习率过大、验证时未切换评估模式和含 NaN 的输入。为每类故障规定应最先触发的断言或日志信号,并编写回归测试,确保修复后正常训练仍能通过。

  7. 学习率比较。 在同一模型上比较三个学习率。固定训练/验证/测试划分、随机种子集合、批量顺序和参数更新次数;报告任务性能、达到指定验证指标所需时间、总训练时间、固定批量预测时间、参数量及峰值内存,并结合损失与梯度日志解释差异。

  8. 批量大小与效率比较。 比较多个训练批量大小,并通过固定处理样本总数或参数更新总数明确训练预算。保持数据划分、随机种子集合、模型和评价程序一致;报告任务性能、总训练时间、固定批量预测时间、参数量及峰值内存。

  9. 检查点与提前停止比较。 比较“始终使用最后一轮”“加载最佳验证检查点”和“带耐心值的提前停止”三种训练流程。固定数据划分、随机种子集合、最大训练预算和模型;报告任务性能、实际训练时间、固定批量预测时间、参数量及峰值内存,并分析提前停止节省的计算与可能的过早停止风险。