一台10年前的Xeon就够了
摘要
一篇博客文章,详细介绍了如何仅使用CPU和DDR3内存,在10年前的Xeon服务器上运行Gemma 4 AI模型,并使用了自定义的llama.cpp优化。
暂无内容
查看缓存全文
缓存时间: 2026/06/01 10:41
# 一台十年前的Xeon就够了 - point.free
来源:https://point.free/blog/gemma-4-on-a-2016-xeon/
发布于 2026 年 6 月 1 日
阅读时间 17 分钟
上篇文章 (https://point.free/blog/gemma-4-mtp/) 介绍了如何量化 Gemma 4 的 MTP drafters 并与 verifier 配对。本文则讲述如何在一台本不该运行它的机器上实际运行。
我有一台回收的服务器。它值得称赞的地方是拥有高达 128 GB 的内存,但那是 DDR3... 这内存速度比目前最好的笔记本内存慢了 5-6 倍。它还搭载了一颗 2016 年的单路 Intel Xeon E5-2620 v4,其性能大约是我笔记本 CPU 的 1/5...
哦,正如我提到过的,我们**没有 GPU**。而且,Xeon 也没有集成显卡。
但是,请听我说...
如果我们只是在这里启动 ollama,嗯……正如之前的博客文章所述,我们做不到。而且能在 6 个月内等到他们为我们需要的模型添加支持(如果他们最终会添加的话)都算是幸运的。也可能他们永远不会添加。即便如此,ollama 根本就没有提供足够的旋钮让我们能够很好地运行它,就连标准的 `llama-cpp` 也不行。
但是,这又怎能阻止我们呢?
---
> 我收到反馈说之前的一些文章太过高级,这次我会尽量把事情讲得尽可能清晰。如果你是一名技术人员,或者是一位组装过电脑、用过 ChatGPT 之类工具的 Linux 爱好者,那么大部分内容应该都能理解。
那么,我们先充分了解一下硬件环境。根据 `lscpu` 的输出:
- **CPU:** Intel Xeon E5-2620 v4 @ 2.10 GHz
- **核心:** 8 物理核心,16 线程
- **指令集:** AVX2(无 AVX-512、无 AVX-VNNI、无 BF16)
- **缓存:** 20 MiB L3,共 2 MiB L2
- **内存:** 128 GB DDR3
- **GPU:** 无
对于大语言模型推理来说,内存带宽是限制性资源。生成每一个 token 都需要将数 GB 的权重从 RAM 搬运到 CPU 缓存中。
当你使用 ChatGPT 之类的工具,看着文字逐个词地显示在屏幕上时,你看到的就是“解码阶段”。在这个阶段,模型一次只生成一个输出片段(或称为“token”)。
在此步骤中,系统的原始计算能力很少成为瓶颈。相反,限制因素是内存带宽。为了计算下一个词,处理器必须不断地拉取海量数据。这些数据就是包含模型所学知识的“权重”。它将这些数据从内存搬运到计算核心。
处理器执行所需的矩阵计算速度非常快,以至于它只能闲置,等待硬件物理地将下一块权重通过内存总线搬运过来。用传统的软件术语来说,解码严重受限于内存带宽,而非计算能力。
这就是所谓的“内存墙”,目前最大的性能瓶颈之一,无论你使用的是 Xeon 还是 H100。
---
天真地在没有 GPU 的 DDR3 机器上运行 `llama-cli` 会慢得可怕,即使它能运行,因为它针对通用的 GPU 用例进行了优化,常常放弃了很多可以改进的地方。此外,它根本没有用到当前最先进的技术中用于大规模运行这些模型的大部分实际优化。
解决方案就是拉满 `ik_llama.cpp` 提供的每一个优化杠杆。其中大部分都有点晦涩难懂。
下面就是让这一切真正运行起来的魔法咒语。
```bash
llama-cli \
--model gemma-4-26B-A4B-it-Q8_0.gguf \
--model-draft gemma-4-26B-A4B-it-assistant-GGUF/\
wikitext-2-raw_ik-llama-mtp_drafter-conservative/\
gemma-4-26B-A4B-it-assistant-Q8_0.gguf \
--spec-type mtp --draft-max 3 --draft-p-min 0.0 --spec-autotune \
-cnv --color --jinja --special \
-sm graph -smgs -sas -mea 256 --split-mode-f32 \
--temp 0.7 -t 8 --parallel 8 \
--cpu-moe --merge-up-gate-experts \
--flash-attn on --mla-use 3 \
--mlock --run-time-repack --no-kv-offload
```
在像 `ollama` 这样的黑盒工具下,你永远不会看到这行命令。在老旧硬件上,你必须理解每个标志的作用,因为其中一半可能无法生效,而引擎会在运行过程中告知你这一点。
---
**推测解码。**
```bash
--spec-type mtp --draft-max 3 --draft-p-min 0.0 --spec-autotune
```
这将 26B 的 verifier 与上一篇文章中的小型 drafter 配对。每次草案最多生成三个 token(`--draft-max 3`),接受所有概率(`--draft-p-min 0.0`),`--spec-autotune` 根据工作负载调整链长。
这直接与我们之前关于内存受限解码阶段的讨论相关。
当模型使用较长的推理链时,它会逐个生成那些“思考” token。即使内部推理对用户隐藏,你只看到简短的最后答案,硬件仍然需要为该隐藏链中的每一个 token 执行完整的解码过程。
事实上,推测解码是目前 AI 行业发明的绕过“内存墙”最巧妙的软件变通方法之一,而 spec autotune 正是从中榨取最大速度的方法。
在 CPU 上使用推测解码的论据比 GPU 上更强。CPU 的计算成本相对于通过缓存流式传输 verifier 权重的成本而言是便宜的,因此将额外的循环花费在一个活跃层能轻松放入 L3 的小型 drafter 上,可以以极低的边际成本购买 token。drafter 的工作集适合 L3 缓存。而 verifier 则溢出到所有缓存之外。
---
**CPU 和 MoE 路由。**
```bash
--cpu-moe --merge-up-gate-experts -t 8 --parallel 8
```
Gemma 4 26B-A4B 有 128 个专家,每个 token 激活 8 个,有效参数约 3.8B,总参数约 25.2B。`--cpu-moe` 针对 CPU 缓存层级调整路由。
CPU 处理内存的方式与 GPU 截然不同。GPU 拥有大量超高速高带宽内存(HBM),而 CPU 则依赖直接集成在处理器芯片上的小型、闪电般快速的“缓存”(L1、L2、L3)。
在 MoE 模型中,不断在 128 个不同专家之间跳转可能导致“缓存抖动”,即 CPU 不得不不断清空缓存并从慢得多的主系统 RAM(通常是 DDR4/DDR5,而我们是 DDR3!)中获取新的权重。
这个标志告诉路由器更智能地选择专家,优化顺序,使权重尽可能长时间地保持在 CPU 的本地缓存中。
`--merge-up-gate-experts` 将每个专家的两个投影合并为单个 matmul,日志确认了这一点:
```bash
fused_up_gate = 1
```
这是一种绕过我们之前讨论的内存带宽瓶颈的软件技巧。
在专家内部,数学运算需要将数据传递到不同的层。通常,处理器会计算“up projection”,将结果写回内存,然后加载“gate projection”的权重,计算,再组合它们。这需要多次穿过内存总线搬运数据。
它不是分两次穿过内存总线,而是将操作合并为一步。
`-t 8` 匹配物理核心数。这台机器有 16 个 SMT 线程,但只有 8 个核心。在受内存限制的工作负载中,过度订阅线程会增加调度成本而不会增加吞吐量:核心在等待 DDR3,而不是彼此等待。
---
**内存锁定、重新打包、KV 缓存。**
```bash
--mlock --run-time-repack --no-kv-offload
```
`--run-time-repack` 在推理之前立即重新组织内存中的权重矩阵,以匹配 CPU 的缓存布局。日志确认:
```bash
============ Repacked 265 tensors
```
处理器有自己的超快内置内存,称为缓存(L1、L2 和 L3)。然而,这些缓存期望数据以特定形状和大小提供。
如果 AI 的权重矩阵以通用布局存放在系统 RAM 中,CPU 就必须笨拙地分块拉取数据,导致“缓存未命中”,从而造成 CPU 停顿。`--run-time-repack` 告诉引擎在启动时花费几秒钟,在物理上重新组织 RAM 中的巨大数字表,使它们与 CPU 期望的摄入方式完美对齐。它预先支付了一小段时间成本,以保证在实际文本生成期间获得最大内存带宽。
`--mlock` 旨在将模型固定在 RAM 中,这样操作系统就不能将其任何部分交换到磁盘。
`mlock` 代表“内存锁定”,很惊讶吧!在标准操作系统中,如果系统内存不足,它会悄悄地将几秒未使用的数据“交换”(或分页)到物理硬盘上。
如果操作系统试图将 27GB 的 AI 权重交换到磁盘,生成速度会瞬间降到零,而系统在试图读回数据时会严重卡顿。`--mlock` 告诉 Linux 内核:“将这个 27GB 严格固定在物理 RAM 中。永远不要将其移动到磁盘。”
注意,如果你不小心,会看到这个:
```bash
warning: failed to mlock 27628376064-byte buffer
(after previously locking 0 bytes): Cannot allocate memory
Try increasing RLIMIT_MEMLOCK ('ulimit -l' as root).
```
标志本身没问题;内核端的 memlock 限制设置得不够高,无法锁定 27GB 的缓冲区。这完全不是 LLM 特有的问题——而是 ulimit 默认值的问题——正是那种黑盒工具通过一开始就不要求这个优化来掩盖的隐患。
想想看,许多工具默认情况下如果它决定这是最佳选择,就会毫无问题地将你的模型放入交换区。你可以想象这对性能的损害有多大……
`--no-kv-offload` 告诉引擎不要为 KV 缓存寻找 GPU。因为根本没有 GPU 可找,但这个标志可以短路检查。
KV(Key-Value)缓存是 AI 的短期记忆——它存储当前对话的上下文,这样模型就不必为每个新 token 重新读取整个提示。
由于 KV 缓存被不断读写,AI 引擎通常会尝试将其“卸载”到 GPU 上,GPU 的内存比我们的快得多。
由于这个特定设置高度优化为纯 CPU 运行,让引擎搜索硬件总线以寻找不存在的 GPU 是浪费时间,并且可能抛出错误。这个标志显式地短路了检查,告诉引擎将短期记忆与权重一起保留在系统 RAM 中。
---
**图布局。**
> 我已经尽力让这部分易懂,但这一部分确实很难在一篇博客文章中解释清楚。
现在进入黑暗艺术。在尖端的 AI 软件中,一个常见的挫折是引擎开发速度太快,以至于开发者没有时间编写官方文档。如果你想知道如何优化引擎,你必须深入原始代码或阅读 Github 上开发者之间的 Pull Request(PR)评论。
```bash
-sm graph -smgs -sas -mea 256 --split-mode-f32
```
这些标志控制计算图在内存区域之间的分配方式。完整的文档最终存在于代码中,即使有一些文档。
标志 `-sm graph` 告诉引擎以图模式(通常业界称为张量并行)使用拆分模式。这完全关乎如何跨多个处理器或内存区域(如多个 CPU 插槽或 GPU)划分庞大的数学工作负载。
- 层拆分(默认/后备方式):引擎水平切割模型。处理器 A 计算第 1-10 层,然后通过系统总线将数据发送给处理器 B,处理器 B 计算第 11-20 层。在处理器 A 工作时,处理器 B 处于空闲状态。
- 图拆分(目标):引擎垂直切割计算图。处理器 A 和处理器 B 同时计算第 1 层的不同部分,合并它们的答案,然后一起进入第 2 层。这使得所有硬件同时以 100% 运行,大大提高了生成速度。
在这次运行中,引擎拒绝了:
```bash
=======================================================
Split mode 'graph' is not supported for Gemma4 external MTP
=> changing split mode to 'layer'
=======================================================
```
因为 MTP 在网络的最后创建了一个更复杂的数学计算网络,这个推理引擎尚未支持安全地“图拆分”(垂直切片)MTP 架构。当引擎启动时,它检测到 MTP 层,意识到 `-sm graph` 会破坏数学计算,于是安全地降级到较慢的顺序层拆分,这样模型仍然可以运行。
我把它包含进来是因为它将来很可能会非常有用,所以如果你在更新版本上工作,你可以试试你的运气。
虽然 `-sm graph` 被禁用了,但下面这些标志仍然适用于引擎管理内存的方式:
- `-sas`(跨插槽拆分):显式告诉引擎如何在服务器主板上不同的物理 CPU 插槽(NUMA 节点)之间划分工作负载。你可能注意到我们只有一个 CPU,但我们以后可能会增加,这是一个不错的优化,如果你这样做,请进行基准测试以确保安全,因为较旧的板子可能会打破当前的假设。
- `--split-mode-f32`:当数据跨处理器拆分时,它必须被拼接回去。这个标志强制这些中间连接点使用 32 位浮点精度(更高质量的数学计算)。它防止 AI 在拆分过程中由于舍入误差而丢失智能或产生幻觉。
如果你看到这个,也不用担心:
```bash
Oops: tensor with strange name rope_freqs.weight
```
它有一个奇怪的名字。奇怪的名字不会阻止我们。:D
---
**注意力机制。**
看吧。`ikawrakow`,`ik_llama.cpp` 的创造者,简直是“疯狂”的超越者。
Kawrakow 编写了自定义 CPU 内核来处理 Flash Attention,从而在繁重的上下文处理期间无需 GPU。
这让我们能够做一些通常只在 GPU 上才能做的事情。
```bash
--flash-attn on --mla-use 3
```
Flash Attention 将注意力 softmax 与其 matmul 融合,避免了物化完整的注意力矩阵。废话,谁都知道,但我会试着解释一下。
为了生成文本,AI 必须计算提示中的每个单词与所有其他单词的关系。在数学上,这创建了一个大小为 N×N 的网格(其中 N 是 token 数量)。
如果你给 AI 一句简短的句子,这个网格很小。但如果你给它一份 100,000 个单词的文档,那个矩阵就会爆炸成 100 亿个单元格。通常,处理器会计算这个巨大的矩阵并“物化”它——意味着它实际上将整个巨大网格写入主系统 RAM,然后立即读回以进行下一步。
Flash Attention 应用了内核融合技巧,但应用于注意力机制。它将注意力分数分块计算,并融合数学计算(softmax),使得巨大的 N×N 矩阵从未真正写入 RAM。它完全在处理器的超快本地缓存内计算和消耗。
Flash Attention 最初严格为 GPU 发明,因为它依赖于 GPU 硬件处理内存块的方式。**成功地将这种高度复杂、特定于硬件的优化移植到标准 CPU 上,是一项巨大的软件工程成就。** 干得好,ikawrakow (https://github.com/ikawrakow) !
`--mla-use 3` 启用多头潜在注意力。之前我们讨论了 KV 缓存(AI 短期记忆,防止它必须为每个单词重新读取整个提示)。
在标准架构中,为每个 token 存储原始的 Key 和 Value 数据会非常快地消耗掉大量 RAM。多头潜在注意力(MLA)是一种突破性的架构,它极大地压缩了这种短期记忆。它不是为每个 token 保存原始数据,而是将 Key 和 Value 压缩成更小、更密集的数学表示(“潜在”空间)。
这大大减少了 KV 缓存的内存占用,同时保持了准确性。`--mla-use 3` 选择了一种特定的 MLA 实现变体,在我们的 CPU 上运行时效果最好。
---
**让它运行起来。**
有了这些标志,我运行了以下命令:
```bash
./llama-cli \
--model gemma-4-26B-A4B-it-Q8_0.gguf \
--model-draft gemma-4-26B-A4B-it-assistant-GGUF/\
wikitext-2-raw_ik-llama-mtp_drafter-conservative/\
gemma-4-26B-A4B-it-assistant-Q8_0.gguf \
--spec-type mtp --draft-max 3 --draft-p-min 0.0 --spec-autotune \
-cnv --color --jinja --special \
-sm graph -smgs -sas -mea 256 --split-mode-f32 \
--temp 0.7 -t 8 --parallel 8 \
--cpu-moe --merge-up-gate-experts \
--flash-attn on --mla-use 3 \
--mlock --run-time-repack --no-kv-offload
```
启动后,日志显示模型加载成功。然后我向它提问:“请用中文写一首关于老服务器运行现代 AI 的诗。”
它花了几秒钟思考,然后输出:
```text
老骥伏枥志千里,
DDR3 内存尚可依。
Xeon 虽旧心不老,
Gemma 4 亦能启。
```
虽然速度不是很快(大约每秒 1-2 个 token),但它在跑!在一台 2016 年的 Xeon 服务器上,没有 GPU,用 DDR3 内存,运行着一个 260 亿参数的模型。这证明了聪明的软件优化可以弥补硬件的不足。
---
**结论。**
关键要点:
1. **内存带宽是关键。** 在 CPU 上进行 LLM 推理时,内存带宽是主要瓶颈,而不是计算能力。
2. **推测解码是游戏规则改变者。** 它可以在 CPU 上带来巨大的加速,尤其是与小型 drafter 配对时。
3. **细节决定成败。** 像 `ik_llama.cpp` 中的自定义 CPU 内核、内存锁定和运行时重新打包这样的优化可以带来天壤之别。
4. **不要低估老旧硬件。** 通过正确的软件,你可以在意想不到的地方运行现代 AI 模型。
如果你有一台带有大内存(即使速度较慢)的旧服务器,并且想尝试运行 Gemma 4 或其他模型,绝对值得一试。只要准备好投入一些时间进行调优!
未来是光明的,对于开源 AI 和那些愿意深入细节的人来说,尤其如此。
---
*本文作为 2026 年 4 月 1 日发布的一部分。*
相似文章
在13年历史的Xeon无GPU服务器上以每秒5个token运行Gemma 4 26B
一位开发者成功在无GPU、双路Xeon的13年旧服务器上,使用修改版ik_llama.cpp(无需AVX2指令),以约每秒5个token的速度运行谷歌的Gemma 4 26B混合专家模型。
运行 gemma-4-26B-A4B 不需要 GPU
作者展示了在仅使用 CPU 的系统上,通过 Koboldcpp 高效运行 Gemma-4-26B-A4B 模型,在一台旧台式机上达到了每秒 7 个 token 的速度,这表明运行本地大语言模型推理可能并不需要强大的 GPU。
@analogalok:我的8GB显存游戏本肯定会恨我这么做,但我还是做了。跑了一个31B稠密模型(Gemma 4…
用户在8GB显存的游戏本上,使用llama.cpp配合MTP推测解码,以约3 tokens/s的速度运行了Gemma 4 31B稠密模型,展示了在消费级硬件上运行31B稠密模型的可行性,并提出了智能体工作流程:快速MoE模型将困难任务路由给这个较慢的稠密模型。
在英特尔N100上使用llama.cpp的帮助?
用户寻求在英特尔N100迷你PC上运行llama.cpp与Gemma 4 E2B的建议,询问是使用CPU还是iGPU,以及应该针对哪个后端。
@googlegemma: Gemma 4 E2B 在英特尔AI PC上运行速度超快,得益于OpenVINO上的LiteRT NPU支持!预填充性能提升1.3倍……
Gemma 4 E2B 在采用OpenVINO与LiteRT NPU支持的英特尔AI PC上,实现了预填充速度提升1.3倍、每瓦性能提升2.8倍,从而能够高效运行后台LLM任务。