Hugging Face让Transformers直接跑llama.cpp的GGUF量化模型
初始版本仅支持Apple Silicon、Qwen3.5架构,推荐先用Q4_K_M量化;官方称生成速度已接近llama.cpp,但打包推理路径目前只在MPS上可用。
AI解读:Hugging Face在transformers里加入了对GGUF模型的支持:用户从Hub下载GGUF检查点,用from_pretrained指定gguf_file就能加载并生成,不用再切换到独立的推理运行时。GGUF是llama.cpp团队开发的本地推理格式,Ollama、LM Studio、Jan等工具的推理引擎都基于llama.cpp,这个格式的模型已被下载数百万次。
对普通用户来说,最直接的变化是同一份量化检查点可以在Python和PyTorch里跑,也能用transformers serve暴露成OpenAI兼容API,再接到Jan、Pi这类客户端上。这解决的是以前量化模型只能走llama.cpp生态、难以用transformers工具链调试和评估的问题;代价是现在还只支持苹果芯片和Qwen3.5系列。
性能上官方称接近llama.cpp。它复用了llama.cpp的ggml Metal内核,并把注意力实现切换为ggml-org/ggml-attn,同时改动generate的同步逻辑减少CPU等待。但两边测量条件并不相同:llama-bench只统计 128 个token的解码吞吐,transformers那一侧还包含prefill,所以这组对比不能当严格的同条件基准。
量化档位的取舍写得很具体:Unsloth的Qwen3.5-4B在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;更激进的量化能让大模型塞进机器,但质量损失取决于模型和任务,需要用自己的实际工作负载去测。
想立刻用的人要注意限制:打包推理路径目前只支持MPS,也就是Apple Silicon;带padding的批处理性能会下降,批量生成还在计划中;打包加载器只覆盖Qwen3.5的稠密和MoE架构,以及兼容的Qwen3.8检查点。没有兼容量化内核时,加载器会退回到反量化并占用更多内存。
Hugging Face明确表示llama.cpp仍是其推荐的本地推理引擎,这次集成更像是让开发者能在transformers里实验、评估和验证GGUF检查点,比如检查权重转换是否正确、用自定义logits processor试新的解码方式,或者把GGUF反量化后继续微调。
Hugging Face在官方博客中宣布,transformers现在支持运行GGUF模型,用户可以用熟悉的transformers API加载为笔记本内存准备的量化检查点:从Hub选一个GGUF,用from_pretrained加载,然后在本机生成。
GGUF由llama.cpp团队开发,是该团队使用的本地推理格式。llama.cpp的推理引擎驱动了Ollama、LM Studio、Jan等本地AI工具;llama.cpp团队在Hub的ggml-org下分享量化检查点,Unsloth、LM Studio Community、bartowski等发布方也提供各种量化档位的即用GGUF检查点。博客称GGUF模型已被下载数百万次。
为了把性能做到接近llama.cpp,Hugging Face通过kernels库复用llama.cpp底层的ggml内核,并减少generate中的开销。初始重点放在Apple Silicon上的本地推理,从Qwen3.5架构开始。
GGUF把模型权重和元数据(包括tokenizer信息和可选的chat template)打包在一个文件里,支持不同量化级别,用精度换更小的内存占用。Q4_K_M这类变体混合张量精度,大部分权重用 4 位,敏感张量保留更高精度。
官方给出的文件大小对比(Unsloth的Qwen3.5-4B):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。更激进的量化有助于让更大的模型装下,但质量取舍取决于模型和任务,应在实际想做的任务上评估。
加载与部署方式
开始使用需要:一台Apple Silicon Mac;一个被已发布ggml-quantization内核构建支持的PyTorch版本,通常是最近两个PyTorch版本;最新版transformers(目前是main分支,直到下个版本发布)以及兼容版本的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" 强制使用。
示例代码为:model_id = "unsloth/Qwen3.5-4B-GGUF",filename = "Qwen3.5-4B-Q4_K_M.gguf",用AutoTokenizer.from_pretrained(model_id, gguf_file=filename) 加载tokenizer,用AutoModelForCausalLM.from_pretrained(model_id, gguf_file=filename) 加载模型。这是唯一GGUF特有的步骤,之后都是标准transformers API。
也可以用transformers serve暴露OpenAI兼容API,命令为transformers serve "unsloth/Qwen3.5-4B-GGUF:Qwen3.5-4B-Q4_K_M.gguf";冒号前是Hub仓库,冒号后是要加载的文件,用于在可能包含多个量化的仓库里选定一个。支持思考的chat template可以加 --reasoning off跳过或 --reasoning on启用,默认 --reasoning auto跟随chat template的默认值。客户端如Jan或Pi可以按Base URL http://localhost:8000/v1、Model ID unsloth/Qwen3.5-4B-GGUF:Qwen3.5-4B-Q4_K_M.gguf添加自定义OpenAI兼容提供方接入。
- 不兼容量化内核时,加载器会退回反量化模型,占用更多内存。
- 打包推理路径目前仅限MPS。
- GGUF导入的反量化路径是另一个独立选项;支持该文件格式不代表所有设备都能用打包内核。
- 带padding的批处理无法享受无padding输入那样的mask优化,性能可能更低;官方希望把工作扩展到MPS上的generate_batch。
- 打包加载器目前覆盖Qwen3.5的稠密和MoE架构,包括兼容的Qwen3.8检查点;其他架构的支持会逐步扩展。
基准对比与性能改动
Hugging Face以llama.cpp作为本地推理性能参照。对比使用三个GGUF检查点:一个小型稠密模型、一个较大的稠密模型和一个MoE模型。llama.cpp一列来自llama-bench(build 5f55650a7,release b10200,ggml 0.18.0的Metal后端),命令为llama-bench -m -p 0 -n 128 -r 3,报告的是tg128,即 128 个解码token的生成速率,三次重复取平均,不含prompt处理。transformers一列用generate从 12 个token的prompt生成同样的 128 个token,三次预热后取最佳,且包含prefill。测量环境为MacBook Pro M2 Max、32 GB统一内存、macOS 26.6、PyTorch 2.12.1、kernels 0.17.0、插电。
博客称transformers在这三个检查点上接近llama.cpp,并说明图表沿用上述测量,并不意味着基准条件相同,因为transformers一侧包含prefill,而llama-bench只报告解码吞吐。
博客介绍了复用的ggml Metal内核:ggml-quantization直接读取打包的量化权重做矩阵运算,包括MoE模型中被选中的专家,避免每次解码前展开整个权重矩阵;ggml-norm融合归一化操作,包括Qwen3.5和Qwen3.8使用的零中心RMSNorm;ggml-attn提供ggml的Metal flash attention用于prompt处理和token解码;ggml-gated-delta-net加速Qwen3.5、Qwen3.8混合架构线性注意力层中的gated delta network;topk为MoE模型逐token选择专家,合并softmax与top-k路由,这是Hugging Face自己的Metal实现。前四个包基于ggml的内核,top-k内核针对MoE路由的另一个瓶颈。
生成循环方面做了两处改动,对所有transformers模型都有改善,不只针对GGUF:一是提前丢弃不必要的注意力mask(#48814),当受支持的decoder-only输入没有padding时,全 1 的padding mask可以在生成开始时移除,下游注意力代码不必反复检查该mask能否跳过,因果注意力仍然保留;二是推迟停止检查(#47975),在受支持路径上,generate异步复制停止决定并在下一步消费,CPU可以继续调度工作而GPU继续运行,流式token用同样的方式,越过停止条件的额外步骤会从结果中移除。
- 内核减少单次操作成本,减少同步点让CPU调度和GPU执行重叠。
- 没有兼容量化内核时会退回反量化,内存占用更高。
- Hugging Face称eager执行不需要torch.compile,目标是交互式使用时快速启动并稳定出token,不出现编译停顿或输入形状变化时的重编译。
与llama.cpp的分工及后续方向
GGML和llama.cpp加入Hugging Face时,官方描述了二者的互补角色:llama.cpp提供本地推理的基础,transformers提供模型定义的基础。GGUF支持让两者更靠近。Hugging Face仍然推荐llama.cpp作为优先追求高效本地推理时的引擎,其专用运行时、内存管理和广泛硬件支持都围绕这个目标构建。
这次集成给出的用途包括:在Python和PyTorch里试验GGUF,用hooks检查中间激活、修改模型forward或原型化自定义层;用现有transformers评估流程衡量量化检查点的质量;通过在同一框架里加载原始检查点和它的GGUF转换来验证转换是否正确,并把量化误差考虑进去;用自定义logits processor和停止条件试验新的解码思路,或在Python里写自己的生成循环;从GGUF检查点微调,反量化权重后继续标准transformers训练流程,用GgufConfig(dequantize=True) 并指定dtype=torch.bfloat16。
博客称更大的机会是把ggml的性能带给llama.cpp不支持的模型。transformers已经提供这些架构的PyTorch实现,有了PyTorch里的ggml内核和量化方案,就可以在不必先为llama.cpp实现整个模型的情况下加速其支持的操作,这对新架构、研究模型和可能永远不会获得专用llama.cpp实现的自定义变体尤其有用。
这一机会不限于GGUF格式本身:内核作用于张量,不要求整个模型来自GGUF文件,同样的构建块可以集成到其他transformers模型和加载流程中,也为其他模态打开路径——计算机视觉模型、音频模型和多模态模型可以复用兼容的注意力、归一化和矩阵乘法内核,而无需先在llama.cpp里有完整实现。但每个架构仍需要集成和验证,本文最初的GGUF示例只覆盖文本生成。