必须用 load_file 加载 .safetensors 文件,因 torch.load 依赖 pickle 反序列化,而该格式是纯张量二进制,强行使用会触发 UnpicklingError、返回空字典或卡死,且部分 transformers 版本会静默 fallback 导致加载失败。

直接用 load_file,别碰 torch.load —— 后者对 .safetensors 文件会报错或静默退化为 CPU 加载。
为什么不能用 torch.load 加载 .safetensors 文件
PyTorch 的 torch.load 默认依赖 pickle 反序列化,而 .safetensors 是纯张量二进制格式,不含 Python 对象结构。强行用 torch.load("model.safetensors") 通常会触发 UnpicklingError 或返回空字典,甚至在某些旧版 PyTorch 中直接卡死。
更隐蔽的问题是:部分 transformers 版本(如 4.36 以下)在 from_pretrained() 中未显式识别 .safetensors 后缀时,会 fallback 到 torch.load,导致加载失败却不报具体错误。
- 典型错误信息:
OSError: Unable to load weights for 'xxx'. Error: invalid load key - 真实原因:不是文件损坏,而是加载器“不认识”这个格式
- 验证方法:用
file model.safetensors查看输出是否含safetensors字样,而非data或Python
正确加载方式:load_file + device 显式指定
load_file 是 safetensors.torch 提供的专用函数,支持按需读取、设备直送、零拷贝解析。关键点在于显式控制张量目标设备,避免先上 CPU 再搬运到 GPU 的冗余步骤。
立即学习“Python免费学习笔记(深入)”;
示例代码:
from safetensors.torch import load_file
import torch
<h1>直接加载到 GPU(假设 device='cuda:0')</h1><p>state_dict = load_file("model.safetensors", device="cuda:0")</p><h1>或加载到 CPU 后再映射(适合显存紧张场景)</h1><p>state_dict = load_file("model.safetensors", device="cpu")
model.load_state_dict(state_dict)
model.to("cuda:0")</p>-
device参数必须是字符串(如"cuda:0"),不支持torch.device实例 - 若模型含 BF16 权重(如 Z-Image),
load_file会自动保留 dtype,无需额外转换 - 不加
device参数默认加载到 CPU,容易引发后续model.to("cuda")时的 shape mismatch 错误
多分片模型(model-00001-of-00004.safetensors)怎么合并加载
分片文件不能直接传给 load_file——它只认单个完整文件。但你也不必手动拼接,transformers 从 4.38+ 开始已原生支持分片 safetensors 自动合并,前提是路径下有 model.safetensors.index.json 索引文件。
如果缺失索引文件(常见于手动下载分片),必须先生成它:
from safetensors.torch import save_file, load_file
import json
import os
<h1>假设分片在 ./shards/ 目录下</h1><p>shard_files = sorted([f for f in os.listdir("./shards") if f.endswith(".safetensors")])
merged_state_dict = {}</p><p>for shard in shard_files:
shard_path = os.path.join("./shards", shard)
merged_state_dict.update(load_file(shard_path, device="cpu"))</p><h1>保存为单个文件(可选)</h1><p>save_file(merged_state_dict, "model.safetensors")</p><h1>生成 index.json(必需!否则 from_pretrained 不认)</h1><p>index = {"metadata": {"total_size": sum(v.numel() * v.element_size() for v in merged_state_dict.values())}, "weight_map": {}}
for k, v in merged_state_dict.items():
index["weight_map"][k] = "model.safetensors"
with open("model.safetensors.index.json", "w") as f:
json.dump(index, f, indent=2)</p>- 跳过索引生成直接调用
from_pretrained("./shards")会导致 KeyError 或只加载第一个分片 - 分片加载本身不提速,但能降低峰值内存——
load_file每次只读一个分片,而非全量 - 合并后文件体积 ≈ 原分片总和,无压缩损耗
加载后校验权重完整性很关键
快速加载不等于加载正确。Safetensors 虽无代码执行风险,但传输中断、磁盘坏道、权限问题仍会导致张量截断。最简单的校验是比对 tensor shape:
例如,已知模型应有 model.layers.0.mlp.up_proj.weight,shape 为 torch.Size([2048, 4096]),加载后立即检查:
if "model.layers.0.mlp.up_proj.weight" not in state_dict:
raise ValueError("Missing expected key")
if state_dict["model.layers.0.mlp.up_proj.weight"].shape != (2048, 4096):
raise ValueError("Shape mismatch for up_proj.weight")
- 不建议依赖
model.num_parameters()校验——它统计的是当前 model 实例参数,不是 state_dict 中实际加载的张量 - SHA256 校验应在加载前做(如用
hashlib.sha256(open("model.safetensors","rb").read()).hexdigest()),加载后无法回溯原始文件一致性 - 遇到
unexpected key in state_dict,大概率是模型类定义与权重键名不匹配,不是 safetensors 本身的问题


















