AI Hero Club

推理模型与强化学习 · 第 6 章

已自行标记完成0 / 8

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

本章提纲 10 个小节
全课目录 8 章
完整课程计划 ↗
推理模型与强化学习 / 课程计划 ↗

CHAPTER 06 / 8建议学习 135 分钟

一次真实RL更新:采样、验证、留一优势与反传

一次采到的40条轨迹,怎样经过验证、留一优势与重评分成为一次全参数更新?

本章要解决的 3 个问题
  • 完整追踪40条二步轨迹如何进入一次参数更新
  • 把监督收益、RL收益、参考惩罚与优化器效应分开
  • 读懂稀疏奖励零梯度、裁剪及17张量更新的证据
课程项目 ZIP ↓

冻结实验之前先确定预算

训练计划在运行前固定:随机种子二十九,CPU单线程,四十步监督暖启动,一百步on-policy强化学习。模型配置与第五章一致,监督和RL都使用AdamW但权重衰减为零;监督学习率0.006,RL学习率0.0015,梯度范数裁剪上限一。RL每步选五道训练题,每题独立抽八条轨迹,因此每步四十条、一百步四千条训练轨迹,不计每阶段独立评价用的额外样本。不能把评价采样也算成训练证据或偷偷追加训练预算。

监督阶段使用全部二十训练题的正确两步响应,目标是平均完整响应负对数概率。四十步后复制为冻结参考,再保存策略作为RL前起点;这是同一个权重快照,不从不同候选挑选某些指标最好的拼成基线。当前实验没有多种训练种子,没有依据测试挑停止点,也没有做“多跑几次直到成功”的选择。所得结果是单条真实训练轨迹,统计泛化结论必须相应收窄。

监督目标与后续奖励目标不同

监督负对数似然直接把正确响应当标签,每次都有梯度;严格奖励只能告诉采到的完整轨迹是否通过,未采到正确路径时不直接给出正确数字。这两种训练信号不可混为一谈。若只报告随机初始化到最终的提升,会把监督学习获得的能力也算作RL收益;本项目明确分别报告监督后的before与RL后的after,测试也同时评价二者。

监督阶段给每道题的完整响应相同权重,每条都含两个随机动作,因而按响应求和再平均与按响应词元平均只差固定二倍系数。若以后允许不同长度,这个等价不再成立,按词元平均会改变长短响应权重。项目只有固定二步,仍在文档中明确目标单位,不让长度归一习惯悄悄换掉本课推导的完整轨迹目标。

LSFT=−1∣D∣∑x∈Dlog⁡pθ(y∗(x)∣x),L^RL=−1BG∑x,istopgrad⁡(Ai)log⁡pθ(yi∣x)L_{\mathrm{SFT}}=-\frac1{|D|}\sum_{x\in D}\log p_\theta(y^*(x)\mid x),\quad \widehat L_{\mathrm{RL}}=-\frac1{BG}\sum_{x,i}\operatorname{stopgrad}(A_i)\log p_\theta(y_i\mid x)
B=5题、G=8样本;两阶段目标与数据来源不同。

算例一:从一组奖励走到损失

假设某题八条样本中只有第一条成功,严格奖励为[1,0,0,0,0,0,0,0]。若当前策略恰等于参考,所有对数概率比零,正则回报就是这些奖励。留一基线给第一条零,其余七条各为1/7,所以优势为[1,−1/7,−1/7,−1/7,−1/7,−1/7,−1/7,−1/7]。损失是这八个优势各乘对应完整log概率后求平均,再取负号。

如果某条错误路径的log概率为−3,优势为−1/7,它对损失的数值贡献为−3/56,数值可以为负。损失为负不意味着程序错误,也不能直接把这个代理损失大小当作任务成功率。真正梯度来自优势乘log概率导数;优化器下降损失,倾向降低负优势路径概率、提高正优势路径概率,但共享参数可能带来其他路径的联动,单步不保证每条行为都按口头描述独立变化。

当当前策略已经偏离参考

若某路径当前比参考更常见,对数比为正,beta0.03乘这个值会从其奖励里扣除;较少见路径对数比为负,减去负数相当于增加回报。这是KL正则期望中的正确组成,不是给错误答案人工加奖励。由于留一中心化,组内比较同时反映正确性和参考偏离。beta只在明确的目标中有意义,不应该因为看见负回报就临时把它裁零,那会换成另一目标。

以一条正确路径对数比0.5、一条错误路径对数比−0.2为例,回报分别0.985和0.006。错误路径数值正,不代表验证器接受错误,只是正则鼓励恢复相对参考被压低的质量。报告把严格奖励和采样log比单独记录,使读者能分辨“训练更接近参考”与“解题更成功”。当beta过大,正则可能压过任务奖励;本实验固定0.03,未搜索一个所谓普适最优系数。

批内任务与随机流怎样组织

每步按固定循环从二十训练题中选连续五题,对每题扩展八次,形成按任务连续的四十行。sampler连续两次前向,各产生一位数字;之后用同一网络重新评分,参考在no_grad下评分。奖励和参考差构造回报,loo_advantages按八条reshape;这一批只反传一次,更新后立即丢弃轨迹。没有用高奖励样本筛选或复用数轮,所以本章实现符合on-policy估计器的采样条件。

固定任务循环每四步覆盖一次二十题,一百步覆盖二十五次;每题训练采样二百条。但采样结果依赖逐步变化的策略,不能把同题二百条当作来自一个固定成功率的IID样本来计算简单二项置信区间。评价阶段冻结策略后再独立采样,才符合固定参数下的重复试验解释。这是日志中的“采样成功率”与最终评价成功率的区别。

算例二:全零组什么时候应该不更新

训练刚开始,当前模型等于参考。若某一组奖励全零,对数比也全零,所有回报和优势都零,该组对梯度贡献零,这是预期行为。两步各十分类、共一百轨迹的空间稀疏奖励本来会遇到许多这种组。若一整批都如此且无额外正则,更新确实可能为零。tests.py 的两步烟雾训练检查完整流程和有限值,不要求每次短训练都改变全部参数;冻结的一百步真实运行才另外核实十七张量实际更新。

当策略已变、参考不变,即使严格奖励全零,各路径log比不同仍能产生正则信号。若实现每次更新前又把参考同步成当前策略,会消除这部分约束,测试参考摘要能抓到这个错误。相反,若所有奖励相同但程序仍因不清空旧梯度产生很大更新,也不是合理“持续学习”;必须确认梯度清零、回报detach和当前批图的边界。

从数学估计到实际优化还隔着几步

REINFORCE无偏结论针对未裁剪梯度在固定参数下的期望。项目先记录原始梯度范数,再按范数上限一进行裁剪,随后AdamW依据历史一二阶矩更新。裁剪与Adam都是实际算法的一部分,不再声称每个参数步等于无偏梯度乘固定学习率。记录这些设置是为了可复现,而不是把它们包装成某个严格收敛定理。

每次backward后逐张量检查梯度存在、全为有限数,再记录范数;出现NaN或缺失梯度立即失败,不把nan_to_num当作正常修复。优化完成后记录RL前后各张量最大绝对差;实际十七个张量都有正变化,最后一批也各有非零梯度。参考模型完整字节摘要前后相同,且没有梯度。这个证据支持“完整网络参数参与RL”,不支持“每个内部神经元都学到了算术算法”。

日志与检查点必须属于同一运行

train输出包含config、数据摘要、随机种子、步数、beta、采样数、分阶段history、before/after全题评价、每张量变化及参考摘要。checkpoint.pt同时保存最终策略与冻结参考,评价命令重新加载后重算精确成功概率和KL,测试确认与results.json一致。不能只把一个终端截图当结果,也不能把另一轮更好权重替换到旧报告旁边;清单中的摘要把源码、检查点和指标捆在一起。

读者修改学习率或步数时,建议通过--output创建新目录,让新实验与随包evidence并存。输出不同目录不是多此一举,因为重写原始证据后,就无法再证明讲义所引数值来自哪次运行。独立复跑可以出现环境舍入差异;应比较概率、梯度和任务结果,并标明是否逐位重放。下一章会读这次冻结运行的实际训练提升和测试明显下降,解释为什么一个实现通过所有测试的系统仍可能没有解决研究问题。

在课程项目目录运行可直接运行的检查
import torch
from run import loo_advantages
r=torch.tensor([1.,0.,0.,0.,0.,0.,0.,0.])
a=loo_advantages(r,8)
assert torch.allclose(a,torch.tensor([1.]+[-1/7]*7))
assert abs(float(a.sum()))<1e-6
print(a.tolist())
终端命令在新目录完整重跑;固定40步监督与100步RL
python run.py train --output my-run
python run.py evaluate --output my-run --split test

独立实验:整棵轨迹树的梯度走完17个张量

本课只有100条允许轨迹,所以可以在同一个模型、同一道题上把期望完全枚举,比较第四章的两条求导路线。新增gradient_audit.py从seed919创建随机float64模型和冻结reference,然后仅给当前head一个坐标加0.1,使KL项不是全零退化例;这次人为扰动用于检验公式,不是优化器更新,也不使用历史训练权重。

J=∑ypθ(y)Fθ(y),Fθ(y)=R(y)−βlog⁡pθ(y)q(y),S=∑ystopgrad⁡(pθ(y)Fθ(y))log⁡pθ(y).J=\sum_y p_\theta(y)F_\theta(y),\quad F_\theta(y)=R(y)-\beta\log\frac{p_\theta(y)}{q(y)},\qquad S=\sum_y\operatorname{stopgrad}(p_\theta(y)F_\theta(y))\log p_\theta(y).
beta=0.2,固定题(2,2)。直接对J求导,与只保留score路径的S求导,应在这个参数点相等;J和S的标量值本来不要求相等。

脚本对17张量的每个坐标比较∇J与∇S,而不再只查head。所有坐标最大差为5.204170×10⁻¹⁷,小于预定10⁻¹²门槛;100路径的概率和也在该门槛内等于一。下表第二列为直接梯度的整张量L2范数,第三列为两路线最大逐坐标绝对差。范数不用于判断哪一层更重要,仅用于避免梯度全零而虚假通过。

参数张量直接梯度范数两路线最大误差
token_embedding.weight5.204599e-022.776e-17
position_embedding.weight5.293632e-023.383e-17
blocks.0.ln_attention.weight2.022516e-042.711e-19
blocks.0.ln_attention.bias3.909932e-048.945e-19
blocks.0.attention.query.weight4.406804e-051.186e-20
blocks.0.attention.key.weight4.168311e-052.795e-20
blocks.0.attention.value.weight8.320259e-035.204e-18
blocks.0.attention.output.weight8.771058e-033.578e-18
blocks.0.ln_feedforward.weight3.317937e-041.355e-19
blocks.0.ln_feedforward.bias2.445171e-041.423e-19
blocks.0.feedforward.0.weight1.228797e-024.770e-18
blocks.0.feedforward.0.bias3.367637e-031.030e-18
blocks.0.feedforward.2.weight1.336448e-024.987e-18
blocks.0.feedforward.2.bias5.428007e-022.342e-17
final_norm.weight1.220381e-035.313e-18
final_norm.bias1.404165e-037.589e-19
head.weight5.522263e-025.204e-17
真实随机模型上的整张量核验;未重训,未替换原40步SFT+100步RL结果。

阴性对照故意删除概率权重和回报上的stopgrad,再对“pF乘logp”求导。它与真正∇J的最大差为0.1358048393,检查器明确拒绝;这说明本例不是任意写一条代理都能通过。直接路线和score路线共享path_logps,因此二者一致仍不能单独证明路径索引正确;前面独立的两次前向评分、语法支持和概率和检查继续保留。

在课程项目目录运行重新枚举100路径并核验全部17张量,同时拒绝错误代理。
from gradient_audit import audit
r = audit()
assert len(r['tensors']) == 17
assert r['negative_control']['status'] == 'REJECTED'
assert r['model_unchanged'] and not r['training_performed']
print(r['max_absolute_error'], r['negative_control']['max_absolute_gradient_error'])
终端命令在本课项目根目录保存新收据;输出到runs,不覆盖原evidence。
.venv/bin/python gradient_audit.py --output runs/gradient-audit.json

这里证明的是这个有限生成树、这个参数点上两种实现的一致性;期望恒等式的一般理由仍是score均值为零的推导。它不意味着随机小批梯度与精确梯度逐次相同,也不意味着裁剪后的Adam增量无偏。脚本不执行optimizer,不读冻结checkpoint,结束时核对被检验的模型参数没有变化。

TRY IT YOURSELF

练习一:预算逐项计数

每步5题、每题8条、100步,每题被均匀轮转25次,共多少训练轨迹?

提示 1
把每步题数、每题采样数、更新步数分开相乘。
提示 2
用每题轮转次数交叉复算,再把每条两随机数字与额外评价采样另列,不把EOS算随机训练动作。
对照参考解答
总数5×8×100=4000。每题25次×8=200条,20题合计4000。每条两随机动作,所以8000个采样数字;EOS不随机。before/after评价的采样不计入训练4000,但消耗额外推理预算,报告应分列。

TRY IT YOURSELF

练习二:正则回报

beta0.03,正确路径log比0.5、错误路径log比−0.2,回报各是多少?

提示 1
严格正确奖励与加入KL后的训练回报分别列两列。
提示 2
对两条路径代入r−beta log比;负log比可以带来正正则贡献,但不会改变验证器标签。
对照参考解答
正确1−0.03×0.5=0.985,错误0−0.03×(−0.2)=0.006。错误仍有严格奖励零;正回报来自KL项,不等于验证通过。不得用回报正负代替解题成功标签。

TRY IT YOURSELF

练习三:短烟雾训练没有更新

随机初始策略等于参考,整批全零奖励,为什么不应在测试中硬要求每张量变化?

提示 1
策略等于reference时先算每条log比,再算零奖励下的留一优势。
提示 2
沿优势到loss梯度的链检查是否本应零;无信号烟雾例与真实有信号运行采用不同验收要求。
对照参考解答
此时每条log比零,回报零、留一优势零、score损失梯度零,理论上就没有更新信号。烟雾测试应查流程、形状和有限值。真实完整运行另查实际梯度与参数变化,不能为了通过测试伪造奖励或引入隐藏权重衰减。

循环抽题时,哪一个目标的梯度无偏?

固定输入的留一无偏不等于每步对全部题目的均匀目标无偏。记 J_x(θ) 为一道题在当前策略下的正则目标,全部训练题的目标 J(θ)=Σ_x J_x(θ)/20。本项目第 k 步确定性取当前五题 B_k,轨迹随机性只保证未裁剪估计器的条件期望等于 ∇J_Bk(θ_k),其中 J_Bk=Σ_(x∈Bk) J_x/5。它一般不等于 ∇J(θ_k)。 最短反例:两题目标 J₁(θ)=θ、J₂(θ)=−θ,全体均匀目标梯度为零;固定抽第一题,估计梯度均值仍是一。轮到第二题后参数已改变,四步走遍二十题也不是在同一参数点做平均。只有冻结同一个 θ 后等权累计四批,才精确回到总体梯度;若每步独立均匀抽题,才可对全体目标逐步无偏。 这不把现有循环训练变成 off-policy:每条轨迹仍由更新前的当前策略采出,满足本章 on-policy 的含义。实际优化还包含梯度裁剪和 AdamW,参数增量本就不能直接当作原始无偏梯度。这里保留循环实现与旧实验结果,只把各层结论的范围写清。

CHECK YOUR UNDERSTANDING

检验理解

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

1. RL提升从哪个起点比较?

查看解析这样把SFT收益和后续RL收益区分开。
2. 一批轨迹更新几次?

查看解析本项目明确on-policy一批一更新,无旧数据多轮复用。
3. 未裁剪梯度无偏是否意味着Adam参数步无偏?

查看解析估计器结论不能直接传给非线性参数更新。
4. 负代理损失说明什么?

查看解析损失是用于求梯度的代理,不能当作准确率或完整正则目标数值。

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