news 2026/5/1 6:56:35

checkpoint怎么选?保存策略与恢复技巧说明

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
checkpoint怎么选?保存策略与恢复技巧说明

checkpoint怎么选?保存策略与恢复技巧说明

微调大模型时,checkpoint(检查点)不只是训练过程中的一个中间产物,它直接决定了你能否回溯效果、复现结果、快速验证想法,甚至影响最终部署的稳定性和灵活性。尤其在单卡资源有限的场景下——比如用一块 RTX 4090D(24GB)跑 Qwen2.5-7B 的 LoRA 微调——每一轮 save_steps 都在显存、磁盘空间和时间成本之间做权衡。选错 checkpoint,轻则白跑几小时,重则无法还原最佳状态。

本文不讲抽象理论,也不堆参数公式,而是从真实微调现场出发,结合你正在使用的镜像(单卡十分钟完成 Qwen2.5-7B 首次微调),手把手拆解:
checkpoint 到底该不该存?存多少?
--save_steps 50是怎么算出来的?为什么不是 10 或 200?
训练中断后,如何精准续训而不是从头再来?
推理时加载checkpoint-xxx和加载最终merged模型,效果真的一样吗?
多个 checkpoint 并存时,怎么一眼识别哪个“最聪明”?

所有答案,都来自你在/root/output/目录下亲手生成的那些文件夹。


1. checkpoint 是什么?它不是“快照”,而是“可执行的状态包”

很多人把 checkpoint 理解成“训练中途截个图”,这是误区。在 ms-swift 框架中,一个典型的checkpoint-100文件夹,实际包含以下核心内容:

  • adapter_config.json:记录 LoRA 的结构配置(rank=8, alpha=32, target_modules=all-linear)
  • adapter_model.bin:真正的低秩增量权重(通常 10–15MB)
  • trainer_state.json:当前训练步数、loss 历史、optimizer 状态(关键!决定能否续训)
  • global_stepX.bin(可选):梯度或 optimizer 分片(仅当启用 ZeRO 类优化时出现)

划重点:只有同时具备adapter_model.bin+trainer_state.json,这个 checkpoint 才能既用于推理,也能用于续训。缺一不可。

而像pytorch_model.bin这类全量权重文件,在 LoRA 微调中默认不会生成——因为没必要。Qwen2.5-7B 原始模型本身已固定,我们只学“小补丁”。这也是为什么本镜像能在 24GB 显存里跑起来的根本原因。


2. 保存策略:不是越多越好,而是“够用+可控+可验证”

镜像默认命令中设置了:

--save_steps 50 \ --save_total_limit 2 \ --eval_steps 50

这组参数不是随便写的,而是针对self_cognition.json(约 50 条数据)、单卡 4090D、LoRA 微调这一具体场景反复验证后的平衡点。我们来逐条拆解:

2.1--save_steps 50:为什么是 50?不是 10,也不是 100?

先看数据量:50 条样本 ×per_device_train_batch_size 1= 每轮 epoch 实际只走 50 步。
再看gradient_accumulation_steps 16:意味着模型每看到 16 个 batch 才更新一次参数 → 实际参数更新频率是每 16 步一次

所以:

  • save_steps=50≈ 每1 个完整 epoch 后保存 1 次(50 ÷ 16 ≈ 3.1 次更新 → 覆盖完整学习周期)
  • 若设为10:10 步 ≈ 0.6 次更新 → 保存太密,磁盘写入频繁,且每个 checkpoint 差异极小,无区分度
  • 若设为200:200 步 ≈ 12.5 次更新 → 跨越多个 epoch,一旦在第 150 步崩溃,就得倒退 100 步重训,损失巨大

实操建议

  • 小数据集(<200 条):save_steps = 数据条数 ÷ 2(如 50 条 → 设 25~50)
  • 中等数据集(500–2000 条):save_steps = 100~200,配合eval_steps保持一致
  • 每次 save 同时触发 eval → 你能立刻看到checkpoint-50对应的 loss 和回答质量,而不是靠猜

2.2--save_total_limit 2:为什么只留 2 个?不怕删掉最好的吗?

save_total_limit控制的是/root/output/同级 checkpoint 文件夹的数量上限。当新 checkpoint 生成,系统会自动删除最旧的那个(FIFO 策略)。

但注意:它只删同级目录,不删子目录。例如:

output/ ├── v2-20250401-102345/ ← 当前训练主目录 │ ├── checkpoint-50/ │ ├── checkpoint-100/ │ └── checkpoint-150/ ← 新生成,触发删除 checkpoint-50

所以limit=2实质是:永远保留最近两次完整评估过的状态
这对 self-cognition 这类目标明确的微调非常友好——你总能对比“前一次”和“这一次”的回答差异,快速判断是否过拟合(比如开始机械重复“我是 CSDN 迪菲赫尔曼 开发的”,但对其他问题答非所问)。

❌ 错误认知:“留越多越保险”。
正确认知:“留够验证窗口,比堆数量更重要”。磁盘空间有限,人工筛选成本高,2 个高质量 checkpoint + 1 份日志,远胜 10 个模糊状态。

2.3--eval_steps 50:保存和评估必须同步,否则 checkpoint 就是“盲盒”

镜像命令中--eval_steps 50--save_steps 50完全对齐。这意味着:

  • 每生成一个checkpoint-50,系统必跑一次验证(用相同 prompt 测 self-cognition 效果)
  • 评估结果(loss、accuracy、示例输出)会写入trainer_state.json和日志文件
  • 你打开output/v2-20250401-102345/checkpoint-100/时,能立刻看到eval_results.json里写着:
{ "eval_loss": 0.214, "eval_samples": 8, "eval_runtime": 12.34, "eval_samples_per_second": 0.65 }

这才是 checkpoint 的“可信标签”。没有 eval 结果的 checkpoint,就像没试飞过的飞机——你不知道它能不能平稳落地。

实操动作:每次训练完,别急着 infer,先去对应 checkpoint 目录下cat eval_results.json,扫一眼 loss 是否持续下降。如果checkpoint-100的 loss 比checkpoint-50高,说明可能过拟合,立刻切回去用checkpoint-50推理。


3. 恢复技巧:中断≠重来,3 步精准续训

训练过程中遇到显存溢出、SSH 断连、系统重启?别慌。只要trainer_state.json完整,就能从断点继续,不丢步数、不重算梯度、不浪费 GPU 时间

3.1 第一步:确认断点位置

进入你的训练主目录(如output/v2-20250401-102345/),执行:

ls -t checkpoint-*

输出类似:

checkpoint-150 checkpoint-100 checkpoint-50

再查看最新 checkpoint 的trainer_state.json

jq '.global_step' checkpoint-150/trainer_state.json # 输出:150

这个150就是已成功完成的总步数,也是续训的起点。

3.2 第二步:修改微调命令,加入恢复参数

原命令:

swift sft --model Qwen2.5-7B-Instruct ... --output_dir output

改为(仅增加两行):

CUDA_VISIBLE_DEVICES=0 \ swift sft \ --model Qwen2.5-7B-Instruct \ --train_type lora \ --dataset self_cognition.json \ --torch_dtype bfloat16 \ --num_train_epochs 10 \ --per_device_train_batch_size 1 \ --per_device_eval_batch_size 1 \ --learning_rate 1e-4 \ --lora_rank 8 \ --lora_alpha 32 \ --target_modules all-linear \ --gradient_accumulation_steps 16 \ --eval_steps 50 \ --save_steps 50 \ --save_total_limit 2 \ --logging_steps 5 \ --max_length 2048 \ --output_dir output \ --system 'You are a helpful assistant.' \ --warmup_ratio 0.05 \ --dataloader_num_workers 4 \ --model_author swift \ --model_name swift-robot \ # 👇 新增两行:指定从 checkpoint-150 恢复 --resume_from_checkpoint output/v2-20250401-102345/checkpoint-150 \ --ignore_mismatched_sizes # 防止因路径微小差异报错

关键细节:

  • --resume_from_checkpoint必须指向完整路径(含output/xxx/checkpoint-xxx),不能只写checkpoint-150
  • --ignore_mismatched_sizes是安全垫:当模型结构微调后略有变化(如新增 token),它跳过校验,避免中断

3.3 第三步:验证续训是否生效

启动后,观察日志首行:

Loading checkpoint from output/v2-20250401-102345/checkpoint-150 Resuming training from global step 150

接着看 step 计数是否从 151 开始:

Step: 151/2000 | Loss: 0.211 | ... Step: 152/2000 | Loss: 0.209 | ...

如果看到Step: 1/2000,说明路径错了,它当成了全新训练。

经验口诀

“看三行日志定生死:
第一行有Resuming,第二行有global step XXX,第三行 step 数 > XXX —— 续训成功。”


4. 推理加载:checkpoint vs merged,选哪个更稳?

训练完成后,你会在output/xxx/下看到两类产物:

类型路径示例特点适用场景
LoRA checkpointoutput/v2-20250401-102345/checkpoint-150/仅含 adapter 权重(10MB),依赖原始模型快速验证、A/B 测试、多身份切换
Merged 模型output/v2-20250401-102345/merged/LoRA 权重已融合进 Qwen2.5-7B,生成完整pytorch_model.bin(~5GB)生产部署、离线使用、跨框架迁移

4.1 为什么推荐优先用 checkpoint 推理?

  • 启动快:加载 10MB 比加载 5GB 快 10 倍以上,swift infer命令秒响应
  • 灵活:你可以在同一基础模型上,同时加载checkpoint-100(偏通用)和checkpoint-150(偏自认知),对比效果
  • 安全:不改动原始模型,避免 merge 错误导致基础模型损坏

命令就是你文档里写的:

swift infer \ --adapters output/v2-20250401-102345/checkpoint-150 \ --stream true \ --temperature 0 \ --max_new_tokens 2048

4.2 什么时候必须 merge?

  • 需要导出给 HuggingFace Transformers、vLLM、Ollama 等不支持 LoRA 动态加载的框架
  • 要打包成 Docker 镜像交付给客户,且客户环境无法保证ms-swift运行时
  • 做量化(如 AWQ、GPTQ):多数量化工具要求输入是完整模型

merge 命令(在训练完成后自动触发,或手动运行):

swift export \ --ckpt_dir output/v2-20250401-102345/checkpoint-150 \ --output_dir output/v2-20250401-102345/merged \ --device_map auto

重要提醒:merge 后的模型仍需指定--model_type qwen,否则 infer 会报错。因为模型结构信息(如 rotary base、attention mask 处理)不包含在权重里,必须由框架注入。


5. 进阶技巧:用 checkpoint 做“模型体检”

checkpoint 不只是恢复用的,它还是你诊断模型健康度的听诊器。三个实用技巧:

5.1 对比 loss 曲线,识别过拟合拐点

进入output/xxx/,执行:

grep "loss" logs/train.log | tail -n 20

你会看到类似:

Step: 130/2000 | Loss: 0.225 | ... Step: 140/2000 | Loss: 0.221 | ... Step: 150/2000 | Loss: 0.218 | ... Step: 160/2000 | Loss: 0.235 | ← 注意!这里上升了 Step: 170/2000 | Loss: 0.242 | ← 持续上升 → 过拟合信号

此时,checkpoint-150就是你的“黄金点”。后续所有推理、merge、测试,都基于它,而不是最后那个checkpoint-200

5.2 提取特定 layer 的 LoRA 变化,定位“记忆焦点”

LoRA 的lora_Alora_B矩阵,分别作用于 attention 和 FFN 层。你想知道模型在哪一层“最努力记住了自我认知”?用以下代码快速探查:

import torch adapter = torch.load("output/v2-20250401-102345/checkpoint-150/adapter_model.bin") # 查看 attention 层 LoRA 的 L2 norm(越大表示改动越强) attn_norms = [v.norm().item() for k, v in adapter.items() if "self_attn" in k and "lora_B" in k] print("Attention layer LoRA strength:", sorted(attn_norms, reverse=True)[:3]) # 输出类似:[12.4, 11.8, 9.2] → 说明前三层 attention 被重点调整

这能帮你理解:为什么模型对“你是谁”回答很准,但对“今天天气”却答得生硬——因为 LoRA 主要强化了 self-attention 的 identity 相关通路。

5.3 一键生成 checkpoint 报告,告别手动翻日志

把下面脚本保存为check_report.py,放在/root/下,每次训练完运行它:

#!/usr/bin/env python3 import os, json, glob from pathlib import Path output_dir = "output" for d in Path(output_dir).glob("v*"): if not d.is_dir(): continue checkpoints = sorted(d.glob("checkpoint-*")) if not checkpoints: continue print(f"\n Report for {d.name}") for cp in checkpoints[-3:]: # 只看最近3个 ts = json.load(open(cp / "trainer_state.json")) eval_f = cp / "eval_results.json" if eval_f.exists(): ev = json.load(open(eval_f)) print(f" {cp.name}: step={ts['global_step']}, loss={ev['eval_loss']:.3f}") else: print(f" {cp.name}: no eval result (run eval manually)")

运行python check_report.py,输出即清晰:

Report for v2-20250401-102345 checkpoint-50: step=50, loss=0.312 checkpoint-100: step=100, loss=0.245 checkpoint-150: step=150, loss=0.218

6. 总结:checkpoint 选择的本质,是工程节奏的掌控

选 checkpoint,从来不是技术问题,而是项目管理问题

  • 你有多少时间?→ 决定save_steps密度
  • 你有多少磁盘?→ 决定save_total_limit上限
  • 你要快速验证,还是长期部署?→ 决定用checkpoint还是merged
  • 你怕中断重来,还是怕效果波动?→ 决定是否开启eval_steps同步

在单卡微调 Qwen2.5-7B 的实战中,记住这四句口诀:

小数据,步频对半砍(save_steps ≈ 数据量 ÷ 2)
双 checkpoint,够看不占地(save_total_limit = 2)
eval 不离身,loss 是标尺(eval_steps 必须 = save_steps)
续训看三行,global_step 定乾坤

你不需要记住所有参数,只需要养成习惯:每次swift sft后,花 30 秒ls checkpoint-*,再cat eval_results.json—— 这个动作,会帮你避开 80% 的微调返工。


获取更多AI镜像

想探索更多AI镜像和应用场景?访问 CSDN星图镜像广场,提供丰富的预置镜像,覆盖大模型推理、图像生成、视频生成、模型微调等多个领域,支持一键部署。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/28 23:43:44

基于WinDbg Preview的跨Windows版本驱动兼容性测试方案

以下是对您提供的技术博文进行 深度润色与结构重构后的优化版本 。本次改写严格遵循您的全部要求: ✅ 彻底去除AI痕迹,语言自然、专业、有“人味”,像一位资深驱动工程师在技术博客中娓娓道来; ✅ 删除所有模板化标题(如“引言”“总结”“展望”),代之以逻辑连贯、…

作者头像 李华
网站建设 2026/4/25 12:47:08

GLM-4.7-Flash新手指南:中文提示词设计技巧与多轮对话实践

GLM-4.7-Flash新手指南&#xff1a;中文提示词设计技巧与多轮对话实践 1. 为什么选GLM-4.7-Flash&#xff1f;不只是“又一个大模型” 你可能已经试过不少开源大模型&#xff0c;但真正用起来总有些卡点&#xff1a;中文回答生硬、多轮聊着聊着就忘了前面说了啥、写文案要反复…

作者头像 李华
网站建设 2026/4/22 21:13:37

Qwen3-Embedding-4B是否值得用?MTEB排名领先实测验证教程

Qwen3-Embedding-4B是否值得用&#xff1f;MTEB排名领先实测验证教程 1. 这不是又一个“参数堆料”模型&#xff1a;Qwen3-Embedding-4B到底强在哪&#xff1f; 你可能已经见过太多标榜“高性能”的向量模型——有的靠大参数撑场面&#xff0c;有的靠小数据刷榜单&#xff0c…

作者头像 李华
网站建设 2026/4/24 15:43:33

手把手教你跑通GLM-4.6V-Flash-WEB视觉模型

手把手教你跑通GLM-4.6V-Flash-WEB视觉模型 你是不是也遇到过这样的情况&#xff1a;好不容易找到一个开源视觉大模型&#xff0c;结果下载卡在99%、部署要配四张A100、跑个图要等三秒、网页界面打不开……最后只能关掉终端&#xff0c;默默打开文档继续看&#xff1f; 别折腾…

作者头像 李华
网站建设 2026/4/24 12:55:48

零配置启动GPEN,AI人像增强从未如此简单

零配置启动GPEN&#xff0c;AI人像增强从未如此简单 你是否遇到过这些情况&#xff1a; 一张老照片泛黄模糊&#xff0c;想修复却卡在环境配置上&#xff1b; 朋友发来一张手机抓拍的人像&#xff0c;细节糊成一片&#xff0c;想增强又怕折腾半天跑不起来&#xff1b; 试了三个…

作者头像 李华
网站建设 2026/4/28 0:42:01

bert-base-chinese实战教程:中文文本对抗样本生成与BERT鲁棒性测试

bert-base-chinese实战教程&#xff1a;中文文本对抗样本生成与BERT鲁棒性测试 1. 为什么从bert-base-chinese开始做鲁棒性测试 你可能已经用过BERT做中文分类或问答&#xff0c;但有没有想过&#xff1a;当输入文字被悄悄改动几个字&#xff0c;模型会不会突然“认错人”&am…

作者头像 李华