首页
/ Transformers 中加载 GGUF 模型的原理与实践:gguf_file 参数、反量化机制与架构适配全解

Transformers 中加载 GGUF 模型的原理与实践:gguf_file 参数、反量化机制与架构适配全解

2026-09-06 15:05:45作者:毕习沙Eudora

GGUF 是 GGML 生态的单一文件模型格式,Transformers 允许通过 gguf_file 参数直接把 GGUF checkpoint(含 Q4_0、Q6_K 等量化权重)加载进 PyTorch 模型用于训练与微调。读完本文,你将掌握 GGUF 模型在 Transformers 中的完整加载链路:从 gguf_file 参数解析、GGUF 元数据到 HuggingFace config/tokenizer 的映射,到量化权重的反量化(dequantize to fp32)与架构级权重重排,并能理解官方测试如何验证不同量化类型的加载正确性。

一、GGUF 是什么,为什么 Transformers 要支持它

GGUF 是用于存储 GGML 推理模型的文件格式。GGML 是一个用 C/C++ 编写的快速轻量级推理框架,而 GGUF 是其 checkpoint 格式:一个单文件,同时包含模型元数据(架构参数、tokenizer 词表等)和全部张量权重

GGUF 格式支持大量量化数据类型(完整量化类型列表见 GGUF 官方文档),显著节省内存,使得 Whisper、Llama 这类大模型可以在本地与边缘设备上完成推理。这也是社区在 Hub 上大量发布 *-Q4_K_M.gguf*-Q6_K.gguf 文件的原因。

Transformers 对 GGUF 的定位是**"量化 checkpoint 的回载入口":把 GGUF 中量化存储的权重反量化为 fp32**,得到一个权重完整、与 PyTorch 兼容的模型,用于后续训练或微调。也就是说,GGUF 在这里不是推理加速格式,而是"以低精度文件分发、以全精度加载使用"的桥梁。

提示:支持 GGUF 加载的模型包括 Llama、Mistral、Qwen2、Qwen2Moe、Phi3、Bloom、Falcon、StableLM、GPT2、Starcoder2 等,完整列表可以从源码 GGUF 映射表 的键名得到。

二、基本用法:gguf_file 参数

给 [~PreTrainedModel.from_pretrained] 和 [~PreTrainedTokenizer.from_pretrained] 传入 gguf_file 参数,指定要加载的 GGUF 文件即可。注意需要先安装 gguf 包:

# pip install gguf
import torch
from transformers import AutoTokenizer, AutoModelForCausalLM

model_id = "TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF"
filename = "tinyllama-1.1b-chat-v1.0.Q6_K.gguf"

dtype = torch.float32 # could be torch.float16 or torch.bfloat16 too
tokenizer = AutoTokenizer.from_pretrained(model_id, gguf_file=filename)
model = AutoModelForCausalLM.from_pretrained(model_id, gguf_file=filename, dtype=dtype)

几个要点:

  • gguf_file 既可以是本地文件路径,也可以是 Hub 上的相对文件名model_id 提供仓库定位,gguf_file 指定仓库中具体文件。
  • dtype 参数指定反量化后张量的目标类型,torch.float32 / torch.float16 / torch.bfloat16 均可。若不显式指定,从源码 modeling_utils.py 看,当 checkpoint 文件以 .gguf 结尾时默认按 torch.float32 处理。
  • 加载完成后,得到的就是普通的 PyTorch 模型与 fast tokenizer,可正常训练、generate 与保存。

模型侧的加载链路

from_pretrained 内部对 gguf_file 的处理在 modeling_utils.py 中:

  1. gguf_file 是本地存在的文件,直接作为 resolved archive 使用;
  2. 否则通过 cached_file 从 Hub 下载并缓存该文件;
  3. 权重解析阶段(modeling_utils.py)调用 load_gguf_checkpoint 完成元数据解析与张量反量化,并把结果按 tensors / config / tokenizer / tokenizer_config 四组返回。

load_gguf_checkpoint 的签名为:

def load_gguf_checkpoint(gguf_checkpoint_path, return_tensors=False, model_to_load=None, torch_dtype=None):

其中 return_tensors=True 才会真正读取并反量化张量(只读元数据则更快);model_to_load 用于建立 GGUF 张量名到 Transformers 参数名的映射;torch_dtype 表示"反量化后立即转换到该 dtype 以节省内存"——这与 from_pretraineddtype 参数直接衔接。

Tokenizer 侧的加载链路

tokenizer 的 gguf_file 处理有两条入口:

  • tokenization_utils_base.py 中,from_pretrained 会把 gguf_file 直接注册为 vocab_file,使原本需要多个词表文件的 tokenizer 也能从一个 GGUF 文件构造;
  • tokenization_utils_tokenizers.py 中,fast tokenizer 的构造流程是:cached_file 定位 GGUF 文件 → load_gguf_checkpoint 取出 config["model_type"]tokenizer 字典 → 调用 convert_gguf_tokenizer 重建 backend tokenizer。

三、GGUF 元数据如何变成 HuggingFace config 与 tokenizer

GGUF 文件的元数据以 general.* 与各架构前缀(如 llama.*qwen2.*)的键值组织,且命名风格与 HuggingFace config 完全不同(例如 block_count vs num_hidden_layers)。Transformers 用三张映射表完成翻译,全部定义在 integrations/ggml.pymodeling_gguf_pytorch_utils.py

GGUF_TO_TRANSFORMERS_MAPPING = {
    "ignore": {
        "GGUF": {"version": "version", "tensor_count": "tensor_count", "kv_count": "kv_count"},
        "general": {"file_type": "file_type", "quantization_version": "quantization_version"},
    },
    "config": GGUF_CONFIG_MAPPING,
    "tokenizer": {"tokenizer": GGUF_TOKENIZER_MAPPING["tokenizer"]},
    "tokenizer_config": {"tokenizer": GGUF_TOKENIZER_MAPPING["tokenizer_config"]},
}

架构白名单

GGUF_SUPPORTED_ARCHITECTURES 直接取 config 映射表的键名,即当前支持加载的 GGUF 架构。从 GGUF_CONFIG_MAPPING 可以看到,涵盖:

generalllamamistralqwen2qwen2_moegpt_osslfm2qwen3qwen3_moefalconphi3bloomt5stablelmgpt2starcoder2mambanemotrongemma2gemma3gemma4umt5deciminimax_m2

映射规则以 Llama 为例,展示了 GGUF 键到 HF config 字段的对照:

GGUF 键 HF config 字段
context_length max_position_embeddings
block_count num_hidden_layers
feed_forward_length intermediate_size
embedding_length hidden_size
rope.dimension_count head_dim
rope.freq_base rope_theta
attention.head_count num_attention_heads
attention.head_count_kv num_key_value_heads
attention.layer_norm_rms_epsilon rms_norm_eps
vocab_size vocab_size

各架构还有各自的特例,例如 mamba 映射了 ssm.conv_kernelssm.state_size 等 SSM 字段,gemma4 则把 attention.key_length 映射为 global_head_dim 以表达混合注意力。

架构识别的补丁逻辑

GGUF 中的 general.architecture 字段有时与 HuggingFace 的 model_type 不一致,load_gguf_checkpoint 中有一系列修正规则,可以从中读出当前实现支持的架构细节:

  • llama.cpp 中 Mistral 与 Llama 共用同一 architecture,因此当架构为 llama 且模型名含 mistral 时改写为 mistral
  • T5/UMT5 架构会补 is_gated_act=True,并按 t5encoder 前缀区分 T5EncoderModel / UMT5EncoderModel
  • Gemma3/Gemma4 的 GGUF 只包含文本主干权重,因此 model_type 被改写为 gemma3_text / gemma4_text(Gemma4 还会补全三个 EOG token 的 eos_token_id);
  • StableLM 通过检查张量列表推断配置:存在 attn_q.bias 等张量则 use_qkv_bias=True,存在 ffn_norm 张量则判断 use_parallel_residual
  • tie_word_embeddings 通过张量列表推断:不存在 output.weight 张量则视为 True(Falcon、Bloom 例外)。

此外,若 config 中缺少 vocab_size,实现会回退到从 tokenizer 的 tokens 列表取长度(源码)。

Tokenizer 的恢复

GGUF_TOKENIZER_MAPPING 定义了 GGUF 中 tokenizer 相关字段到 HF 字段的映射:

GGUF_TOKENIZER_MAPPING = {
    "tokenizer": {
        "ggml.model": "tokenizer_type",
        "ggml.tokens": "tokens",
        "ggml.scores": "scores",
        "ggml.token_type": "token_type",
        "ggml.merges": "merges",
        "ggml.bos_token_id": "bos_token_id",
        "ggml.eos_token_id": "eos_token_id",
        "ggml.unknown_token_id": "unk_token_id",
        "ggml.padding_token_id": "pad_token_id",
        "ggml.add_space_prefix": "add_prefix_space",
    },
    "tokenizer_config": {
        "chat_template": "chat_template",
        "ggml.model": "model_type",
        ...
    },
}

拿到这些原始字段后,convert_gguf_tokenizer 按架构选择对应的转换器(GGUF_TO_FAST_CONVERTERS 表)重建 tokenizers 库的 backend:

转换器 适用架构 实现要点
GGUFLlamaConverter llama、deci、decilm BPE 词表 + merges,特殊 token 按 token_type==3 识别;Llama 3 走 byte-level pre-tokenizer 补丁
GGUFQwen2Converter qwen2/qwen3 及其 MoE、minimax_m2 BPE,并补 <|im_start|> 等特殊 token
GGUFPhi3Converter phi3 BPE,补齐 Phi3 系列特殊 token
GGUFGPTConverter bloom、falcon、stablelm、gpt2、starcoder2、mamba、nemotron 复用 GPT2 转换逻辑
GGUFT5Converter t5、umt5 Unigram 词表,</s> 后处理器
GGUFGemmaConverter gemma2/gemma3/gemma4 文本 Unigram,空格用 编码并做词表清洗

一个值得注意的细节:若 checkpoint 中没有 merges 字段,GGUFTokenizerSkeleton 会用 tokensscores 在线重建 merges 列表(枚举所有可合并的 token 对并按分数排序),并打印 "Merges were not in checkpoint, building merges on the fly." 的警告——这解释了为什么部分 GGUF 文件能正常恢复 BPE tokenizer。

四、权重反量化与架构级张量处理

load_gguf_checkpointreturn_tensors=True 时的核心循环是(源码):

  1. GGUFReader 迭代所有张量,对每个张量调用 gguf-py 的 dequantize(tensor.data, tensor.tensor_type)——这一步把 Q4_0、Q6_K、IQ2_XXS 等量化块还原为 fp32 数组
  2. 经过该架构的 TensorProcessor.process() 做必要的形状重排/重命名;
  3. 通过 tensor_key_mapping(GGUF 张量名 → HF 参数名)对齐后,转成 torch 张量,并按需 to(torch_dtype) 存入 parsed_parameters["tensors"]

张量名映射:get_gguf_hf_weights_map

GGUF 张量采用标准命名约定 blk.N.BB.weight/.bias(N 为层号,BB 为组件名)。get_gguf_hf_weights_map 借助 gguf-py 包的 MODEL_ARCH_NAMESget_tensor_name_map(arch, num_layers) 生成 GGUF→HF 的名称映射:先实例化一个空壳 HF 模型拿到全部参数名,逐个查表转换;查不到的交给架构自己的 perform_fallback_tensor_mapping 兜底(常见于 MoE 的一对多映射)。该函数还会递归遍历子模块(如 Bloom 从 BloomModel 而非 BloomForCausalLM 转换而来的 checkpoint),因此要求同时安装 torchgguf>=0.10.0,否则抛出明确的 ImportError。

TensorProcessor:每个架构的差异修正

GGUF 存储的张量布局与 HF 模型期望的并不总是一致,TENSOR_PROCESSORS 注册了各架构的处理器:

处理器 架构 做了什么
LlamaTensorProcessor llama attn_q/attn_k 权重做逆置换(GQA 场景下按 num_key_value_heads 重排),还原 llama.cpp 转换时的 head 间交错布局
Qwen2MoeTensorProcessor qwen2moe、qwen3moe ffn_gate_exps/ffn_up_exps 交错合并进 HF 的 gate_up_proj(第 2 维翻倍,gate 在前、up 在后);共享专家 gate 补维度
GptOssTensorProcessor gpt_oss 把堆叠的专家张量 ffn_down/gate/up_projs 逐专家拆开gate_up_projs 按半宽切分后转置
BloomTensorProcessor bloom 逆还原 attn_qkv 的 QKV 交错 reshape(权重与 bias 分别处理)
T5TensorProcessor t5、t5encoder 从张量名中解析块号 bid 供后续对齐
GPT2TensorProcessor gpt2 attn_qkvffn_down/upattn_output 等权重转置output.weight 特判为 lm_head.weight
MambaTensorProcessor mamba ssm_conv1d 补维度;ssm_alog(-x) 还原指数化存储
NemotronTensorProcessor / Gemma2TensorProcessor nemotron、gemma2/gemma3 norm.weight 减 1(还原 1+weight 式存储)
Lfm2TensorProcessor lfm2 shortconv.conv.weight 补中间维
MiniMaxM2TensorProcessor minimax-m2 同 Qwen2MoE 的 gate/up 交错合并,外加路由 bias 映射

这些"逆操作"的参照实现全部注释指向 llama.cpp 的 convert_hf_to_gguf.py,可以理解为:Transformers 执行的是 llama.cpp 转换脚本的逆向过程

默认值补全

GGUF_CONFIG_DEFAULTS_MAPPING 只补"HF 默认值与 llama.cpp 约定不一致"的参数,例如 qwen3_moenorm_topk_prob=True(HF 默认 False,但 llama.cpp 需要 True)、minimax_m2use_routing_bias=True(GGUF 元数据不存储该开关)。

五、测试如何验证 GGUF 加载

仓库中的 tests/quantization/ggml/test_ggml.py 是这条功能的主测试入口(标注 @require_gguf @require_torch_accelerator @slow,需要加速器与 gguf 包)。其核心方法就是文档示例的最小复现:

def run_gguf_model(self, gguf_model_id: str, gguf_filename: str, expected_text: str):
    tokenizer = AutoTokenizer.from_pretrained(gguf_model_id, gguf_file=gguf_filename)
    model = AutoModelForCausalLM.from_pretrained(gguf_model_id, gguf_file=gguf_filename).to(torch_device)

    text = tokenizer(self.example_text, return_tensors="pt").to(torch_device)
    out = model.generate(**text, max_new_tokens=10)
    self.assertEqual(tokenizer.decode(out[0], skip_special_tokens=True), expected_text)

测试用 TheBloke/TinyLlama-1.1B-Chat-v1.0-GGUF(Q4_0 / Q5_0 / Q8_0 标准量化)与 legraphista/Qwen2.5-0.5B-Instruct-IMat-GGUF(Q2_K~Q6_K 的 K 量化、IQ1_S 等 i-Matrix 量化)做参数化验证:加载后以 "Hello" 为 prompt 生成 10 个 token,并断言解码文本等于预期前缀。这组测试同时覆盖了反量化数值正确性tokenizer 重建正确性——两者必须都正确,生成结果才会命中预期。

六、微调后保存并转回 GGUF

按文档给出的流程,用 Transformers 调整完模型后,先 save_pretrained 存回 HF 格式,再交给 llama.cpp 的 convert-hf-to-gguf.py 转回 GGUF:

tokenizer.save_pretrained("directory")
model.save_pretrained("directory")

!python ${path_to_llama_cpp}/convert-hf-to-gguf.py ${directory}

这与本文描述的加载链路正好构成闭环:load_gguf_checkpoint 里的 TensorProcessor 做的是"GGUF → HF"的逆转换,而 llama.cpp 的转换脚本做的是"HF → GGUF",两者互为逆操作。

七、小结与注意事项

  • 入口AutoModel*.from_pretrained(model_id, gguf_file=filename, dtype=...)AutoTokenizer.from_pretrained(model_id, gguf_file=filename)gguf_file 支持本地路径或 Hub 文件名;依赖 gguf>=0.10.0 与 PyTorch。
  • 加载本质:GGUF 元数据经 GGUF_CONFIG_MAPPING / GGUF_TOKENIZER_MAPPING 翻译为 HF config 与 tokenizer;量化张量经 dequantize 还原为 fp32,再按 TensorProcessor 重排并按 dtype 落地。
  • 架构范围:以 GGUF_CONFIG_MAPPING 的键为准(llama/mistral/qwen 系列/gpt2 系/gemma 系/t5 系/mamba/bloom/stablelm/falcon/phi3 等);遇到不支持的架构会抛出 GGUF model with architecture {architecture} is not supported yet.
  • 精度提醒:从低比特量化文件反量化后,权重已经不可逆地受量化误差影响,因此该流程更适合"以 GGUF 为分发载体的 checkpoint 回载",而非替代原始全精度权重做精细微调;dtype 参数用于控制内存占用。
  • 验证:可参考 tests/quantization/ggml/test_ggml.py 的"加载 + 短生成 + 断言解码文本"模式,对自己的 GGUF 文件做快速自检。

更多背景可继续阅读原文档 GGUF 页面

登录后查看全文
热门项目推荐
相关项目推荐