模型预训练 / 工程基础 阅读导览入门 11 分钟阅读 查看源文件 ↗

工程基础:数据、损失与参数更新#

本页内容8 个部分

1. 预训练流程与阅读范围#

自回归语言模型预训练从大量文本中学习下一个 token 的条件分布。预训练工程需要明确四项内容:(1)语料组织为训练序列的规则;(2)损失的平均范围;(3)训练量与参数更新次数的对应关系;(4)训练状态的监控和恢复方式。即使模型结构相同,数据采样、损失聚合方式或参数更新频率不同,训练过程也会不同。[1]

本篇以 decoder-only 语言模型为背景,说明数据、损失、梯度与参数更新之间的关系。优化器和损失的完整推导见对应专篇。具体模型的学习率、batch 和数据配比属于配方,不能直接当作通用默认值。

2. 从语料到 next-token 目标#

本篇的计数算例采用以下配置:4 个数据并行副本,每个副本一次处理 2 条序列,累积 8 次后更新参数;每条输入有 1024 个位置,其中 960 个标签参与损失。计算时分别统计一次参数更新使用的序列数、送入模型的位置数和计入 loss 的标签数。这组配置只用于解释计数,不是推荐的预训练配方。

2.1 Tokenizer、数据采样与文档边界#

Tokenizer 把文本变成 token ID。语料需要经过清洗、去重和来源采样,再组织为有限长度的训练序列。数据来源和采样比例会影响训练序列的数据分布。语料库的 token 总数与训练中累计读取的 token 数需要分别记录,重复读取会增加后者。GPT-3 的数据混合与采样就是具体配方的实例。[1]

不同 tokenizer 对同一段文本可能得到不同的 token 数。统计数据量、比较 loss 与规划上下文长度时,应固定 tokenizer 版本。切分训练和验证数据后,还应检查重复或近似重复样本是否跨集合泄漏。

训练序列需要明确文档结束符、截断规则和拼接方式。Packing 将多个样本组织到同一序列中,以减少 padding 位置。拼接本身不阻止跨文档注意力;attention mask 决定允许读取的上下文,位置编号标识 token 的位置,监督 mask 决定哪些标签计入损失,详见 Packed Sequence。

2.2 标签对齐与有效监督位置#

下面用一个短序列说明输入与监督标签的对齐关系。假设“我、喜欢、学习、EOS”各对应一个 token,其中 EOS 是文档结束标记。在末尾补一个填充标记 PAD 后,取前四个 token 作输入、后四个作标签。该例仅示意标签对齐,不表示真实 tokenizer 必然这样切词。

输入位置 1 2 3 4
输入 token 我 喜欢 学习 EOS
下一 token 标签 喜欢 学习 EOS PAD
是否进入 loss 1 1 1 0

前三个输入位置各预测后面的一个 token;最后的 PAD 标签被忽略。EOS 在第三个标签位置参与预测,不能因为它也出现在输入中就把该标签排除。Causal attention(因果注意力)限制每个位置只读取允许的前缀;监督 mask 决定哪些标签计入 loss,两者作用不同。

把同一规则写成一般形式:原始 token 串为 xi,0,…,xi,Sx_{i,0},\ldots,x_{i,S},序列 ii 的输入位置 tt 使用前缀 xi,0:tx_{i,0:t} 预测 xi,t+1x_{i,t+1},其中 t=0,…,S−1t=0,\ldots,S-1。这里 xi,0:tx_{i,0:t} 包含位置 0 到 tt 的 token,SS 是送入模型的输入位置数;未移位原始串共有 S+1S+1 个 token。

记 θ\theta 为模型参数,pθ(xi,t+1∣xi,0:t)p_\theta(x_{i,t+1}\mid x_{i,0:t}) 为模型对下一 token 的条件概率。用 mi,t∈{0,1}m_{i,t}\in\{0,1\} 表示标签是否参与监督,其中 1 表示参与。下面的 ii 遍历一次参数更新使用的全部序列,包括所有数据并行副本和累积的 microbatch。本篇的 log⁡\log 表示自然对数。有效标签总数大于零时,先累加参与监督位置的负对数概率,再除以有效标签数:

L(θ)=−∑i∑t=0S−1mi,tlog⁡pθ(xi,t+1∣xi,0:t)∑i∑t=0S−1mi,t.\mathcal L(\theta)=-\frac{\sum_i\sum_{t=0}^{S-1}m_{i,t}\log p_\theta(x_{i,t+1}\mid x_{i,0:t})}{\sum_i\sum_{t=0}^{S-1}m_{i,t}}.

用短序列实际计算一次 loss。假设模型给“喜欢”“学习”“EOS”这三个正确标签的概率分别为 0.50.5、0.250.25、0.1250.125,这些是手算设定。先对每个正确标签的概率取负对数,再对三个有效位置平均:

有效标签负对数概率之和=−log⁡0.5−log⁡0.25−log⁡0.125≈4.158883,L=−log⁡0.5−log⁡0.25−log⁡0.1253≈1.386294.\begin{aligned} \text{有效标签负对数概率之和} &=-\log0.5-\log0.25-\log0.125\approx4.158883,\\ \mathcal L &=\frac{-\log0.5-\log0.25-\log0.125}{3}\approx1.386294. \end{aligned}

PAD 标签对应的预测概率不参与分子,也不增加分母。这个数值是损失函数的输出,参数怎样变化还取决于反向传播得到的梯度和优化器。

上面的短序列共有 4 个输入位置,但 loss 分母为 3。1024 个输入位置、960 个有效标签的训练配置也是同一种区分;输入位置数与有效标签数需要分别统计。Padding 等被忽略标签不进入分母,ignore_index 是实现排除的一种方式。[2]

交叉熵给出单个位置的损失及其对 logit 的梯度;本篇说明如何聚合多个位置的损失。实现时仍需确认移位由模型内部还是数据侧完成,避免移位两次或完全没有移位。

3. 训练量与成功更新次数#

3.1 数据量、训练量与算力预算#

设模型参数量为 NN,训练累计处理的 token 数为 DD,训练计算量为 CC,单位为 FLOPs。固定计算预算时,扩大模型通常会减少能处理的 token;Chinchilla讨论怎样用多规模实验估计这项取舍。常规 dense Transformer 的参数相关训练计算可粗估为 C≈6NDC\approx6ND,但仍需考虑注意力、序列长度与实现开销,FLOPs 也不等于实际耗时。[3]

应记录 DD 的计数口径:原始语料 token、重复采样后的训练 token、实际送入模型的位置数和有效监督 token 不一定相等。使用缩放定律或计算器时,应采用对应公式使用的 token 计数定义。

3.2 Microbatch、累积与数据并行#

设数据并行副本数为 RR,每个副本每次前向处理的批次称为 microbatch,其中包含 BB 条序列。每个副本累积 KK 个 microbatch 的梯度后,尝试更新一次参数。若每批都满额,一个完整梯度累积窗口覆盖的序列数为 Bglobal=RBKB_{\mathrm{global}}=RBK。固定每条输入长度为 SS 时,模型处理的位置数为 Tstep=RBKST_{\mathrm{step}}=RBKS。

代入本篇配置,一个完整梯度累积窗口的序列数为 Bglobal=4×2×8=64B_{\mathrm{global}}=4\times2\times8=64;每条输入 1024 个位置,处理量为 Tstep=64×1024=65536T_{\mathrm{step}}=64\times1024=65536,有效监督量为 有效标签数=64×960=61440\text{有效标签数}=64\times960=61440。在每个 microbatch 的序列数、输入长度和有效标签数固定时,两项都与累积次数成正比;训练 loss 仅以有效标签数为分母。

这里乘的是数据并行副本数,不是所有 GPU 的总数。张量并行(Tensor Parallel)将同一个模型的计算分到多台设备上,这些设备不能再作为独立数据副本计入 RR。分布式数据并行(DDP)同步副本之间的梯度,模型并行的执行细节见并行策略。[4]

若没有跳步或丢弃的累积窗口,每次成功更新都处理 TstepT_{\mathrm{step}} 个位置,且共成功更新 UU 次,则累计处理位置数为 Dprocessed=UTstepD_{\mathrm{processed}}=UT_{\mathrm{step}}。这里“成功更新”指优化器实际执行一次参数更新,不要求每个参数的增量都非零。序列长度变化、末尾批次不足额或自动混合精度(AMP)跳过参数更新时,应分别累计实际处理量、有效监督量与成功更新次数,不能只用一个 step 计数替代三者。AMP 跳过参数更新时,已送入模型的位置仍计入实际处理量。

4. 训练处理量与监督量的计算#

沿用前面的 R=4R=4、B=2B=2、K=8K=8、S=1024S=1024,每条输入仍有 960 个有效标签。假设没有尾批或跳步,连续成功更新 100 次,将每次更新的统计量累计起来:

一次参数更新的序列数、处理位置数与有效标签数

要核对的量 计算 结果
每次更新的序列数 4×2×84\times2\times8 64
每次更新处理的位置 64×102464\times1024 65,536
每次更新的 loss 分母 64×96064\times960 61,440
100 次更新处理的位置 100×65536100\times65536 6,553,600
100 次更新的有效监督量 100×61440100\times61440 6,144,000

再假设本次更新中,每个有效标签的负对数概率都是 1.5;这是为演示平均方式设定的数值。累加有效标签的损失,得到 负对数概率之和=61440×1.5=92160\text{负对数概率之和}=61440\times1.5=92160,平均 loss 为 L=92160/61440=1.5\mathcal L=92160/61440=1.5。如果误除以全部处理位置,就得到 误用处理位置数得到的 loss=92160/65536=1.40625\text{误用处理位置数得到的 loss}=92160/65536=1.40625,训练目标已被改变。

这组数仅用于核对 token 计数和损失聚合,不能据此推断任务得分或显存需求。

若各 microbatch 的有效标签数相同且大于零,对各批的有效 token 平均 loss 作等权平均,就与全局有效标签平均的目标一致。有效标签数不同时,等权平均一般不等于全部有效 token 的平均 loss;即使某次计算恰好相等,也不能保证梯度一致。要保持全局有效标签平均的目标,应按各 microbatch 的有效标签数加权。有效标签数不同的数据并行副本也需要采用同样的加权原则。

若某个 microbatch 的有效标签数为零,该批对损失分子和有效标签总数的贡献都为零,不单独计算该批的 token 平均 loss。整个累积窗口的平均 loss 仍要求有效标签总数大于零。具体推导与末尾不足额批次的处理见梯度累积。

5. 优化器、学习率调度与梯度缩放#

5.1 从梯度到参数变化#

损失函数定义优化目标,优化器根据梯度计算参数更新。SGD 与 Momentum分别介绍按当前梯度更新参数和使用历史梯度的动量估计,Adam通过一阶矩与二阶矩估计调整各坐标的更新,AdamW将权重衰减与梯度矩估计分开。矩阵参数的 Muon 更新另见 Muon。

学习率调度决定学习率系数随训练进度怎样变化;不同阶段的组合与适用场景见学习率配方。设置 warmup 或衰减前,应明确日程按成功优化步、已消费 token 还是其他量推进;改变累积步数后,一次参数更新对应的处理位置数和有效标签数可能改变。

5.2 梯度累积结束后的缩放与裁剪#

在一个梯度累积窗口内,完成各 microbatch 的前向计算和反向传播。使用 loss scaling 时,窗口内保持同一缩放因子;全部梯度累积完成后,先解除缩放,需要限制梯度范数时再裁剪。使用 PyTorch GradScaler 时,由 scaler.step 根据非有限梯度的检查结果决定是否执行参数更新,随后调用 scaler.update 更新缩放因子。[5]

训练循环给出这些机制组合的代码。实现时应分别规定优化器、学习率调度器(scheduler)和梯度缩放器(scaler)的调用条件。若日程按成功优化步推进,AMP 跳过参数更新时,scheduler 不应增加步数;scaler 仍需根据检查结果更新缩放因子。

6. 精度、显存占用与并行执行#

机制 主要改变 不能由名称直接推断的结果
混合精度 部分算子的计算 dtype 与张量存储 开启 autocast 不代表所有参数、梯度和优化器状态都以低精度存储
梯度累积 一次参数更新包含的 microbatch 数量 梯度累积本身不减少参数、梯度和优化器状态的元素数
激活重算 前向保存哪些张量,反向重算哪些片段 激活显存节省量取决于重算范围,重算会增加计算量
参数与状态分片 每台设备常驻哪些参数、梯度和状态 临时聚合与通信缓冲仍可能增加峰值显存
数据并行 各副本分别计算 microbatch 的梯度,再聚合 普通数据并行的每个副本仍保存完整模型,不能降低单个副本的参数存储量

数值格式与 loss scaling 见混合精度,模型状态和激活的分项估算见分布式训练基础,激活保存与重算的执行过程见激活重算。比较吞吐与显存时,应固定模型、输入长度、每次更新的处理位置数及损失聚合方式,并分别记录处理位置数和有效标签数。否则,单步耗时较短可能只是因为该步处理量较少。

7. 执行验证、监控与恢复#

7.1 输入、梯度与参数更新的执行检查#

先用固定小批数据核对输入、移位标签、mask 和 loss 分母,再检查梯度和参数增量中是否存在 NaN 或无穷值。结合 AMP 跳步记录,核对优化器实际执行更新的次数。再在小数据集上重复训练,检查训练 loss 是否在多次更新后总体下降,不要求每一步都下降。同时记录成功更新次数、学习率、裁剪前梯度范数、AMP 跳步次数和有效标签数。

数据量和模型扩大后,分别记录训练与验证曲线。比较候选配置时,使用相同验证集和损失聚合方式。训练 loss 降低本身不能证明下游任务得分、概率校准或语料质量改善,这些目标需要分别评估;具体模型报告通常同时给出训练设置与多项评估。[6]

7.2 监控范围与检查点恢复状态#

预训练的监控指标用于检查各层梯度、激活以及混合专家(MoE)模型的专家路由等训练状态。解释指标前,应明确统计窗口,以及统计量是在单台设备上计算还是跨设备聚合。异常发生后,按诊断页保留样本和更新状态,再逐步检查原因。

检查点(checkpoint)除了模型参数,还应保存优化器、学习率调度器、梯度缩放器的状态,以及随机状态与数据读取进度。恢复后先核对这些状态是否对应同一次保存;分布式数据加载与随机算子还可能影响逐步可复现性,成功加载权重不足以证明恢复后的训练与中断前连续执行一致。[7]

超参数计算器可辅助核对项目经验规则下的规模与预算。它给出候选配置,最终仍要用目标数据、精度和并行方式验证训练行为、峰值显存与端到端单步耗时。

参考资料#

  1. Language Models are Few-Shot Learners(2020). §2、附录 B:自回归预训练、数据混合与训练设置。
  2. CrossEntropyLoss(PyTorch 2.9). 文档:忽略标签与损失聚合。
  3. Training Compute-Optimal Large Language Models(2022). 原文:参数量、token 数与算力约束。
  4. Distributed Data Parallel(PyTorch 2.9). 文档:副本梯度同步;batch 公式为本篇设定下的直接计数。
  5. AMP examples(PyTorch 2.9). 梯度累积:缩放、解除缩放与有效更新边界。
  6. Llama 2(2023). §2:预训练数据、设置与评估的具体案例。
  7. PyTorch 训练恢复与可复现性. Checkpoint、Reproducibility(2.9):恢复训练状态与随机性的边界;具体数据加载进度需由训练程序另行保存。

原文小节的位置

以下小节已整理到独立文章,旧链接会直接转到对应位置。