AI Hero Club

大模型后训练 · 第 2 章

已自行标记完成0 / 8

仅保存在当前浏览器;完成标记不代表通过项目验收。

本章提纲 7 个小节
全课目录 8 章
完整课程计划 ↗
大模型后训练 / 课程计划 ↗

CHAPTER 02 / 8建议学习 120 分钟

SFT:从回答似然到全部参数梯度

提示和回答拼成一串后,怎样只计算回答的每个词元及 EOS,并沿全部参数反传?

本章要解决的 3 个问题
  • 逐步推导softmax交叉熵的p−y梯度,并沿线性策略更新全部参数
  • 对多token回答准确放置response-only错位掩码,保留首回答token与EOS
  • 区分按回答、按token和按示范重复频数加权的监督目标
课程项目 ZIP ↓

任务与先修

本章实现监督微调,英文缩写SFT。输入是提示x与示范回答y,任务是增加示范的条件概率。读者需掌握上一章的四候选策略,以及一元指数、对数和链式法则。我们先在有限候选中把全部八个参数的梯度推完,再说明语言模型多token回答的求和与掩码。本章没有把四分类参考改名为语言模型;它只用最小可计算形式检验同一种条件似然原则。项目SFT运行二百次全批梯度下降,所有示范与参数更新都可打印重建。

对提示x,动作a的logit是 za=ba+waxz_a=b_a+w_ax。定义概率 pa=exp⁡(za)/∑jexp⁡(zj)p_a=\exp(z_a)/\sum_j\exp(z_j)。只要logit有限,所有概率严格正且和为一。logit本身可负、可大于一,不是置信概率;给所有类别加同一常数不改变softmax。这个平移自由度说明参数并非每个方向都可由观测唯一确定,但不影响分布与目标的定义。数值实现先减去最大logit,再计算指数和,避免大正数溢出。

从似然到交叉熵

一条示范类别k的似然为 pkp_k,负对数为 ℓ=−zk+log⁡∑jexp⁡(zj)\ell=-z_k+\log\sum_j\exp(z_j)。这是精确代数变换:将softmax分子分母取log,得到logit差与归一化项。对第j个logit求导,归一化项的导数是 exp⁡(zj)/∑iexp⁡(zi)=pj\exp(z_j)/\sum_i\exp(z_i)=p_j;负zkz_k贡献负的指示值,即j等于k时减一。因此 ∂ℓ/∂zj=pj−1[j=k]\partial\ell/\partial z_j=p_j-\mathbf1[j=k]。梯度各分量之和为零,正好对应共同平移不会改变损失。

ℓ=−zk+log⁡∑iezi,∂ℓ∂zj=−1[j=k]+ezj∑iezi=pj−1[j=k].\begin{aligned}\ell&=-z_k+\log\sum_i e^{z_i},\\ \frac{\partial\ell}{\partial z_j}&=-\mathbf1[j=k]+\frac{e^{z_j}}{\sum_i e^{z_i}}=p_j-\mathbf1[j=k].\end{aligned}
对归一化项逐项求导,指示值只由示范类别给定。

再对实际参数求导。因为zjz_j对bjb_j导数为一,对wjw_j导数为x,所以偏置梯度就是pjp_j减目标指示,斜率梯度再乘x。其他类别的参数也有梯度,不能只给正确类别加分而不管分母。对N条示范取平均,逐条梯度相加后除N。项目实现直接累加这八个标量,再用学习率乘梯度从参数中减去;没有自动微分黑箱,也没有冻结某一层参数。

∂ℓ∂ba=pa−1[a=k],∂ℓ∂wa=x(pa−1[a=k]).\frac{\partial\ell}{\partial b_a}=p_a-\mathbf1[a=k],\qquad \frac{\partial\ell}{\partial w_a}=x(p_a-\mathbf1[a=k]).
有限四候选策略的全部参数梯度;样本均值再除示范数。

算例一:一个提示的一步更新

设x=2,四个logit都为零,真实示范是编号一“正数,简短”。概率各四分之一,损失log4。偏置梯度依次是 [0.25,−0.75,0.25,0.25];斜率梯度是 [0.5,−1.5,0.5,0.5]。若初始全部参数零、学习率0.1,更新后偏置为 [−0.025,0.075,−0.025,−0.025],斜率为 [−0.05,0.15,−0.05,−0.05]。同一x下新logit为 [−0.125,0.375,−0.125,−0.125]。

正确类别相对其余高0.5,故新概率为 e0.5/(e0.5+3)e^{0.5}/(e^{0.5}+3),约0.354661,大于更新前0.25;新损失约1.036592,低于log4约1.386294。独立检查一是四个偏置梯度与四个斜率梯度各自求和为零;独立检查二是对任一参数做中心有限差分,重算两次loss,结果应与解析导数接近。有限差分只验证该点数值,不代替前面的导数推导。

语言模型的回答条件与掩码

若回答由多个token组成,记提示为x,回答token依次是y1到yT,其中可把最后EOS也列作回答结束目标。条件概率按链式法则为各步概率乘积:第t步只读提示与此前回答token。取负log后变成T项求和。这不是把整段回答当四分类,而是把每个输出位置的词表分类接到同一条件序列上。teacher forcing给模型真实的过去回答,不给同一预测位置读取当前或未来目标的权限。

LSFT=−1N∑i=1N∑t∈responseilog⁡πθ(yi,t∣xi,yi,<t).\mathcal L_{SFT}=-\frac{1}{N}\sum_{i=1}^N\sum_{t\in\mathrm{response}_i}\log\pi_\theta(y_{i,t}\mid x_i,y_{i,<t}).
这里按回答总NLL平均,不是按全体token数平均;采用哪一种须显式声明。

response-only指只对回答及其EOS评分,提示token用于条件而不进入损失。它不是从输入中删掉提示,否则就改变任务。也不是仅对“输入看起来属于回答”的位置评分,因为首回答token由提示末尾位置预测。正确掩码必须以目标所属片段决定,先做输入目标错位,再把非回答目标设为忽略值。序列填充也要从loss分母中排除,但真实EOS不排除。

算例二:首回答token在哪一格

玩具完整串是提示 [10,11]、分隔符 [12]、回答 [20,21]、EOS [2]。输入为 [10,11,12,20,21],目标为 [11,12,20,21,2]。response-only目标应改成 [−100,−100,20,21,2];有效mask为 [0,0,1,1,1]。第三个输入位置是分隔符12,却负责预测首回答20,所以它必须计分。若按“输入是回答token”决定mask,就漏掉20,还可能在别处额外计一个错误位置。

设三个回答目标真实概率为0.5、0.25、0.5,总NLL为四倍log2,三项负log分别为log2、二倍log2、log2,总四倍log2,再除三个目标,得到约0.924196。直接把总串五格平均会得到较低的约0.554518,却只是把两个未评分提示位置放入分母,不是模型更好。EOS构成第三项,删掉它会改变终止学习。

第二个独立检查是枚举预测对:12预测20、20预测21、21预测2,恰好覆盖回答与结束;10预测11、11预测12只作提示,不评分。第一回答token和最后结束token都在台账中。若对批次右填充,目标负一百完全不查词表;有效计数由mask或长度给出,不能根据输入编号猜测。这些原则可以直接迁移到decoder训练,但有限四候选项目每条示范只有一次完整响应决策,不含伪造的token掩码接口。

经验分布、重复与权重

本项目同一x的示范有两条正确简短、一条正确冗长。若忽略参数共享,把该x的自由分布记为q,对应经验频率为2/3与1/3。平均交叉熵为 −(2/3)log⁡qbrief−(1/3)log⁡qverbose-(2/3)\log q_{brief}-(1/3)\log q_{verbose}。用约束q简短加q冗长等于一求极小:导数为负的三分之二除q简短,加三分之一除一减q简短,令零解得q简短2/3。这个最优只在排除错误类别或允许其概率趋零的理想边界成立,有限softmax训练只能接近。

这个例子解释为何示范不等于偏好。把正确简短推到0.99会让那一条正确冗长示范的负log很大,SFT可能反对进一步简化;偏好数据则明确要求简短胜过冗长。课程把两种目标分别保留,不把“后训练效果”压成同一个loss。若真实示范含互相矛盾的答案,SFT会拟合这种经验混合,而不是自动知道哪条是真理。数据质量假设必须在损失之前说明。

多token回答还带来另一种权重选择。若两个回答长度分别一和九,把所有token总NLL除总长度,会使长回答总体权重更高;若先每回答平均再对回答平均,二者等权。也可以每回答取总NLL再平均,那又给长回答更大的典型梯度尺度。项目的四候选响应长度在统计上都是一个动作,因此按十八条示范平均。不能把它的权重结果直接套到长短文本SFT后声称已处理长度偏差。

梯度检查能证明什么

项目测试对八个参数逐一加减十万分之一,重算相同固定示范集合的损失,以中心差分验证解析梯度,最大误差要求小于亿分之一。还检查全部八参数从随机base到SFT确有变化。第一项定位推导或实现错,第二项定位梯度虽算出却未更新的问题。八参数全部变化不证明全局最优,也不保证任意数据都让每个参数每步非零;本任务对称时某些梯度可能精确抵消,必须区分合理零值与断链。

SFT使用全批梯度下降、固定学习率0.15、二百更新,无动量和随机抽样,因此继续训练只依赖当前参数与固定数据,不需要恢复Adam矩或数据游标。随机性只在初始八参数的小范围均匀初始化;保存的seed与初始参数可重建起点。本章不把这种轻量状态约定推广为真实大模型训练的完整checkpoint需求,后者还有优化器、调度器、随机源与分布式状态。

验证SFT应看同一留出上下文的完整概率,而不是只看argmax。一个模型可能每次greedy都正确,却给冗长回答大量概率;偏好阶段要调整的正是分布质量。反过来,某个靠近零的新上下文可能因为共享线性斜率而不够自信,即使远离零的训练点loss很低。按上下文打印四概率,能把总体均值里的这种差异找出来。本项目测试中的正负零点五就是一个预先固定的边界观察。

本章交付是SFT的目标、解析梯度、真实全参数更新与回答mask规则。下一章不再假设“标签给出唯一示范”,而是把同一提示下的winner/loser作为新的数据对象。reference必须在SFT结束时深复制并冻结,因为后面DPO的比率将以它为固定基准;若它随策略一起更新,本章得到的模仿分布就不再承担原定参照角色。

均值的分母还决定梯度尺度。两回答长度分别三和十二,若每个token的局部梯度方向相同,按回答总NLL平均会让长回答贡献四倍总幅度;按每回答token均值再平均则二者相近。若按全体十五个token平均,每个token等权,但每回答总权重仍一比四。三种目标都可以明确实施,不能把“避免长样本多占权重”当作未写出的默认。序列项目选择回答总和再平均,使DPO的完整回答事件定义与SFT台账可直接对应。

监督梯度在单个样本上对错误类别的正项并不等于“惩罚所有未示范回答永远错误”。同一提示下一条示范可能把另一个类别作为正确项,平均后得到经验频率平衡。若把所有未示范响应都标成绝对坏回答,就引入比SFT更强的比较监督。本课通过三条示范的频率求解展示这一区别,偏好数据的winner/loser关系在下一章另行提供。

序列SFT沿真实过去回答训练,因此可以在生成时自己的错误前缀上失效。这一条件分布差异不是mask故障:正确mask仍只使用过去,但训练过去来自示范,生成过去来自策略。应保留自由生成及停止状态作为独立检查,不能把teacher-forcing每目标NLL很低直接翻译成整段回答一定正确。

独立运行标准库独立验证:八参数中心差分、一步损失下降与回答错位掩码。
import math
x=2.; label=1; lr=.1
W=[[0.,0.] for _ in range(4)]
def loss(w):
    z=[b+s*x for b,s in w];a=max(z)
    return a+math.log(sum(math.exp(v-a) for v in z))-z[label]
grad=[[.25-float(i==label),x*(.25-float(i==label))] for i in range(4)]
errors=[]
for i in range(4):
    for j in range(2):
        a=[r.copy() for r in W];b=[r.copy() for r in W];a[i][j]+=1e-5;b[i][j]-=1e-5
        errors.append(abs((loss(a)-loss(b))/2e-5-grad[i][j]))
assert max(errors)<1e-9
new=[[v-lr*g for v,g in zip(row,gr)] for row,gr in zip(W,grad)]
assert loss(new)<loss(W)
target=[11,12,20,21,2]; response_target=[-100,-100,20,21,2]
assert [v for v in response_target if v!=-100]==[20,21,2]
print('before',loss(W),'after',loss(new),'max gradient error',max(errors),'response targets',response_target)

TRY IT YOURSELF

练习一:首token掩码

提示[7]、分隔符[8]、回答[9]、EOS[2],写输入、目标和response-only目标。

提示 1
先写完整序列,再逐位置标明“该输入预测下一项”。
提示 2
首回答由分隔符位置预测;response-only mask根据目标是否属于回答/EOS,而非输入词元是否属回答。
对照参考解答
输入[7,8,9],原目标[8,9,2];response-only为[−100,9,2]。输入8负责预测首回答9,所以不能只对输入属于回答的位置计分。结束2由输入9预测,必须保留;一共有两个有效回答目标。

TRY IT YOURSELF

练习二:监督最优分布

同一提示有三条A、两条B示范,自由两类概率的最优分布是什么?写一阶条件。

提示 1
用q与1−q表示两类概率,并用示范频数作平均权重。
提示 2
对加权负对数似然求导,再检查边界与二阶导;别把示范频率当偏好胜率。
对照参考解答
令q为A概率,loss为 −(3/5)log⁡q−(2/5)log⁡(1−q)-(3/5)\log q-(2/5)\log(1-q)。导数为 −3/(5q)+2/(5(1−q))-3/(5q)+2/(5(1-q)),令零得到2q=3(1−q),所以q=3/5。二阶导为正,边界loss发散,因此为唯一内部极小。它是经验频率拟合,不是偏好胜率的估计。

TRY IT YOURSELF

练习三:验收全参数学习

解析梯度正确但参数没有变化,列两个可能原因与能区分它们的检查。

提示 1
区分求出正确梯度、执行update、将更新对象交给评估三步。
提示 2
先保存update前后数值,再核对评估对象身份;梯度一致不能排除更新副本或漏调用。
对照参考解答
可能没有执行update,或更新了一个副本而评估仍读旧对象。先保存参数值并检查一次update后的对象数值差,再检查训练返回对象是否就是评估传入对象。真实大模型还要检查optimizer参数组与requires_grad;本项目手写SGD直接修改八参数嵌套列表,避免把梯度检查单独当作训练闭环证明。

CHECK YOUR UNDERSTANDING

检验理解

先作答,再决定是否展开解析。选择题用于发现理解缺口;独立实现与迁移任务仍需另行检验。

1. 交叉熵对logit的梯度是什么?

查看解析归一化项给p,真实logit项减one-hot。
2. response-only是否删除提示输入?

查看解析掩码定义损失而非移除条件。
3. 两回答长度不同,平均token loss与平均每回答总NLL是否相同?

查看解析归一化对象不同会改变训练权重。
4. SFT结束后的reference应如何获得?

查看解析共享可变对象会让DPO参考随更新漂移。

自行标记用于记录学习进度,不代表通过项目验收。