wikiLLM01|前沿 LLM 的训练与推理:总览与阅读路线03|预训练的数据管线、梯度与规模规律
44 分钟
1 次观看

03|预训练的数据管线、梯度与规模规律

返回导读 · 前置:上一篇的 ID、logits 与因果 mask。目标:把“学习下一 token”落实为一轮可核对的数据、损失和更新。

两份正文经五个有效目标推动同一共享参数,平均规则改变梯度方向

上表行是两份正文;下方两列比较同一初值的两种平均目标。全文逐步复算这条路径。

从网页记录到一次参数更新,每个选择都会改变训练信号。数据处理、训练、独立评估和下一轮数据选择构成反馈环;过滤不是一次完成的“清洗”。本篇先把这个环中的一批数据摊开,数清哪些位置进入损失、同一参数收到了哪些梯度。

一个“训练token数”没有说明来源、重复、混合和有效预测位置。训练数据是一种被设计出来的概率分布。 最顶级模型的完整分布通常未公开;本篇以公开数据工作与基础优化机制解释可检查的部分,不推断 GPT-6.1 或 Claude 的具体语料比例与超参数。

本篇按 语料 → 采样 → 序列与标签 → 损失与反传 → 优化器状态 → 预算与验证 展开。想核对一轮训练,可先读第 3—5 章;想判断数据与计算分配,按完整顺序阅读。

贯穿例只取两份正文 aaa 与 bcbc,编码为小词表 ID,先得到 2 与 3 个有效预测目标,再用同一个可训练标量完成交叉熵、归一化与一次 SGD。本例全部数值是本站教学设定,非厂商语料、配方或实测;它不是语言模型训练。 原有 BOS/EOS packing、单位置 CE、AdamW、二次损失与规模预算例分别保留,并明确切换配置。

1. 数据质量如何进入训练分布

1.1 从原始记录分离正文与模板

模板去除、同源去重和来源身份保留的直觉图

图 1|图形纹理表示来源和重复,不代表真实网页或质量分数。

先看图 1 上面的灰色页眉和页脚:它们会反复出现,却不等于新的正文。中间保留彩色正文并识别重复来源;下面的蓝、绿 token 条仍带来源身份。颜色只标来源簇,不表示绿色更正确。编码、打包和采样还要继续决定如何消费这些内容。

网页抓取结果不是训练样本。网页包含正文、菜单、广告、脚本、重复版权声明;代码仓库包含生成文件、依赖副本、许可证和测试;论文包含页眉页脚与提取错误。若这些部分不加区分,训练预算可能大量用于重复模板。公开 FineWeb 工作展示了过滤和去重的系统消融,并公开了相关数据处理代码;它可以作为可研究管线的案例,不能视为商业旗舰实际数据。来源:FineWeb;官方实现:datatrove。

1.1.1 贯穿小例:正文、ID 与真实长度

两份正文的三词表ID和padding后真实长度

图 2|a/b/c 是教学字符;最后的灰色 0 是存储 padding,不能按 ID 值推断有效性。

为把后面的每一步复算到底,假设提取后保留 A=aaa、B=bcbc。单独使用字符级教学词表 a→0,b→1,c→2,词表大小 V=3;这里不模拟真实 BPE,也暂不加入 BOS/EOS。片段的首项没有前缀监督,尾部也不额外伪造结束目标。原有带 BOS/EOS 的例子在第 3 章独立展开。

补齐到 T=4 后,token_ids 为 [[0,0,0,0],[1,2,1,2]],真实长度为 [3,4]。A 的最后一个 0 是 padding 存储值,前三个 0 却都是正常的 a;因此不能用 token_id != 0 找有效内容。正文共 7 个真实 token、物理存储有 8 槽,这两个数从一开始就不同。

1.2 过滤条件同时改变覆盖范围

过滤正文也会改变语言、来源、长度和时间的组成;这些分组应持续记录,而非只看通过率。下一小节的去重预算只是教学计算,不是某过滤器的测得通过率。语言过滤器若只在主流语言上可靠,会过度丢弃低资源语言;“教育质量”分类器若偏好教科书,会降低口语、论坛经验和特殊代码的覆盖。应保留分组统计并用小模型消融验证,不能把过滤数量当作质量证明。

1.3 去重尺度与有效信息预算

同样190000曝光预算下区分原件重复转载与新文档覆盖

图 3|横轴为曝光 token 数;红色转载与绿色新文档不是同一种信息覆盖。

原集合的红色90000 token是重复转载;去重后绿色同额预算可用于新文档,新内容仍需质量验证。去重尺度包括整篇精确哈希、分段指纹或近似匹配、长公共子串检测;它们产生的数据集不同。新闻更新稿若整篇丢弃可能损失后续事实,只有精确匹配又会留下轻微改写副本。公开研究报告了减少记忆性复现和改善部分指标的实证;收益仍取决于数据与去重策略。 来源:Deduplicating Training Data

1.3.1 190000 token 的重复曝光手算

图 3 的原件部分是 100×1000=100000。这里“10 篇被转载 9 次”明确指每篇在原件之外再多 9 份,于是新增 10×9×1000=90000,合计 190000。若“9 份”含原件,总数就会是另一道题。去重后再补新文档,是固定预算下的替代选择,不表示凭空多出已核验事实。

做一个原创预算例:100 个不同文档各有 1000 token,其中 10 篇被转载 9 次。原始集合共有 190000 token,训练 190000 token 相当于反复看到少数文章;去重后只有 100000 token,剩下预算可以加入新文档。两次训练 token 数相同,信息覆盖却不同。这说明不能把重复曝光当作同等数量的新事实,也说明“去重后变少”并非自动浪费。

1.4 污染检查要越过精确字符串

同源题译文和解析按簇分训练与保留集

图 4|连线表示来源关联,先成簇再分割。

图 4 上半部把同源题面与译文拆到训练和保留两边,关联信息仍跨越分割线;下半部把整簇分配给训练或保留集。污染还可能来自答案、解析、代码补丁,以及先看全量数据、再切分时落入两边的同一网页段落。来源级、时间级或簇级分割能减少重叠,仍不能证明零污染;需要独立保留集、去污染记录与新题评估。

2. 混合采样与有效曝光量

2.1 原始数据量与实际训练概率

图 5 每类先画蓝色可用池,再画绿色期望消耗,二者使用相同的“亿 token”横轴;每组下方的比值才叫曝光倍数。网页的 0.625 倍不表示某篇文章被切成 0.625 次阅读,而是此类总体的期望消费量除以池大小。

去重可用池训练曝光和曝光倍数的不同单位

图 5|池和消耗都用亿 token;消耗除以池才是无量纲曝光倍数。

假设有网页、代码、数学三类语料,原始量分别为 80、15、5 亿 token。如果直接均匀抽 token,比例就是 80%/15%/5%;如果为数学能力把采样比例改成 50%/30%/20%,模型实际看到的分布随之改变。这里的比例是教学设定,不是对任何产品的猜测。

E[Di]=piD,ei=piDSi,∑i=1Kpi=1.\mathbb{E}[D_i]=p_iD,\qquad e_i=\frac{p_iD}{S_i},\qquad\sum_{i=1}^{K}p_i=1.
符号含义、形状与单位
K,iK,i数据类别数与类别索引,本例 K=3K=3
pip_i类别采样概率,标量无量纲;假设按 token 预算设定
D,DiD,D_i总训练 token 数与某类别曝光数,单位 token
SiS_i此类别去重后的可用 token 数,单位 token
eie_i期望覆盖倍数,无量纲;并非每条样本都恰好出现该次数
E\mathbb{E}对随机采样取期望;有限训练会有波动

2.1.1 数学 4 倍与代码 2 倍的曝光量

若训练预算 D=100D=100 亿,数学类 pi=0.2,Si=5p_i=0.2,S_i=5 亿,期望曝光为 20 亿、覆盖倍数为 4。代码类 30 亿对 15 亿语料是 2 倍。过采样会提高这些类别的梯度权重,也增加重复与过拟合风险。先抽文档再按变长文档训练,实际 token 比例未必等于文档抽样比例;实现应记录最终消费的 token 分布,而不是只记录配置里的几个权重。

2.2 阶段混合与合成数据的验证

混合比例还可以随阶段改变。前期扩大覆盖、后期提高代码或高质量内容的比重,可能是合理工程选择,但必须通过同预算对照验证。合成数据也遵守这条规律:题目质量、错误率、重复度和验证方法影响有效信息量。由强模型生成并不等于样本自动正确,重复模仿一种解题风格也不等于覆盖新问题。

3. Packing、边界与下一 token 标签

3.1 物理排布与可见范围分别决定

8项BOS-EOS原串右移后只有7个预测行

图 6|行 i 是预测位置;label mask=0 只忽略这一行的损失。

图 6 用蓝、绿区标出两份文档;每行对齐同一位置的输入、下一项目标和 label mask。排布、position ID 与是否学习边界目标是三个额外选择;EOS 本身不承担硬隔离。真正控制读取的矩阵将在图 7 单独画出。

GPU喜欢规则形状,文档长度却不规则。把短样本各自 padding 到 4096,会浪费大量计算;packing 把多个短样本放到一条长序列里。它只是物理排布,是否允许跨文档 attention、是否重置 position ID、是否学习边界目标,是额外的建模选择。

3.2 输入、目标与跨文档边界

原串去掉最后一项得到 input,去掉第一项得到 target。图 6 第 3 行的红色 0 只忽略 A 的 EOS 预测 B 的 BOS 这一次跨文档转移;第 4 行 BOS 预测 B 的首个内容仍有效。label mask 控制哪些预测计入损失,块状因果矩阵控制每个输入读取谁,两者不能互相替代。

考虑两个教学文档:A 为 [BOS,猫,睡觉,EOS],B 为 [BOS,雨,停了,EOS]。拼接后通常令 input = tokens[:-1]、target = tokens[1:]。若不遮蔽跨文档,B 可以读取 A;若希望它们独立,attention 需要块状因果 mask。并且 A 的 EOS 位置预测 B 的 BOS 这个跨样本目标也应忽略,BOS 位置预测 B 的第一个内容 token 才属于 B。

Mi,j={0,j≤i 且 ci=cj,−∞,其他情况;mi=1[ci=ci+1].M_{i,j}=\begin{cases}0,&j\le i\ \text{且}\ c_i=c_j,\\-\infty,&\text{其他情况};\end{cases} \qquad m_i=\mathbf{1}[c_i=c_{i+1}].
符号含义、形状与单位
i,ji,jquery 与 key 的位置索引,单位 token 位置
cic_i完整原串第 ii 个 token 的文档 ID,整数,无排序意义;包含被预测的末项
MMattention 加性 mask,形状 [T,T][T,T];只允许同文档的当前与过去位置
mim_i第 ii 个预测位置的 loss mask,形状 [T][T],值为 0 或 1
1\mathbf{1}条件成立取 1,否则取 0;最后一个无下一标签的位置另外忽略

预先右移后的7个输入位置如何按文档形成块状因果attention

图 7|本次 x 有 7 项,故可见性表为 7×7;格内 1 对应加性 M 的 0。

现在数清三种长度:完整原串有 8 项,完整文档 ID 为 [A,A,A,A,B,B,B,B];预先右移的输入/目标各 7 项,因此 M 是 7×7,预测位置的 m 为 [1,1,1,0,1,1,1]。图中 1/× 表示可读/禁读,不是实现里加到分数上的 1/0:允许格加 0,禁止格加 −∞。最后 B 的 EOS 在本次只作最后一项标签,没有作为 query/key 输入;不能把原串的 4+4 格直接画成本次的 8×8 score。

只看矩阵第 4 行:B 的 BOS 可以读取自己 j=4,不能读取 A 的 EOS j=3。反过来看第 3 行:A 的 EOS 仍能读取 A 内的 0–3,但这一行预测下一个 B 的 BOS,label loss 被忽略。一个位置的直接损失为 0,不等于这条输入被删除;忽略 label 更不会自动隔离 attention。

如果把有效性标在完整原串“被预测 token”的位置,则 target_is_valid=[0,1,1,1,0,1,1,1],取 [1:] 才得到同一个 7 项预测 mask。前一个 0 不参与后续切片。判断 m_i 时用的是完整 c 的相邻两项 c_i,c_{i+1},所以末项标签的文档身份不能遗漏。

3.3 EOS、位置重置与硬 mask 的边界

B 的 position ID 即使重置为 0,也只是位置编号变化;没有 c_i=c_j 的硬可见性限制,B 仍可能读到 A。BOS、EOS、position ID、attention mask 和 label mask 分别是内容/位置/读取/监督的不同约定,不能用一个名字替代全部边界。

不同预训练工作可能允许跨文档上下文,也可能采用 sample-level mask;两种策略都存在,不能把一种包装方式当成行业统一配方。更不能只加 EOS 就宣布已隔离:EOS 是可学习 token,不是 attention 的硬屏障。position ID 重置同样不能阻止读取另一篇。

4. 交叉熵如何变成梯度

4.1 自监督标签与单位置梯度

先用图 8 的独立单位置例认识 p−onehot:这里的概率是 [.5,.25,.25]、目标是第 2 号候选。随后回到图 2 的两份记录,用同一个共享参数累计五个有效目标;不要把两组概率当成同一参数配置。

独立三候选交叉熵概率和单位置logit梯度

图 8|独立单位置例;上方纵轴为概率,下方为未平均的 logit 梯度。

三根柱为[0.5,0.25,0.25],第三项是目标;下方梯度为[0.5,0.25,−0.75]。SGD减去梯度,所以两个错误项的logit下降,目标上升;共享参数仍需继续反传。

给定历史,模型输出 VV 个 logits,将其归一化成下一 token 分布。正确答案来自原序列右移一格,训练不需要人手为每个 token 写标签。这里称自监督,是因为监督由数据自身构造。

下面 softmax 固定一个位置 t,只沿该行的词表候选轴求和;不跨时间 t,也不跨 batch 行归一化。保留公式采用候选编号 1…V,具体 ID 算例则采用 0…V−1:这是同一词表的两套编号约定,改写求和上下限后数值相同。图 8 的 v=2 因而是第三项。

pt,v=ezt,v∑u=1Vezt,u,L=−1∑tmt∑tmtlog⁡pt,yt,∂ℓt∂zt,v=pt,v−1[v=yt].\begin{aligned} p_{t,v}&=\frac{e^{z_{t,v}}}{\sum_{u=1}^{V}e^{z_{t,u}}},\\ \mathcal{L}&=-\frac{1}{\sum_t m_t}\sum_t m_t\log p_{t,y_t},\\ \frac{\partial\ell_t}{\partial z_{t,v}}&=p_{t,v}-\mathbf{1}[v=y_t]. \end{aligned}
符号含义、形状与单位
t,v,ut,v,u位置、候选词表索引与归一化求和索引
z,pz,plogits 与概率,均为 [T,V][T,V];概率无量纲
yty_t第 tt 个位置的正确下一 token,整数标量
mtm_t有效监督位置标志,0 或 1;分母假设非零
ℓt\ell_t单位置负对数概率,单位 nat,使用自然对数
L\mathcal{L}有效 token 平均损失,单位 nat/token
∂ℓt/∂zt,v\partial\ell_t/\partial z_{t,v}未平均的单位置梯度;全局梯度还需乘 mask 和平均系数

4.1.1 1.3863 的损失与一次简化更新

取三个候选 logits 为 [log⁡2,0,0][\log2,0,0],概率为 [0.5,0.25,0.25][0.5,0.25,0.25]。若目标是第三项,损失为 −log⁡0.25=1.3863-\log0.25=1.3863,梯度为 [0.5,0.25,−0.75][0.5,0.25,-0.75]。为了看更新方向,暂把 logits 自身当成参数、用学习率 0.1 的 SGD:新 logits 为 [log⁡2−0.05,−0.025,0.075][\log2-0.05,-0.025,0.075],正确项增加,两个错误项减少。这是简化演算;真实训练先通过输出投影、各 decoder 层和 embedding 反传,再更新共享权重。

4.1.2 回到两份记录:五个有效目标的损失和梯度

对于图 2 的两行,先保留完整的 4 行模型 logits,再让第 4.4 节的代码取前三行,与后移标签对齐。A 的标签是 [0,0,PAD],有效性 [1,1,0];B 的标签是 [2,1,2],有效性 [1,1,1]。这批物理上有 6 个预测槽,直接计入损失的只有 5 个。

为了看共享梯度,只设一个可训练标量:所有位置都输出 z=[θ,0,0]。这个缩小模型刻意不读取上下文,只隔离 label、平均单位与同一参数的更新;它不是把每行 logits 当成各自独立的参数。取:

θ0=ln⁡(18/11)≈0.4924764851,p=[0.45,0.275,0.275].\theta_0=\ln(18/11)\approx0.4924764851,\qquad p=[0.45,0.275,0.275].

五个有效位置的目标概率CE与共享参数导数

图 9|行=有效预测位置,列=目标/目标概率/未平均 CE/对同一 θ 的导数。

沿 A0 这一行:目标为 0,因此 p(target)=.45,损失是 −ln(.45)=.7985076962。完整 logit 梯度为 [-.55,.275,.275]。只有 z_0=θ 随 θ 变化,另外两个 logits 固定,所以链式法则给 dℓ/dθ=−.55。

沿 B0:目标为 2,损失是 −ln(.275)=1.2909841813,完整 logit 梯度为 [.45,.275,−.725],对 θ 的导数取第 0 分量 +.45。B1 的目标为 1,完整向量改为 [.45,−.725,.275],对同一 θ 的导数仍是 +.45。A2 的 padding 标签不进入损失分子,也不进入有效目标分母。

同一参数先把所有位置的贡献加起来,不能每读一行就更新一次 θ。按有效 token 等权,分子与分母分别是:

UA=2(0.7985076962)=1.5970153924,UB=3(1.2909841813)=3.8729525439,M=2+3=5,Ltoken=(UA+UB)/5≈1.0939935873,gtoken=[2(−0.55)+3(0.45)]/5=0.05.\begin{aligned} U_A&=2(0.7985076962)=1.5970153924,\\ U_B&=3(1.2909841813)=3.8729525439,\\ M&=2+3=5,\\ L_{\mathrm{token}}&=(U_A+U_B)/5\approx1.0939935873,\\ g_{\mathrm{token}}&=[2(-0.55)+3(0.45)]/5=0.05. \end{aligned}

这里 CE 来自自然对数,单位置损失单位是 nat;L_token 采用有效 token 平均,常写作 nat/token。它要求 M>0。每序列先除各自有效数、再把两条序列等权,则是另一目标:

Lseq=12(UA/2+UB/3)≈1.0447459388,gseq=12(−0.55+0.45)=−0.05.\begin{aligned} L_{\mathrm{seq}}&=\tfrac12(U_A/2+U_B/3)\approx1.0447459388,\\ g_{\mathrm{seq}}&=\tfrac12(-0.55+0.45)=-0.05. \end{aligned}

L_seq 是“每序列 token 平均 CE 的等权平均”,不是整句 NLL 的平均,不能把它改称整句 nat/sequence。两种目标的数值和梯度都不同;第 5 章先做实际一步算术,再从每个目标的权重解释原因。

4.2 用 log-sum-exp 保持稳定

先减最大logit再计算稳定log概率

图 10|候选轴不变;减同一个数保留 logit 分差。

[1000,999]同减1000后得到[0,−1],分差与概率不变。目标为第二项时,稳定损失为1.3133;不要先把极小概率下溢成0再取log。

数值实现不应直接对很大的 logit 求指数。目标损失等于“所有 logits 的 log-sum-exp 减去正确项 logit”;先减去该行最大值再求指数,可以保持 softmax 不变,并避免常见溢出。若 logits 为 [1000,999]、目标为第二项,直接计算指数可能超过浮点范围;减去 1000 后只需处理 [0,−1],损失为 1+log⁡(1+e−1)≈1.31331+\log(1+e^{-1})\approx1.3133。正确项即使概率很小,也应从稳定的 log probability 计算损失,避免先把概率下溢成零再取对数。

4.3 预测收益与真实性的边界

不同来源上下文共享参数预测但不等于独立事实验证

图 11|箭头表示学习关系,输入文本可能含错误或相互矛盾的信息。

图 11 的三路只举例说明不同上下文都使用同一套参数。能帮助条件预测的关系会得到学习信号;优化的仍是条件概率,不能把这条路径解释为自动产生事实验证或用户目标。

为何会学到语法、事实甚至部分推理?同一套参数要在众多上下文下压低预测误差,区分不同情境、记录关系、利用长程线索会帮助预测。但目标只要求提高数据上的条件概率;数据中常见误解也会获得梯度。预测能力提供可迁移表示,不能自动保证生成内容真实、遵循指令或适合用户。

4.4 代码中的切片、有效标签与平均分母

贯穿两序列例的target有效性与右移后label-mask精确对应

图 12|标在原串 token 上的有效性,也要与标签一起取 [1:]。

图 12 上表的列是完整原串位置,target_is_valid 标在被预测 token 上;下表的列是预测行 i。代码保留 logits 前 T−1 行,对齐原串后 T−1 个 ID 与有效性。标在目标 token 上的有效性,比预测位置的 m_i 后移一格,两者必须一起切片。

贯穿例采用完整输入接口:token_ids/target_is_valid:[B=2,T_raw=4],模型返回 logits:[2,4,V=3];切片后的 scores:[2,3,3]、labels:[2,3]。展平传给交叉熵的是 6 行候选分数,图 9 只列其中 5 个有效目标;ignore_index 控制损失贡献,不表示代码必须先物理删掉那一行。两份记录分处 batch 的不同行,不跨行读取;它们不需要把独立文档 packing 的边界再套一遍。

图中的 0/1 是布尔有效性:传入函数时,token_ids 应为整数类别索引(PyTorch 的 long),target_is_valid 应为 torch.bool,logits 为浮点数。对整数 0/1 张量直接使用 ~ 是按位取反,不是这里的布尔逻辑。

这段 loss 函数不构建 attention mask;模型须已采用各行独立的因果读取,query i 只能读本行 0…i。A 的右侧存储 padding 不会被更早的有效 query 读取;最后一行模型输出又被切掉。换成左 padding、双向读取或其他接口时,仍须按实现另设输入可见性,不能把 target_is_valid 当作 attention mask。

下面只实现右移、有效标签和平均损失,输入 logits 为 [B,T,V]。PyTorch 交叉熵接收 logits,内部完成 log-softmax;不要提前 softmax 后再送入同一接口。代码为未实测教学片段,正式可运行版本见后续源码附录。接口语义可核对 PyTorch cross_entropy。

import torch
import torch.nn.functional as F

def next_token_loss(logits, token_ids, target_is_valid):
    # token_ids / target_is_valid: [B,T]
    scores = logits[:, :-1, :].contiguous()
    labels = token_ids[:, 1:].clone()
    labels[~target_is_valid[:, 1:]] = -100
    if not (labels != -100).any():
        raise ValueError("batch has no supervised tokens")
    return F.cross_entropy(scores.reshape(-1, scores.shape[-1]),
                           labels.reshape(-1), ignore_index=-100)

target_is_valid 标注的是原序列中被预测 token 的位置;与前面的 mim_i 相差一个索引。把这两个约定写清楚,可以避免边界 mask 错位。预期返回标量;对于一个有效目标的手算例应约为 1.3863。loss mask 为 0 的位置不直接贡献交叉熵,仍可能作为其他位置的历史参与计算。

预先右移与完整原串接口二选一避免重复移位

图 13|这两条是替代接口,不应串联。

对贯穿例,代码得到的 labels 是 [[0,0,-100],[2,1,2]],展平的六槽中只有五项不是 −100。默认的 cross_entropy(..., ignore_index=-100) 对这五个有效位置平均,因此返回前面的 L_token≈1.0939935873;不是先算每行均值再平均的 L_seq。

图 13 把前面预先右移的 BOS/EOS packing 入口和这段代码分开:若已准备 x=tokens[:-1] 并得到对应的 7 行 logits,就直接配 7 项 y;若把完整 8 项送模,代码才丢最后一行。两者在前缀计算、mask、位置和随机状态一致时对齐同一组预测对象,不能先预移一次又在此函数里再移一次。

若想改成序列等权,需要先以 reduction='none' 获得各位置损失,再按每条有效数分别求均值,最后平均序列。有效数为 0 的行必须按明确策略排除或报错,不能默默把 0/0 当成 0。源代码保留其“全批无有效目标则报错”的边界,不伪称已经实现了另一种平均。

本页保留的 PyTorch 片段仍未在此单独执行。新增例已用 Python 标准库复算、用中心差分核对两条共享参数梯度;这是教学算术验证,不是模型训练或厂商实现复现。

5. 参数更新、学习率与稳定性

5.1 Microbatch、累积与每次更新的 token 数

图 14 的 2048 指每样本有效目标数,不是含 BOS、padding 或忽略项的原串物理长度。若用单条连续序列提供 2048 次下一项监督,需要相应的下一目标;不能直接把张量存储长度当作有效预测数。这里八个 microbatch 计数相等,所以每次均值再等权平均才恰好等价于总分子除总分母;变长时必须另算有效数。

8个microbatch梯度累积到一次step的有效目标计数

图 14|每格消费 65536 个有效目标;8 格合成一次更新。

八个microbatch各消费65536个有效预测,累计524288后更新一次参数。批量梯度是数据分布梯度的估计;增大batch或累积可降低随机波动,也会改变每token对应的更新次数。比较步数时须同时报告这些量。

5.1.1 汇总同一参数的梯度,再做一次更新

同批CE两种统计目标给出相反梯度和一步SGD

图 15|这是同一批数据、同一 θ 的两种优化目标;两列不是连续两步。

回到五个有效目标,选择 L_token 时先得到 g=+.05,再取教学学习率 η=.2:

θtoken′=θ0−0.2(0.05)=θ0−0.01≈0.4824764851.\theta'_{\mathrm{token}}=\theta_0-0.2(0.05)=\theta_0-0.01\approx0.4824764851.

如果选择序列等权,g=−.05,同一学习率给出:

θseq′=θ0−0.2(−0.05)=θ0+0.01≈0.5024764851.\theta'_{\mathrm{seq}}=\theta_0-0.2(-0.05)=\theta_0+0.01\approx0.5024764851.

两个更新都来自真实的交叉熵定义;它们是在同一初值上比较的两条替代更新,并非先做左列再接右列。只更新一个共享输出偏置,是为让梯度从每个目标一路追到同一个参数;真实 decoder 还要把 logit 梯度继续传过输出投影和各层参数。

接下来换回原有的 AdamW 独立首步例,观察动量、平方统计与衰减如何改变优化器的状态;不要把它的 g=.2 当成这批 CE 的梯度。

5.2 AdamW 的状态与解耦衰减

AdamW首步的一阶二阶状态偏差修正衰减和更新

图 16|β 值是本图教学设定;先修正统计,再区分解耦衰减与自适应梯度项。

图 16 从参数 1、梯度 .2 和零统计开始读。为显示中间量,单独取 β1=.9、β2=.999;原有首步偏差修正结论不依赖把这组值当成产品默认配方。

AdamW 保存梯度的一阶、二阶滑动统计,并将参数衰减与自适应梯度更新分离。它是公开可讲解的优化器例子,不是对所有旗舰的统一断言。来源:AdamW。

as=β1as−1+(1−β1)gs,bs=β2bs−1+(1−β2)gs2,θs+1=(1−ηsλ)θs−ηsa^sb^s+ϵ.\begin{aligned} a_s&=\beta_1a_{s-1}+(1-\beta_1)g_s,\\ b_s&=\beta_2b_{s-1}+(1-\beta_2)g_s^2,\\ \theta_{s+1}&=(1-\eta_s\lambda)\theta_s-\eta_s\frac{\hat a_s}{\sqrt{\hat b_s}+\epsilon}. \end{aligned}
符号含义、形状与单位
s,θs,gss,\theta_s,g_s更新步、参数和平均损失梯度;状态形状均与参数相同
as,bsa_s,b_s梯度一阶与平方二阶滑动统计;平方与除法逐元素计算
β1,β2\beta_1,\beta_2统计保留率,介于 0 与 1;区别于后训练中的 KL 系数
a^s,b^s\hat a_s,\hat b_s偏差修正值,分别除以 1−β1s1-\beta_1^s、1−β2s1-\beta_2^s,这里从 s=1s=1 起步
ηs,λ,ϵ\eta_s,\lambda,\epsilon学习率、衰减系数与数值稳定项;通常采用约定的无物理单位参数

5.2.1 从参数 1 更新到 0.989

若标量初值 θ=1\theta=1、首步梯度 g=0.2g=0.2、统计初值为零,偏差修正后为 a^=0.2,b^=0.04\hat a=0.2,\hat b=0.04。取 η=0.01,λ=0.1\eta=0.01,\lambda=0.1、忽略极小 ϵ\epsilon,得到 0.999−0.01=0.9890.999-0.01=0.989。仅看这一步,更新幅度不会随梯度乘以 10 而直接乘以 10,因为分母也变化;多步情况由历史统计共同决定。

5.3 数值稳定需要联合定位

按数据数值路由与执行对象定位同一loss异常

图 17|排错关系表,不是测得的 loss 曲线或运行日志。

图中五条异常来源只组织排查,不是测得的训练曲线。先将数据记录、梯度范数与验证损失对齐到同一步,再定位来源。学习率warmup让早期更新逐渐放大,之后可使用余弦或其他衰减。梯度裁剪限制异常全局范数,混合精度减少存储和运算成本,必要位置保留高精度统计。它们都需要记录数值异常、梯度范数和验证损失。loss 稳定下降支持优化在工作,独立验证才支持分布外收益。 个别 loss spike 可能来自坏样本、batch 变化、溢出、路由失衡或硬件异常,应以状态和数据定位,不能直接归为“学习率太大”。

5.4 按步调度与按曝光量调度

优化器step和有效token是两个不同调度计数

图 18|横轴为优化器 step;纵轴为相对峰值学习率。

学习率调度还要注明按什么计数。假设线性 warmup 覆盖前 1000 个优化器步,第 500 步达到峰值的一半;如果每步有效 token 数加倍,同样的配置会在 warmup 中处理两倍数据。如果希望保持按数据曝光量定义的课程,就要按累计有效 token 调度,或同步调整步数。恢复检查点时只恢复权重、重新从零计 warmup,也会改变继续训练的更新轨迹。

5.5 Token 平均与样本平均不是同一目标

先解释图 15 为什么会异号。五个有效目标里,A 的两个目标都是 0,B 的三个都不是 0。token 平均给“目标 0”合计权重 2/5=.4;序列等权先给 A/B 各一半,所以“目标 0”合计权重为 .5。当前 p0=.45 位于两者之间:前者要把它往下推,后者要往上推。

每个 A 目标在两个目标中的权重是 1/5 与 1/4;每个 B 目标是 1/5 与 1/6。这不是 CE 或 SGD 算错,而是训练目标改变了。下面的 2/6 个目标是独立的权重示意,随后保留一套二次损失反例,让每个损失值和导数都能再次完整核对。

2和6有效目标在token平均与序列等权下的权重

图 19|圆表示有效目标,圆的行仅用于排版;标注分数才是权重。

图 19 的 2 颗蓝珠是短样本 A,6 颗绿珠是长样本 B。上半部每珠拿到总权重的1/81/8;下半部先给每个样本1/21/2,于是蓝珠各分1/41/4、绿珠各分1/121/12。圆大小保持相同,权重由旁边分数明确给出;圆的换行仅为排版,不是训练时间。平均规则先改变每个目标的权重,再改变共享参数的梯度。

5.5.1 同一批数据,更新方向也可以相反

原有二次loss的两个目标与相反参数更新方向

图 20|原独立二次损失例;下方轴是参数 θ,不是训练时间。

用一个可完整验算的标量模型隔离分母效应,不冒充真实语言模型训练:参数θ=1\theta=1,A有2个相同目标,B有6个相同目标。每个目标采用以下非负二次损失,区别于本篇前面的交叉熵;它们只为给出数值与导数完全一致的局部例子:

ℓA(θ)=12(1.5θ+0.5)2,ℓB(θ)=12(3−2θ)2.\begin{aligned} \ell_A(\theta)&=\tfrac12(1.5\theta+0.5)^2,\\ \ell_B(\theta)&=\tfrac12(3-2\theta)^2. \end{aligned}

在θ=1\theta=1,A每个目标的损失为2、梯度为1.5×2=+31.5\times2=+3;B的损失为0.5、梯度为(−2)×1=−2(-2)\times1=-2。按所有token平均,损失为(2×2+6×0.5)/8=0.875(2\times2+6\times0.5)/8=0.875,梯度为(2×3+6×(−2))/8=−0.75(2\times3+6\times(-2))/8=-0.75。若先对每样本平均再平均,损失为(2+0.5)/2=1.25(2+0.5)/2=1.25,梯度为(3−2)/2=+0.5(3-2)/2=+0.5。

同用学习率η=0.1\eta=0.1的SGD,前者更新到1−0.1(−0.75)=1.0751-0.1(-0.75)=1.075,后者更新到1−0.1(0.5)=0.951-0.1(0.5)=0.95。两个更新各自降低其对应目标,却朝相反方向走;实现中把分母换掉,相当于换了优化问题,不能只称“不同写法”。真实交叉熵也受这个加权关系约束,具体梯度由网络决定。分布式、变长样本和梯度累积都应先声明优化哪个平均,再跨设备保持一致的总分子与总分母。数据混合比例、loss权重和累积分母一起记录;跨设备实现见第09篇。

6. 规模规律与训练阶段延伸

6.1 经验拟合与计算预算

规模律是对指定实验范围内的平均损失作经验拟合,帮助分配模型、数据和计算预算。Kaplan 等研究了参数、数据及计算的幂律关系;Chinchilla 研究进一步比较计算预算下的模型大小与训练长度。结论依赖数据、模型和实验设置,不是任意架构的永恒常数。来源:Scaling Laws;来源:Chinchilla。

用一个抽象拟合解释取舍,以下系数不取自任何厂商:

L(N,D)=L∞+AN−α+BD−γ,C≈6ND.L(N,D)=L_\infty+AN^{-\alpha}+BD^{-\gamma},\qquad C\approx6ND.
符号含义、形状与单位
N,DN,D模型参数数、训练曝光 token 数;单位分别为 parameter 与 token
L,L∞L,L_\infty验证交叉熵与拟合下限,单位 nat/token
A,B,α,γA,B,\alpha,\gamma拟合系数与正指数;数值取决于 N,DN,D 的单位约定
CC近似训练 FLOPs;6ND6ND 忽略额外 attention、embedding、MoE通信等成本

6.1.1 固定预算下平衡两个误差项

图 21 为了给三条曲线可复算的坐标,另定义归一化规模 n=N/N0、数据量 d=D/D0,固定 n·d=1,选 α=γ=1、两项系数各为 1 nat/token。于是模型项为 1/n,数据项为 1/d=n,误差合计 1/n+n;没有画入常数下限。

n=.5 时两项为 2 与 .5、合计 2.5;n=1 时为 1 与 1、合计 2;n=2 时为 .5 与 2、合计 2.5。横轴刻度按 log2 等间隔排列,纵轴写教学误差的 nat/token。这里 n=d=1 是归一化量相等,不是参数个数和 token 个数的物理单位相同。

固定归一化预算下两项误差与合计的明确函数和坐标

图 21|教学函数 1/n、n 与 1/n+n;横轴采用 log2 间隔。

图中的曲线是归一化教学函数,没有厂商实验数据:蓝色模型误差下降,绿色数据误差上升,橙色为合计。固定 CC,代入 D=C/(6N)D=C/(6N),损失变成 L∞+AN−α+B(6N/C)γL_\infty+AN^{-\alpha}+B(6N/C)^\gamma。第一个误差项随模型变大下降,第二个随数据预算缩短上升;对 log⁡N\log N 求导为零,得到 αAN−α=γBD−γ\alpha AN^{-\alpha}=\gamma BD^{-\gamma}。它要求平衡两个边际收益,而不是一味增加参数。若简化取 α=γ,A=B\alpha=\gamma,A=B,在相同归一化单位下会得到 N=DN=D;这只是展示平衡机制,绝非“参数数必须等于 token 数”。

6.2 训练计算最优与部署成本最优

图 22 的每个点同时给参数 N 与训练量 D,横纵轴分别有自己的单位。10B/200B 与 20B/100B 在同一条 N·D=2000 B² 的预算曲线上;不能因为一根参数柱和一根 token 柱都更高,就直接比较其面积或声称损失更低。

同一dense训练计算预算的参数和token双单位曲线

图 22|横轴 B 参数,纵轴 B 训练 token;不比较不同单位的柱高。

另一预算手算:10B dense 参数训练 200B token,主体近似计算为 1.2×10221.2\times10^{22} FLOPs;若把模型增到 20B、预算不变,数据要降到约 100B。哪一种损失更低需拟合和验证。若产品要服务数十亿次请求,较小模型训练更久可能降低总生命周期成本,即使没有达到最低训练计算的点。因此“计算最优训练”与“部署成本最优”应分别讨论。MoE 也不能直接把总参数代入这个 dense 近似。

6.3 继续预训练与遗忘检查

新领域和旧领域保留集分别做更新前后CE对照

图 23|数字是诊断教学设定,不是实际训练结果;先在同一行比较前后。

图 23 对通用保留集与新领域集分别做前后对照。数值只是教学诊断设定,假定每一行的分词、数据和评测条件固定;没有据此设定配方比例。新域 CE 从 1.4 降到 1.0,同时旧域从 .9 升到 1.2,就应分别记录收益与遗忘,而不是只报告新域下降。Continued pretraining是从已有权重继续优化类似预测目标,可能更新知识、增强领域覆盖或调整分布;mid-training 是某些工作对中间阶段的命名,并无统一强制边界。保留通用数据、控制学习率和检查遗忘,通常比只看新领域 loss 更可靠。原训练已经学到的内容不保证在新梯度下完全保留。

6.4 长上下文需要三个条件共同成立

图 24 的三个小区分别问:位置能否合理表示、是否学过远距离关系、系统能否承担更长序列。最下方把长度 4 与 8 的 score 方阵画成 16 与 64 格,只核对 dense attention 的 query×key 数量;这不是整个模型显存或时间都恰好变四倍的实测结论。

长上下文的位置关系学习与系统score预算三个条件

图 24|行=query 位置 i,列=key 位置 j;蓝为因果可读、灰为被 mask。两色都计入 dense score 槽位。

长上下文还需同时处理三个问题:位置表示在新长度上是否合理,网络有没有学过远距离关系,系统是否负担得起长序列。位置插值研究提供了将更长索引映射到原位置范围的方法,但仅修改位置尺度不能替代长上下文数据和训练。来源:Position Interpolation。全文检索、跨文档推理和长代码依赖需要不同评估;找到一个隐藏字符串不能证明已能理解一本书。

至此,预训练可以被还原为一条明确链:数据分布决定要预测什么,mask 决定能读取什么,交叉熵决定哪些方向获得梯度,优化器决定状态如何变化,预算与验证决定何时扩展。下一篇只改变数据组织和目标,就能从“续写语料”走到“按用户指令行动”,再进入偏好学习。

回到开头的两条记录,可以不读源码先检查:

  • 原始 7 个 token、物理 8 槽、右移后的 6 个预测槽、5 个有效目标为什么各不相同?padding 和目标错位分别减少了什么?
  • A 第 2 行输入是正常 a,为什么它的 label 被忽略?不能用 ID!=0 判断哪一个 0 是 padding。
  • packing 的 M[4,3] 为何不可读,而 m[3]=0 是另一条规则?屏蔽一条损失不会隔离两份文档。
  • 同一初值、同一批 CE,为什么 token 平均使 θ 减 .01,序列等权却使它加 .01?当前 .45 位于两种目标权重 .4/.5 之间。
  • 8 次 backward 不应被记成 8 次 optimizer step;比较学习率日程时,还要报告每步的有效目标总数。

沿这些具体格子、分母和状态检查,才知道一次“loss 下降”究竟优化了什么。

下一篇:SFT、奖励模型与 DPO · 返回导读

正在连接 GitHub 评论…