[Bug] llm_bench 在 ARM CPU 上测试 gemma-3-1b-it 模型时出现异常高的解码速度(1500 toks/s)
我最近在使用 llm_bench 工具对端侧大模型进行性能测试。在测试 gemma-3-1b-it-qat-q4_0-gguf-MNN 模型时,我发现了一些异常高且可能不正确的解码速度。特别地,目前只有在这个模型上才会出现这个情况
问题描述
llm_bench 工具在特定条件下(例如 prompt=128, decode=128)报告 Gemma 模型的解码速度超过了 1500 tokens/秒。这个数值远高于预期,也比 llama.cpp 等类似框架(在相同模型上,llama.cpp 的速度约为 52 tok/s)快得不合常理。同时,这个速度会随着输入长度、参数(-c[precison 1:High,2:Low])的变化而发生剧烈的、不符合逻辑的波动。
与此对比,使用本项目(MNN)的llm_demo 工具交互式聊天也并没有体现出1500 tokens/秒 左右的decode,目测应该是50 tok/s左右(大概)?
不合理点一:Decode 速度异常高且剧烈波动
-
现象:
- 在高精度、8线程、输入128的条件下,Decode 速度达到了
1684.20 tok/s。 - 在高精度、8线程测试中,输入从128变为256,Decode速度就从
1684.20暴跌到307.38。 - 在输入512时速度又回升到
748.56,在1024时又跌回317.14。
- 在高精度、8线程、输入128的条件下,Decode 速度达到了
不合理点二:低精度(Low)模式下decode速度骤降
-
现象:
- 在8线程、输入512的条件下,高精度 Decode 速度为
748.56 tok/s,而低精度骤降至32.10 tok/s。 - 在4线程、输入512的条件下,也出现了同样的情况,低精度速度为
35.14 tok/s。
- 在8线程、输入512的条件下,高精度 Decode 速度为
如何复现
- 环境
- MNN 版本: main branch
- 操作系统: Android 15
- 设备型号: One Plus13-9Elite
- 模型:
gemma-3-1b-it-qat-q4_0-gguf-MNN。 - 复现指令: 运行
llm_bench,使用如下参数:LD_LIBRARY_PATH=. ./llm_bench -m /path/to/gemma-3-1b-it-qat-q4_0-gguf-MNN/config.json -a cpu -c 1 -p 128,256,512,1024 -n 128 -t 8 -kv true
截图
# High Precision, 8 Threads
| model | modelSize | backend | threads | precision | llm_demo | speed(tok/s) |
| ----------------------------- | ---------- | ------- | ------- | --------- | ------------------------ | --------------------- |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 8 | High | prompt=128<br>decode=128 | 295.09 ± 7.41<br>1684.20 ± 33.36 |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 8 | High | prompt=256<br>decode=128 | 258.10 ± 10.33<br>307.38 ± 3.74 |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 8 | High | prompt=512<br>decode=128 | 233.18 ± 3.77<br>748.56 ± 42.66 |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 8 | High | prompt=1024<br>decode=128| 206.89 ± 6.09<br>317.14 ± 3.65 |
# Low Precision, 8 Threads
| model | modelSize | backend | threads | precision | llm_demo | speed(tok/s) |
| ----------------------------- | ---------- | ------- | ------- | --------- | ------------------------ | --------------------- |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 8 | Low | prompt=128<br>decode=128 | 291.25 ± 12.48<br>1549.26 ± 62.67 |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 8 | Low | prompt=256<br>decode=128 | 301.29 ± 14.12<br>1086.25 ± 19.91|
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 8 | Low | prompt=512<br>decode=128 | 282.61 ± 17.78<br>32.10 ± 0.41 |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 8 | Low | prompt=1024<br>decode=128| 223.93 ± 1.03<br>30.26 ± 0.18 |
# Low Precision, 4 Threads
| model | modelSize | backend | threads | precision | llm_demo | speed(tok/s) |
| ----------------------------- | ---------- | ------- | ------- | --------- | ------------------------ | --------------------- |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 4 | Low | prompt=128<br>decode=128 | 141.08 ± 0.47<br>1459.18 ± 20.27 |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 4 | Low | prompt=256<br>decode=128 | 164.22 ± 12.45<br>1084.68 ± 7.46 |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 4 | Low | prompt=512<br>decode=128 | 150.31 ± 1.24<br>35.14 ± 0.26 |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 4 | Low | prompt=1024<br>decode=128| 147.38 ± 0.34<br>32.54 ± 0.09 |
# High Precision, 8 Threads(第二次测)
| model | modelSize | backend | threads | precision | llm_demo | speed(tok/s) |
| ------------------------------ | ---------: | ---------- | ----: | ---------- | ---------- | ------------ |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 8 | High | prompt=128<br>decode=128 | 192.81 ± 15.27<br>1441.38 ± 101.12 |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 8 | High | prompt=256<br>decode=128 | 197.49 ± 3.67<br>284.73 ± 5.64 |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 8 | High | prompt=512<br>decode=128 | 188.80 ± 2.44<br>706.67 ± 17.71 |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 8 | High | prompt=1024<br>decode=128 | 174.25 ± 1.52<br>298.71 ± 6.05 |
希望团队能帮忙调查一下这个问题。非常感谢!
原因
原因是 gemma3 输出终止 token(stop_token) 非常快,实际只输出了 3~4 个 token 就结束了,而 llm_bench 中却根据输出 128 个 token 计算 decoding tps 指标,二者出现了偏差。
fix
修复的代码如下,计算 TPS 的 nGenerate 从 llm 中获取:
diff --git a/transformers/llm/engine/demo/llm_bench.cpp b/transformers/llm/engine/demo/llm_bench.cpp
index 029077f5..f32c8e36 100644
--- a/transformers/llm/engine/demo/llm_bench.cpp
+++ b/transformers/llm/engine/demo/llm_bench.cpp
@@ -892,6 +892,7 @@ int main(int argc, char ** argv) {
if (instance.mCmdParam.kvCache == "true") {
std::vector<int> tokens(prompt_tokens, 16);
+ t.nGenerate = 0;
for (int i = 0; i < instance.mCmdParam.nRepeat + 1; ++i) {
llm->response(tokens, nullptr, nullptr, decodeTokens);
auto prefillTime = context->prefill_us;
@@ -899,6 +900,7 @@ int main(int argc, char ** argv) {
if (i > 0) { // Exclude the first performance value.
t.prefillUs.push_back(prefillTime);
t.decodeUs.push_back(decodeTime);
+ t.nGenerate += llm->getCurrentHistory() - tokens.size();
}
}
if (printHeader) {
修改后打印的结果如下:
| model | modelSize | backend | threads | precision | llm_demo | speed(tok/s) |
|---|---|---|---|---|---|---|
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 4 | Low | prompt=128 decode=20 |
45.16 ± 0.19 50.01 ± 0.78 |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 4 | Low | prompt=256 decode=20 |
44.89 ± 0.52 48.47 ± 0.21 |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 4 | Low | prompt=512 decode=512 |
44.30 ± 0.17 48.58 ± 0.16 |
| gemma-3-1b-it-qat-q4_0-gguf-MNN | 994.65 MiB | CPU | 4 | Low | prompt=1024 decode=20 |
43.50 ± 0.11 46.38 ± 0.33 |
上一份评论中的代码有误,修复后的代码见 PR #3954
Marking as stale. No activity in 60 days.