Skip to content

第 3 章 模型加载与保存 ​

学习目标 ​

  • 掌握 from_pretrained / save_pretrained 与本地缓存机制
  • 认识 config.json、model.safetensors 等文件的作用
  • 会用 from_config 随机初始化模型,理解「结构」与「权重」的分离
  • 会用 dtype 参数控制加载精度
  • 会解读 transformers v5 的 LOAD REPORT

3.1 from_pretrained:从 Hub 或本地加载 ​

from_pretrained 是 transformers 最重要的方法:传入一个模型 id 或本地目录,它会自动下载(若在 Hub)并加载配置、分词器或权重。

python
from transformers import AutoModel

model = AutoModel.from_pretrained("google-bert/bert-base-uncased")
print(type(model).__name__, "参数总数:", sum(p.numel() for p in model.parameters()))

输出:

BertModel 参数总数: 109482240

BERT-base 有约 1.09 亿参数。第一次运行时,transformers 会逐文件下载并打印进度条;文件缓存到本机(默认 ~/.cache/huggingface/hub),第二次加载直接读缓存。

3.2 模型目录里有什么 ​

把模型保存到本地,看看文件清单:

python
from transformers import AutoModel, AutoTokenizer

model = AutoModel.from_pretrained("google-bert/bert-base-uncased")
tokenizer = AutoTokenizer.from_pretrained("google-bert/bert-base-uncased")

model.save_pretrained("./my-bert")
tokenizer.save_pretrained("./my-bert")

目录内容:

my-bert/
├── config.json            # 结构配置:层数、维度、词表等
├── model.safetensors      # 模型权重
├── tokenizer.json         # 分词器(序列化格式,fast tokenizer)
└── tokenizer_config.json  # 分词器配置(特殊 token 等)

逐项说明:

  • config.json:描述「模型长什么样」。同一个目录,模型权重可以换,config 定义了每层的大小。
  • model.safetensors:权重文件,采用 safetensors 格式(安全、快、无 pickle 风险)。旧格式是 pytorch_model.bin。
  • tokenizer.json / tokenizer_config.json:分词器本体与配置。

保存后重新加载:

python
reloaded = AutoModel.from_pretrained("./my-bert")
print(type(reloaded).__name__)

输出:

BertModel

from_pretrained 的入参可以是 Hub 模型 id,也可以是本地目录——两处对调用方完全透明,这就是第 2 章说的「统一接口」。

3.3 结构与权重分离:随机初始化 ​

有时你不想用预训练权重,而是按结构随机初始化一个新模型。用 AutoConfig 或具体 Config 类描述结构,再传给模型类:

python
from transformers import BertConfig, BertModel

config = BertConfig(hidden_size=64,
                    num_hidden_layers=2,
                    num_attention_heads=2,
                    intermediate_size=128,
                    vocab_size=1000)

model = BertModel(config)
print("随机初始化模型参数:", sum(p.numel() for p in model.parameters()))

输出:

随机初始化模型参数: 168128

因为结构由 config 决定、权重随机生成,所以「加载」与「初始化」在 transformers 里是两件不同的事:

操作代码结果
加载预训练权重AutoModel.from_pretrained(id)结构与权重都来自 checkpoint
随机初始化BertModel(config) / from_config(config)结构来自 config,权重随机

3.4 控制加载精度:dtype ​

大模型按 fp32 加载占显存大,常用半精度(bf16/fp16)加载。v5 用 dtype 参数(旧写法 torch_dtype 已弃用):

python
import torch
from transformers import AutoModel

model = AutoModel.from_pretrained("google-bert/bert-base-uncased",
                                  dtype=torch.bfloat16)
print(next(model.parameters()).dtype)

输出:

torch.bfloat16

要点:

  • torch.bfloat16:范围大、精度低,现代 GPU(NVIDIA Ampere 及以后)友好,训练常用。
  • torch.float16:范围小,可能出现溢出,推理常用。
  • 加载后仍可 .to("cuda") 移动设备。

3.5 解读 LOAD REPORT ​

transformers v5 在加载权重时会打印一份报告。以「用 BERT 主干加载分类头」为例:

[transformers] BertForSequenceClassification LOAD REPORT from: prajjwal1/bert-tiny
Key                       | Status     |
--------------------------+------------+-
cls.predictions.bias      | UNEXPECTED |
cls.seq_relationship.bias | UNEXPECTED |
classifier.weight         | MISSING    |
classifier.bias           | MISSING    |

Notes:
- UNEXPECTED: can be ignored when loading from different task/architecture
- MISSING: those params were newly initialized because missing from the checkpoint

两类状态的含义:

  • UNEXPECTED:checkpoint 里有、但当前模型结构用不上的权重(这里是预训练 MLM 头的权重)。加载「不同任务/架构」时出现属正常,可忽略。
  • MISSING:当前模型结构需要、但 checkpoint 里没有的权重——被随机初始化了。微调前看到分类头 MISSING 是正常的,这正是你要训练的部分。

训练前先看一遍 LOAD REPORT,能立刻发现「模型头选错」或「权重没加载上」的问题。

动手实践 ​

  1. 下载一个模型(如 prajjwal1/bert-tiny),打印 LOAD REPORT,解释每个 MISSING/UNEXPECTED 来自哪里。
  2. 用 BertConfig 自定义一个 hidden_size=32, num_hidden_layers=1 的迷你 BERT,保存到本地,再加载回来,对比两次打印的参数数量。
  3. 用 dtype=torch.float16 加载 bert-tiny,统计模型一半以上参数是否为 fp16。

常见错误 ​

错误 1:模型 id 拼错或模型 config 缺字段。

transformers v5 的 AutoConfig 要求 config.json 里有 model_type。某些老仓库(如 prajjwal1/bert-tiny)缺少该字段,AutoModel.from_pretrained 直接报:

ValueError: Unrecognized model in prajjwal1/bert-tiny. Should have a `model_type` key in its config.json.

解决:用显式类 + 显式 config 加载:

python
from transformers import BertConfig, BertForSequenceClassification
config = BertConfig.from_pretrained("prajjwal1/bert-tiny", num_labels=2)
model = BertForSequenceClassification.from_pretrained("prajjwal1/bert-tiny", config=config)

错误 2:用 torch_dtype=(旧参数)。

[transformers] `torch_dtype` is deprecated! Use `dtype` instead!

v5 中改为 dtype=。

错误 3:以为保存目录可以删掉 config.json。

没有 config.json,from_pretrained 无法重建结构,加载必然失败。config 与权重都要保存。

章末练习 ​

基础

  1. 保存 bert-tiny 到本地目录,列出目录所有文件,并说明每个文件的作用。
  2. 用 BertConfig(hidden_size=32, num_hidden_layers=1, num_attention_heads=2, intermediate_size=64, vocab_size=500) 随机初始化模型,打印参数量。

提高

  1. 分别用 AutoModel 与 AutoModelForSequenceClassification 加载 prajjwal1/bert-tiny,对比两次 LOAD REPORT 的差异,写出解释。
  2. 用 dtype=torch.bfloat16 加载 bert-tiny,把模型移到 GPU(如果可用),做一次前向并打印输出 dtype。

挑战

  1. 实现函数 load_or_init(model_id, config):AutoConfig.from_pretrained 成功则从 checkpoint 加载,失败则用传入的 config 随机初始化,并打印提示。

章末自测 ​

  1. model.safetensors 文件里存的是什么?
  2. from_pretrained 能接受哪两类路径?
  3. LOAD REPORT 中 MISSING 状态意味着什么?
  4. v5 中控制加载精度的参数是 torch_dtype 还是 dtype?
  5. 随机初始化模型时,结构由谁决定?
  6. 判断:没有 config.json 也能用 from_pretrained 加载模型。