3. 单GPU推理基础:加载模型、运行推理、理解性能瓶颈
有了环境,模型也下载好了,接下来就是真刀真枪地干活了。这一章,我带你走一遍单GPU推理的全流程。
说白了,这是后面多卡并行的基础。你连一张卡都玩不转,多卡肯定更头疼。我个人习惯,先跑通最小的闭环,再考虑优化。
3.1 模型加载:选对方式,省一半功夫
llama.cpp加载模型,核心就一个函数:llm_load_session。但参数怎么配,差别很大。
我的建议:第一次跑,用默认参数就够了。别一上来就调什么
--n-gpu-layers、--threads,容易把自己搞晕。
先看看最基本的加载命令:
# 最简单的CPU推理(测模型是否正常)
./main -m qwen2.5-7b-q4_k_m.gguf -p "你好" -n 64
# 启用GPU加速(把部分层卸载到GPU)
./main -m qwen2.5-7b-q4_k_m.gguf --n-gpu-layers 99 -p "你好" -n 64
--n-gpu-layers 这个参数,我刚开始搞的时候踩过坑。你以为设得越大越好?不一定。
来看这个表,就知道分层卸载是怎么回事:
| n-gpu-layers 值 | 计算位置 | 显存占用 | 适用场景 |
|---|---|---|---|
| 0 | 全部CPU | 极低 | 首次验证,测模型是否损坏 |
| 全部层数(如99) | 全部GPU | 最高 | 追求极致速度,显存足够 |
| 部分层(如20) | CPU+GPU混合 | 中等 | 显存不够时,兼顾速度 |
注意:显存不够时不要硬上全部GPU。我曾经把一张8G卡的
--n-gpu-layers设到100%,结果模型加载到一半直接OOM(Out of Memory)。最后只能退回到CPU+GPU混合模式。
3.2 运行推理:跑通第一句话
模型加载成功后,运行推理其实就一行命令。但这里面有几个关键参数,我得给你说明白。
./main -m qwen2.5-7b-q4_k_m.gguf \
--n-gpu-layers 99 \
--ctx-size 4096 \
--threads 8 \
--batch-size 512 \
-p "解释一下什么是量子纠缠" \
-n 256
几个关键点:
- --ctx-size:上下文窗口大小。你想想看,你问的问题越长,需要的上下文越大。但别设太大,显存会爆。
- --threads:CPU线程数。这个主要影响Prompt处理阶段(prefill),推理阶段(decode)影响不大。
- --batch-size:批处理大小。我建议别超过512,大了反而容易出奇怪的问题。
3.3 理解性能瓶颈:别只看Token/s
很多人跑完推理,看一眼Token/s就完了。太浪费了。这里面能挖的信息很多。
举个例子,推理过程其实分两个阶段:
- Prefill(预填充):处理你的输入Prompt。这一阶段计算量大,速度快不起来。
- Decode(逐token生成):一个字一个字往外蹦。这一阶段延迟高,是用户感知的“卡顿”来源。
你打开--verbose选项,就能看到这两个阶段的耗时。
./main -m qwen2.5-7b-q4_k_m.gguf --n-gpu-layers 99 --verbose -p "你好" -n 32
输出里会看到类似这样的行:
llm_load_tensors: offloaded 27/27 layers to GPU
llama_prompt_eval: time = 123.45 ms / 10 tokens (12.35 ms per token)
llama_kv_cache: re-creating cache for this model
llama_decode: time = 1234.56 ms / 32 tokens (38.58 ms per token)
注意看:llama_prompt_eval是prefill阶段,llama_decode是decode阶段。如果prefill太慢,说明你的Prompt太长或者模型太大。如果decode太慢,说明单卡算力不够了。
3.4 真正常见的瓶颈在哪?
我整理了一个清单,你跑完推理后,按这个顺序排查:
| 瓶颈类型 | 现象 | 最可能的解法 |
|---|---|---|
| 显存不足 | 加载模型直接报OOM | 降低--n-gpu-layers,或换小模型 |
| Prefill太慢 | 输入很长时,首token延迟高 | 增大--batch-size,或升级CPU |
| Decode太慢 | 生成时一个字半天才出来 | 这是单卡上限,多卡并行能解决 |
| 内存带宽瓶颈 | CPU-GPU频繁数据传输 | 尽量把层全卸载到GPU |
核心结论:单卡推理的瓶颈,90%出在decode阶段。而多GPU并行,正好是解决decode速度慢的终极手段。这就是为什么我们要学这个课程。
3.5 一张图看懂:单GPU推理全过程
下面这张SVG图,把整个流程和瓶颈点串起来了。你想想看,从加载模型到输出第一个字,中间经历了什么?
3.6 跑一个完整示例:从加载到输出性能报告
好了,理论知识差不多了。我们动手跑一个完整的测试命令:
# 1. 先跑CPU基准(n-gpu-layers=0)
./main -m qwen2.5-7b-q4_k_m.gguf \
--n-gpu-layers 0 \
--ctx-size 2048 \
--threads 8 \
--batch-size 512 \
--verbose \
--prompt "写一首关于春天的诗" \
--n-predict 128 \
2>&1 | tee cpu_benchmark.log
# 2. 再跑GPU加速(调用全部层)
./main -m qwen2.5-7b-q4_k_m.gguf \
--n-gpu-layers 99 \
--ctx-size 2048 \
--threads 8 \
--batch-size 512 \
--verbose \
--prompt "写一首关于春天的诗" \
--n-predict 128 \
2>&1 | tee gpu_benchmark.log
跑完之后,你对比两个日志文件里的llama_prompt_eval和llama_decode耗时。你会发现:
- Prefill阶段,CPU和GPU差距不大(因为计算量受内存带宽限制)
- Decode阶段,GPU快很多(这才是GPU真正发挥作用的地方)
实用技巧:我一般会保存每次跑出来的性能日志,格式化成表格。这样不同配置、不同模型之间的差异一目了然。
嗯,这一章就到这里。单卡推理是基本功,你把上面的流程跑一遍,理解每个阶段的时间开销,后面学多卡并行的时候,就知道每一分性能提升是从哪里来的了。