English interface selected · this article is currently written in Chinese.
哪些 token 应该计算损失:回答监督、多轮对话与标签边界
English overview →具备清晰骨架、初步数学推导或工程验证,持续补充论据与实测。
数字花园
🌿 什么是数字花园与思想演进?
遵循 Maggie Appleton 与 Andy Matuschak 的常青笔记理念:这里不是按时间沉底的流水账,而是持续修剪打磨的知识生态。文章按成熟度经历:
- 🌱 萌芽 (Seedling): 发散灵感、读书摘录、开放猜想
- 🌿 演进 (Budding): 结构渐明、初步代码推导、积极修正
- 🌳 常青 (Evergreen): 逻辑闭环、持久经得起检验的基石
- 🔬 实验待证 (Speculative): 结合沙盒与仿真探针的理论探索
一条训练序列里有任务规则、用户材料和示范回答。它们都需要参与计算,但不一定都应该作为模型要模仿的输出。
例如,我们希望模型读取一篇很长的实验记录,再输出短 JSON。如果每个位置都算损失,训练会同时要求它预测那篇实验记录本身。这样做不是程序错误,却改变了监督信号的分配。
loss mask 决定哪些目标参与损失。它不负责决定模型能看见哪些输入。 这一区别在第二卷出现过,现在放到 SFT 样本里逐项检查。
本篇继续使用消息与模板的约定,先讲清一个回答,再扩展到多轮与变长样本。
三种常见选择在教不同的东西
先不管框架参数名,直接描述目标:
| 监督范围 | 哪些内容被要求预测 | 需要注意什么 |
|---|---|---|
| 全序列 | 提示、材料、回答及选定控制标记 | 大量输入文字也会贡献损失 |
| 所有 assistant 回答 | 每轮选定的助手输出 | 历史错误回答可能也被模仿 |
| 仅最后一次回答 | 最后一轮选定输出 | 前面回答只作上下文,监督数量较少 |
还有“只训练 completion”这种说法。它描述的是 prompt 与 completion 的分段,不总等价于“所有 assistant 消息”。如果 completion 中包含多个角色,或历史助手回复属于 prompt,两种规则选择的位置就可能不同。
因此,先定义想训练的内容,再把定义映射到训练器参数。不要看到一个开关名称就跳过实际标签检查。
用八个位置看清首个回答 token
下面是自定义的极简 token 序列。为便于逐项检查,假设每个方括号项目都恰好对应一个 token;这不是实际分词器输出。
0 [BOS]1 [USER]2 [材料]3 [END]4 [ASSISTANT]5 [答案甲]6 [答案乙]7 [END]我们希望只学习答案甲、答案乙,以及结束回答的 END,不学习角色头。完整序列标签可以写成:
输入: BOS USER 材料 END ASSISTANT 答案甲 答案乙 END标签: -100 -100 -100 -100 -100 答案甲 答案乙 END这里继续采用“模型内部错位一次”的接口约定。实际计分配对是:
| 输出所在位置 | 该位置已经看到的末尾 | 它预测的目标 |
|---|---|---|
| 4 | ASSISTANT | 答案甲 |
| 5 | 答案甲 | 答案乙 |
| 6 | 答案乙 | END |
关键是:标签位置 5 保留答案甲,会让位置 4 的输出学习预测它。 不能因为位置 4 是角色头,就把位置 4 的输出也一概排除,否则首个回答 token 可能丢失监督。
类似地,最后一个输入 END 所在位置没有后续目标,但 END 本身仍可作为前一个位置要预测的标签。这是两种不同的“最后一个”。
若实现已经在外部切出输入和目标,就应该把上述标签同时转换成外部错位形式。不能在原始序列上标好范围后,又按输出位置误移一遍。
不计提示损失,模型仍然可以利用提示
把用户材料的标签设为忽略值,不会删掉对应的输入向量。回答位置仍然可以通过因果注意力读取材料。
而且,回答损失的反向传播仍可能经过提示位置的表示及相关参数。因此,“提示不算 loss”不等于“提示没有参与学习”,更不等于“提示对应的嵌入绝不会收到梯度”。
需要区分三件事:
- 输入存在:文字是否送入模型。
- 注意力可见:当前输出能否读取它。
- 目标计分:是否直接要求模型预测这一位置的 token。
只监督回答通常保留前两项,选择性保留第三项。用 attention mask 把整个提示挡住,不能达到相同效果;那会让提取任务失去依据。
多轮里,错误历史能否保留
假设第一轮助手错误地把未记录步数填成 10000,用户随后指出“材料没写步数,不要猜”,最后助手修正成 null。
若目的是训练纠错,可以把错误历史作为可见背景,但只监督正确的最终回答。这样不会直接要求模型再次生成那段错误回答。
若采用“所有 assistant 消息都计分”的规则,错误的历史回复也会进入模仿目标。这可能与当前训练意图冲突。
同样,如果历史回答本来就是正确示范,监督全部回答可以提供更多有效目标。但若把每一轮都拆成一个训练样本,再在完整对话里重复监督,会让早期回复被重复计数。
没有一种规则自动适合所有对话。应为样本标注角色和轮次来源,明确哪些回复可信、哪些只是错误背景,再检查转换后的目标位置。下一阶段的数据筛选也要考虑这些区别。
结束标记应该按实际生成协议监督
提取任务需要模型在 JSON 完成后停止。如果标签过滤把真实结束标记全删了,模型就缺少相应的直接监督。
但“把所有 EOS 都加回来”也不是稳妥答案。某些模板区分消息结束与轮次结束;有的角色头由提示提供,有的控制 token 属于生成范围。应该按照目标模型的模板和推理停止规则决定。
如果 padding 与 EOS 共用编号,尤其要按实际填充位置处理,不能仅依据编号把真实结束标记一起忽略。第二卷的打包与边界已经说明,这类错误会改变训练目标,而不仅是影响吞吐。
最直接的验收方式,是打印最后几个有效标签的可读形式,确认回答内容和预期结束标记都还在,并且 padding 没有混入。
框架开关必须与模板和数据格式配套
以固定版本 TRL 0.23.1 为例,assistant_only_loss=True 用于对话数据中的助手回复;文档要求模板能够返回对应 token mask。prompt-completion 数据又有 completion_only_loss 这一分段约定,二者可以结合使用,但并非任何输入格式都能直接套用。TRL SFT Trainer
Transformers 4.57.1 的模板接口也提供 return_assistant_tokens_mask,其支持取决于模板中的 generation 区域标记。分词器模板接口
这些文档说明如何表达意图,不替代输出核对。即使开关已经设为真,也应抽查每轮监督范围,检查角色头、结束标记、截断和首个回答 token 是否符合预期。
本文用这些固定版本说明语义,没有声称本站训练项目安装了它们,或已经运行了相应配置。
为什么用字符串搜索助手标记容易出错
一种看似方便的做法是:在文本中找到 assistant 标记,后面全部算损失。
它至少会遇到几个问题:多轮中有多个边界;用户材料可能引用相同文字;模板标记与自然语言正文不一定容易区分;同一字符串单独分词与放在完整上下文中分词,边界未必完全一致。
更可靠的起点是使用结构化消息与模板提供的生成区域信息,或在自定义流水线里维护可核对的位置映射。无论采用哪种机制,都要用含边界样式文字的材料做检查。
“找到一段看起来像助手的字符串”并不等于“确认这段 token 真属于应监督的助手输出”。
截断后可能一条有效标签也没有
假设最大长度很短,长材料占满了窗口,回答全部被截掉。输入张量仍有很多 token,loss mask 却全为零。
这种样本不能当作普通训练数据继续平均;否则会出现无效更新,或在处理不当时产生非有限损失。应明确排除、重新分段或采用其他已定义策略,并记录数量。
另一种情况更难察觉:只保留了半个答案,存在有效目标,但末尾结束标记不见了。程序不会因为“至少有一个标签”就知道这个样本已经不符合完整任务要求。
因此,检查必须同时覆盖有效目标数量与目标完整性。回答越短的任务,越要注意长输入在截断和采样中是否占据了过多预算。
只算回答以后,样本权重怎么变
假设两个样本的有效回答长度分别为 2 和 8,平均 token 损失分别为 1 和 3。
按有效 token 平均:
按样本平均:
前者让每个目标位置等权,因此长回答贡献更多;后者让每条记录的平均损失等权。究竟选择哪一个,应与任务和比较问题一致。
如果想比较“全文监督”和“只监督回答”,也不能只把开关切换后比较原始 loss 大小:两者计分的位置集合不同,数字不可直接当成同一个测量。
可以固定数据和训练资源,同时在相同的回答位置上计算验证指标,再看提取任务结果。这样更接近回答“哪种监督范围更适合当前任务”,而不是比较两个定义不同的损失值。
一个最小标签检查可以怎样写
下面代码只检查上面的教学序列与内部错位约定,不依赖训练框架,也不负责生成真实聊天模板:
# 每项是自定义的教学 token ID,不是实际分词结果。ids = [0, 1, 2, 3, 4, 5, 6, 3]answer_mask = [0, 0, 0, 0, 0, 1, 1, 1]labels = [token if keep else -100 for token, keep in zip(ids, answer_mask)]
# 内部错位:位置 t 的输出,预测 labels[t + 1]。pairs = [(t, labels[t + 1]) for t in range(len(ids) - 1) if labels[t + 1] != -100]assert pairs == [(4, 5), (5, 6), (6, 3)]它验证首个答案和结束标记的位置关系。真实数据还应覆盖多轮、左右 padding、空回答、模板不支持 mask、截断及 packing;不能把这个小检查的通过扩大成整套训练器正确。
之后可以做一个短程对照:固定模型、数据与有效预算,只改变监督范围,并在相同回答目标上评价。若某方案只改善角色和标点,却没有减少字段错误,就把这一结果如实写出来。
两个检查理解的问题
第一,提示标签全部忽略,为什么提示中的 token 仍可能影响参数更新?请分别从前向信息流和反向梯度说明。
第二,一段多轮记录里,早期助手回答错误,最后回答正确。若目标是学习纠错,你会保留哪些上下文、监督哪些位置,又怎样确认首个修正 token 没被漏掉?
监督位置明确以后,下一步要检查示范本身:哪些任务和错误类型应该覆盖,合成答案如何审核,以及近似重复会怎样改变训练权重。
文章概念网络
从章节进入正文概念。实线表示所属层级,虚线连接跨章节重复出现的概念,不代表因果关系。
50 / 50 个节点 · 正文标记术语与关键词概念
哪些 token 应该计算损失:回答监督、多轮对话与标签边界
回到原文 ↗最后更新于 2026-10-20
引用本文
@article{2026-10-20-llm-training-sft-03-loss-mask,
author = {枫语},
title = {哪些 token 应该计算损失:回答监督、多轮对话与标签边界},
journal = {枫语},
year = {2026},
month = {oct},
url = {https://meiluosi.github.io/posts/2026-10-20-llm-training-sft-03-loss-mask/}
}