Back to writing

/ What Is Series

What Are Checkpoints?

A practical explanation of checkpoints in LLMs: what they store, how they enable resume training, how they relate to model weights and .safetensors, and how serving systems load them.

4 minLLM · Checkpoint · Safetensors · Training

在大模型语境里,Checkpoint 可以先理解成模型训练到某个时刻留下的一份状态快照。

一句话概括:

Checkpoint 把模型参数、训练进度和必要的运行状态保存下来,让后续可以继续训练、回滚版本、评估模型,或者把某个版本拿去部署推理。

这句话里有三个关键词:

  • 状态快照:它不是抽象概念,而是落到磁盘上的一组文件。
  • 可恢复:训练中断后,可以从最近的 checkpoint 接着跑,而不是从头开始。
  • 可交付:推理部署时,加载的通常就是某个已经训练好或量化好的 checkpoint。

中文里有时会把 checkpoint 翻译成检查点、模型快照、模型权重文件。严格说,checkpoint 是更大的概念,权重只是其中最核心的一部分。

1. Checkpoint 到底是什么#

假设你在训练一个模型,参数会随着 step 不断变化:

step 0      初始参数
step 1000   参数更新了一部分
step 10000  参数进一步优化
step 50000  得到一个较好的模型状态

如果在 step 50000 把当前模型保存下来,这个保存结果就可以叫一个 checkpoint。

完整训练 checkpoint 往往包含:

模型参数 weights
优化器状态 optimizer state
学习率调度器状态 lr scheduler state
当前训练步数 global step
随机数状态 random state
混合精度 scaler 状态
分布式训练相关状态

其中最重要的是模型参数,也就是 weights。但如果目标是“完全恢复训练”,只保存 weights 通常不够,因为 optimizer、scheduler、随机数状态都会影响后续训练轨迹。

所以可以把 checkpoint 分成两种常见理解:

训练 checkpoint = 可恢复训练状态
推理 checkpoint = 可加载模型权重目录

它们都叫 checkpoint,但关注点不一样。

2. 训练里的 Checkpoint:为了恢复状态#

在训练场景中,checkpoint 代表的是:

当前训练进度下,整个训练系统的一个可恢复状态。

大模型训练可能持续几天、几周甚至更久,中间任何环节都可能中断:

机器故障
显存 OOM
网络通信错误
训练任务被调度系统杀掉
代码 bug
集群维护

如果没有 checkpoint,训练到第 10 天崩了,代价会非常高。有 checkpoint 后,就可以从最近保存点继续:

加载 checkpoint-50000
恢复 optimizer / scheduler / step
继续训练到 checkpoint-60000

这就是常说的 resume training

这里要注意:resume training 不是简单地“重新加载模型权重”。如果只恢复 weights,而不恢复 optimizer state,Adam 的一阶矩、二阶矩会丢失;如果不恢复 scheduler,学习率位置可能错掉;如果不恢复 global step,日志、保存策略、warmup 进度也可能错乱。

因此,训练 checkpoint 更像一次完整的“游戏存档”:不只保存角色属性,也保存当前关卡、背包、任务进度和随机状态。

3. 为什么训练要保存多个 Checkpoint#

训练过程中通常不会只保存最后一个版本,而是周期性保存:

checkpoint-10000
checkpoint-20000
checkpoint-30000
checkpoint-40000
checkpoint-50000

这样做有三个直接价值。

第一,防止中断损失扩大。保存间隔越短,故障后需要重跑的 step 越少;但保存太频繁又会占用 I/O 和存储,所以需要权衡。

第二,方便选择最佳模型。训练不一定越久越好。可能训练 loss 还在下降,但验证集效果开始变差。这时 checkpoint-30000 可能比 checkpoint-50000 更适合发布。

第三,方便回滚和对比。如果某次数据、代码或超参数变更后模型行为变差,可以回到较早 checkpoint 做评估,定位问题从哪里开始出现。

所以,checkpoint 不只是容灾工具,也是模型版本管理工具。

4. 推理里的 Checkpoint:为了加载权重#

在推理场景中,checkpoint 通常主要指:

已经训练好、可以被推理框架加载的模型权重目录。

例如启动 vLLM:

vllm serve /data/models/Qwen3-32B-w8a8-sq/

这里的 /data/models/Qwen3-32B-w8a8-sq/ 本质上就是一个推理 checkpoint 目录。

推理服务启动时大致会做:

读取 config.json
读取 tokenizer
加载模型权重 checkpoint
根据模型结构初始化参数
把权重搬到 GPU / NPU 显存中
创建 KV cache 管理器
开始接收请求

和训练 checkpoint 不同,推理 checkpoint 通常不需要 optimizer state、scheduler state 或 mixed precision scaler。它更关注:

模型结构配置
模型权重
tokenizer
生成配置
量化配置

所以在推理里,checkpoint 经常和这些词混用:

模型文件
模型权重
模型目录
部署版本
推理模型包

5. 训练 Checkpoint 和推理 Checkpoint 的区别#

二者虽然都叫 checkpoint,但保存内容和使用目的不同。

场景Checkpoint 代表什么是否包含优化器主要用途
训练训练过程的完整可恢复状态通常包含断点续训、回滚、继续训练
推理训练好或量化好的模型权重目录通常不包含部署、加载模型、生成结果

训练 checkpoint 往往比推理 checkpoint 大很多。以 Adam 为例,除了模型参数本身,还要保存一阶矩、二阶矩等 optimizer state。对于大模型来说,完整训练 checkpoint 的体积可能是模型权重本身的数倍。

推理 checkpoint 则更像一个精简交付包。它保留让模型跑起来所需的权重、配置和 tokenizer,但不保留继续训练所需的全部状态。

6. Checkpoint 在模型生命周期里的作用#

大模型不是一次训练完就结束。实际链路里,checkpoint 会贯穿预训练、微调、对齐、量化和部署。

一个常见流程是:

Base checkpoint

SFT 微调

SFT checkpoint

RLHF / DPO / 其他对齐方法

Aligned checkpoint

量化 / 压缩

Inference checkpoint

所以 checkpoint 是模型演进的中间产物,也是不同阶段之间的交接物。

例如你可以从一个基础模型开始:

通用大模型 checkpoint

行业数据继续训练

domain-specific checkpoint

也可以从一个高精度权重转换出量化版本:

BF16 checkpoint

W8A8 量化

W8A8 checkpoint

推理系统最终加载的,就是这个链路上某一个确定版本的 checkpoint。不同 checkpoint 即使模型结构相同,权重不同,模型行为也会不同。

7. Checkpoint 和模型目录是什么关系#

在 Hugging Face 生态里,一个推理可用的模型目录通常长这样:

Qwen3-32B/
├── config.json
├── generation_config.json
├── tokenizer.json
├── tokenizer_config.json
├── model-00001-of-00016.safetensors
├── model-00002-of-00016.safetensors
├── ...
└── model.safetensors.index.json

可以这样理解这些文件:

文件作用
config.json描述模型结构,例如层数、hidden size、head 数、rope 配置等
*.safetensors保存模型权重 tensor,是推理 checkpoint 的核心
tokenizer.json保存分词器规则和词表信息
generation_config.json保存默认生成参数
model.safetensors.index.json记录每个 tensor 位于哪个 shard 文件

严格区分一下:

checkpoint = 某一时刻保存下来的模型状态
weights = checkpoint 中最核心的模型参数部分
model directory = 包含权重、配置、tokenizer 的完整目录

在日常部署里,大家会把整个模型目录称为一个 checkpoint,这是可以接受的工程简写。

8. .safetensors 是什么#

.safetensors 是一种专门用来保存深度学习张量权重的文件格式。现在 Hugging Face 生态里的大模型权重,很多都会用它保存。

一句话概括:

.safetensors 是一种比 pickle-based .bin.pt.pth 更安全,也更适合大模型分发和加载的权重格式。

它保存的是一个个 tensor,例如:

model.embed_tokens.weight
model.layers.0.self_attn.q_proj.weight
model.layers.0.self_attn.k_proj.weight
model.layers.0.mlp.gate_proj.weight
model.norm.weight
lm_head.weight

每个 tensor 会有自己的名字、dtype、shape、数据偏移和原始二进制数据:

q_proj.weight: shape = [4096, 4096], dtype = BF16
k_proj.weight: shape = [1024, 4096], dtype = BF16
v_proj.weight: shape = [1024, 4096], dtype = BF16

.safetensors 不是完整的 Python 模型对象。它通常不保存:

模型 Python 类定义
forward 逻辑
tokenizer 词表
config.json
generation_config.json
训练代码
推理代码

所以单独拿到一个 .safetensors 文件,往往不能完整说明“这是什么模型”。它需要和 config.json、tokenizer、index file 等一起使用。

9. .safetensors 内部结构#

.safetensors 的文件结构很简单,可以简化成:

[8 bytes header length]
[JSON header]
[raw tensor data]

第一段 8 字节记录 header 长度。第二段是 UTF-8 JSON header,描述每个 tensor 的 dtype、shape 和 data offsets。第三段是连续的权重二进制数据。

可以抽象成这样:

8 bytes:
    header_size
 
JSON header:
    {
      "model.layers.0.self_attn.q_proj.weight": {
        "dtype": "BF16",
        "shape": [4096, 4096],
        "data_offsets": [0, 33554432]
      },
      "model.layers.0.self_attn.k_proj.weight": {
        "dtype": "BF16",
        "shape": [1024, 4096],
        "data_offsets": [33554432, 41943040]
      }
    }
 
raw tensor data:
    一整块连续的二进制权重数据

这个设计的好处是:加载器不需要执行 Python 反序列化逻辑,只要解析 header,再按 offset 读取对应二进制数据即可。

10. 为什么叫 Safe#

这里的 safe 主要指:

加载 .safetensors 时不需要执行任意 Python 代码。

传统 PyTorch 权重文件,例如:

pytorch_model.bin
model.pt
model.pth

很多底层依赖 Python pickle。pickle 的问题是,它不只保存数据,也可能携带对象反序列化逻辑。如果从不可信来源下载权重文件,加载 pickle-based 文件理论上存在执行恶意代码的风险。

.safetensors 的取舍更保守:只保存数值 tensor 和有限 metadata,不保存任意 Python 对象,不执行自定义反序列化代码。因此它更适合第三方模型分发和生产部署。

但 safe 不等于模型一定可信。它解决的是“加载文件时不要执行恶意代码”这个问题,不解决:

模型是否被投毒
模型输出是否安全
权重是否被篡改
license 是否合规
模型是否包含后门行为

也就是说,.safetensors 是加载安全,不是内容安全,也不是版权保护或权重加密。

11. 为什么 .safetensors 适合大模型#

它适合大模型,主要有三个工程原因。

第一,更安全。不依赖 pickle,不执行 Python 对象反序列化逻辑,适合从模型仓库下载后直接加载。

第二,支持 lazy loading。加载器可以按需读取某些 tensor,而不是先把整个 checkpoint 反序列化成一个巨大的 Python 对象。对于几十 GB 甚至上百 GB 的模型,这一点很重要。

第三,更适合分片加载。大模型通常会被切成多个 shard,再通过 index file 记录每个 tensor 位于哪个 shard:

model.layers.0.self_attn.q_proj.weight  -> model-00001-of-00016.safetensors
model.layers.20.mlp.down_proj.weight    -> model-00007-of-00016.safetensors
lm_head.weight                          -> model-00016-of-00016.safetensors

这对 tensor parallel、pipeline parallel、多卡加载和推理框架权重分发都很友好。

可以把 .safetensors 和传统 PyTorch 文件做个对比:

对比项.safetensors.bin/.pt/.pth
常见用途模型权重分发、推理加载PyTorch 权重、训练 checkpoint
是否依赖 pickle通常是
加载时是否可能执行代码通常不会存在风险
是否支持 lazy loading支持较好较弱
是否保存任意 Python 对象不支持支持
适合大模型分片很适合可以,但不如 safetensors 清晰

所以 .safetensors 的核心取舍是:牺牲任意对象序列化能力,换取更简单、更安全、更适合大模型加载的权重格式。

12. 为什么会有很多个 .safetensors 文件#

因为模型太大。

一个 32B 模型如果用 BF16 保存,粗略估算就是:

32B 参数 * 2 bytes ~= 64 GB

单个文件太大,不方便下载、上传、校验和加载,所以通常会切成多个 shard:

model-00001-of-00016.safetensors
model-00002-of-00016.safetensors
...
model-00016-of-00016.safetensors

这些 shard 不是 16 个不同模型,而是同一个模型的权重被拆成了 16 份。一般不能只下载其中一个,而是要完整下载:

所有 .safetensors 分片
model.safetensors.index.json
config.json
tokenizer 相关文件

否则加载时很容易遇到:

missing weight
cannot find tensor
cannot find model weights
index references missing shard

13. 分布式训练里的 Checkpoint#

分布式训练里,checkpoint 还会更复杂。

大模型参数、梯度和 optimizer state 可能被切到不同 rank 上:

TP shard
PP shard
DP shard
ZeRO optimizer shard
FSDP shard

这意味着某个 rank 保存的文件,可能只是完整训练状态的一部分。恢复训练时,框架需要根据并行策略重新组合或重新分发这些 shard。

例如 ZeRO / FSDP 训练中,每张卡可能只保存自己负责的参数 shard 和 optimizer shard。这样可以降低单卡内存和存储压力,但也带来两个问题:

  1. checkpoint 文件数量更多,目录结构更复杂。
  2. 更换 world size、并行策略或框架版本时,恢复和转换成本更高。

所以在大规模训练里,checkpoint 不只是“保存一下文件”,而是训练系统设计的一部分。保存频率、异步写盘、分片格式、对象存储、校验、清理策略都会影响训练稳定性和集群效率。

14. Checkpoint 和 KV Cache 不是一回事#

推理里很容易把 checkpoint、KV cache、prefix cache 混在一起。它们不是同一种东西。

名称含义生命周期
Checkpoint模型权重快照或模型目录长期保存,用于加载模型
KV cache推理过程中保存的 attention Key / Value请求级或会话级,动态产生
Prefix cache已计算前缀的 KV 复用推理优化缓存
Activation checkpointing训练省显存技术不是模型保存文件

在 vLLM 这类推理系统里,可以这样理解:

服务启动时:加载 checkpoint,模型参数固定在显存中
请求进来后:prefill 阶段产生 KV cache
decode 阶段:复用并更新 KV cache

Checkpoint 是模型本身。KV cache 是模型处理某次请求时产生的中间状态。前者长期存在,后者动态产生。

15. Activation Checkpointing 又是什么#

还有一个容易混淆的概念叫:

activation checkpointing
gradient checkpointing

它和保存模型 checkpoint 不是一回事。

Activation checkpointing 是一种训练省显存技术。正常训练时,前向传播会保存大量 activation,反向传播时直接使用。activation checkpointing 的思路是:

前向时少保存一些 activation
反向时重新计算一部分 activation
用计算时间换显存空间

它的作用是降低显存占用,让训练更大的模型或更大的 batch size 成为可能。代价是训练速度会变慢。

所以它名字里也有 checkpoint,但不是把模型保存到磁盘,而是在训练计算图里选择性保存中间激活。

16. 在 vLLM 推理里怎么理解 Checkpoint#

如果你看到这样的命令:

vllm serve /data/models/Qwen3-32B-w8a8-sq/

可以把它理解成:

加载一个已经训练好或量化好的推理 checkpoint

vLLM 要做的事情大致是:

1. 读取 checkpoint 权重和 config
2. 根据 config 构建模型结构
3. 加载 tokenizer 和 generation config
4. 将权重加载到设备显存
5. 按 tensor parallel / pipeline parallel 切分权重
6. 处理量化权重的加载和 kernel 路径
7. 创建 KV cache 管理器
8. 接收请求并执行 prefill / decode

在这个链路里,checkpoint 本身通常不变。推理优化更多发生在这些地方:

权重加载方式
权重分片方式
量化格式
算子实现
KV cache 管理
调度策略
并行通信

也就是说,checkpoint 是推理系统的输入资产;vLLM、TGI、SGLang 这类 serving 框架的工作,是把这个资产高效加载、切分、调度并执行起来。

17. 和 GGUF、ONNX、TensorRT Engine 的区别#

.safetensors 不是唯一的模型格式。不同格式服务于不同生态和阶段。

格式主要生态典型用途
.safetensorsHugging Face / Transformers / vLLM / TGI / SGLang保存标准模型权重
.ggufllama.cpp本地 CPU / GPU 轻量推理,常见于量化模型
.bin/.pt/.pthPyTorch训练、保存 PyTorch 对象或权重
.onnxONNX Runtime跨框架推理图
.engineTensorRT已编译优化后的推理引擎

.safetensors 更像通用权重存储格式;GGUF 更偏 llama.cpp 推理生态;ONNX 更偏跨框架计算图;TensorRT engine 则是已经针对特定硬件和 shape 编译优化后的产物。

18. 简单读取 .safetensors#

如果想看一个 .safetensors 文件里有哪些 tensor,可以用 safetensors Python 包:

from safetensors import safe_open
 
path = "model-00001-of-00016.safetensors"
 
with safe_open(path, framework="pt", device="cpu") as f:
    print("metadata:", f.metadata())
 
    for name in f.keys():
        tensor = f.get_tensor(name)
        print(name, tensor.shape, tensor.dtype)

如果只想看 keys,可以这样:

from safetensors import safe_open
 
with safe_open("model.safetensors", framework="pt", device="cpu") as f:
    for key in f.keys():
        print(key)

保存一个简单的 .safetensors 文件:

import torch
from safetensors.torch import save_file
 
tensors = {
    "linear.weight": torch.randn(4096, 4096, dtype=torch.float16),
    "linear.bias": torch.randn(4096, dtype=torch.float16),
}
 
save_file(tensors, "model.safetensors")

这类代码适合做权重检查、格式转换和模型目录排查。但真正的大模型加载,通常交给 Transformers、vLLM 或训练框架的 model loader 处理。

19. 常见误区#

误区一:Checkpoint 就等于 .safetensors#

不准确。

Checkpoint 是概念,.safetensors 是保存 checkpoint 权重的一种文件格式。一个完整推理 checkpoint 目录通常还需要 config.json、tokenizer、index file 和生成配置。

误区二:.safetensors 是模型结构文件#

不是。

.safetensors 主要保存权重 tensor。模型结构通常由 config.json 和框架里的模型实现决定。

误区三:.safetensors 一定是量化模型#

不是。

.safetensors 只是存储格式,可以保存 FP32、FP16、BF16、INT8、FP8、W4A16、W8A8 等不同 dtype 或量化权重。具体是不是量化模型,要看 config.jsonquantization_config、目录名和加载器逻辑。

误区四:.safetensors 可以防止模型被盗#

不能。

它不是加密格式。只要别人拿到文件,就可以读取里面的权重 tensor。safe 指的是反序列化加载更安全,不是访问控制、防逆向或版权保护。

误区五:.safetensors 一定让推理 token/s 更快#

不一定。

它更直接影响的是模型启动加载、权重分发和多卡加载阶段。真正 decode 阶段的 token/s 主要取决于 attention kernel、GEMM、KV cache 管理、调度策略、显存带宽、通信性能和量化 kernel。

20. 总结一句话#

Checkpoint 是大模型在某个阶段留下的状态资产:训练时它用于恢复和继续优化,推理时它用于加载权重和部署服务。

如果再把 .safetensors 放进来,可以这样记:

checkpoint 是概念;
weights 是 checkpoint 中最核心的参数;
.safetensors 是保存 weights 的主流安全文件格式;
model directory 是 config、tokenizer、weights 和 index 的完整交付目录。

在 AI Infra 里,checkpoint 连接了训练、微调、评估、量化、部署和推理优化。训练系统关心它能不能快速、稳定、完整地保存和恢复;推理系统关心它能不能安全、高效、正确地加载到设备上。

所以,理解 checkpoint,不只是知道“模型权重在哪里”,更是在理解大模型从训练到上线之间最重要的交付边界。

参考资料#

  1. Hugging Face, Safetensors: https://huggingface.co/docs/safetensors/en/index
  2. Safetensors GitHub, Format and implementation: https://github.com/huggingface/safetensors
  3. PyTorch Foundation, Safetensors: https://pytorch.org/projects/safetensors/
  4. Hugging Face Transformers, Big model loading and sharded checkpoints: https://huggingface.co/docs/transformers/v4.44.2/big_models
  5. Hugging Face TGI, Safetensors: https://huggingface.co/docs/text-generation-inference/conceptual/safetensors
  6. vLLM, Loading model weights with fastsafetensors: https://docs.vllm.ai/en/stable/models/extensions/fastsafetensor/