层1: 损失缩放终解——显式退出 HF 新式梯度累积契约(model_accepts_loss_kwargs=False)
第二幕根因:新式契约的 ×world_size 补偿在基类 compute_loss 尾部(v5 trainer.py:2028),整体重写会绕过它 → loss 与梯度 ÷4(sanity 0.244≈0.85/4)。 按 HF 文档建议(trainer.py:1977)退出新式契约回经典行为;docs/02 勘误改为 两幕全记录。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
+12
-8
@@ -111,6 +111,15 @@ class SFTTrainer(Trainer):
|
||||
for module in self.model.modules():
|
||||
if isinstance(module, torch.nn.Dropout):
|
||||
module.p = 0.0
|
||||
# 非显然约束:显式退出 HF 的新式梯度累积契约(v5 trainer.py:1977 文档
|
||||
# 原话:"If you are not using num_items_in_batch ... overwrite
|
||||
# self.model_accepts_loss_kwargs to False")。新式契约要求返回
|
||||
# sum/全局token数,且依赖基类 compute_loss 尾部的 ×world_size 补偿
|
||||
# (trainer.py:2028)——我们整体重写了 compute_loss,那段补偿不会执行,
|
||||
# 曾致 loss 与梯度 ÷4(2026-07-18,第二幕;第一幕是返回裸 mean 被 ×8,
|
||||
# 全程记录见 docs/02 §5)。退出后回到经典契约:返回本微批 mean,
|
||||
# Trainer 负责 ÷累积步数,日志跨卡平均,版本稳定
|
||||
self.model_accepts_loss_kwargs = False
|
||||
self._token_counts: list[int] = []
|
||||
|
||||
def compute_loss(
|
||||
@@ -133,14 +142,9 @@ class SFTTrainer(Trainer):
|
||||
inputs["labels"],
|
||||
inputs["attention_mask"],
|
||||
)
|
||||
# 非显然约束:HF 梯度累积契约(transformers 4.46 修正后的新式)。模型
|
||||
# forward 接受 loss_kwargs(Qwen3 是)时,Trainer 不再帮你除以累积步数,
|
||||
# 而是期望 compute_loss 返回 sum/num_items_in_batch(整个累积组的总有效
|
||||
# token 数),各微批直接相加得到精确的全局 per-token 均值。返回裸 mean
|
||||
# 会导致日志与梯度同时放大"累积步数"倍——2026-07-18 远程 sanity 的
|
||||
# loss 7.5 ≈ 0.94×8 正是此坑(诊断记录见 docs/02 §5)
|
||||
if num_items_in_batch is not None:
|
||||
loss = loss * num_tokens / num_items_in_batch # mean → sum/N_total
|
||||
# num_items_in_batch 有意忽略:已在 __init__ 退出新式契约(见彼处注释),
|
||||
# 本函数返回微批 mean,÷累积步数由 Trainer.training_step 负责。
|
||||
# 代价是微批按相同权重而非 token 数加权(百分之几的偏差,与参考实现同行为)
|
||||
self._token_counts.append(num_tokens)
|
||||
return (loss, outputs) if return_outputs else loss
|
||||
|
||||
|
||||
Reference in New Issue
Block a user