无GPU实测:新旧llama.cpp跑Gemma模型的性能差异

纯CPU对比两版llama.cpp:新版生成快9.1%,预填充反慢6.5%。
一位开发者在纯 CPU 环境下,用同一量化模型(Gemma 系列 Q4_K_XL)对比了 llama.cpp 的 build 9976 与 build 11571,只改变构建版本、其余条件全部锁定,每个构建运行三次取平均。结果显示新版生成速度从 6.05 提升到 6.60 tok/s(+9.1%),256 token 生成耗时从 42.57 秒降到 38.64 秒;但预填充速度反而从 11.91 降到 11.14 tok/s(-6.5%)。这说明推理性能并非单一数字,预填充与生成是两个性质不同的阶段。实验还观察到明显的运行间波动,三次平均比挑最快一次更可靠,但样本量仍不足以做统计结论。新版引入的按需加载模型特性未被本次实验测量。作者最终基于真实使用场景选择新构建。
本地运行大模型不一定需要昂贵显卡。一位开发者用纯CPU环境,对比了两个不同版本的 llama.cpp 在同一个量化模型上的实际表现,结论有些意外。

实验设计:控制变量做对比
这次对比的核心思路很简单:只改变 llama.cpp 的构建版本,其他所有条件保持一致。使用的两个构建分别是 build 9976(commit e3546c794)和 build 11571(commit 097cf33d9),后者基于 llama.cpp 的 0.6.0-dev 版本,用 GNU 12.2.0 在 Linux x86_64 上从源码编译。
模型方面,两个构建都加载同一个文件:gemma-4-E2B-it-qat-UD-Q4_K_XL.gguf,量化方式为 Q4_K_XL。作者刻意锁定模型和量化参数,就是为了让差异只来自构建本身,而不是模型或量化级别带来的噪声。
测试环境完全走 CPU,不做任何 GPU offloading。推理线程设为 3,批处理线程设为 4,上下文长度 4128,并行槽位 1。采样参数(temperature 0.7、top-p 0.8、top-k 20)和 prompt 都保持一致,每次运行前重启服务,输出固定为 256 token。
这样的控制力度在个人实验中算是比较严谨的——尤其是重启服务和清空缓存的细节,很多非正式 benchmark 会忽略。
量化与 GGUF 格式:文中模型文件名里的 Q4_K_XL 是一类特定的量化方案。GGUF 是 llama.cpp 生态使用的模型文件格式,它把权重、词表和元数据打包进单个文件,并按块对权重做量化存储。Q4 表示权重被压缩到约 4 比特,K 指采用 k-quant 分块量化,不同张量可按敏感度选择不同精度;XL 通常是社区(如 Unsloth)在该基础上进一步调整的混合精度变体。相比 FP16,4 比特量化能把模型体积和内存占用降到约四分之一,这正是普通 CPU 机器能跑起本地大模型的关键前提。代价是精度略有损失,因此同一模型的不同量化级别在速度和质量上会有可感知差异。作者锁定同一个 .gguf 文件,就是为了排除量化差异这一变量。
性能数据:生成快了,但预填充慢了
每个构建运行三次,取平均值。结果呈现出一种"一半好一半坏"的格局:
| 指标 | 旧构建 9976 | 新构建 11571 | 变化 |
|---|---|---|---|
| 生成速度 (tok/s) | 6.05 | 6.60 | +9.1% |
| 预填充速度 (tok/s) | 11.91 | 11.14 | -6.5% |
| 256 token 生成耗时 | 42.57 s | 38.64 s | 节省约 4 秒 |
新构建在文本生成环节平均快了约 9.1%,生成 256 个 token 从 42.57 秒缩短到 38.64 秒。但预填充(prompt processing)反而慢了 6.5%,从 11.91 tok/s 降到 11.14 tok/s。
这说明一个常被忽视的事实:LLM 推理性能不是单一数字。预填充和生成是两个性质不同的计算阶段——前者是并行处理输入序列,后者是逐 token 自回归输出。构建优化可能只作用于其中一个阶段,不能笼统说"新版本更快"。
预填充与生成为何是两种负载:LLM 推理分两个阶段。预填充(prompt processing / prefill)会一次性把整段输入送进模型,所有 token 可以并行计算,属于高吞吐、算力密集型的矩阵运算,速度通常以「每秒处理多少输入 token」衡量。生成(decode / generation)则是自回归的:每产生一个 token 都要重新过一遍模型,且必须等上一个 token 算完才能算下一个,因而高度依赖内存带宽和缓存,难以并行,速度以「每秒输出多少 token」衡量。两者对硬件的瓶颈不同——预填充吃算力,生成吃带宽——所以针对某一阶段的优化(如算子融合、KV 缓存策略)完全可能让另一阶段变慢。这就是为什么「新版本更快」这种笼统说法在 LLM 推理里往往站不住脚。
运行间波动:为什么取三次平均
单个 run 的数据波动其实不小。旧构建的生成速度在 5.41 到 6.45 tok/s 之间浮动,新构建在 6.39 到 6.82 tok/s 之间。预填充的波动更大,新构建的三次结果分别是 13.45、10.62 和 9.36 tok/s,极差超过 4 tok/s。
这种波动在 CPU-only 环境下很常见,后台进程、温度管理、内存带宽争用都会影响结果。作者用三次平均来减少单次抽样的偶然性,但坦承三个样本做统计推断仍然不够。
从实用角度读这组数据:9.1% 的生成提升不是质变,但在纯 CPU 机器上,每次省下几秒钟,累积到日常使用中还是有感的。
附带发现:按需加载模型
新版构建还引入了一个值得关注的特性——load model on demand(按需加载模型)。对硬件资源有限的用户来说,这个方向比单纯的推理加速更有想象空间。
但作者没有在本次实验中测量这个特性的实际效果,包括服务启动时间、模型按需加载耗时、加载前后的 RAM 占用、闲置时的内存释放行为等。这些都是独立于推理速度的维度,需要单独设计实验来验证。
这种"看到新特性但不下结论"的态度值得肯定——benchmark 的价值在于诚实地划分"测过的"和"没测过的"。
load model on demand 的意义:传统上 llama.cpp 的服务启动时会把整个模型权重一次性读入内存(RAM),之后常驻。这对内存有限的机器不友好——一个 4 比特量化的中等模型也可能占用数 GB,加上 KV 缓存和系统开销,很容易吃紧。「按需加载模型」的思路是延迟加载:服务启动时不立即载入全部权重,而是在收到首个请求、真正需要某部分参数时才从磁盘读入,闲置时还可能把已加载部分释放回内存。这能显著降低服务常驻的空闲内存占用、加快服务启动,但也可能把加载开销转移到第一次请求上,导致首 token 延迟变高。它到底是省内存的利器还是引入抖动的新变量,必须靠实测启动耗时、加载延迟和 RAM 曲线来判断,而不能只看特性名称。
实践建议
作者最终选择继续使用新构建,理由有三层:生成速度有可观测的提升、预填充的退化在实际交互中感知有限、以及新特性值得持续跟进。但他也明确指出,这个决定不是为了追求 benchmark 上的数字优势,而是基于真实工作场景——写文档、起草正式信函、处理日常任务。
对想在普通电脑上跑本地大模型的用户,这个实验提供了几个可参考的点:
- 保持模型和量化一致,只改动一个变量,才能判断构建升级是否值得
- 分别看预填充和生成两个指标,不要被单一数字误导
- CPU-only 环境下运行间波动较大,多次取样取平均比挑最快的一次更可靠
- 关注新特性时,先确认它是否被实际测量过
本地 LLM 的门槛正在降低。没有高端 GPU 的普通笔记本或旧台式机,配合合适的量化和构建版本,已经能跑起能用的模型。这种可及性本身,或许比 benchmark 上多几个百分点更有意义。
相关推荐

B站最细Codex保姆级攻略:从安装到实战全解析
B站最细Codex保姆级攻略:从应用商店安装到日常工作模式配置,用真实咖啡馆项目演示文件整理、数据提取、仪表盘制作等实战任务,教你用计划模式和桌面宠物高效使用Codex。

体渲染中的外观补偿:为何RGB准确无法保证密度正确
体渲染研究揭示:完美复现外部RGB视图的体数据仍可能存在密度错误。外观补偿机制使中心密度翻倍、L2误差超14.52%时外部射线仍不变,密度恢复依赖外观容量、空间分辨率与测量设计。

TMLE与AIPW的样本分割选择:交叉拟合与重复分割的影响
一项TMLE与AIPW模拟研究发现,样本分割方式显著影响区间覆盖率:样本内拟合倾向得分可使覆盖率跌至0.12-0.48,双nuisance交叉拟合则恢复至0.91-1.00;近正性下AIPW优于未加权TMLE,重复划分降低划分依赖但使区间更保守。