必须用 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 的冗余步骤。
示例代码:
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><div class="aritcle_card flexRow artxards">
<div class="artcardd flexRow">
<a class="aritcle_card_img" rel="nofollow" href="/xiazai/skill8910" title="361SCAN security check your skill python scripts"><img
src="https://img.php.cn/upload/skill/000/000/081/179231049778675.jpg" alt="361SCAN security check your skill python scripts" onerror="this.onerror='';this.src='/static/lhimages/moren/morentu.png'" ></a>
<div class="aritcle_card_info flexColumn">
<a rel="nofollow" href="/xiazai/skill8910" title="361SCAN security check your skill python scripts" class="overflowclass">361SCAN security check your skill python scripts</a>
<p class="overflowclass">扫描并分析已安装技能,用于查看指定技能目录的名称、描述和详情,或列出所有已安装的技能。</p>
</div>
<a rel="nofollow" href="/xiazai/skill8910" title="361SCAN security check your skill python scripts" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span>
</a>
</div>
</div><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 本身的问题
Python免费学习笔记(深入):立即使用
在学习笔记中,你将探索 Python 的核心概念和高级技巧!










