上篇文章《P104-100 矿卡跑 35B-A3B 大模型:从“电子垃圾”到“Token FREE”》里,我们硬趟了驱动、编译、共享内存三股浑水,终于让这张被时代抛弃的魔改矿卡,在 Ubuntu 下跑起了35B缩编版 Qwen3.6-28B-A3B 这个 28B 的巨物。当时速度稳在二十出头,我已经觉得“矿渣”复活了。

但用过几天后,总觉得那股“矿工之魂”还没烧干净。显存明明有 8GB,比那些 4GB、5GB 的亮机卡宽裕多了,凭什么只跑 20 t/s?是参数没调到位,还是卡本身就只能到这里了?

于是就有了这一篇——用 llama-bench 一档一档地试,把 P104 最后那点隐藏性能,连根刨出来。


一、老规矩,先把能动的旋钮搞明白

在开始盲目跑分之前,必须先学习学习弄清楚到底有哪些参数可以拧。上一篇我们主要解决了“能不能跑”的问题,参数都是求稳的保守值。现在要追求性能,就得理解背后的原理。

MoE 模型(混合专家)每一层都包含两个部分:轻巧但频繁使用的共享注意力模块,和庞大但每次只激活少数几个的MoE 专家模块。我们的核心思路不变:把必须快的东西留在 GPU,把占地方的东西赶到 CPU 内存。 具体到 llama.cpp 里,有三个关键杠杆:

  • -ngl(GPU 层数):控制模型多少层加载到 GPU。越大越快,但显存也越紧张。在我们测试P2000时我们已经验证了 -ngl 999(能进则进)是可行的,这篇全程保持 999。
  • --n-cpu-moe(MoE 专家卸载):这是重中之重。它指定前 N 层的 MoE 专家模块留在 CPU 内存,而注意力模块照样进 GPU。这个参数是显存与速度之间的唯一旋钮——n-cpu-moe 越小,留在 GPU 的专家越多,速度越快,但显存占用也越高;稍微越界,程序直接崩溃。
  • -ctk / -ctv(KV Cache 量化):我们已经固定使用 q8_0,它在长上下文下能省下近一半的 KV 缓存空间,而且质量几乎无损。

理解了这个关系,今天的任务就很明确了:在 -ngl 999 的前提下,一步步减小 --n-cpu-moe,直到找到既不爆炸、速度又最快的那个临界点。


二、实战:四轮测试,逼出 30 t/s

测试平台还是那台没锁我可以升级的老家伙:NVIDIA P104-100 8GB,Ubuntu 24.04,i7-6950x,llama.cpp build: (8981)。模型依然是
Qwen3.6-28B-REAP20-A3B-Q4_K_M.gguf(16.07 GiB,28.24B 参数)。下面所有数据都是 llama-bench 实测,pp512 是处理 512 token 提示的速度,tg128 是生成 128 token 的速度——后者才是你实际聊天时感受到的快慢。

第一轮:保守探路,打下基线

先从最保守的值开始——--n-cpu-moe 36,把绝大多数专家都卸到 CPU,留出充足的显存余量。

-ngl 999, --n-cpu-moe 36, -t 8, -ctk q8_0
pp512: 41.68 t/s
tg128: 26.51 t/s

26.51 t/s,比上篇的二十出头已经明显提升,而且运行极其稳定。这说明 -ngl 999 策略是有效的,把所有非 MoE 部分塞进 GPU 换来了可观的加速。既然这么稳,说明显存还有余量,那就减卸载层数。

第二轮:逐步施压,惊喜连连

依次把 --n-cpu-moe 往下调,让更多专家留在 GPU。测试数据如下:

n-cpu-moe

pp512

tg128

趋势

36

41.68

26.51

基线

32

46.12

27.71

30

48.51

28.18

28

50.60

28.85

24

55.53

30.06

新高

每一步,性能都在提升。pp512 从 41 一路涨到 55,说明 GPU 吃得越来越饱,提示处理越来越猛。而 tg128 也从 26.51 稳步爬到 30.06 t/s,首次突破 30 大关。此时,40 个 MoE 层里,有 16 层的完整专家都留在了 GPU,算力利用得相当充分,但显存还没报警。

第三轮:一脚踩空,撞上物理极限

30.06 t/s 已经让我两眼放光。既然 24 层还稳,那再少卸载两层,试试 --n-cpu-moe 22 行不行?

命令敲下去,没等来数字,程序直接 退出。没有 OOM 报错,没有警告,就是干干净净地退出了——典型的 CUDA 内存分配失败。此时的 P104,就像一头倔驴,多一根稻草都扛不住。

从 24 到 22,GPU 要多装整整两个 MoE 专家层。这俩层在 Q4 量化后约 1.2 GB,加上运行时开销,直接顶破了 8GB 的显存天花板。这条红线,就这么冰冷地刻在那儿:--n-cpu-moe 绝对不能小于 24。

第四轮:确认甜点,锁定最终配置

经过这轮暴力测试,P104 的最佳配置已经呼之欲出:

-ngl 999 --n-cpu-moe 24 -t 8 -ctk q8_0 -ctv q8_0 -c 65536 -np 1

这个组合下,Token生成速度稳定在 30 t/s,提示Prefill处理高达 55 t/s(呵呵,你别笑。P104接口速度也就这样了,我认了),显存刚好卡在安全线上。而且,和之前多轮测试一样,线程数 8 依然是最优解。试过 12 线程,反而掉速到 27 左右——原因还是老生常谈:MoE 卸载模式下,CPU 内存带宽是真正的瓶颈,线程多了互抢总线,得不偿失。


三、P104 的终极性能密码,就藏在这三条经验里

折腾完这一轮,我脑海里只剩三条血泪教训,也成为了以后调优任何老卡的固定流程。

1. 程序“闪退”才是真正的显存边界
你不用等 CUDA OOM 的红色报错。在 llama-bench 里,如果某个 --n-cpu-moe 值能跑出漂亮数字,下一个值直接程序退出,那这条线就是这卡的物理极限,一步都不能跨。P104 跑35B-A3B的这条线就是 22。

2. 二分法找 --n-cpu-moe 甜点最高效
从保守的 36 能跑,到激进的 22 崩溃,中间只测了四五个值就锁定了 24 这个最优解。千万别从零开始一个一个加——先用一个大跨步找到能跑和不能跑的两个端点,再在中间对折逼近,效率最高。

3. 线程不是越多越好,CPU 带宽是隐形天花板
无论是在 P104 还是之后的任何卡,只要你用了 --n-cpu-moe,CPU 就得频繁把专家权重从内存往 GPU 运。内存带宽是固定的,线程数一旦超出最优值,反而互相抢道。经验值是,老平台从 8 线程开始测,基本没错。


四、写在最后

从“矿渣”到“30 t/s 推理机”,这张 P104 的翻身仗算是打完了。

没有新驱动加持,没有专属优化,靠的就是对 MoE 模型结构的学习理解和几十行 llama-bench 的反复测试。把一层层专家权重拆开、分配,像玩一个极度烧脑的拼图游戏——直到所有碎片都卡在正确的位置上,性能喷涌而出。

如果你手里也有这么一张被时代遗忘的老卡,别急着挂闲鱼。装上 Ubuntu,拉下 llama.cpp,花一个下午去调调 --n-cpu-moe,它或许能给你一个远超预期的答案。

我知道还有说慢的,不过这速度养虾是足够了,欢迎来辩。

Logo

中国智能体开发者社区,聚焦智能体与大模型开发,提供前沿资讯、实用工具链、开源项目及行业案例。通过技术沙龙、开发者大赛等活动,促进经验交流与协作,助力开发者快速构建创新智能应用。

更多推荐