← 返回信息流
AI 资讯Hacker News·3 小时前

13年前Xeon无GPU跑Gemma 4 26B,速度仅5 tokens/秒

原标题:Running Gemma 4 26B at 5 tokens/SEC on a 13-year-old Xeon with no GPU

速览

通过优化,在13年前的Xeon CPU上实现了Gemma 4 26B模型的运行,无需GPU支持。速度仅为每秒5个token,远低于现代GPU,但证明了低硬件环境下运行大模型的可行性。这一成果或推动边缘计算和低成本AI部署的研究。

AI 深度解读

背景

2026年6月,Hacker News 上出现了两篇关于在老旧 CPU 上运行现代大语言模型的有趣实践。前一篇题为“A 10 year old Xeon is all you need”的文章,作者使用一颗 2016 年的 Xeon(Broadwell 架构)、无 GPU、128 GB 慢速 DDR3 内存,搭配 ik_llama.cpp(llama.cpp 的一个分支,专为 Gemma 4 的 MoE 推理优化)以及约 25 个精心调优的编译与运行时标志,成功跑起了 Google 的 Gemma 4 26B(一个 260 亿参数的开源混合专家模型),速度达到“阅读速度”。

本文作者 Ryan Findley 看到这篇帖子后,也想在自己地下室的一台更老的服务器上尝试。这台服务器是一台翻新的 HP StoreVirtual 存储箱,大约 13 年历史,搭载两颗 Ivy Bridge 架构的 Xeon(E5-2690 v2),没有 GPU,原本设计用来挂载磁盘而非做数学计算。他的复现一开始却失败了。

核心内容

从失败到诊断

Ryan 尝试直接编译并运行前文作者提供的 ik_llama.cpp 分支,但程序启动即崩溃。他将错误信息丢给 Claude(运行在同一台服务器上的 AI 助手),询问问题所在。Claude 迅速给出具体诊断:

  • 前文作者的 2016 年芯片是 Broadwell 架构(支持 AVX2 和 FMA3 指令集);而 Ryan 的是 Ivy Bridge(Intel 称为 v2 代),这两条指令集直到 2014 年的 Haswell(v3 代)才引入。
  • 该 fork 中的快速内核假设 AVX2 和 FMA3 可用,但 Ryan 的 CPU 比这些指令集出生的时间还要老,因此优化路径根本无法执行。

Ryan 接着追问能否让它跑起来。他自己先用一个免费模型做了初次尝试,接近成功但未能最终解决。Claude 接手了那个半成品的方案,认可其方向正确,并完成了修整——重写了关键的热路径代码,使其在没有 AVX2 的芯片上干净地降级,而不是试图调用不存在的指令。

Ryan 特别强调:这个过程并非一次性输入“修复它”就得到完整补丁。而是有人(Claude)阅读了他人编写的性能关键的 C++ 代码,找出了一个内核在该特定微架构上无效的原因,并在不丢弃该 fork 中有价值的优化前提下绕过了它。Claude 完成了这些工作,而 Ryan 的角色是运行正确的实验、识别输出是否最终正确。他对整个过程印象深刻。

最终成果

Gemma 4 的 26B MoE 模型现在能够在这台 13 年前的、无 GPU 的硬件上以阅读速度生成文本——大约 5 tokens/秒。原帖没有给出具体的每秒 token 数,只说了“阅读速度”,这里给出了确切数字:大约 5 tokens/秒,且几乎是免费的(电费忽略不计)。

证明运行成功的截图展示了 Gemma 4 26B 在地下室服务器(仅 CPU)上回答问题的画面。

修复的补丁已经提交至 ikawrakow/ik_llama.cpp#2138(仍在等待维护者审查),任何拥有老旧企业级硬件的人都可以获取该分支来在本地运行模型,作为付费 API 故障时的后备方案,或是在按 token 计费不合算时进行低成本批量处理。

实际修复的 bug 细节

Ryan 坦诚自己并非 C++ 程序员,只是能读栈追踪、熟悉构建系统,但并非手写量化矩阵乘法引擎的内核降级。实际的诊断和补丁来自运行在服务器上的 Claude 实例。以下是他请 Claude 撰写的修复摘要(轻度编辑):

真正坏了什么?

所需引擎是 ik_llama.cpp(ikawrakow 的 llama.cpp 分支,加入了 Gemma 4 MoE 推理所需的优化)。它默认假定 AVX2 可用。而 Ryan 的 Xeon E5-2690 v2 支持 AVX1 但不支持 AVX2。在构建时关闭 GGML_USE_IQK_MULMAT 后,大部分代码会尊重该设置:快速路径被排除编译,模型降级为纯标量/SSE 数学。这对于普通的 Q8_0 矩阵乘法没问题。

但有两个图操作是例外:Gemma 4 MoE 前馈网络会生成 MOE_FUSED_UP_GATE(每专家 gate+up 融合的 SwiGLU 矩阵乘法)和 FUSED_UP_GATE(其非 MoE 的对应操作)。这两个操作在计算调度器内部被 #if 保护在 GGML_USE_IQK_MULMAT 后面,但图构建器却无条件地发射它们。在该构建中,调度器的 switch 语句没有针对这些操作枚举的 case,因此它们落到了 default,导致每个专家 FFN 的目标张量从未被计算。Gemma 4 26B 有 30 层 × 每 token 8 个活跃专家,所以每次前向传播消耗了大约 240 个张量,里面填的是之前内存缓冲区中的残留数据。

症状是看起来流畅但多语言的胡言乱语:token ID 均匀分布在 26.2 万词汇表上,模型随意输出泰文、韩文、<unused> 哨兵或英文片段。温度 0 下确定性输出,单线程与多线程运行之间字节一致,没有任何 NaN。只是隐藏状态每层被一个大的常数推动,直到最后的 softmax 变成平坦分布。

正是这种确定性暴露了问题。Claude 在采样前插桩了原始 logits,打印 Top-5 token 及其范围、均值和 NaN 计数。数字表明:第一个预测 token 的 logit 均值高达 +16(正常应接近 0),大约 80% 的词汇表具有正 logit。随机损坏不会这样;如此干净的偏差只可能发生在隐藏状态的大部分是未初始化内存,且恰好包含小正浮点数的情况下。

修复方法

在 fork 的 main 分支之上叠加了三个提交:

  1. 编译修复iqk_quantize.cppquantize_row_q8_0_x4quantize_row_q8_1_x4_T 的标量 #else 分支实际上不是真正的标量,仍然引用了 hsum_i32_8 等 AVX2 辅助函数。这些被重写为可移植的标量循环;同时在 ggml.cggml-quants.c 中为少量泄露的 IQK 调用添加了 #if GGML_USE_IQK_MULMAT 保护;还修复了一个缺失的 include,使 iqk_cpu_ops.cpp 能独立编译。如果没有这些修复,该 fork 无法在非 AVX2 硬件上构建。

  2. 运行时 bug 修复:不是修改调度器,而是让图构建器发射那些在当前构建中有计算路径的操作。在 ggml_moe_up_gate 中,当 GGML_USE_IQK_MULMAT 关闭时:如果权重是合并的 up_gate_exps 张量(形状 [n_embd, 2*n_ff, n_experts],前半为 gate,后半为 up),则将其分割为两个 ggml_view_3d 切片,分别执行两个 ggml_mul_mat_id 调用,然后用 ggml_fused_mul_unary(gate, up, SILU) 合并。如果 gate 和 up 已经是独立的权重,则跳过分割,直接进行两次 mul-mat-ID 加上融合的 mul-unary。对于密集层中使用的 ggml_fused_up_gate 也做了类似处理。所涉及的所有操作都已经有非 IQK 的实现(mul_mat_id 是标准 ggml,fused_mul_unary 一次完成 SILU 和相乘)。整个修改位于 #if !GGML_USE_IQK_MULMAT 内,所以 AVX2 构建保持与原版比特一致。

  3. CI 存根:iqk 源

查看原文 →neomindlabs.com