本地跑 Ollama 时最常遇到的两种情况:一是模型加载后风扇狂转但输出慢得像挤牙膏,二是显存明明还剩不少却报内存不足。这两种大概率都跟 num_gpu 这个参数有关。这篇把它控制的到底是什么、和 Ollama 自动判断的关系、手动设多少合适、以及设了没反应的排查顺序讲一遍,让你按自己的卡和模型调出合理档位。
本地跑 Ollama 最常撞上的两种情况:一是模型加载完风扇狂转,输出却慢得像挤牙膏;二是显存看着还剩不少,偏偏报内存不足。这两种大概率都跟 num_gpu 这个参数有关。它名字起得有迷惑性,很多人以为是「用几张卡」或者「显存上限」,其实都不是。
这篇把它控制的到底是什么、跟 Ollama 自动判断是什么关系、手动设多少合适、设了没反应按什么顺序排查,一条条讲清楚。你看完不用照抄别人的数字,按自己的卡和模型调出一个合理档位就行。
num_gpu 管的到底是什么
它控制的是「有多少层模型权重被卸载到 GPU 上跑」,剩下的层留在内存里由 CPU 扛。不是显卡数量,不是显存上限,也不是并发数。搞混这一点,后面所有判断都会歪。
- 层数
- 模型被切成很多层,num_gpu 决定其中多少层交给 GPU,其余给 CPU
- 不设置时
- Ollama 自己估一个值,估得偏保守或偏激进都有可能
- 真正占显存的东西
- 权重层、KV 缓存、并发切分,三者互相挤占同一块显存
- 层数只管「多少权重放显存」,管不了你开多长的上下文
- 它和量化档位是此消彼长的关系:量化越轻,同样显存能塞的层越多
- 调大它不代表一定更快,超过某个点收益会明显变缓
- 它和你用几张卡无关,多卡是另一套并行配置的事
先看默认值,再决定要不要手动改
别上来就盲设。Ollama 加载模型时会自己算一个层数,你要做的是先看它算出来是多少、实际跑成什么样,再判断要不要插手。跳过这一步直接改,很容易把原本合理的估算打乱。
- 看当前实际加载情况模型跑起来后用 ollama ps 看它加载了多少层、哪部分是 CPU 在扛,这是你的起点数据
- 判断默认值够不够用显存有余量、速度也正常,就继续用默认;显存只用了小一半却明显慢,才是需要手动的信号
- 确认卡的正常水平拿同卡同模型的社区预期速度做个粗参照,或者用站内测速工具量一遍基线,别凭手感判断快慢
| 观察到的现象 | 大概率原因 | 先做什么 |
|---|---|---|
| 显存只用了小半,速度明显偏低 | 默认卸载层数偏保守 | 小幅上调层数后复测 |
| 加载直接报内存不足 | 默认层数偏激进或余量算少了 | 往下压层数或降量化档位 |
| 加载成功但输出忽快忽慢 | 层数踩在余量边界,模型反复重载 | 退一层,留出稳定余量 |
| 速度和显存都对得上预期 | 默认值合理 | 什么都不用改 |
注意这个判断有一个不适用场景:如果你的机器压根没被 Ollama 识别到独立显卡,那看到的「慢」跟层数无关,先解决识别问题再说,往上加层只会更慢。
num_gpu 的几种设置方式与生效位置
设置方式有三种,用途不一样,混着用最容易出「我明明设了怎么没变」的问题。命令行临时生效适合试值,环境变量全局生效适合固定习惯,Modelfile 里写死适合某个模型长期用一套参数。
- 命令行临时生效:适合一次性试层数,退出就没了,试出好值再固化
- 环境变量全局生效:对所有模型默认生效,适合你只有一张卡、习惯固定档位的场景
- Modelfile 写死:跟着模型走,适合某个大模型单独配一套参数,不受全局影响
- 优先级上后设的覆盖先设的,同一模型同时存在多处设置时以更贴近模型的那份为准
- 无论哪种方式,改完都不会对已经在跑的模型热生效,必须重新加载
# 临时指定层数并加载模型(示意,层数按自己机器填)
OLLAMA_NUM_GPU=20 ollama run 模型名
# 模型跑起来后,看实际卸载了多少层
ollama ps验证有没有生效,别看自己输入了什么,去看运行时的实际层数。这是新手最常犯的错:以为设了就生效了,其实被别处的配置覆盖了。
按显存给一个层数:可以照着走的步骤
思路不复杂:先知道整模型有多少层,再估单层权重在当前量化档位下占多少显存,最后给 KV 缓存和系统留出余量,剩下的才是能卸载的层数。具体每个模型的层数和显存对照,到 /models/deploy 自己算一遍更靠谱,别照抄别人的数字,卡不一样、量化不一样,抄来的值基本没用。
- 记住整模型层数这个数在模型信息里能查到,是你所有计算的分母
- 估单层显存开销结合当前量化档位估算,量化越轻单层越小,能塞的层越多
- 留出安全余量给 KV 缓存、系统占用和其他进程留出空间,别把显存吃到见底
- 先设一个能吃下的层数跑起来看 ollama ps 和实际显存占用,确认稳定
- 小步往上加一层再测出现加载失败或直接被退回 CPU,说明踩到余量底线,退回一层即可
这套步骤在单卡、显存就是唯一瓶颈时最有效。如果你同时开了别的吃显存程序,或者机器本身内存也不宽裕,就得把余量留得更保守,甚至先关掉其他程序再调。
只卸载一部分层行不行,会有什么表现
行,而且是常态。部分卸载的意思是权重一部分在显存、一部分在内存,每算到分界处都要在内存和显存之间搬一次数据。这个搬运是有成本的,所以速度不会随层数线性上涨。
- 超过某个层数后收益明显变缓,这时候继续加层不如换个更小的量化档位
- 显存特别紧张时,宁可少卸几层保住速度下限,也不要把余量吃干净
- 反复重载是最坏情况,比稳定跑在部分卸载状态更拖后腿
- 判断标准很简单:加了层速度没起色,就说明你已经过了那条收益拐点
有个例外要注意:如果模型大部分层都在 CPU 上、只有少数层在 GPU,整体速度会被 CPU 拖住,这种情况加层确实有用,直到瓶颈从 CPU 转到显存为止。所以先搞清楚当前瓶颈在哪,再决定是加层还是换量化。
设了还是慢:排查顺序
按顺序往前排,能省很多来回。最怕的是一上来就怀疑层数设低了,结果折腾半天发现压根没识别到卡。
- 确认跑的是 GPU 版不是 CPU 版有些机器上 Ollama 没识别到独立显卡,速度慢跟层数毫无关系
- 确认参数真正生效看运行时的实际层数,而不是看你输入了什么,排查是否被别处配置覆盖
- 确认显存没被别的进程占看看是不是其他程序在抢显存,或者模型被反复卸载重载
- 最后才怀疑层数设低前面都排干净了,再小步上调层数复测
| 排查顺序 | 看什么 | 结论方向 |
|---|---|---|
| 1 | 是否识别到显卡 | 没识别先解决驱动和识别问题 |
| 2 | 运行时实际层数 | 和输入值不一致就是配置被覆盖 |
| 3 | 显存占用与重载情况 | 被抢或反复重载,先腾空间 |
| 4 | 层数与量化档位 | 都正常才对层数和量化下手 |
这条排查链不适用的一种情况:你的慢是出在模型本身太大、或者提示词特别长导致每次都要重算,那属于另一类问题,往下调层数也救不了。
和量化、上下文、并发的关系(什么时候不用调它)
num_gpu 不是孤立参数,它跟量化档位、上下文长度、并发数一起抢同一块显存。只看它一个,往往调到最后一头雾水。
- 量化档位越低,单层越轻,能塞进显存的层数越多,调不动时换量化往往比调层数有效
- 上下文开得越长,KV 缓存占的显存越多,留给权重的空间越少,两者必须一起看
- 多并发场景下显存被切分,num_gpu 应该往下压而不是往上顶
- 换模型后所有参数都要重估,上一套值搬过来不一定合适
还有一个明确的不适用场景:如果你压根不做本地推理、直接调各家 API,这个参数跟你一点关系都没有。别在这儿耗时间,把精力放在挑选合适的中转站和比价上更划算,这类信息可以到 /sites 和 /price-watch 看当时的数字。
一份可照着勾的调参清单
把前面几节压成一张能直接照着做的清单。核心是别跳步、别一次性大改、别凭手感判断快慢。
- 确认显卡被识别,确认跑的是 GPU 版
- 看默认卸载层数与显存占用,确认是否需要手动介入
- 用测速工具记录当前输出速度作为基线
- 小步加减层数,每次改完重新加载并复测
- 把层数、量化档位、上下文长度、速度记在同一张表里,换模型时不用从零试
- 速度没起色就换量化或查上下文,别再跟层数死磕
基线这一步很多人偷懒,结果调了半天不知道到底有没有变快。速度基线可以用站内测速类工具先量一遍,你看的是相对变化,不是绝对数字。
下一步想看各模型的层数、量化档位和显存对照,自己算一遍比抄别人的值靠谱;顺手把测速基线也量了,后面调参数才有参照。→常见问题
num_gpu 是不是设得越大越快?
不是。它只决定多少层放显存,放到某个点之后再加层收益很小,而显存被吃满会触发重载甚至加载失败,反而更慢。做法是先看默认值和实际占用,再小步往上加,速度不涨就退回去。
我把 num_gpu 设成 0 会怎么样?
相当于全部用 CPU 跑,速度会明显掉下来,但显存占用极低。这个设置适合显卡特别小、只想验证模型能不能跑通的场景,不适合日常使用。想调回来的话把参数去掉或改成合适的层数即可。
为什么我设了参数但看起来没生效?
最常见的原因是没有重新加载模型,参数不会对已加载的模型热更新;其次是写在了不会被读取的位置,比如只改了某个终端的环境变量。改完用 ollama ps 看实际层数,比看你输入了什么更可靠。
设高了报内存不足,是不是显存不够只能用 CPU?
不必。先退一层到能加载为止,或者把量化档位降一档、把上下文长度调小,通常就能在显存里塞下更多层。全部退回 CPU 是最后的选择,中间还有不少可调空间。
这个参数和显卡数量有关系吗?
名字容易让人误会,它指的是卸载到 GPU 的层数,跟插了几张卡没关系。多卡场景下显存怎么切分是另一套机制,别指望靠调这个数字把第二张卡用起来。