llamafactory sft微调坑 继续训练 ,为什么 `save_steps: 40` 没有生效,实际 100 步才保存

llamafactory sft微调坑 继续训练 ,为什么 save_steps: 40 没有生效,实际 100 步才保存

这是一个很典型的问题,让我帮你排查。核心怀疑是:从 checkpoint 恢复训练时,save_steps 被旧 checkpoint 里的 training_args 覆盖了

让我先检查一下你的 checkpoint 目录和配置文件:

Sandbox 里没有你的实际文件,让我写一个你可以在本机运行的诊断脚本,同时先给你分析最可能的原因:

分析:为什么 save_steps: 40 没有生效,实际 100 步才保存?

你的配置看起来没问题,save_steps: 40 写得很清楚。问题最可能出在 resume_from_checkpoint 上。以下是排查思路:

🔴 最可能的原因:旧 checkpoint 里的 training_args 覆盖了新配置

你的 checkpoint-600 很可能是之前用 save_steps: 100 训练保存的(600 ÷ 100 = 6,恰好整除)。

当使用 resume_from_checkpoint 时,HuggingFace Trainer / LLaMA-Factory 可能会从 checkpoint 目录下的 training_args.json 读取旧的训练参数(包括 save_steps: 100),覆盖你新配置的 40

验证方法:在你本机运行上面的诊断脚本,重点看第 3 步的输出:

复制代码
checkpoint-600/training_args.json 里的 save_steps 是多少?
  • 如果是 100 → 确认是旧配置覆盖了
  • 如果是 40 → 需要看其他原因

🟡 其他可能原因

# 可能原因 说明
1 命令行参数覆盖 如果启动时用了 --save_steps 100 命令行参数,会覆盖 YAML 配置文件
2 LLaMA-Factory 版本行为 某些版本的 LLaMA-Factory 在 resume 时会从 checkpoint 恢复完整的 TrainingArguments
3 save_strategy 未显式设置 虽然 HF 默认 save_steps 设了就自动用 "steps",但某些版本需要显式指定

✅ 解决方案(按推荐顺序)

方案 1:删除旧 checkpoint 中的 training_args 文件(推荐)
bash 复制代码
# 删除旧的 training_args,强制使用新配置
rm /mnt/workspace/output/train_1024_0/checkpoint-600/training_args.json
rm /mnt/workspace/output/train_1024_0/checkpoint-600/training_args.bin 2>/dev/null
# 但保留 trainer_state.json(里面保存了 global_step 等恢复信息)

然后重新启动训练,新配置的 save_steps: 40 应该会生效。

方案 2:显式添加 save_strategy

在 YAML 配置中加上:

yaml 复制代码
save_strategy: steps
save_steps: 40
方案 3:检查启动命令

确认启动命令中没有通过命令行覆盖:

bash 复制代码
# ❌ 如果有这样的命令行参数,会覆盖 YAML
--save_steps 100
# ✅ 确保只通过 YAML 文件配置
llamafactory-cli train your_config.yaml
方案 4:如果以上都不行 --- 手动修改 checkpoint 的 step 计数
python 复制代码
import json
# 修改 trainer_state.json,让 global_step 对齐到 40 的倍数
path = "/mnt/workspace/output/train_1024_0/checkpoint-600/trainer_state.json"
with open(path) as f:
    state = json.load(f)
# 600 已经是 40 的倍数 (600/40=15),所以这里不需要改
# 但确认 save_steps 字段
state['save_steps'] = 40  # 强制写入
with open(path, 'w') as f:
    json.dump(state, f, indent=2)
print("已修改 trainer_state.json 中的 save_steps 为 40")

📋 快速诊断清单

请在你的机器上运行以下命令,把结果发给我:

bash 复制代码
# 1. 看旧 checkpoint 的训练参数
cat /mnt/workspace/output/train_1024_0/checkpoint-600/trainer_state.json | python -m json.tool | grep -E "save_steps|global_step|logging_steps"
# 2. 看 training_args.json
cat /mnt/workspace/output/train_1024_0/checkpoint-600/training_args.json | python -m json.tool | grep -E "save_steps|logging_steps|eval_steps"
# 3. 看启动命令(检查是否有命令行覆盖)
# 确认你的启动方式,是否额外传了 --save_steps 参数

最关键的一步 :看 checkpoint-600/training_state.json 里的 save_steps 值。如果它是 100,那就是罪魁祸首------修改这个文件再重启训练即可。

直接删除 training_state.json 可能会报错 ,导致训练无法启动。因为 HuggingFace Trainer 或 LLaMA-Factory 在恢复训练时,可能会尝试读取这个文件;如果找不到,可能会抛出 FileNotFoundError

更安全、更推荐的做法是:直接修改里面的值,而不是删除。

我们可以直接把旧 checkpoint 里的 save_steps 强制改成 40,这样既不影响恢复训练(优化器状态、步数等依然保留),又能让新配置生效。

你可以直接在终端运行这段 Python 脚本来"安全打补丁":

python 复制代码
import json
import os
ckpt_dir = "/mnt/workspace/output/train_1024_0/checkpoint-600"
# 1. 修改 training_state.json
ta_path = os.path.join(ckpt_dir, "training_state.json")
if os.path.exists(ta_path):
    with open(ta_path, 'r') as f:
        ta = json.load(f)
    ta['save_steps'] = 40
    ta['logging_steps'] = 20  # 顺便确保日志也是你要的频率
    with open(ta_path, 'w') as f:
        json.dump(ta, f, indent=2)
    print(f"✅ 已修改 {ta_path} 中的 save_steps 为 40")
# 2. 修改 trainer_state.json (HuggingFace 的状态文件里也会存一份)
ts_path = os.path.join(ckpt_dir, "trainer_state.json")
if os.path.exists(ts_path):
    with open(ts_path, 'r') as f:
        ts = json.load(f)
    ts['save_steps'] = 40
    ts['logging_steps'] = 20
    with open(ts_path, 'w') as f:
        json.dump(ts, f, indent=2)
    print(f"✅ 已修改 {ts_path} 中的 save_steps 为 40")

总结一下哪些文件能动,哪些不能动:

checkpoint-600 文件夹里:

  • 绝不能删adapter_model.binpytorch_model.bin(模型权重)、optimizer.bin(优化器状态)、scheduler.pt(学习率调度器)、rng_state.pth(随机数种子)。删了等于没法接着训练了。
  • ⚠️ 不要直接删,建议修改training_state.jsontrainer_state.json。删了可能报错,按上面的脚本改成你想要的数值最稳妥。
  • 可以删training_state.bin(如果存在的话,这是旧版遗留文件,一般没用)。
    你先跑一下这个脚本打补丁,然后再用原本的 YAML 配置启动训练,这次 40 步应该就会乖乖保存了!