如果你在 Hugging Face 上拉过模型,大概率见过 .safetensors;如果你在笔记本上跑过 llama.cpp、Ollama 或 LM Studio,一定见过 .gguf。两者都号称“安全”、都支持 mmap,但设计目标几乎正交:Safetensors 是 PyTorch/Hugging Face 生态的 pickle 替代品,GGUF 是 llama.cpp 生态的量化推理容器。下面按来源、架构、使用、互转四条线拆开讲。
1. 来源
Safetensors
由 Hugging Face 于 2022 年推出,动机非常单一:替代 PyTorch 基于 pickle 的 .bin/.pt 检查点。pickle 反序列化时会执行任意 Python 代码,加载来源不明的模型等于给攻击者开 shell。Safetensors 把“权重文件”严格降级为“数据文件”,反序列化零代码执行。2026 年它并入 Linux 基金会旗下的 PyTorch 基金会,成为中立治理项目。
GGUF
由 Georgi Gerganov 与 llama.cpp 社区于 2023-08-21 发布,用来取代早期的 GGML/GGMF/GGJT 系列。GGML 时代超参和 tokenizer 是硬编码进 loader 的,每加一个新架构(Falcon、MPT、Llama2 GQA)就得改解析器还破坏旧文件兼容。GGUF 用统一 KV 元数据块解决扩展性,当前规范到 version 3。
2. 架构
Safetensors 磁盘布局
小头 + 裸 buffer:
| u64 LE : header_len | JSON header (utf-8) | raw tensor bytes |
- JSON header 内含
__metadata__特殊键,以及每个张量的dtype/shape/offsets([begin,end)相对 buffer 起点)。 - header 长度硬上限 100 MB,解析时校验 offset 不越界、不重叠。
- dtype 覆盖 U8–U256、I8–I256、F16/F32/F64/F128、BF16、FP8 等。
- Rust core 是
no_std友好,反序列化返回借用原 buffer 的 view,可做零拷贝 mmap;写文件走 tempfile + atomic rename,macOS 上用F_NOCACHE直 IO。 - 它本身不定义量化:存的是完整精度张量,GPTQ/AWQ/FP8 是上层旁挂。
GGUF 磁盘布局
magic + version + 三段变长区,全 little-endian(v3 前隐式 LE,v3 可选 BE):
| "GGUF" 4B | u32 version | u64 tensor_count | u64 kv_count |
| KV metadata block |
| tensor info block |
| aligned tensor payload (default 32B align) |
- KV 元数据类型化:key 是 length-prefixed UTF-8,value 带显式 type tag(i/u/f/bool/str/数组)。
- 命名空间约定:
general.architecture、llama.*、tokenizer.ggml.*等,loader 不认识 key 就跳过,向前兼容。 - tensor info 记录 name、ndim、dims[]、GGML quant type(如 10=Q2_K)、offset。
- 量化是格式的一等公民:blockwise 量化,经典块 32 元素,超级块 256 元素;Q4_0/Q8_0 单 FP16 scale,K-quant(Q4_K/Q5_K/Q6_K)超级块带 FP16 主 scale + 子块 scale/min,i-quant(IQ*)用校准集算 importance matrix 做非均匀码本。
关键差异一览
| 维度 | Safetensors | GGUF |
|---|---|---|
| 定位 | 权重存储格式 | 推理容器(权重+tokenizer+超参+量化) |
| 单文件自包含 | 否,常配合 config.json 分片 | 是 |
| 原生量化 | 否 | 是(Q2–Q8、K-quant、i-quant) |
| 代码执行 | 无 | 无 |
| mmap 友好 | 是 | 是(32B 对齐) |
| 主生态 | Transformers/vLLM/TGI | llama.cpp/Ollama/LM Studio/KoboldCpp |
3. 如何使用
Safetensors
装库:pip install safetensors
存:
import torch
from safetensors.torch import save_file
tensors = {"w": torch.randn(4, 4, dtype=torch.float16)}
save_file(tensors, "m.safetensors",
metadata={"__metadata__": {"train_step": "1000"}})
全量读:
from safetensors.torch import load_file
t = load_file("m.safetensors")
惰性/零拷贝读大文件:
from safetensors import safe_open
with safe_open("big.safetensors", framework="pt", device="cpu") as f:
for k in f.keys():
w = f.get_tensor(k) # 可只取部分张量
BLOOM 在 8×GPU 上加载从 ~10 min 降到 ~45 s 就是靠这个。
GGUF
典型消费端不是 Python,而是 C++ 二进制。
llama.cpp 直接跑:
./llama-cli -m model-q4_k_m.gguf -p "explain gguf" -n 100
部分层卸到 GPU:
./llama-cli -m model.gguf -ngl 35
Ollama 导入本地文件,写 Modelfile:
FROM ./model-q4_k_m.gguf
ollama create mymodel -f Modelfile
ollama run mymodel
Python 侧若只想读元数据/权重,用 gguf 包:GGUFReader 解析,gguf.quants.dequantize() 反量化。
4. 互相转换
Safetensors → GGUF
主线走 llama.cpp 自带脚本,两阶段(先转 F16,再量化):
git clone https://github.com/ggml-org/llama.cpp && cd llama.cpp
pip install -r requirements.txt
# 阶段1:HF 目录(里面是 safetensors)转 F16 GGUF
python convert_hf_to_gguf.py /path/to/hf-model \
--outfile model-f16.gguf --outtype f16
# 阶段2:量化
./llama-quantize model-f16.gguf model-q4_k_m.gguf Q4_K_M
--outtype 可选 f32/f16/q8_0;更激进的 IQ* 需要先用 llama-imatrix 跑校准集生成重要性矩阵。注意:convert_hf_to_gguf.py 吃的是 HF 模型目录(含 config.json + safetensors 分片),不是单扔一个 .safetensors 就完事;纯单文件场景需自己拼 config。
GGUF → Safetensors
官方无正向工具,社区脚本本质是“反量化 + 重存”:
from gguf import GGUFReader
from safetensors.torch import save_file
import torch
r = GGUFReader("model-q4_k_m.gguf")
out = {}
for t in r.tensors:
arr = t.data # 或调用 gguf.quants.dequantize
if hasattr(t, "dequantize"):
arr = t.dequantize()
out[t.name] = torch.from_numpy(arr.reshape(t.shape))
save_file(out, "model.safetensors")
命令行有 gguf_to_safetensors.py --input m.gguf --output m.safetensors(默认 F16,可 --bf16)。
硬约束:
- 只有源 GGUF 是 F16/F32 时,回转才是近似无损;Q4_K_M/Q5 等量化回转是有损反量化,不会再变回原始训练权重。
- 输出 safetensors 不含 tokenizer/vocab,Transformers 加载还需同目录补
config.json、tokenizer*。 - 新版 GGUF(新 quant type / v3 扩展)可能超出老脚本解析范围,转换前核对 llama.cpp 版本。
5. 怎么选
- 在 Transformers/vLLM/TGI 里做训练、微调、服务端 GPU 推理 → Safetensors,完整精度、零拷贝、Hub 默认。
- 在消费级硬件、CPU/混合卸载、Ollama/LM Studio 本地聊模型 → GGUF,单文件自带 tokenizer,Q4_K_M 通常是最优性价比档。
- 两者不是替代关系:Safetensors 管“权重怎么安全存”,GGUF 管“量化模型怎么跑起来”。常规流水线就是 HF 出 safetensors → llama.cpp 转 GGUF → 量化 → 本地跑;反向只在你要把量化模型拿回 PyTorch 做实验时用,且接受有损。