wikiLLM07.1|OPD:从学生轨迹到语音 LLM 的学习路线07.1.7|OPD 的工程实现:轨迹、对齐、缓存与评测
26 分钟
2 次观看

07.1.7|OPD 的工程实现:轨迹、对齐、缓存与评测

返回 OPD 专题导读 · 前置:分布、目标与梯度 · 方法比较:MiniLLM 与 GKD

训练能正常反传,仍可能在学习错误的位置。例如把回答的第一个 token 与第二个 token 的教师分布比较,损失可以下降;把补齐用的 PAD 当成终止符,模型也可能越来越喜欢提前结束。OPD 的工程核心,是把“学生在自己经过的位置接受反馈”落实为版本明确、前缀一致、位置对齐的一批张量。

本篇沿一批数据走完生成、评分、损失、缓存和评测。论文事实依据 GKD §3.1、MiniLLM §2 和 X-OPD §3—4;为连接这些事实而提出的张量接口、诊断顺序和评测设计,均为本站工程建议。代码是教学伪代码;实际执行的只有第三、四章的有限枚举验算,没有运行训练框架或复现模型基准。

1. 一批轨迹的版本与身份

一次训练批次从参数快照到生成、评分、更新的时间线

图 1|生成版本、评分参数与更新顺序(教学示意)

图中蓝色的 θk\theta_k 先产生回答,右侧绿色的 θk+1\theta_{k+1} 是更新后的参数。两者之间的 token IDs 是固定数据;它们来自哪个参数版本,不会随优化器调用自动改变。GKD 对学生采样分布停止反传,仍对学生在已抽到前缀上的评分求梯度。因而,在实现中把生成放进 no_grad,只解决了采样不保留计算图这一部分;不能把随后的学生评分也包进同一段 no_grad。来源:GKD §3.1、Algorithm 1。

一个可排查的教学批次至少保留 prompt_id、rollout_policy_version、生成的 token IDs、真实回答长度和终止原因。涉及概率比时,再保留算法所需的旧策略对数概率及其定义。保存解码后的字符串仍不充分:重新编码可能改变空格、特殊 token 或聊天模板,评分就不再对应原来的离散轨迹。

图中从更新参数往左看的红箭头,也说明“新旧”必须落到具体对象。复用旧轨迹、复用旧概率和复用旧 KV 缓存是三件事。旧轨迹可以作为明确的离线数据;能否在所选 OPD 更新中多次复用、需要什么校正,应由目标决定。GKD 没有因此自动变成带概率比的算法;MiniLLM 的 teacher-mixed sampling 则显式改变行为分布,并讨论了精确重要性权重的高方差与实际近似。不能往所有 rollout 训练里加同一个 ratio,就称作通用修复。来源:MiniLLM §2.2。

还有一个容易藏在配置里的身份变化:温度、top-k、top-p 等采样变换会改变行为分布。若某目标使用 πθ/πold\pi_\theta/\pi_{\mathrm{old}},分子分母必须使用该目标约定的相同条件和分布定义;原始 softmax 概率与截断后采样概率不能只因数组长度相同就混用。这里是工程约束分析,不能据此推断 X-OPD 官方代码采用了哪一种具体概率实现。

2. 同一前缀的两路评分

学生产生一条离散序列,两路评分读取同一前缀,独立教师答案被排除

图 2|复制的是学生轨迹,教师重新评分(原创教学图)

图中红圆和黄三角是已经生成的历史,绿色方块是当前候选 token。蓝色学生评分与紫色教师评分都站在这同一个位置。右下角另写的答案从第二格开始不同,即使两条回答长度相等,第 tt 格也不再代表相同历史。OPD 所需的是教师读取学生的前缀;不必让教师重新生成一份答案再逐格相减。

在固定输出位置 tt,用 ht=y<th_t=y_{<t} 表示学生已经生成的历史,用 vv 表示共同输出词表中的候选 token。文本场景中两路可以同读输入 xx;X-OPD 则让语音学生读音频 SS、文本教师读语义对应的文字 TT:

qt(v)=pT(v∣T,ht),pt(v)=pS(v∣S,ht).q_t(v)=p_T(v\mid T,h_t),\qquad p_t(v)=p_S(v\mid S,h_t).

qt,ptq_t,p_t 均为长度 VV 的概率向量,VV 为输出词表大小;它们的输入模态可以不同,输出坐标必须有对应关系。X-OPD 的共同比较空间是文本输出,不是音频帧或音频码本。来源:X-OPD §3.1—3.3。

把这个条件落实到接口,可以要求评分模块返回 [B,L,V]:BB 为回答条数,LL 为对齐后的回答位置数。教师 prompt 比学生多几个 token,或者音频输入展开成另一种长度,都不意味着可以直接取两个原始 logits 张量的同一行。应分别按各自 prompt 长度,提取“预测第 tt 个回答 token”的行,再组成共同的回答位置轴。

词表也有同样的问题。教师的 token ID 42 可能与学生的 ID 42 对应不同字符串;即使两者都能解码出同一完整答案,也不代表逐 token 的分解相同。跨 tokenizer 的两个概率数组不能直接按下标计算 KL。 本篇伪代码限定共同输出 tokenizer 与词表坐标。跨词表蒸馏需要额外的对齐方法,不能只用 padding 把两条向量补到同长。

3. 回答位置、EOS 与归一化

3.1 当前输入行预测下一格

输入 token、下一 token 预测、loss mask 和 attention mask 的精确索引

图 3|预测 a 的 logits 位于最后一个 prompt token 那一行

沿图 3 从上往下读。输入为 [x₀,x₁,a,b,EOS,PAD,PAD],前两格是 prompt。第 1 行索引处已经看完 x₀,x₁,它的 logits 预测 a;下一行预测 b,再下一行预测 EOS。若对 logits 做 [:, :-1],目标做 [:, 1:],监督回答的 mask 就是 [0,1,1,1,0,0]。

最下面的 attention mask 是 [1,1,1,1,1,0,0]。它决定哪些输入格属于有效上下文,不能直接拿来当回答损失 mask。两者混用,会把 prompt 的预测也纳入目标,或者错过最后一个 prompt token 对第一个回答 token 的预测。

EOS 还要按终止元数据判断。若真实生成到 EOS,这个终止决策可以是有效回答目标;若达到最大生成长度后被截断,不应凭空增加一个“模型选择了 EOS”的监督位置。如果 tokenizer 共用 EOS 与 PAD 的 ID,仅以 token_id != pad_id 构造 mask 会误删真实 EOS。图中用不同名称区分两种角色,实际代码应保留真实长度,而不只比较整数 ID。

给这六个预测位置设置教学损失 [9,0.1,0.2,0.6,8,7],有效三格的均值为:

0×9+1×0.1+1×0.2+1×0.6+0×8+0×73=0.3.\frac{0\times9+1\times0.1+1\times0.2+1\times0.6+0\times8+0\times7}{3}=0.3.

把 prompt 与 padding 上的大数故意放大,可以快速检查它们是否泄入平均值。不过,实际 logits 若产生 NaN 或无穷值,事后乘零并不可靠,因为 0×NaN0\times\mathrm{NaN} 仍是 NaN;应先确保评分行有效,并在正确的位置选择和归约。

3.2 平均的单位也是目标的一部分

先将每条不同长度的回答内部平均,再等权平均回答

图 4|回答内部平均与回答之间平均(原创教学图)

图 3 中三个绿色位置先合成一条回答的损失。对变长 batch,下一步可以等权平均回答,也可以把所有有效 token 一起平均,两者给长回答的权重不同。GKD 的序列差异先按长度平均;X-OPD §3.4 也保留先轨迹内平均、再轨迹间平均的结构。GKD Eq. (2),X-OPD §3.4。

用两条教学回答检查:A 的有效损失为 [0.1,0.3],B 为 [0.9]。等回答平均得到 ((0.1+0.3)/2+0.9)/2=0.55((0.1+0.3)/2+0.9)/2=0.55;合并 token 后为 (0.1+0.3+0.9)/3=0.433333(0.1+0.3+0.9)/3=0.433333。它们都可以计算,但已经在优化不同的加权目标。有关两层平均的视觉推导,可接着读 X-OPD 的轨迹归一化。

4. 完整词表与采样信号

4.1 一个负的采样值不等于负的 KL

完整三 token 分布与单个采样对数比的数值对照

图 5|同一前缀下,完整分布与采样值是不同对象

图 5 左侧教师概率为 q=[0.6,0.3,0.1]q=[0.6,0.3,0.1],学生为 p=[0.3,0.3,0.4]p=[0.3,0.3,0.4],三个位置对应 token a,b,ca,b,c。两组概率均严格为正,以下使用自然对数;数值没有物理单位。前向与反向 KL 分别为:

DFKL=∑vqvlog⁡qvpv=0.6log⁡2+0.3log⁡1+0.1log⁡14=0.415888+0−0.138629=0.277259,\begin{aligned} D_{\mathrm{FKL}}&=\sum_v q_v\log\frac{q_v}{p_v}\\ &=0.6\log2+0.3\log1+0.1\log\frac14\\ &=0.415888+0-0.138629=0.277259, \end{aligned} DRKL=∑vpvlog⁡pvqv=0.3log⁡12+0.3log⁡1+0.4log⁡4=−0.207944+0+0.554518=0.346574.\begin{aligned} D_{\mathrm{RKL}}&=\sum_v p_v\log\frac{p_v}{q_v}\\ &=0.3\log\frac12+0.3\log1+0.4\log4\\ &=-0.207944+0+0.554518=0.346574. \end{aligned}

两者都非负,但某个 token 的对数比可以是负数。学生这次若采到 aa,观测到 log⁡(pa/qa)=−0.693147\log(p_a/q_a)=-0.693147。这个值是一份采样信号,不是该前缀上完整词表求和得到的 KL。 在固定前缀下,按 pp 对全部可能采样求期望,才得到上面的反向 KL 数值;不能把一次采样值与完整 KL 的非负性作直接比较。

4.2 数值估计相同,不代表直接反传相同

图 5 右侧三个箭头也可以用来检查梯度。令学生由 logits zz 经 softmax 得到,教师固定;对完整反向 KL,有:

∂DRKL∂zj=pj(log⁡pjqj−DRKL).\frac{\partial D_{\mathrm{RKL}}}{\partial z_j} =p_j\left(\log\frac{p_j}{q_j}-D_{\mathrm{RKL}}\right).

jj 遍历三个候选 token;zjz_j 是第 jj 个无单位 logit。代入后,梯度为 [−0.311916,−0.103972,0.415888][-0.311916,-0.103972,0.415888],三项之和为零。若只把抽到 token 的 logp-logq 直接当可微损失,求得的是另一个梯度;固定前缀下,未加系数的 ∇log⁡p(y)\nabla\log p(y) 按 y∼py\sim p 的期望甚至为零。

在这个固定前缀、固定教师的教学问题里,一种匹配完整反向 KL 梯度的采样估计器是:

g^(y)=stopgrad⁡ ⁣(log⁡p(y)q(y))∇zlog⁡p(y),y∼p.\widehat g(y)= \operatorname{stopgrad}\!\left(\log\frac{p(y)}{q(y)}\right) \nabla_z\log p(y),\qquad y\sim p.

stopgrad 使括号内的对数比只作为系数,不再从那里额外反传。对 a,b,ca,b,c 的三种可能分别算梯度,再按 0.3,0.3,0.40.3,0.3,0.4 加权,可回到上面的完整梯度。这只是单个固定前缀的等价性;序列中前缀本身的分布还会随策略改变。MiniLLM 的序列反向 KL 推导包含未来回报和方差控制,不能以这里的单步公式代替。来源:MiniLLM §2.1—2.2、Eq. (1)—(4)。

教学验算使用 Python 3.12.14 枚举三种 token,并以步长 10−610^{-6} 做中心差分,解析梯度与差分的最大绝对误差为 1.28×10−101.28\times10^{-10};采样估计器的枚举期望也相符。该检查验证上面的教学计算,不证明任何训练系统的实现正确。

kxzxvbk 的中文解读从采样 token 的 reverse-KL 写法走向完整词表,是理解图 5 的另一条入口。实际看实现时要分三层:这次抽到的 log-prob 差、按采样分布取期望的数值目标、以及由自动微分或策略梯度估计得到的更新。第二层数值表达相同,不说明第三层可以随意把采样值直接反传。上面的停止梯度系数和三候选枚举,正是检查这一点。

中文介绍偶尔把该差值口语称作“logit 距离”。此处比较的是同一条件下归一化概率的对数;原始 logits、log-probability 与完整词表 KL 应在接口中明确区分。文章同时提到 tokenizer 难点:自蒸馏通常容易满足共同词表,却仍需处理额外教师 prompt、学生原轨迹与回答位置偏移,不能省掉图 2、图 3 的对齐检查。

材料中的简写本篇对应对象实现时补什么条件
token 级蒸馏信号图 5 的采样值或完整词表分布明确支持集、期望和梯度估计器
教师给出更好答案原前缀评分,或独立教师生成先确定是哪条流程;不能只按两条回答的序号相减
自蒸馏解决词表问题同模型往往共用输出坐标仍核对 prompt 长度、mask、模型版本和教师额外条件

4.3 一段职责明确的教学主干

GKD Algorithm 1 中数据分支汇合到学生梯度更新的原始算法

来源:GKD Algorithm 1(截图裁切,CC BY 4.0)

原算法把“取得本批数据”与“计算差异梯度”分成两个阶段;图 2 确定两阶段的数据流,图 3 确定回答位置,图 5 确定完整词表损失。把三者连接起来,可得到下面的 GKD 风格固定轨迹、完整词表前向 KL 教学伪代码。它没有实现原图的数据混合分支、MiniLLM 的序列策略梯度或 X-OPD 的双路代理目标,不能直接作为这些论文的复现代码。

python21 行
# common output tokenizer; response axis is already position-aligned
with no_grad():
    rollout = sample(snapshot(student), prompts, generation_config)
batch = pack(prompts, rollout.token_ids, rollout.true_lengths)

# Return aligned [B, L, V] log-probabilities, not raw input-row logits.
with no_grad():
    logq = score_response(teacher, batch.teacher_inputs, logprob_dtype="float32")
logp = score_response(student, batch.student_inputs, logprob_dtype="float32")

mask = batch.response_loss_mask       # [B, L], including real EOS
assert every_sequence_has_target(mask)
assert same_output_coordinates(logq, logp)
assert finite_on_valid_positions(logq, logp, mask)

per_token = (exp(logq) * (logq - logp)).sum(axis=-1)
per_sequence = masked_sum(per_token, mask) / mask.sum(axis=-1)
loss = per_sequence.mean()
optimizer.zero_grad()
loss.backward()                      # teacher detached; student score differentiable
optimizer.step()

score_response 要负责模型各自的 prompt 偏移与下一 token 错位;logprob_dtype 指定计算 log-softmax 时的精度,不能先在低精度下 softmax、取对数后再转 float32,就视为等价;masked_sum 表示选择有效项后求和,不能依赖零乘 NaN。这些辅助步骤都属于主计算。首个诊断样本宜只有一个 prompt 和一条短回答,逐行打印 (response_index, target_token_id, student_row, teacher_row, mask),人工确认后再扩大 batch。教师 eval 模式与教师停止梯度也各有职责:前者通常关闭 dropout 等训练行为,后者切断自动微分;二者不能互相替代。比较固定输入下的 logits 时,应先让相关随机行为、精度和评分配置一致。

5. 语音与文本配对的语义边界

同一语音中丢失否定词导致文本指令相反的教学反例

图 6|少一个否定词,两路输入可能要求相反的动作

图中音频说“不要关灯”,上方文本保留否定词,下方转写丢掉“不”。灯的亮暗只是两种指令含义的示意,没有展示模型执行动作或实验结果。若把下方文本交给教师,它更偏向“关灯”相关输出,分数差就不再只表示学生的语音理解能力弱,也包含教师正在回答另一个问题。

X-OPD 实验使用口语化文本、TTS 合成语音与 ASR 回转写过滤,丢弃 WER 大于 5% 的样本。这个阈值是论文的数据流程,不能自动变成全部真实录音任务的通用标准。整体错误率较低时,一个否定词、数量、实体或单位仍可能改变答案。来源:X-OPD §4.1。

本站建议为配对样本保留原始问题、口语改写、音频来源、回转写文本、过滤原因及同源分组 ID。遇到跨模态分数差突然变大,先抽查这些字段是否指向同一语义。文本题“把 15 改成 50”被合成成另一个数字,或者问句在截音后失去条件,都可能让优化器忠实地学习错误的对应关系。这里需要修数据身份,而不是先增大 KL 权重。

音频输入的 padding 长度、采样率与实际有效帧,也应来自预处理约定。X-OPD 报告的 24 kHz 合成条件不能说明任意模型可直接接收 24 kHz 波形。训练前将一条样本的音频时长、重采样结果、有效帧数与对应文本一起读出,比只检查文本端 batch shape 更容易发现截断或单位错误。更完整的模态路径与实验边界见 X-OPD:语音 LLM 的跨模态能力对齐。

上下文与经验内化的共同模板还提醒防止特权信息泄漏。对本篇的批次而言,额外材料应有明确身份:学生生成时用什么、教师重评时多读什么、评测时又移除了什么。若把参考答案同时塞入学生 rollout,训练访问的条件已经改变;随后去掉材料,不能再只凭“同一个模型”认为差异自动消失。SDFT 所观察的引用“上文”风格残留,就是需要另外检查的现象之一。

6. 缓存、显存与计时边界

固定教师与更新学生的两种缓存身份关系

图 7|缓存对应模型、条件、位置与前缀的共同身份

图 7 上方教师权重固定,同一输入前缀的 KV 才具备复用前提;仍需保证 attention mask、位置编码、模态条件和精度等配置相符。下方学生已经更新,旧 KV 是用 θk\theta_k 计算的,不能仅因为 token 字符串相同,就当作 θk+1\theta_{k+1} 的缓存。对有模态条件的模型,两个不同录音共享一份转写,也不能据此共享全部音频条件缓存。

这是缓存正确性的工程推论,不是对某个框架性能的测量。相同固定输入下,先分别跑“全量评分”和“缓存评分”,比较有效位置的 logits 或 log-probability;报告绝对误差、容差、精度和缓存边界。两次独立随机生成的文本相似,无法证明缓存等价;文本不同,也可能只是采样随机性。

完整词表监督的存储量可以先做量纲检查。一个 [B,L,V] 的 float32 张量需 4BLV4BLV 字节。取教学配置 B=4,L=512,V=128000B=4,L=512,V=128000,单个张量为 1,048,576,0001{,}048{,}576{,}000 字节,约 0.9770.977 GiB;这还不包含另一侧 logits、激活、梯度和优化器状态。分块计算词表求和、按回答长度分桶等是可研究的工程方案;只保留 teacher top-k 则会改变可获得的分布信息,不能默认与完整 KL 精确等价。

计时也要沿图 1 分开:rollout、自回归生成之外的教师评分、学生前向反向、优化器与数据传输,分别记录后再报端到端训练步耗时。若生成后的一整条学生轨迹已经确定,教师可以按因果 mask 对它做并行的 teacher-forced 评分;这减少了再生成答案的需要,并不消除教师前向计算或完整词表输出的成本。

语音服务还存在另一条计时路径:音频接收与预处理、首个文本 token、完整回答,以及若有语音输出时的声学生成。训练更快、教师打分更少、文本质量更好,均不能直接推出用户听到回答更早。本文没有测量这些延迟;比较速度时应固定硬件、batch、长度、精度、预热和计时起止点。

7. 独立评测与故障定位

同源文本、合成语音与噪声变体按组切分以避免跨集合泄露

图 8|先定义独立样本,再切训练与测试

图 8 左侧的问题在于,同一个问题的文字版进入训练,合成语音版进入测试;模型可能已经记住答案。右侧把一个来源的全部视图放在同一侧。具体按原始问题、说话人、录音会话还是数据来源分组,取决于要验证的问题:要验证没见过的说话人,就不能只按问题文本分组。这是建议的评测设计,不能写成 X-OPD 论文已经完成的全部对照。

对语音输入、文本输出的 OPD,建议在同一组独立问题上分别测语音输入表现和文本输入表现,保留各自原始指标,再看二者差距。文本能力下降、语音能力上升,与两路一起上升,是不同结果。合成干净语音、真实录音、噪声与口音也应按条件报告;不将一个条件下的结果直接外推到全部场景。

故障定位可以从最靠近数据的证据向目标推进:

观察到的现象先比较的具体对象这一步能排查什么
loss 在下降,回答却爱提前结束真实 EOS、PAD 的长度与 mask;生成终止原因错把补齐位置当成终止监督,或遗漏真实 EOS。
更新前 ratio 已明显偏离 1同一 token 的旧、新 log-probability 定义;采样配置与模型版本版本、温度、截断或条件混用;若评分随机,先固定随机行为。
batch size 改变后目标数值异常同一批固定样本的逐序列损失与有效 token 数sum/mean 位置改变,或长回答获得额外权重。
只有语音侧异常图 6 的原音频、改写、回转写、时长与文本教师输入错配、截音、否定词或数字改变;不能只根据该现象断定音频塔损坏。
单 token “KL” 为负图 5 的完整词表 KL 与采样 log-ratio 分别输出记录项命名混淆;负采样值本身不证明实现错误。
缓存版与全量版的固定输入评分不同图 7 中权重、位置、mask 与模态条件身份缓存失效或评分配置不一致。

每个修复先回到一条固定短轨迹,再扩大到变长 batch 和独立评测。有限枚举检查能证明某个公式或归约写对了;小样本 loss 能下降,只能说明系统可以拟合这些样本。能力、泛化和用户延迟仍分别需要对应测量。

本文的三条论文来源分别是 GKD v3(2024-01-17)、MiniLLM v6(2026-01-31) 与 X-OPD v3(2026-06-12)。本文采用上述论文的方法与指定实验范围,未验证官方框架实现。继续阅读 MiniLLM 的序列目标与未来回报,可以看到为何单步数值一致仍不足以确定整套训练算法;返回 专题导读 可按目标选择后续分支。

正在连接 GitHub 评论…