Transformers 现在支持直接运行 llama.cpp 的 GGUF 量化模型
GGUF 文件格式是什么?
GGUF 是由 llama.cpp 团队开发的一种文件格式,它把模型权重、分词器信息,甚至可选的聊天模板都打包进一个文件里。这种格式最大的特点是支持多种量化级别,让你可以用一点精度换更小的内存占用。
比如 Unsloth 发布的 Qwen3.5-4B 模型,不同量化版本的大小差异很明显:
BF16(未量化):8.42 GBQ6_K:3.53 GBQ5_K_M:3.14 GBQ4_K_M:2.74 GB
像 Q4_K_M 这种混合精度方案,大部分权重用 4-bit,但对敏感层保留更高精度,是本地运行的一个实用起点。如果你机器内存够,可以试试 Q5_K_M 或 Q6_K。不过具体效果还得看你实际要跑的任务,别光看数字。
用 Transformers 加载 GGUF 模型
想尝鲜,你得有台 Apple Silicon 的 Mac,并装上最新版的 PyTorch 和 Transformers(目前得从 main 分支安装)。加载过程出乎意料地简单,只需要在 from_pretrained 时指定 gguf_file 参数就行。
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
)后面就完全是标准的 Transformers API 了,聊天模板、生成文本,一切照旧。库会自动检测并加载兼容的 ggml/Metal 内核来处理量化权重。如果没找到合适的内核,它会回退到先解量化再运行的模式,但这样会吃更多内存。
用你喜欢的界面来服务 GGUF 模型
除了在脚本里跑,你还能用 transformers serve 命令启动一个 OpenAI 兼容的 API 服务。这样,像 Jan 或 Pi 这样的客户端就能直接连上你本机的模型了。
transformers serve "unsloth/Qwen3.5-4B-GGUF:Qwen3.5-4B-Q4_K_M.gguf"命令里的冒号分隔了模型仓库 ID 和具体的文件名,方便你在同一个仓库里切换不同量化版本。对于支持“思考”模式的模型,还可以通过 --reasoning 参数来开关这个功能。
和 llama.cpp 的性能对比
大家最关心的肯定是速度。毕竟 llama.cpp 是本地推理的标杆。官方在一台 M2 Max MacBook Pro 上做了基准测试,对比了三个不同规模的 GGUF 模型。
结果显示,Transformers 的性能已经非常接近 llama.cpp 了。测试用的是生成 128 个新 token 的速率。需要注意的是,Transformers 的测量包含了预填充(prefill)阶段,而 llama.cpp 的 llama-bench 工具默认只测解码(decode)阶段,所以 Transformers 的数据其实更“吃亏”一点。即便如此,差距依然很小,这说明这套方案是靠谱的。
Transformers 和 llama.cpp 的关系
这次集成并不是要取代 llama.cpp。官方明确说了,如果你追求极致的本地推理效率,llama.cpp 依然是首选。它的专用运行时、内存管理和广泛的硬件支持都是围绕这个目标打造的。
那么 Transformers 支持 GGUF 的意义在哪?在于灵活性和可编程性。你现在可以在熟悉的 Python/PyTorch 环境里:
- 实验和调试:用钩子(hooks)检查中间激活值,或者修改模型的前向传播逻辑。
- 评估模型:用现有的 Transformers 评估流程来测试量化模型的质量。
- 验证转换:同时加载原始模型和 GGUF 版本,方便检查转换是否正确。
- 尝试新解码策略:使用自定义的 logits 处理器或停止条件。
- 微调模型:通过设置
dequantize=True,可以把量化权重解压成浮点数,然后接着用标准流程微调。
超越 GGUF:让 ggml 内核加速更多模型
更大的机会其实在于,把 ggml 高性能的内核带给那些 llama.cpp 还不支持的模型架构。
Transformers 本身就实现了大量模型。现在有了这些 PyTorch 可用的 ggml 内核,我们就有机会在不重写整个模型到 llama.cpp 的前提下,加速其中的关键操作。这对于新出的研究模型、自定义变体尤其有用。这条路甚至能通向多模态领域,比如视觉或音频模型,只要它们用到了兼容的注意力、归一化或矩阵乘法操作。
在 Python 和 PyTorch 里实现快速本地推理
这次工作的核心目标之一,就是证明一件事:只要内核够快、生成循环够高效,纯 Python 和 PyTorch 也能跑出强劲的本地推理性能。他们刻意避开了 torch.compile,就是为了保证交互体验的流畅——没有编译等待,输入长度变了也不用重新编译。
复用 ggml 的 Metal 内核
关键在于那几个从 ggml 借来的 Metal 内核,它们被封装在 kernels 库里,可以从 Hugging Face Hub 直接安装。
ggml-quantization:直接读取打包好的量化权重做矩阵运算,省去了每次解压整个权重矩阵的开销。ggml-norm:融合了归一化操作,特别针对 Qwen 系列用的零中心 RMSNorm。ggml-attn:提供了 ggml 的 Metal 闪存注意力实现。ggml-gated-delta-net:加速 Qwen3.5/3.8 混合架构里的门控 Delta 网络。topk:这是 Transformers 团队自己写的 Metal 内核,用于 MoE 模型中高效地选择专家。
把这些内核关掉再跑一遍,性能差距立竿见影,足见它们的贡献。
让 CPU 和 GPU 协同工作
光有快内核还不够,得让 GPU 一直有活干。之前的生成循环里有些不必要的同步点,会让 CPU 干等着 GPU 完事,每生成一个 token 就等一下,累积起来就很伤吞吐量。
为此,他们在 generate 函数里做了两个关键优化:
- 提前丢弃无用的注意力掩码:对于没有填充(padding)的输入,那个全 1 的掩码其实在生成一开始就可以扔掉,省得后面每次注意力计算都要检查一遍。
- 推迟停止检查:把判断是否停止生成的逻辑异步化,CPU 不用等 GPU 返回结果,可以立刻去安排下一步的计算。
这两个改动不仅对 GGUF 模型有效,对所有 Transformers 模型的生成速度都有提升。它们和内核优化是相辅相成的:内核降低了单次操作的成本,而减少同步点则让 CPU 和 GPU 能更好地并行工作。
当前限制和下一步计划
目前这个功能还处于早期阶段,有几个明显的边界:
- 仅限 Apple Silicon (MPS):打包推理路径现在只在 Mac 上可用。其他设备还是得走解量化那条老路。
- 批处理和填充支持不足:现在的优化主要针对单条、无填充的输入。带填充的批处理还不能享受同样的性能红利。
- 架构覆盖有限:目前只支持 Qwen3.5(包括稠密版和 MoE 版)以及兼容的 Qwen3.8 模型。
官方表示会逐步扩展支持的架构。如果你有特别想在 Transformers 里跑的 GGUF 模型,不妨去 GitHub 开个 issue,告诉他们你的用例,这能帮助他们排定优先级。