系统篇

05|训练的一步:从正确标签到参数真正改变

系统篇约 6.8 千字1 组分步图解
本章目录

本章预备知识

训练要先定义“希望预测什么”,才有误差和更新方向。梯度是参数小变化对损失的局部影响;Adam保存过去梯度的统计,模型参数、激活、优化器状态是不同存储对象。

本章各题列出所需基础。可先完成相应基础课,也可通过自检确认掌握程度。

进入深读前的小检查:用x=2、目标4、w=1算预测2、损失2、梯度−4;以步长0.2更新w为1.8,检查误差是否下降。

术语带虚线时可点击速查。公式中的字母先看定义;不要用猜缩写替代推导。

这一章不以“预训练是预测下一个词”结束,而是跟踪一条训练样本怎样形成标签、损失、梯度、优化器状态和新权重。默认讨论自回归Decoder;具体架构和训练配方可改变细节。

沿着对象与状态理解本章

训练的一批数据里,输入和正确后继已经给定,因此可以对多个位置一起计算预测误差,但因果mask仍禁止偷看未来。读训练公式时先分清前向、损失、反向与更新;backward并不意味着参数已经改变。

下方图解的固定输入在“输入与适用条件”中声明。它用于解释本章机制,不与本章其他独立例子的数值暗中接续。

动态图解 · F18

训练:给每个位置一道“下一项”题

为什么训练看完整句,生成却只能往前走?

训练时答案放在试卷的评分区,所以各位置的题目可以同时准备;mask负责不让模型读到自己的答案。生成时后续Token还未决定,下一题的前缀依赖本题选择。两者共享因果预测目标,但已知信息不同。

标签用于评分的真实下一Token。
交叉熵本例为真实目标概率的负对数。
有效目标数实际参与评分的位置数,不必等于补齐长度。

输入与适用条件:标签对齐使用5项序列;单位置交叉熵与PAD平均分别是明确独立的小例,不假称那些概率来自对齐图的模型。

1 / 5 · 把输入和目标错开一格

第1步,共5步

窄屏可左右滑动图形,或点击“放大图形”。文字解释紧随图后。

训练:给每个位置一道“下一项”题:把输入和目标错开一格我输入0爱输入1学习输入2!输入3爱目标0学习目标1!目标2EOS目标3

完整教学序列为“我/爱/学习/!/EOS”。输入用前四项,目标用后四项。每个输入位置预测的是其后一个真实Token。

输入=[1,2,3,5];目标=[2,3,5,6]

默认静止。用“下一步”看完解释再继续;播放到最后一步自动停止。键盘聚焦播放器后,可用左右键逐步查看、空格播放/暂停。图中颜色辅助区分,含义同时用文字注明。

为什么需要

用清晰的预测任务,把参数更新与语言序列关系连接。

怎样实现

正确移动标签、限制可见性、屏蔽无效目标、按有效数归一化。

可能的代价与误解

偷看未来会产生漂亮但虚假的训练成绩;训练样本重复或泄漏也会高估泛化。

如何判断是否做对

用极小固定序列验证每个输入位置和目标位置,再验证PAD不影响有效损失。

Q017|Next-token训练到底预测什么?标签如何移动,损失又对哪些位置计算?

核心回答

模型在位置i读取不超过i的前缀,输出位置i+1的分布;训练代码把logits与右移一位的真实Token对齐。所有已知前缀能在一次前向中并行处理,因果mask阻止偷看未来。模型最小化真实Token的负对数概率,不是直接比较生成句子和答案的编辑距离。[TR][RLHF]

用五个Token走完对齐

设训练序列为[BOS, 我, 爱, 编程, EOS]。常见实现把整段作为输入,再在计算loss时对齐如下:

logits位置 可见输入 应当预测的标签
0 BOS 我
1 BOS,我 爱
2 BOS,我,爱 编程
3 BOS,我,爱,编程 EOS

最后位置没有后继标签,通常不计入这一段loss。等价写法是输入直接取前四个Token、标签取后四个Token;不要同时在数据处理和模型内部再移动一次,否则会变成预测后后一个Token。

对位置t,模型得到词表logits z_t,转为概率p_t,损失是 ℓ_t = −log p_t[y_t]。若正确Token概率是0.1,loss约2.3026;若提升到0.8,loss约0.2231。一个batch的loss通常是有效标签位置的平均。这里“有效”由loss mask决定,不等于attention mask。

SFT样本可能是用户问题 + 助手答案。有的配方只对助手答案位置计loss,但答案位置仍可注意用户问题。把用户位置的标签设置为ignore,不等于从输入删除问题。数据代码必须同时正确维护角色边界、结束标记、padding和被忽略标签。[CHAT]

运行示例 · Q017

标签移位错误,训练也能看起来很顺利

输入与条件。输入序列为 [BOS,我,爱,学习,EOS]。正确训练将前四个位置与后四个目标对齐。

步骤与对象内部动作中间结果 / 新状态
1正确输入[BOS,我,爱,学习]每个位置只看自己及以前。
2正确目标[我,爱,学习,EOS]所有目标相对输入移动1位。
3逐格解释输入“我”所在位置预测“爱”不是预测当前位置已经知道的“我”。
4错误对齐把目标也设为 [BOS,我,爱,学习]模型可能轻松复制当前输入,损失下降但没学对next-token目标。
5额外maskSFT若只训练助手回答用户Prompt可作为输入但不一定参与loss;具体目标策略要明确。

把过程连起来。损失能下降,只证明某个目标容易优化;必须先核验目标含义。

边界与反例。不同训练框架可能在模型内部自动移位,调用者不可再移第二次;这里显示数学对齐而非某个API调用约定。

依据与适用范围:[CE]。示例输入和场景由本书明确设定。

追问:为什么训练准确率很好,实际生成仍会跑偏?

训练常用真实前缀,推理使用模型自己的前缀。某一步选错Token后,后续可能进入训练中较少出现的状态;这类训练与生成条件的差异通常称为exposure bias。另一个原因是loss按Token平均,格式、语言流畅性的改善可以掩盖少数高风险事实错误。验证时不能只看训练loss,还要让模型自己生成,并检查完整任务结果。

追问:Perplexity能直接比较两个不同Tokenizer的模型吗?

一般不能直接比较。Perplexity通常是exp(平均Token负对数似然);一个Tokenizer把同一文本拆成更多Token,平均的单位已不同。跨Tokenizer比较需要明确按字节、字符或统一评估设置归一化,同时控制数据集。不同语料上的PPL也不能当成同一尺度的综合能力榜。

追问:把多个样本拼接训练,插入EOS就能隔离信息吗?

EOS是Token,不自动建立计算上的隔离。若只用普通因果mask,后一个样本仍可看到前一个样本。是否允许这种跨样本关注是训练设计;若要求严格独立,要使用分块attention mask或实现支持的边界机制,同时处理position IDs。把“遇到EOS学会结束”与“显式切断注意力”分开。

Q018|Loss算出来后,参数怎样更新?为什么AdamW不只是梯度乘学习率?

核心回答

反向传播按计算图的链式法则,从loss逐层计算参数梯度;优化器用梯度和自身历史状态得到更新量。AdamW维护梯度的一阶、二阶指数移动平均,并把权重衰减与自适应梯度更新解耦。缓存、梯度、优化器状态是不同对象。[ADAMW]

从输出投影一直走回Embedding

设最终隐藏状态为h,输出矩阵为W,z=hW。对softmax交叉熵,∂ℓ/∂z = p−one_hot(y)。如果正确类别概率太低,该类别logit的梯度为负;梯度下降会推动其logit上升。这是概率预测变为参数调整的第一步。

接着∂ℓ/∂W = hᵀ(p−y),∂ℓ/∂h = (p−y)Wᵀ。后一项继续经过最终归一化、每一层FFN、Attention、残差支路,最后到Embedding。残差分支的梯度要相加,共享参数被多处使用时梯度也要累加。自动求导做的是这些局部导数的组合,不是在搜索“哪个神经元知道这条事实”。

AdamW的一种常见写法为:

m_t = β1 m_(t−1) + (1−β1) g_t
v_t = β2 v_(t−1) + (1−β2) g_t²
m_hat = m_t / (1−β1^t)
v_hat = v_t / (1−β2^t)
θ_t = θ_(t−1) − η m_hat/(sqrt(v_hat)+ε) − η λ θ_(t−1)

平方、除法是逐元素操作。m平滑梯度方向,v估计梯度平方的尺度,偏差修正处理初始状态为零造成的偏差。权重衰减项没有先混入g再被v缩放,因此不同于一般情形下“把L2惩罚加进Adam的loss”。哪些参数衰减、ε放在哪里、混合精度如何维护主权重,要看具体实现。

运行示例 · Q018

AdamW的第一步,把动量、偏差修正与衰减都算出来

输入与条件。初始w=1,梯度g=0.2;m0=v0=0;β1=0.9、β2=0.999;学习率0.1,weight_decay=0.01,ε=1e−8。

步骤与对象内部动作中间结果 / 新状态
1更新一阶矩m=0.9×0+0.1×0.20.02。
2更新二阶矩v=0.999×0+0.001×0.2²0.00004。
3偏差修正m̂=m/(1−0.9),v̂=v/(1−0.999)分别0.2与0.04。
4解耦权重衰减w先乘(1−lr×wd)从1变0.999。
5归一化梯度更新再减0.1×0.2/(√0.04+1e−8)新w约0.899000005。
6与SGD对照只做w−lr×g会得0.98,不是同一个更新规则。

把过程连起来。AdamW保存历史状态并做归一化与偏差修正;不能只把它描述为“梯度乘学习率”。

边界与反例。本例是第一步标量更新,无梯度裁剪、混合精度或调度器;实际实现参数组可有不同衰减。

依据与适用范围:[ADAMW]。示例输入和场景由本书明确设定。

追问:梯度清零为什么重要?

很多训练框架默认累积.grad。这方便梯度累积,但普通一步一更新若忘记清零,会把前几步的梯度无意叠加。反过来,在每个micro-batch前清零又会破坏有意的累积。正确的位置通常是一个有效优化步开始前或完成后,而不是机械放在所有循环的第一行。

追问:梯度裁剪改变了什么?为什么不能修复全部NaN?

全局范数裁剪会在梯度范数超过阈值时,按比例缩小整个梯度向量,限制极大更新。它不修复已发生的非法前向数值、全mask softmax、除零或损坏数据。混合精度下还要在适当时机解除loss scaling后再裁剪,否则阈值单位不对。出现NaN时应定位最早的非法张量,而不是只减小学习率碰运气。

追问:恢复训练只加载权重够不够?

继续同一条训练轨迹通常还要恢复优化器m/v、学习率调度器、步数、数据采样位置及随机状态;分布式训练还涉及分片与全局进度。只加载权重可以启动新的优化过程,但不等于无缝续训。推理部署一般不需要优化器状态,这就是训练checkpoint与推理权重包体积可能显著不同的原因。

Q019|预训练数据进入模型前经历什么?为什么数据质量会变成系统问题?

核心回答

训练不是“把互联网文本喂进去”这么简单。数据获取、许可和隐私处理、清洗、去重、混合采样、Tokenization、分片及训练/验证划分共同决定模型看到的分布。统计量要在处理链的多个阶段观察,不能只记录最终总Token数。[CHINCHILLA]

一份文档的完整生命周期

先保存原始来源和采集版本,提取正文;HTML导航、重复页脚、乱码和机器生成垃圾会让梯度反复学习无意义模式。随后进行语言、格式、质量及敏感数据处理。过滤器也会引入选择偏差:过于偏爱某种文风,可能误删专业论坛、口语或稀有语言。

去重至少要区分精确重复、近重复和同源改写。精确hash只能识别相同字节;近重复方法通常基于片段特征或相似性,再配合阈值。阈值过宽会丢掉有价值的独立样本,过窄会保留成批模板。去重不仅节约算力,也影响记忆性与评测污染风险。

接下来按数据源、语言、代码和难度设置采样混合,转换Token并装入训练序列。一个来源原始体积大,不意味着它应有相同训练权重;重复采样会让实际训练分布不同于硬盘上的分布。应记录“每类数据在训练中实际消耗了多少Token”,而不只是下载了多少。

评测集应在可能共享来源的层面隔离。把同一仓库相邻函数随机拆到训练和测试,可能让结果主要反映见过的项目;把某道题的不同网站转载分别放两边,仍可能泄漏。对代码Agent,还应区分模型训练污染、检索库泄漏和测试本身暴露,这三条路径并不相同。

运行示例 · Q019

重复样本怎样把一次评测变成“背过答案”

输入与条件。资料有文档A、A的空白格式变体A′、独立文档B。先随机逐文件切分,把A放训练、A′放测试。

步骤与对象内部动作中间结果 / 新状态
1原始切分文件名不同看似训练和测试没有同名文件。
2规范化比较去掉无意义空白后A与A′相同测试已泄露训练内容。
3按重复簇切分把A/A′作为一组整组只进入一侧,B独立分配。
4记录处理链原文身份、清洗策略、去重簇、分区后续可追溯数据为何进入训练。
5评价泛化使用真正未见任务不能用重复样本上的低loss证明新问题能力。

把过程连起来。数据工程影响模型能力,也影响对能力的判断;去重不是只为节约磁盘。

边界与反例。语义近重复需要更细策略;去空白只用于这个明确构造的重复例子,不适合所有代码/文本。

依据与适用范围:[DERIVE]。示例输入和场景由本书明确设定。

追问:为什么更多数据可能反而降低某项能力?

训练目标优化的是混合分布上的期望。新增数据改变了比例,可能稀释原有高质量任务,也可能引入矛盾、噪声或风格偏移。总loss下降不保证每个任务子集改善,因此需要分语言、任务和风险类别的验证集。数据规模与质量不能用单一数字相互替代。

追问:知识截止日期是数据库里的统一时间戳吗?

通常不是。不同来源被收集和混合的时间不同,训练后还可能进行后训练;模型也可能从工具得到更近事实。对某件事是否知道不能仅靠一个“截止日期”推断。工程系统应把实时事实交给有来源、可更新的检索,而不是依赖模型口头承诺“我知道最新”。

追问:训练数据去重与Agent记忆去重可以用同一套办法吗?

目的不同。语料去重主要控制样本分布和污染;记忆去重还要保留事实适用范围、时间、证据和否定关系。“接口需要重试”与“此接口不能自动重试”词面接近却不能合并。可以复用相似度作为候选发现,但不能直接用它裁决知识等价。

Q020|训练为什么比推理更吃显存?梯度累积、Checkpoint和分片各节省什么?

核心回答

训练除了参数,还要保存梯度、优化器状态和用于反向的激活;推理通常没有这些对象,但长上下文需要KV缓存。不同优化技术针对不同对象,不能把“节省显存”当作同一件事。

从对象清单估算,而不是背一个固定倍数

以一个教学配置为例:低精度参数2字节、低精度梯度2字节、FP32主权重4字节、Adam两个FP32状态8字节,共约16字节/参数,尚不含激活、临时缓冲和通信。某些实现没有独立主权重、梯度为FP32或优化器量化,这个系数就会变。估算时先列对象及dtype,再乘参数量。

激活占用依赖batch、序列长度、层数和内核。标准attention如果显式保存[B,H,T,T]会非常昂贵;更省内存的内核避免物化它。Activation checkpointing则不保存部分中间值,反向时重新前向计算,用算力换显存。它与“保存模型checkpoint文件”不是同一个概念。[FLASH]

梯度累积把大batch切为K个micro-batch,连续反向但延后更新。若每个micro-batch包含相同有效Token数,loss除以K通常能得到对应平均梯度;有效Token数不等时,机械平均各micro-batch平均loss会改变样本权重。应按有效Token总量归一化。Dropout随机性、浮点累加顺序等也会使数值不完全一致。

参数/梯度/优化器分片解决跨设备的冗余;tensor parallel切分层内矩阵计算;pipeline parallel按层拆分;data parallel处理不同样本后同步梯度。它们可组合,但通信与调度成本不同。第08章继续拆解推理侧的并行。

运行示例 · Q020

训练显存:同样100万个参数,额外状态从哪里来

输入与条件。假设全部使用FP32:100万参数、对应梯度、一阶矩、二阶矩各一份;每个数4字节。

步骤与对象内部动作中间结果 / 新状态
1参数1,000,000×44MB。
2梯度同样大小再4MB。
3Adam状态m与v各4MB再8MB,四类合计16MB。
4激活反向还需要中间张量或重算材料其占用取决于batch、长度、层数,尚未包含在16MB中。
5梯度累积小批逐次算、累积梯度再更新减少单次激活峰值,不删除参数和优化器状态。
6Checkpoint/分片前者少存激活多重算;后者分摊状态代价分别是计算或通信,不能都叫免费省显存。

把过程连起来。先列对象再算大小,才能判断某项优化究竟减少哪一部分。

边界与反例。按十进制MB;真实混合精度、主权重副本、ZeRO实现和工作区会改变账本。

依据与适用范围:[DERIVE]。示例输入和场景由本书明确设定。

追问:梯度累积能降低单条长序列的峰值显存吗?

它降低micro-batch数量造成的峰值,但一条序列本身的激活仍要处理。如果batch已经是1,累积更多次不会缩短这条序列。需要更省内存的attention、checkpointing、序列并行、分片或缩短序列等针对性措施。

追问:量化到4bit是否意味着训练所有内存都变为四分之一?

不是。量化通常主要改变底座权重存储,反向激活、适配器、优化器、量化scale和临时反量化计算仍占内存。QLoRA冻结量化底座、训练低秩适配器,因此不是任意4bit权重都可以直接全参数更新。[QLORA]

追问:训练学习率越小越安全吗?

小学习率减少单步变化,但也可能在预算内学不动;大batch、累积、warmup和数据变化会改变合适尺度。工程上看梯度范数、更新/权重比例、分任务验证损失和数值异常。训练不稳定不是靠单一“保守参数”就能消除。

本章分布式训练与并行部分的延伸依据:PyTorch张量并行说明与ZeRO原始论文。[TP][ZERO]

记录保存在本机浏览器。

输入关键词即可检索。

↑ ↓ 选择 Enter 打开Esc 关闭 · 仅本地搜索

阅读设置

阅读设置仅保存在本机浏览器,不上传任何数据。