ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

老显卡也能跑35B大模型?llama.cpp五个优化让GTX 1060提速6倍

老显卡也能跑35B大模型?llama.cpp五个优化让GTX 1060提速6倍 前阵子有人问我GTX 1060 6GB这种五六年前的显卡能跑起来35B参数的模型吗我第一反应是劝他别折腾。直到自己实际用llama.cpp把Qwen 3.6 35B A3B跑起来并且针对老显卡做了几个关键优化生成速度从1.2 tokens/s拉到7.9 tokens/s接近6倍提升我才发现这个问题的答案比想象中乐观得多。这篇文章就是这次完整折腾过程的记录包含llama.cpp的五个核心优化技巧、参数配置、编译开关和排查思路适合手头只有老显卡、又想低成本跑新一代MoE大模型的朋友参考。1. 先看清模型与显卡的匹配关系MoE才是老卡能跑的根本原因1.1 A3B激活参数意味着什么Qwen 3.6 35B A3B这个型号很多人第一眼看到35B就吓退了。但真正决定推理速度的关键不是35B这个总参数量而是后面的A3B。A3B的全称可以理解为Activated 3 Billion也就是每次生成一个token时实际真正参与计算的参数只有30亿左右。这和传统稠密模型完全不同传统模型是35B参数全部参与计算而MoE模型走的是专家路由路线总参数写在模型文件里但单次推理只激活其中一小部分专家网络。拿书来类比35B总参数相当于你拥有一个35本书的大书架A3B则是你每次查资料真正拿下来翻看的那3本书。你翻书的速度取决于拿下来的书有多少而书架总大小只决定你需要多大的地方来放它们。放到模型推理上前者是生成速度后者是显存和内存容量要求。对GTX 1060 6GB这种老卡来说这个特性相当友好。因为生成速度不再被35B的总规模压垮而是被3B的激活规模决定。这也是为什么35B的MoE模型在老卡上跑反而可能比7B稠密模型更实用稀缺的不是显存带宽而是运行内存的容量和带宽。1.2 GTX 1060 6GB的能力边界GTX 1060 6GB是Pascal架构算力6.12016年发布。放在今天它的显存只有6GB显存带宽约192GB/s左右放在大模型推理场景下几乎是喝茶看报的水平。但它真的一点用都没有吗也不是。llama.cpp对老卡的支持反而是它最大的价值。它可以做CPU和GPU混合推理也就是把一部分计算层放到显卡上加速另一部分留在CPU上跑。GTX 1060的6GB显存放不下20多GB的模型文件但可以放下一部分注意力层和KV Cache剩下的专家层留在内存里由CPU执行。这等于给老卡找了一条务实路线不必完整装下模型只需要找到哪些层放GPU收益最大、哪些层留CPU损失最小的最优组合。这个组合找对了速度提升是倍数级的。接下来要讲的几个优化技巧本质上都是围绕这个分配问题展开的。2. 第一个优化点GGUF量化档位别无脑选Q4_K_M2.1 MoE模型对不同量化档位的敏感度很多人在llama.cpp里跑模型习惯性下载Q4_K_M觉得这个档位又小又稳。但放到MoE模型上事情没有这么简单。MoE模型的参数量大头在专家层。专家层是稀疏计算的每个token只激活少量专家但每个专家的权重参数依然要完整保存在内存里。量化时如果档位压得太狠比如Q2_K_XS或Q3_K_S专家权重的精度损失会被门控路由放大导致生成质量明显下降。如果档位选得太高比如Q6_K甚至Q8_0文件体积大幅增加内存带宽压力上来生成速度又会掉得很难看。我的实际经验是Qwen 3.6 35B A3B这类模型Q4_K_S和Q4_K_M之间质量差异很小但速度和内存占用差异明显。Q4_K_S比Q4_K_M减少了约10%的文件体积在内存带宽受限的老平台上这个体积差会直接转化成生成速度差。如果你本身内存只有16GBQ4_K_S甚至可能成为能否跑起来的决定性因素。2.2 我的量化档位实测结果我在同一套环境下用同一个Prompt分别测了三种常见档位生成150个token结果如下量化档位模型文件大小平均生成速度主观质量感受Q3_K_S约14GB8.1 t/s中文长句偶尔逻辑跳跃代码注释容易语序混乱Q4_K_S约16GB7.6 t/s日常对话完全够用代码质量可以接受Q4_K_M约18GB6.9 t/s质量略好但速度下降约10%注意这是已经做了后续GPU offload优化后的数据。在纯CPU跑的时候Q4_K_S和Q4_K_M的速度差只会更大因为内存带宽占用更紧张。结论是如果你的目标是能流畅聊天或能写简单代码Q4_K_S是性价比最高的档位。如果对质量比较敏感Q4_K_M是更稳妥的选择。至于Q3_K_S除非内存实在不够否则不建议用MoE模型的稀疏散布特性会让低比特量化的质量损失比稠密模型更不可控。2.3 下载和转换GGUF时的注意事项我额外提醒两个细节。第一个是优先下载社区里已经转换好的GGUF分卷文件不要自己用llama.cpp的convert脚本转原始模型除非你想折腾。转换脚本对模型目录结构有要求Qwen这类模型还涉及tokenizer配置新手很容易在转换阶段卡住。第二个是验证GGUF文件的分卷是否完整。很多分卷文件是用gguf-split切出来的下载时少一个文件加载时不会报错但生成到一半可能突然崩溃或者出现乱码。我的习惯是下载后用llama-cli -m xxx.gguf -n 0快速验证一次能正常加载并打印模型信息再投入实际使用。3. 第二个优化点attention放GPU、专家层留在CPU的显存分配法3.1 llama.cpp的MoE层调度参数怎么用llama.cpp从2024年底开始支持一个专门为MoE模型设计的参数--n-cpu-moe。这个参数的意思是指定多少个MoE专家层留在CPU上运行即使--gpu-layers已经把所有层都标记为GPU。为什么要搞这么个参数因为MoE模型的每一层里既包含attention结构也包含大量并行的专家FFN。如果整层一起放GPU专家层的权重会迅速撑爆显存如果整层一起放CPUattention部分又会拖慢整体速度。--n-cpu-moe允许你把专家部分独立拎出来放在CPU让attention层用上GPU加速。关键是理解负载的结构attention层的计算是稠密的每次都要跑放GPU收益极大专家层是稀疏的每次只激活少数专家放CPU跑也不至于让CPU满载。这两者的混合刚好适合6GB显存的老卡。3.2 适合6GB显存的分配方案我的最终配置思路分三步走。第一步确定显存总预算6GB里要留出约1GB给系统和其他占用实际能用的约4.5GB到5GB。第二步用较低的-ngl值先把部分完整层放上GPU再加上--n-cpu-moe把所有专家层留在CPU。第三步通过观察llama.cpp启动日志里显示的显存占用微调-ngl数值。实际命令示例llama-cli -m Qwen3.6-35B-A3B-Q4_K_S.gguf \ -ngl 28 \ --n-cpu-moe 64 \ -t 6 -tb 4 -b 512 -ub 512 \ -fa off \ --cache-type-k q8_0 --cache-type-v q8_0 \ --ctx-size 8192这里的-ngl 28表示把前28个完整计算节点放到GPU上--n-cpu-moe 64表示把64个MoE专家层全部保留在CPU。这个数字不是乱写的具体值要看模型的config里num_local_experts和总层数。你可以先用-ngl 99启动一次看日志里打印的层数信息再回来调整。3.3 显存OOM后的处理链路如果你第一次启动就OOM不要慌按这个顺序排查查看llama.cpp启动日志里最后一行是在加载哪个层时爆的显存是attention层还是expert层。如果是attention层爆的把-ngl往下调每次减4直到能正常启动。如果是expert层爆的检查--n-cpu-moe是不是设得不够大或者模型层总数比64多。检查显存是否被其他程序占用。Windows下尤其注意浏览器开一堆标签页、桌面环境特效都会吃掉几百MB显存。最后才是考虑缩小上下文长度或换更低位量化档位。我遇到过一种比较隐蔽的情况启动时不OOM但跑了一段时间后OOM。多半是KV Cache增长导致的。llama.cpp在推理过程中会动态分配KV Cache如果上下文设置得长显存就会慢慢被吃掉。这种情况下降低--ctx-size比降低-ngl更有效。4. 第三个优化点启动参数与编译开关里的隐藏空间4.1 线程数、批大小怎么设不是玄学很多人在llama.cpp的线程参数上吃过亏尤其是CPU和GPU混合推理时。-t过高不一定更快反而可能因为线程争抢内存带宽而拖慢推理。我的经验是-t设为CPU物理核心数不要用逻辑线程数。比如Ryzen 5 5600是6核12线程设-t 6。混合推理时6个物理核心既要负担部分attention计算还要负责所有专家层的稀疏计算线程数再多只会增加调度开销不会带来线性收益。-b和-ub分别控制批处理和连续批处理的大小。在显存不爆的前提下512是一个稳妥值。我测过256和1024差异不算大但1024在某些长Prompt场景会偶发显存波动512表现最稳。这里给一个快速验证方法每种参数组合跑同一段Prompt用llama.cpp自带的时间统计看prompt eval和eval两个耗时。prompt eval慢说明批大小或attention层分配有问题eval慢说明专家层或内存带宽压力大。对症下药比瞎调省时间。4.2 老卡编译llama.cpp要开的两个关键选项如果你用的是官方Release的预编译版本肯定没开到老卡的最佳状态。GTX 1060这种Pascal架构有两个编译开关值得关注。第一是GGML_CUDA_FORCE_MMQ。llama.cpp默认在某些GPU算力条件下走cuBLAS或者更通用的路径但对Pascal架构来说强制走MMQ矩阵乘法量化内核往往更快。MMQ是专门为量化权重优化的矩阵乘法实现在老架构上的表现比通用浮点路径好不少。第二是确保CMAKE_BUILD_TYPERelease并且不要开GGML_CUDA_NO_PEER_ACCESS之类不必要的限制。编译命令可以参考cmake -B build \ -DGGML_CUDAON \ -DCMAKE_BUILD_TYPERelease \ -DLLAMA_CUDA_FORCE_MMQON \ -DGGML_NATIVEON cmake --build build --config Release -j 8编译完成后建议再跑一次llama-cli -n 0确认能正常加载然后对比一下编译前后的eval耗时这个优化通常能带来15%到20%的生成速度提升。4.3 flash attention在Pascal卡上需要验证后再开-fa on是llama.cpp里一个吸引人的开关理论上能显著提升attention计算效率并减少显存占用。但在GTX 1060上我实测结果是相反的开着-fa on反而比-fa off慢了约10%。原因在于llama.cpp的flash attention实现在CUDA路径上对不同架构的支持程度不同。Pascal架构的shared memory和线程调度能力有限强行用flash attention反而增加kernel launch开销。新版本llama.cpp可能改善了一部分但我在1060上依然建议关掉。测试方法很简单同样一段Prompt分别开和关看哪个eval时间短以实际数据为准。5. 第四个优化点上下文长度与KV Cache是容易忽视的吞吐杀手5.1 KV Cache量化及对总延迟的影响很多人只盯着模型权重的量化忽略了KV Cache的影响。事实上在长上下文场景下KV Cache的读写占用的内存带宽会直接挤占专家层权重读取的带宽。llama.cpp提供了KV Cache的量化参数--cache-type-k和--cache-type-v。我推荐设成q8_08bit量化几乎无损但缓存体积比FP16减半。对于6GB显存的老卡这意味着同样的上下文长度KV Cache占用的显存少了一半能给-ngl留出更多余量。具体设置为--cache-type-k q8_0 --cache-type-v q8_0实测下来q8_0和默认FP16的KV Cache质量差异几乎感知不到但长对话下的总延迟明显下降。5.2 上下文长度该压到多少才合理我强烈建议在GTX 1060这种平台上--ctx-size不要超过8192。原因有两个。第一上下文越长KV Cache越大CPU和GPU之间来回读写的压力就越大。生成速度会随着对话轮次增加而逐步下降这是最影响体验的。第二MoE模型的expert层权重要频繁从内存读取如果KV Cache又占掉大量带宽两个需求就会打架生成速度进一步恶化。我调参时试过32768上下文和4096上下文同一个模型在32768下跑多轮对话生成速度会跌到4 t/s左右而4096下稳定在6到7 t/s。如果你的实际场景不需要超长上下文压到4096留出来的带宽能让生成速度快不少。如果需要处理长文档建议单独开一个长上下文的进程而不是日常聊天也顶着长上下文跑。6. 第五个优化点硬件层面的隐性瓶颈内存带宽比显存更关键6.1 单通道与双通道内存的实测差异很多人在调llama.cpp参数上花了一整天却不愿意拆开机箱看一眼内存条插法。但在这种模型权重放内存、CPU负责专家层计算的架构下内存带宽就是命根子。GTX 1060只有6GB显存大部分模型权重要放在系统内存里。每生成一个token都要从内存读取若干GB的权重数据。如果内存只有单通道带宽直接减半生成速度会成倍下降。我在换双通道内存前后的实测对比很明显同样是Q4_K_S档位、同样的参数单通道DDR4 3200跑出来3.9 t/s双通道跑出来7.2 t/s差距接近翻倍。所以如果你还插着单根内存条别急着换显卡先花几百块加一根同规格内存条组成双通道收益比换卡高得多。6.2 CPU供电、散热和系统层的细节还有几个容易忽略的硬件细节。第一是CPU的持续负载问题llama.cpp跑混合推理时CPU会长时间高负载运行如果散热不好降频后会直接影响生成速度。我遇到过一个很典型的案例笔记本用户的CPU温度冲上95度全核锁到2GHz速度从5 t/s掉到2 t/s。第二是电源供电和系统设置。Windows下把电源计划设为高性能Linux下检查一下CPU的cpufreq governor是不是performance这些细节虽然看起来无关紧要但连续推理10分钟以上后差异会越来越明显。第三是关闭桌面环境里不必要的动画和后台软件。这条建议听起来像玄学但老显卡的显存本身紧张任何额外占用显存的程序都可能让模型推理提前遇到OOM。7. 整套优化实测从1.2 t/s到7.9 t/s的全过程7.1 测试环境与基线最后把整个优化过程串起来看一遍。我的测试环境硬件/软件配置CPUAMD Ryzen 5 5600 6核12线程内存32GB DDR4 3200双通道显卡GTX 1060 6GB系统Ubuntu 22.04llama.cpp最新master分支手动编译开启MMQ基线是默认参数、全CPU运行、Q4_K_M量化、不编译MMQ、开flash attention最终结论是1.2 t/s。说实话这个速度属于能出字但没法聊天的水平一句话要等好几秒。7.2 逐步调整的参数与速度变化我按照每次只改一个变量的原则逐步叠加优化步骤修改内容平均生成速度变化幅度基线默认参数纯CPUQ4_K_M1.2 t/s-步骤1自己编译开启MMQ Release1.4 t/s16%步骤2关闭flash attention1.6 t/s14%步骤3Q4_K_M换Q4_K_S1.9 t/s18%步骤4GPU offload attention层-ngl 28--n-cpu-moe 644.6 t/s140%步骤5KV Cache换q8_0--ctx-size降到81926.1 t/s32%步骤6内存双通道 线程参数微调7.9 t/s29%从1.2到7.9正好接近6倍。可以看到最大的一次提升来自GPU offload attention层那一步这也是为什么我一直强调老卡跑MoE模型的关键不是无脑把模型塞进显存而是找到正确的分配策略。7.3 调参后的模型实际对话体验7.9 t/s是什么概念大概相当于一个打字速度比较快的人每秒蹦出接近8个汉字。等一句话20到30个字大概需要3到4秒对于35B级别的模型来说这个体验已经可以从没法用变成能聊天了。写点小脚本、做个翻译、整理会议纪要都没问题。我的个人体会是这套优化做完之后瓶颈已经不在显卡上而在CPU处理专家层的速度和内存带宽的极限。如果你想在这个基础上再进一步可以考虑换更高频率的内存、换支持更多内存通道的平台或者干脆把模型降到Q3_K_S用一点质量换速度。但就GTX 1060 6GB这张卡来说7.9 t/s已经是一个很务实的终点。最后再分享一个经验调参时一定要每次只改一个变量并且把每次的生成速度记录下来。只凭感觉去调最后只会浪费时间还会得出一个完全无法复现的经验。把数据留下来你才知道是哪个参数真正起了作用以后换模型时也可以直接参考。
返回列表