让 2B 当侦察兵:投机解码的原理、实测数据与失效边界
让 2B 当侦察兵:投机解码的原理、实测数据与失效边界
上一篇我们提到,2B 小模型最"值钱"的用法之一是给大模型当草稿机。这个技术的正式名字叫投机解码(Speculative Decoding)。它的效果相当戏剧化:有人实测把 27B 模型的生成速度从 25 tok/s 提到 45 tok/s,也有人实测把 60 tok/s 掉到 45 tok/s——用的是同一个技术。
本文面向没有推理优化背景的读者,先讲清"为什么能加速",再讲清"为什么有时反而变慢",中间穿插多组真实实测数据。
一、先搞懂一个反直觉的事实:大模型生成慢,不是因为算不过来
这是理解投机解码的唯一前提。
大模型生成文字是一个字一个字往外蹦的(术语叫自回归)。每蹦一个字,都要把整个模型的全部权重从显存里完整读一遍。以 27B 模型 Q4 量化为例,权重约 16 GB——也就是说,每生成一个字,就要搬运 16 GB 数据。
这带来一个关键结论:瓶颈在内存带宽,不在计算能力。显卡的计算单元绝大部分时间在空转等数据。用一张带宽 936 GB/s 的 RTX 3090 举例,理论上限就是 936 ÷ 16 ≈ 58 tok/s,无论这张卡的算力有多强。
所以加速的方向有两条:
- 减少要搬运的数据量(量化、用小模型)——代价是质量。
- 让空转的算力干点活——这正是投机解码的思路,且不损失任何质量。
二、核心思路:让便宜的小模型去"猜",让贵的大模型去"批改"
打个比方。大模型是个写文章很慢但水平很高的资深编辑,小模型是个打字飞快但水平一般的实习生。
- 传统方式:编辑一个字一个字亲自写,写一个字想一下,慢。
- 投机解码:实习生先一口气猜出接下来 5 个字,编辑拿过来一次性扫一眼——“前 3 个对,第 4 个不对”。于是前 3 个字直接采纳(几乎白赚),第 4 个字由编辑自己改,第 5 个字扔掉重来。
关键在于:编辑一次性检查 5 个字的成本,和检查 1 个字的成本几乎一样。因为权重的搬运量在一次前向传播里是固定的,检查 5 个 token 只是把这条数据多算几遍而已——而算力本来就是空闲的。
别把 2B 当小号 GPT-4:llama.cpp + Qwen 2B 的六种实战玩法
别把 2B 当小号 GPT-4:llama.cpp + Qwen 2B 的六种实战玩法
在本地跑一个 2B 级别的模型(Qwen2.5-1.5B、Qwen3-1.7B 这一类),最常见的失望是「它连个像样的回答都给不出来」。于是很容易得出一个结论:小模型没用,还得上 32B 甚至 72B。
这个结论错在前提。2B 的定位从来不是"小号 GPT-4",而是流水线里一个廉价、快速、输出确定的专用零件。
在一台普通笔记本上,Qwen 2B(Q4_K_M 量化)的生成速度可以轻松跑到 30 tokens/s 以上,显存占用不到 2GB。这意味着它一秒能吞下几十条请求。真正的技术含量不在于它有多聪明,而在于你如何把任务切到它擅长的那一格。
一句话概括本文的判断:不要让小模型去"思考",要让它去"填空"。
先确认你的跑法
下文所有玩法都建立在 llama-server 上——它提供 OpenAI 兼容接口,任何现成的 SDK 都能直接接。一个够用的启动命令:
./llama-server \
-m models/Qwen2.5-1.5B-Instruct-Q4_K_M.gguf \
-c 4096 \
-np 8 --cont-batching \
--jinja \
--host 127.0.0.1 --port 8080
几个参数值得单独说明:
| 参数 | 作用 |
|---|---|
-c | 上下文长度,小模型不要盲目开大 |
-np --cont-batching | 并行槽位 + 连续批处理,是批量吞吐的关键 |
--jinja | 启用模型自带对话模板,工具调用能力依赖它 |
-ctk q8_0 -ctv q8_0 | KV Cache 量化,长上下文时能省一半显存 |
--mmproj xxx.gguf | 加载视觉投影层,进入多模态模式 |
玩法一:语法约束输出器 —— 最高杠杆的一招
llama.cpp 原生支持 GBNF 语法与 JSON Schema 约束解码。这是它相对于 vLLM、Ollama 最显著的差异点,也是让 2B 从"勉强能用"跳到"近乎可靠"的关键。