SafeTensors vs GGUF:大模型权重格式的硬核拆解

如果你在 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:

java 复制代码
| 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):

rust 复制代码
| "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

存:

python 复制代码
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"}})

全量读:

python 复制代码
from safetensors.torch import load_file
t = load_file("m.safetensors")

惰性/零拷贝读大文件:

python 复制代码
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 直接跑:

bash 复制代码
./llama-cli -m model-q4_k_m.gguf -p "explain gguf" -n 100

部分层卸到 GPU:

bash 复制代码
./llama-cli -m model.gguf -ngl 35

Ollama 导入本地文件,写 Modelfile:

bash 复制代码
FROM ./model-q4_k_m.gguf
bash 复制代码
ollama create mymodel -f Modelfile
ollama run mymodel

Python 侧若只想读元数据/权重,用 gguf 包:GGUFReader 解析,gguf.quants.dequantize() 反量化。

4. 互相转换

Safetensors → GGUF

主线走 llama.cpp 自带脚本,两阶段(先转 F16,再量化):

bash 复制代码
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

官方无正向工具,社区脚本本质是"反量化 + 重存":

python 复制代码
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 做实验时用,且接受有损。
相关推荐
Bazingga13 分钟前
Java16 record 完整拆解——语法、语义、限制、反射
java·后端
第404号工位14 分钟前
40块钱二手瘦客户端,如何跑满家庭物联网中枢?(拒绝Docker爆盘实录)
linux·架构·node.js
对象存储与RustFS14 分钟前
网盘限速逼你开会员?用 RustFS 自己搭一个不限速的“私人网盘
服务器·后端·docker
Thneonl17 分钟前
你写的 NetworkPolicy 可能一条都没生效
后端·架构
王中阳Go19 分钟前
质保期第 90 天我翻了一遍日志目录:交付后真正会坏的 3 处
人工智能·后端·agent
卷无止境41 分钟前
一人公司的全栈选型指南:让 AI Agent 写得快,也让生意跑得稳
后端·python
桃西西呀1 小时前
我把整本接口文档塞进 system prompt,前 3 轮答得准,第 8 轮开始胡说,账单还翻了 4 倍
人工智能·llm·ai编程
天天代码码天天1 小时前
给孩子打印一本“数字连点画”!连出小鱼、火箭,画完还能涂色
人工智能
SL_staff2 小时前
规则联动:给工厂装上‘自动化神经反射弧’——JVS·物联网平台规则引擎实战教程
java·人工智能·物联网
众壹新能源科技2 小时前
逆变器自带无功不够用,加装5MVar SVG后功率因数从0.85回到0.99
运维·人工智能·自动化