本地模型运行工具 llama.cpp 合并了一项优化,让 Gemma 4 E2B 和 E4B 更快地读取长输入。在本地运行模型的开发者可以缩短生成回答前处理提示词的等待时间。

1. 缩减了复用前层计算结果区段的计算

11月 3日合并的改动会在复用前层 KV 缓存、且不写入新值的层中,跳过输出不需要的 token 计算。在预先处理输入 token 的预填充阶段,中间批次会跳过这些层,最后一批只处理一行,从而减少复用已有计算结果时的重复工作。

开发团队还整理了各层输入表示,即逐层嵌入的缩放计算,并避免对数据进行连续化复制。

以下是原始改动代码的适用条件。它会检查是否存在缓存共享层、同时处理的输入流是否只有一个等条件,避免连必要的中间结果也被裁掉。

    // KV-shared layers do not write to the KV cache, so prune non-output token rows before the first KV-shared layer
    bool prune_shared = crop_before_nextn(inp_out_ids) &&
                        hparams.n_layer_kv_from_start > 0 && hparams.n_layer_kv_from_start < n_layer &&
                        !cparams.embeddings && cparams.n_seq_max == 1;
    for (int il = (int) hparams.n_layer_kv_from_start; prune_shared && il <= n_layer; ++il) {
        prune_shared = !cparams.embeddings_layer_inp[il];
    }

2. M4 Pro 上 E2B 的长输入吞吐量提升

PR 作者使用 Google 官方 QAT(训练时考虑量化影响的)Q4_0 模型,对比了改动前的 master 开发基线与修改版。在 M4 Pro 上使用 Metal·BLAS 和 10 个线程测试 E2B 时,三种输入长度的预填充吞吐量,即每秒处理的输入 token 数,均大幅提升。

表:E2B 不同输入长度的预填充吞吐量

条件:M4 Pro,MTL,BLAS,10 个线程,gemma4 E2B Q4_0,3.10 GiB,4.63 B

单位:token/秒,± 列为原文数值的误差部分

E2B 预填充吞吐量变化512: 改动前 1613.78, 改动后 4603.18; 2048: 改动前 1535.38, 改动后 4451.68; 8192: 改动前 1323.11, 改动后 3748.03改动前改动后5121613.784603.1820481535.384451.6881921323.113748.03
E2B 预填充吞吐量变化
M4 Pro 上 E2B 的长输入吞吐量提升
输入 token 数改动前改动前 ±改动后改动后 ±
5121613.780.794603.184.99
20481535.381.014451.6840.58
81921323.110.893748.034.43

同一环境下,128 token 的生成测试从 109.65 变为 110.98 token/秒,变化不大。改进主要体现在读取输入的速度,而非续写回答的速度。

3. E4B 在各输入长度下也有改善

作者在 M4 Pro 上的测量显示,E4B 也出现了同方向的变化。下表仅列出 E4B,硬件和线程设置与前一项测试相同,但模型大小和参数量不同。

表:E4B 不同输入长度的预填充吞吐量

条件:M4 Pro,MTL,BLAS,10 个线程,gemma4 E4B Q4_0,4.79 GiB,7.46 B

单位:token/秒,± 列为原文数值的误差部分

E4B 预填充吞吐量变化512: 改动前 805.91, 改动后 1318.62; 2048: 改动前 785.84, 改动后 1306.18; 8192: 改动前 722.91, 改动后 1213.38改动前改动后512805.911318.622048785.841306.188192722.911213.38
E4B 预填充吞吐量变化
E4B 在各输入长度下也有改善
输入 token 数改动前改动前 ±改动后改动后 ±
512805.911.061318.6223.13
2048785.840.221306.1810.30
8192722.914.201213.385.43

同一环境下,128 token 的生成吞吐量从 63.39 变为 63.62 token/秒。E4B 同样表现为输入吞吐量上升,同时生成速度保持稳定。

作者报告称,文本、图像和音频输入的输出均与改动前相同,也测试了 16K·32K 长度的提示词。

4. CPU 和骁龙上的输入吞吐量也有所提升

作者的 M4 Pro CPU 测试使用了相同的官方量化模型和 10 个线程。在 512 token 输入下,E2B 从 629.04 提升至 1811.26,E4B 从 326.06 提升至 543.23 token/秒。

骁龙 S26+ 的测试条件为 OpenCL·HTP、6 个线程、微批次大小 1024、HTP0 设备,以及用于设置 GPU 卸载层数的 ngl 值 -1。同一官方 E2B 模型在 512 token 输入下从 2303.07 提升至 5099.01,在 8192 token 输入下从 1896.88 提升至 4686.80 token/秒。各平台结果反映的是各自环境内改动前后的差异。

5. 要获得收益,需检查服务器的并发配置

作者于 10月 30日公布的 M4 Pro·Metal 服务器测试中,处理 13,789 token 输入时,使用合并缓存的统一 KV 耗时 4.22 秒,使用分开缓存的分离式 KV 耗时 11.72 秒。按未启用、启用预先预测多个 token 的 MTP 的顺序,统一 KV 吞吐量为 3261.9·3264.4,分离式 KV 为 1175.2·1175.0 token/秒。

合并时的裁剪条件是使用统一 KV 的单序列,即一次处理一条输入流;像默认服务器那样使用多序列,或提取嵌入的配置不在适用范围内。作者解释,26B 在处理提示词时所有层都会向缓存写入值,因此无法从这项优化中受益。

减少输入计算的收益,代价是可适用的运行配置范围受限。如果服务器需要同时处理多个请求,就应同时考虑单序列下的输入吞吐量收益和现有的并发需求。

这项优化的价值在于缩短长输入的等待时间,而非回答生成本身;是否采用,应从模型与服务器配置出发判断。