返回 文章 apply CMS 文章

Transformers 现已支持 llama.cpp 的 GGUF 量化模型

transformers 集成 GGUF 量化,让本地推理在 Python 中也能接近 llama.cpp 性能。

transformersGGUFllama.cpp量化
成长分 / 100 78 综合收获、行动、留存与影响

Transformers 现已支持 llama.cpp 的 GGUF 量化模型
为什么值得读了解如何在 transformers 中直接加载 GGUF 量化模型,无需额外配置即可在 Apple Silicon 上运行。

掌握量化级别(如 Q4_K_M)对模型大小和精度的影响,以及如何选择适合自己机器的版本。

关键洞察
  1. transformers 通过 kernels 库复用 llama.cpp 的 ggml 内核,在 Apple Silicon 上实现接近 llama.cpp 的推理性能。
  2. GGUF 格式将模型权重和元数据打包在一个文件中,支持多种量化级别,Q4_K_M 是本地推理的实用起点。
  3. generate 循环的优化(异步停止决策、减少同步)提升了所有 transformers 模型的生成速度,不仅限于 GGUF。
转成行动

深入阅读

正文与原文对照

原文保真覆盖:全文原文字符:14297

图像-文本转文本 • 4B • 已更新 • 908k • 433

from_pretrained

,然后在你自己的机器上开始生成。

在笔记本电脑上运行 AI 模型已经变得容易得多,而 llama.cpp 在其中发挥了重要作用。它的推理引擎为 Ollama、LM Studio 和 Jan 等本地 AI 工具提供支持。与 MLX 等项目一起,它帮助本地推理成为日常使用的实用选择。

本地 AI 体验的一个近期例子:

这就是我们目前的进展。说实话,感觉相当神奇 🧙‍♀️

— Julien Chaumond (@julien_c)

Qwen3.6 27B 通过 Llama.cpp 在 MacBook Pro 上的 Pi 编程代理中运行

对于[@huggingface]代码库上的非平凡任务,这感觉非常非常接近 Claude 中最新的 Opus……[pic.twitter.com/lsIxLoUneU][2026年4月24日]

GGUF 由 llama.cpp 团队开发,是一种广泛用于本地推理的格式。该团队还在 Hub 上的 ggml-org 下分享量化检查点。UnslothLM Studio Communitybartowski 等发布者也提供各种量化的即用型 GGUF 检查点,因此用户可以选择适合自己机器的版本。GGUF 模型已被下载数百万次。

我们也希望让使用 transformers 在本地运行这些模型变得更加容易。只有当模型运行起来令人愉快时,兼容性才有用。为了让性能接近 llama.cpp,我们通过 kernels 库复用其底层的 ggml 内核,并减少

generate

中的开销。我们最初的重点是在 Apple Silicon 上进行本地推理,从 Qwen3.5 架构开始。GGUF 将模型权重和元数据(包括分词器信息和可选的聊天模板)打包在一个文件中。它支持不同的量化级别,让你可以用一些精度换取更小的内存占用。诸如 Q4_K_M

之类的变体混合了张量精度,主要使用 4 位权重,同时将敏感张量保持在更高精度。

以下是量化如何改变 Unsloth 的 Qwen3.5-4B 文件大小:

GGUF 变体 文件大小 权衡
BF16
8.42 GB 未量化参考
Q6_K
3.53 GB 比更小的变体精度更高
Q5_K_M
3.14 GB 大小与精度之间的折中
Q4_K_M
2.74 GB 本地推理的实用起点

我们建议从 Q4_K_M

开始,然后如果你有更多可用内存,再尝试 Q5_K_M

Q6_K

。更激进的量化可以帮助更大的模型适配,但质量权衡取决于模型和任务。请在你实际希望模型完成的工作上评估它。Hub 的 GGUF 文档描述了可用的量化类型。

要开始使用,你需要:

kernels

pip install -U "git+https://github.com/huggingface/transformers.git" kernels

要加载 GGUF 模型,请将其 Hub model_id

和文件名作为 gguf_file

传给 from_pretrained

无需额外配置:当权重在 Metal 上保持打包状态时,transformers 会自动加载兼容的 ggml/Metal 层内核,并使用 ggml-org/ggml-attn

作为注意力实现。如果无法获取该内核,模型会回退到 "sdpa"

并给出警告,你也可以随时通过显式传入 attn_implementation="sdpa"

来强制使用 "sdpa"

。更多加载选项请参阅 GGUF 文档

import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id = "unsloth/Qwen3.5-4B-GGUF"
filename = "Qwen3.5-4B-Q4_K_M.gguf"
tokenizer = AutoTokenizer.from_pretrained(model_id, gguf_file=filename)
model = AutoModelForCausalLM.from_pretrained(
model_id,
gguf_file=filename
)

这是唯一一个 GGUF 特有的步骤。之后的全部内容都是标准的 transformers API:

messages = [{"role": "user", "content": "Explain why the sky is blue in a few sentences."}]
inputs = tokenizer.apply_chat_template(
messages,
tokenize=True,
add_generation_prompt=True,
return_dict=True,
return_tensors="pt",
).to(model.device)
with torch.inference_mode():
outputs = model.generate(**inputs, max_new_tokens=256)
print(tokenizer.decode(outputs[0], skip_special_tokens=True))

如果没有兼容的量化内核,加载器会回退到对模型进行反量化,并占用更多内存。

你也可以将同一个检查点与 transformers serve 一起使用,它会暴露一个与 OpenAI 兼容的 API:

pip install -U "transformers[serving] @ git+https://github.com/huggingface/transformers.git" kernels
transformers serve "unsloth/Qwen3.5-4B-GGUF:Qwen3.5-4B-Q4_K_M.gguf"

model 参数使用 <model_id>:<filename>.gguf 的格式

冒号之前是 Hub 仓库(unsloth/Qwen3.5-4B-GGUF

),冒号之后是要加载的文件(Qwen3.5-4B-Q4_K_M.gguf

)。这会从可能包含多个量化版本的仓库中选择一个特定的量化版本。

对于聊天模板支持思考(thinking)的模型,添加 --reasoning off

可跳过思考,或添加 --reasoning on

以启用思考。默认值 --reasoning auto

会遵循聊天模板的默认设置。详情请参阅推理选项

你可以通过添加一个自定义的 OpenAI 兼容提供程序来连接诸如 JanPi 之类的客户端,设置如下:

设置
Base URL http://localhost:8000/v1
Model ID unsloth/Qwen3.5-4B-GGUF:Qwen3.5-4B-Q4_K_M.gguf

transformers 在你的 Mac 上运行模型,而客户端提供对话界面。其他支持此 API 的客户端也可以使用同一个端点。

我们衡量本地推理性能的参照是 llama.cpp。下面的比较聚焦于三个 GGUF 检查点:一个小型稠密模型、一个较大的稠密模型,以及一个混合专家模型。

llama.cpp 一列的数据来自 llama-bench 工具(构建版本

5f55650a7

,发布版 b10200,来自 ggml 0.18.0 的 Metal 后端),以 llama-bench -m <file> -p 0 -n 128 -r 3

运行,报告的是 tg128

:在 128 个解码 token 上的 token 生成速率,取三次重复的平均值,不包含提示处理。transformers 一列是 generate

从 12 个 token 的提示生成同样的 128 个 token,取三次预热运行中的最佳值,且包含预填充。在 MacBook Pro M2 Max、32 GB 统一内存、macOS 26.6、PyTorch 2.12.1、kernels 0.17.0、接通电源的条件下测得。

import time
import torch
from transformers import AutoModelForCausalLM, AutoTokenizer
model_id, filename = "unsloth/Qwen3.5-4B-GGUF", "Qwen3.5-4B-Q4_K_M.gguf"
model = AutoModelForCausalLM.from_pretrained(model_id, gguf_file=filename)
tokenizer = AutoTokenizer.from_pretrained(model_id, gguf_file=filename)
inputs = tokenizer("The capital of France is Paris. The capital of Germany is", return_tensors="pt")
inputs = inputs.to(model.device)
with torch.inference_mode():
model.generate(**inputs, max_new_tokens=8, min_new_tokens=8, do_sample=False) # warm up
torch.mps.synchronize()
for _ in range(3):
time.sleep(90) # let the machine cool: back-to-back runs decay by 10% or more
start = time.perf_counter()
model.generate(**inputs, max_new_tokens=128, min_new_tokens=128, do_sample=False)
torch.mps.synchronize()
print(f"{128 / (time.perf_counter() - start):.1f} tok/s")

对于另一列:

llama-bench -hf unsloth/Qwen3.5-4B-GGUF:Q4_K_M -p 0 -n 128 -r 3

Transformers 在全部三个检查点上都与 llama.cpp 接近。该图表使用上文所述的相同测量方式;它并不意味着基准测试条件完全相同,因为 Transformers 的测量包含预填充,而 llama-bench

报告的是仅解码吞吐量。

GGML 和 llama.cpp 加入 Hugging Face 时,我们描述了它们互补的角色:llama.cpp 为本地推理提供基础,而 transformers 为模型定义提供基础。GGUF 支持让这两者更加紧密地结合在一起。

当你的优先事项是高效的本地推理时,llama.cpp 仍然是我们推荐的引擎。 其专用运行时、内存管理和广泛的硬件支持都是围绕这一目标构建的。这一集成让开发者可以方便地在 transformers 中使用相同的 GGUF 检查点:

generate

,或者用 Python 编写你自己的生成循环。对于后一种情况,请使用 GgufConfig(dequantize=True)

import torch
from transformers import AutoModelForCausalLM, GgufConfig
model = AutoModelForCausalLM.from_pretrained(
"unsloth/Qwen3.5-4B-GGUF",
gguf_file="Qwen3.5-4B-Q4_K_M.gguf",
quantization_config=GgufConfig(dequantize=True),
dtype=torch.bfloat16,
)

更大的机会在于将 ggml 的性能带给 llama.cpp 不支持的模型。

transformers 已经提供了这些架构的 PyTorch 实现。借助 PyTorch 中可用的 ggml 内核和量化方案,我们可以致力于加速其支持的操作,而无需先在 llama.cpp 中实现整个模型。这对于新架构、研究模型以及可能永远不会获得专用 llama.cpp 实现的自定义变体尤其有用。

这个机会超越了 GGUF 格式本身。内核作用于张量;它不要求整个模型来自 GGUF 文件。相同的构建块可以集成到其他 transformers 模型和加载工作流中。这也为其他模态开辟了道路:计算机视觉模型、音频模型和多模态模型可以复用兼容的注意力、归一化和矩阵乘法内核,而无需先在 llama.cpp 中拥有完整实现。每个架构仍然需要集成和验证;这里的初始 GGUF 示例涵盖文本生成。

我们还希望展示在将模型和生成循环保持在 Python 中的情况下能走多远。有了合适的内核和高效的生成循环,Python 和 PyTorch 可以提供强大的本地推理性能。 内核处理繁重的计算,而生成循环通过避免不必要的同步来保持 GPU 忙碌。

我们的重点是让 eager 执行变得快速,而不需要 torch.compile

。对于交互式使用,我们希望快速启动并稳定输出 token,没有编译暂停或输入形状变化时的重新编译。这项工作的两个主要部分是内核和 generate

本身。

内核是在 GPU 上执行操作的小程序。PyTorch 提供通用实现;专用内核可以完成更少的工作、组合多个操作,或直接以存储格式读取量化权重。

kernels

库让我们能够在 Hub 上分发 ggml 的 Metal 内核的兼容构建,并从 transformers 中调用它们。这将 ggml 的工作带入 PyTorch 模型,而无需用单独的推理运行时替换模型。

内核 功能
ggml-quantization

ggml-norm

ggml-attn

ggml-gated-delta-net

topk

前四个包基于 ggml 的内核构建;top-k 内核解决了 MoE 路由中的另一个瓶颈。它们共同减少了每个生成 token 所需的 GPU 工作。

为了展示层内核的贡献,我们比较了相同的打包 GGUF 检查点在启用和不启用它们时的情况。量化内核在两种配置中都保持启用:禁用它还会改变权重的表示方式,并衡量不同的权衡。

更快的内核只有在 GPU 有工作可做时才有帮助。在生成过程中,CPU 调度 GPU 操作并控制产生下一个 token 的循环。从 GPU 读回结果可能会迫使 CPU 等待排队的操作完成。即使每个 token 只等待一小段时间,也会显著降低吞吐量。

generate

中的两项更改解决了这个问题,从而为所有 transformers 模型带来了改进(而不仅仅是在运行 GGUF 文件时):

generate

异步复制停止决策,并在下一步消费它。CPU 可以在 GPU 运行的同时继续调度工作。流式 token 使用相同的方法,任何超出停止条件的额外步骤都会从结果中移除。这些改动改进了模型周围的生成循环,因此它们的用处不仅限于 GGUF。它们与内核工作相辅相成:内核降低单个操作的成本,而更少的同步点则让 CPU 调度与 GPU 执行得以重叠。

这些测量保持所有层内核启用;柱状图隔离出生成循环的改动。

最初的目标是在 Apple Silicon 上进行单次交互式对话。有几点边界需要记住:

generate_batch

在 MPS 上。如果你有一个想在 transformers 中使用的 GGUF 模型,请带着检查点和你的用例提交 issue。这将帮助我们优先支持人们在本地运行的模型。

我们要感谢 Arthur Zucker 发起这项工作并审阅了我的所有 PR,以及 Cyril Vallezgenerate

PR 的贡献。我们感谢 Sayak Paulllama.cpp 团队 和 Bertrand Chevalier 在集成内核方面的帮助。我们也感谢 Aritra Roy GosthipatyPedro Cuenca 审阅这篇博文,以及 Lysandre Debut 监督该项目。