尧图网站设计 尧图网站设计YAOTU DESIGN
ARTICLE DETAIL

资讯详情

深耕网站设计与一线实操的经验洞察。

大模型量化推理与部署实战:从原理到vLLM和Ollama

大模型量化推理与部署实战:从原理到vLLM和Ollama 直接进入正题。这篇是“大模型推理优化”系列的 task5主题是量化推理与部署。前几个 task 我分别聊过 KV Cache、连续批处理continuous batching、投机采样和并行策略这次轮到量化。量化这个话题在大模型社区里热度一直很高核心原因很简单它能把推理成本打下来而且往往不需要你动模型结构、不需要重新训练属于“性价比极高”的优化手段。这篇文章我会从量化的核心原理讲起然后落到基于 vLLM 和 Ollama 这两类主流工具的实操部署最后把我在多个项目里踩过的坑整理成一份排查清单希望能给正在这个地方摸索的人提供一套可以“抄作业”的完整方案。1. 量化推理的核心逻辑为什么换一种数字表示就能提速省钱1.1 量化的本质用更少的比特数表达权重和激活值先做一个非常朴素的解释。大模型里的参数本质上是无数个浮点数。主流模型默认用的是 FP1616 位浮点或者 BF16bfloat16每个参数占 2 个字节。一个 70B 的模型光权重文件就有 140GB这在单卡 A100/H10080GB 显存上根本塞不进去更别提推理时还有 KV Cache 和激活值要占显存。量化的思路非常直接既然 FP16 表示范围那么宽而模型训练好之后权重数值往往集中在某个很小的区间里那我能不能用更少的比特数比如 8 比特、4 比特去近似表达这些权重答案是可以的。把 FP16 权重映射到 INT8 或者 INT4 的过程就叫量化。换算一下7B 模型用 FP16 要 14GB 显存用 INT8 只要 7GB用 INT4 只要 3.5GB。这个差距直接决定了一张 24GB 的消费级显卡能不能跑起 7B 甚至 13B 模型。可能有人会问那不用量化直接用 FP16 跑不行吗当然行如果你有足够多的 A100当然可以很“奢侈”地跑。但问题在于绝大多数团队和个人开发者手里的 GPU 资源是有限的或者是要按量付费的云实例。同样的模型量化之后能跑在更小的卡上单位 token 的成本直接下降这在生产环境里就是纯利润。注意量化不是“压缩文件”那种有损压缩的思维。它确实会引入精度损失但好的量化方案能把损失控制在一个可接受范围内甚至有些场景下量化后的模型表现和 FP16 几乎无差。1.2 计算瓶颈与访存瓶颈量化到底优化了哪个环节很多人以为量化就是在减少显存占用这只是表层。量化真正带来的收益来自它对“访存量”的缩减和“计算效率”的提升。要理解这一点得先搞清楚大模型推理是“访存密集型”还是“计算密集型”。在 LLM 的 decode 阶段也就是一个 token 一个 token 往外蹦的阶段每次只生成一个 token但需要读取整个模型的所有权重。假设模型是 7B FP16每生成一个 token 就要从显存里读取 14GB 的数据。这时候 GPU 的计算单元大多数时间都在“等数据”而不是“算数据”。这就是典型的访存密集场景——瓶颈在内存带宽而不在算力。量化之后权重用 INT8 或 INT4 存储读取单个 token 需要搬移的数据量就减少到原来的 1/2 或 1/4。数据搬运少了GPU 的等待时间就短了能效自然就上来了。这也是为什么在消费级显卡上量化的提速效果非常明显而在 A100/H100 这种大带宽卡上提速效果相对小一些但显存节省依然有巨大价值。另外在部分支持 INT8/INT4 矩阵运算的硬件比如 Ada Lovelace 架构的 GPU 拥有 FP16/INT8/INT4 张量核心上量化还能让计算单元同时处理更多数据。这就是“硬算力”的直接翻倍理论峰值。访存拉低、吞吐提高这两个收益叠加起来量化就成了推理优化里避不开的一环。1.3 常见量化精度选型INT8、INT4、W8A8 到底怎么选现在市面上的量化前缀特别多什么 GPTQ、AWQ、GGUF、W8A8、W4A16第一次看很容易懵。这里先帮大家梳理一下命名逻辑。形如“W4A16”这类写法W 指的是 Weight权重A 指的是 Activation激活值数字代表它们各自的量化位数。比如 W8A8 表示权重和激活值都是 8 比特量化W4A16 表示权重用 4 比特量化激活值保持 16 比特。这里有个重要的区别权重量化相对安全因为权重在推理过程中是固定的可以用很“重”的校准算法去找最优映射激活值量化就难得多因为激活值随输入变化分布波动大。所以早期成熟方案大多只量化权重保留激活值的高精度比如 GPTQ 和 AWQ 都是 W4A16 路线的代表。而 INT8 量化则倾向于权重和激活一起量W8A8配合支持 INT8 计算的新硬件在吞吐上优势明显。那么选型怎么判断如果你追求极致的显存节省能在小卡上跑更大模型优先考虑 4 比特方案GPTQ/AWQ 算权重GGUF Q4_K_M 提升兼容。如果你更看重推理速度尤其是高并发服务场景且硬件支持 INT8 张量核心W8A8 的全量化更合适。如果在 CPU 上推理或者做边缘部署GGUFllama.cpp 的量化格式几乎是一统天下的选择从 Q2 到 Q8 都有丰俭由人。注意量化位数越低精度损失通常越大但不是线性的。实测中INT8 的损失几乎可以忽略INT4 开始有感知差异3 比特以下就要仔细评估业务场景是否受影响了。2. 量化方案背后的关键技术原理2.1 校准数据集在量化中的作用没有校准数据的量化都是碰运气在动手量化之前得先搞明白一个概念校准calibration。像 GPTQ 和 AWQ 这类“训练后量化”PTQPost-Training Quantization方法并不是简单地把 FP16 权重除以某个最大值再取整而是需要用一小批真实输入去“观察”模型每一层激活值的分布范围然后基于这个范围设计量化区间。为什么需要这一步因为量化的本质是把一个连续的大区间映射到离散的小区间。如果区间设置得太宽小数部分的精度全丢了如果区间设得太窄大量超大值会被截断。校准数据集的作用就是让这个区间设置尽量贴合真实推理时遇到的数据分布。实操里校准数据集通常取 128~256 条样本就够了。但是选择什么样的样本很有讲究。如果你做的是代码生成模型结果拿一堆新闻文本去校准激活值分布会偏量化后的效果很可能不尽如人意。我个人的习惯是从真实的业务语料里采样覆盖不同长度、不同风格尽量平均分布。2.2 GPTQ 和 AWQ 在做同一件事但思路不同GPTQGeneralized Post-Training Quantization是目前流传最广的 4 比特量化方法之一核心思想是“逐层量化 误差补偿”。它把每一层的权重量化后计算量化引入的误差然后用 Hessian 矩阵损失对权重的二阶导数去指导误差补偿把误差分摊到这一层其他未被量化的权重上。这个思路可以概括为“先破坏再修复”用全局的视角减少单点量化带来的精度崩塌。AWQActivation-aware Weight Quantization则走了另一条路。它的核心洞察是一个权重矩阵里不同的通道对模型输出的重要性是不一样的而重要性可以从激活值的分布里看出来。AWQ 会统计每个通道的激活值尺度对于容易被量化误差“伤害”的重要通道给它乘上一个缩放因子保留更高的有效精度。翻译过来就是“重点通道重点保护”。这种方法的好处是量化速度快而且不需要像 GPTQ 那样反复迭代补偿。从效果上看在 4 比特量化这个档位AWQ 往往在指令跟随和复杂推理任务上比 GPTQ 稍稳一点尤其在量化 30B 以上的大模型时差异更明显。但 GPTQ 也不是没有优势它的生态更成熟vLLM、Transformers、ExLlama 都原生支持踩坑资料多排障也容易。提示在动手之前建议先想清楚自己的场景。不是所有人都有必要把 FP16 模型量化到 INT4。如果显存够用INT8 在速度和质量上更均衡如果追求极致调度INT4 才是正道。先明确约束再选方案。2.3 量化粒度per-tensor、per-channel、group 怎么选择量化粒度是另一个影响精度的重要参数。Per-tensor 量化是把整层所有权重共用一个缩放因子最简单但精度相对差。Per-channel 量化是对权重矩阵的每一行输出通道单独计算一个缩放因子精度明显提升也是目前最主流的做法。Group 量化group quantization则更进一步比如每 128 个参数一组每组独立缩放因子精度最高但需要存储的缩放因子也更多。Granularity 的选择其实是“存储开销”和“精度”之间的权衡。组越小量化越精细但额外的缩放因子会抵消一部分量化节省的空间。在 INT4 量化里常见的 Group Size 是 128。这个值不是随便定的而是经过大量实验得出的平衡点。在实际项目中如果量化后模型输出质量异常优先检查一下量化配置文件里的 Group Size 是不是设置得太粗了。2.4 权重分布中的离群值量化误差的大头来源说到量化绕不开“离群值”outlier这个概念。大模型的权重和激活值并不是均匀分布的大多数数值都集中在均值附近但偶尔会有一些特别大的离群值。如果量化区间为了容纳这些离群值而无限拉宽那些密集的“正常值”就会被压到非常窄的量化区间里精度损失惨重。AWQ 的思路前面讲了是通过缩放因子保护重要通道。还有一种常见的做法是“混合精度”也就是把少数离群值保留为 FP16其余部分量化到 INT8/INT4代表方法是 LLM.int8()。这种做法在万亿参数模型上表现稳健但在小模型上收益没那么明显而且会额外增加判断逻辑和访存开销。如果你要部署的模型在 7B~70B 这个范围用 GPTQ/AWQ Group Size 128 基本就够打了不必上混合精度这种重型方案。3. 实操基于 vLLM 部署量化模型3.1 环境准备与依赖安装在动手部署之前先把环境说清楚。我在生产环境里常用的组合是Ubuntu 22.04 CUDA 12.1 Python 3.10 PyTorch 2.1 vLLM 0.4 以上版本。如果你用的是 Docker可以直接拉 vLLM 官方镜像省去很多环境编译的麻烦。但我更推荐先在本地装好干净的 Python 环境因为很多时候排查问题需要跑脚本容器里反而多了一层隔阂。# 创建虚拟环境 python -m venv vllm_env source vllm_env/bin/activate # 安装 PyTorch根据你的 CUDA 版本选择对应 index-url pip install torch2.1.2 torchvision0.16.2 torchaudio2.1.2 --index-url https://download.pytorch.org/whl/cu121 # 安装 vLLM pip install vllm0.4.2安装完成之后可以用python -c import vllm; print(vllm.__version__)验证一下。vLLM 这个项目迭代速度极快版本之间 API 会有变化这里给出的命令针对 0.4.2 这个版本如果你用的是更新的版本以官方文档为准。注意vLLM 的安装对 GPU 驱动版本和 CUDA 版本有要求建议先确认nvidia-smi里显示的驱动支持的最高 CUDA 版本再决定 PyTorch 的 cu 版本避免安装完才发现 CUDA runtime 不匹配。3.2 量化模型从哪来直接下载 vs 自行量化部署量化模型第一步是拿到量化后的模型权重。有两条路一是直接从 Hugging Face 下载社区量化好的权重二是拿开源量化脚本自己量化。对于绝大多数场景我强烈建议直接用社区量化版本。为什么因为量化是一个需要大量实验的过程——校准数据集、量化参数、验证集效果每一步都可能影响最终质量。社区里的热门量化版如 TheBloke 系列通常经过了大量用户验证踩坑概率低很多。你需要做的事情就是根据框架要求选一个合适的量化方式。以 AWQ 为例在 Hugging Face 上找一个带-AWQ后缀的模型仓库然后下载下来。HF 的下载可以用huggingface-cli或者直接git clone如果仓库用 git-lfs。要注意量化模型的文件结构和 FP16 不同会多出quant_config.json之类的配置文件部署框架需要认读这些文件来正确反量化。如果项目特别在意数据安全或者模型是私有微调过的那就只能自己量化了。自量化推荐用 AutoAWQ 或者 GPTQ-for-LLaMa 的脚本。以 AutoAWQ 为例最简用法如下from awq import AutoAWQForCausalLM from transformers import AutoTokenizer model_path your_fp16_model_dir quant_path your_awq_model_dir quant_config {zero_point: True, q_group_size: 128, w_bit: 4, version: GEMM} # 加载 FP16 模型 model AutoAWQForCausalLM.from_pretrained(model_path) tokenizer AutoTokenizer.from_pretrained(model_path, trust_remote_codeTrue) # 量化并保存 model.quantize(tokenizer, quant_configquant_config) model.save_quantized(quant_path) tokenizer.save_pretrained(quant_path)这里有个容易踩的坑quantize方法里的tokenizer参数同时充当了“校准数据加载器”的角色所以你的 tokenizer 必须能和你的模型配合能正常把校准文本转成 input_ids。3.3 vLLM 启动量化模型一个完整的实测命令先交代一下我这一步实验的硬件环境单张 24GB 的 RTX 4090目标模型是 7B 参数规模的 AWQ INT4 量化模型。显存占用理论上在 5GB 左右实际跑起来加上 KV Cache 后大概在 8~10GB24GB 的卡跑起来完全没有压力并发能力也很不错。启动命令如下python -m vllm.entrypoints.openai.api_server \ --model /path/to/your/awq-model \ --quantization awq \ --dtype half \ --max-model-len 4096 \ --gpu-memory-utilization 0.9 \ --port 8000解释几个关键参数--quantization awq告诉 vLLM当前模型是 AWQ 量化格式。如果用的是 GPTQ就换成--quantization gptq。--max-model-len 4096控制上下文长度上限。显存不够用时调低这个值是最直接的释放显存手段。--gpu-memory-utilization 0.9设置 GPU 显存利用率上限。vLLM 会预留一部分显存给模型权重和 KV Cache这个参数决定它能吃多少显存。启动之后如果看到类似Starting vLLM API server on http://0.0.0.0:8000的日志说明服务已经起来了。然后可以用 curl 请求一下curl http://localhost:8000/v1/completions \ -H Content-Type: application/json \ -d { model: /path/to/your/awq-model, prompt: quantization 的本质是什么, max_tokens: 512, temperature: 0.7 }返回的 JSON 里choices[0].text就是模型生成的文本。这一步只需要确认服务能通生成速度后面再量化评估。3.4 量化前后对比速度、显存与生成质量三维评估部署完成不等于优化完成。我通常会做三组对比测试FP16 版本和量化版本在同一个 prompt 上的生成速度、显存占用、以及输出质量。速度可以用 vLLM 日志里打印的Throughput指标或者自己写个并发脚本测每秒生成 token 数。显存占用直接看nvidia-smi。在我实测的 7B 模型上FP16 版本的显存占用大约 14GBAWQ INT4 版本大约 4.5GB峰值时包括 KV Cache 也只有 9GB 左右。生成速度上单卡 4090 上 FP16 大概是每秒 60~80 tokensINT4 版本能到每秒 110~140 tokens提升接近一倍。这个提升主要来自访存量的降低前面讲过原理。质量评估我推荐两个维度一是通用基准测试二是业务场景实测。基准测试可以用 lm-eval-harness 跑一些公开任务比如 MMLU、GSM8K量化版本的分数降低通常不超过 1%——如果超过 3%就要怀疑量化的 calibration 或者参数设置有问题。业务场景实测更直观拿 20~50 条线上真实 prompt 分别问 FP16 和量化版本逐条比对回答质量重点看逻辑性、细节完整度、指令遵循度。这里给大家一个经验值INT8 几乎无损INT4 在通用对话场景损失轻微但在复杂代码生成、长文档摘要这类任务上偶尔会出现“知道答案但表述不准确”的情况。提示如果你是做生产部署上线前一定要做量化模型的回归测试。不要只看公开 benchmark 分数把自己的业务测试集跑一遍用统一评分标准对比量化版和原始版。这一步省不了也偷不了懒。4. 本地轻量化部署Ollama 与 GGUF 的工程化实践4.1 Ollama 加载 GGUF 量化模型一条命令跑通本地大模型除了以 vLLM 为代表的高并发服务端部署另一个非常常见的部署场景是本地个人电脑、离线环境或者边缘设备。这时候 Ollama 是一个极佳选择。Ollama 本身集成了 llama.cpp 的推理后端上层封装简洁拉起一个模型几乎只需要一条命令。Ollama 默认的模型仓库里已经有很多 GGUF 量化版本。如果你要用的模型不在官方列表里可以从 Hugging Face 下载 GGUF 文件然后写一个模型配置文件Modelfile加载进来。下面是我常用的步骤# 1. 安装 OllamaLinux/macOS curl -fsSL https://ollama.com/install.sh | sh # 2. 下载 GGUF 模型文件到本地目录 # 假设你下载了 qwen2.5-7b-instruct-q4_k_m.gguf # 3. 创建 Modelfile # FROM ./qwen2.5-7b-instruct-q4_k_m.gguf # 4. 构建并运行 ollama create qwen2.5-7b-q4 -f Modelfile ollama run qwen2.5-7b-q4这里需要注意ollama create的时候Modelfile 里的FROM路径必须是相对路径或绝对路径而且模型文件和 Modelfile 最好放在同一个目录下避免路径解析问题。4.2 如何选择 GGUF 的量化版本Q4_K_M 还是 Q5_K_MGGUF 格式里有一套独特的命名体系比如 Q4_K_M、Q5_K_S、Q6_K 等。我简单拆解一下Q4 表示 4 比特量化K 表示使用了 K-quant 算法S/M/L 表示量化粒度的大小——Ssmall更小省显存Mmedium中等Llarge精度更高。所以在资源有限的时候Q4_K_M 是一个均衡选择如果显存宽裕且精度敏感Q6_K 或者 Q8_0 会更接近 FP16 的效果。在 16GB 或 32GB 内存的 MacBook 上7B 模型的 Q4_K_M 版本跑得很流畅在 8GB 显存的旧 GPU 上Q4_K_S 可能更稳妥。我的习惯是先下载最小版本跑通流程确认推理逻辑没问题再换更高精度的量化版本做质量对比。千万不要一上来就下最大的版本万一环境有问题浪费时间不说还可能因为显存不够炸 OOM。4.3 量化模型在 CPU 上跑显存不够时的临时方案有时候没有 GPU或者 GPU 显存不够只能在 CPU 上跑推理。llama.cpp 支持 CPU 推理Ollama 底层也是 llama.cpp所以在 CPU 上跑 GGUF 模型是可行的只是速度较慢。7B 的 Q4 模型在 M1 Pro 上大概能跑到每秒 10~20 token在旧款 Intel CPU 上大概只有每秒 3~5 token。对于 CPU 推理有几个提升体验的技巧调整线程数Ollama 支持设置环境变量OLLAMA_NUM_THREADS比如设置为 CPU 物理核心数通常能带来可感知的速度提升。使用量化更低的版本比如 Q4_K_S 或 Q3_K_M减少内存带宽压力。控制上下文长度CPU 的内存带宽是瓶颈上下文越长KV Cache 越大解码越慢。如果业务允许把上下文限制在 2048 或 4096 以内。注意CPU 推理能跑但遇到大并发请求依然会崩。Ollama 默认是单请求串行处理多用户同时请求会导致排队。如果要在本地给多人提供服务建议还是上 GPU 加 vLLM。5. 常见问题与排查技巧实录5.1 显存够但生成速度依然上不去很多人以为显存够就有速度其实不是。在 vLLM 部署中影响生成速度的因素很多batch size 大小、KV Cache 预留多少、模型权重访存量、张量并行设置等。如果你发现显存占用不高但速度低建议优先检查有没有开连续批处理。vLLM 默认开着但如果请求模式是稀疏的单发、间隔长批处理效果不明显速度自然上不来。另外记得设置--max-num-seqs这个参数它决定一个 batch 最多能容纳多少条序列。默认值通常偏低在高并发场景下可以适当调大比如设成 256同时留意显存是否够用。我实测下来并发翻倍带来的吞吐提升在 1.5~2 倍之间但这个窗口期很有限建议边调边用nvidia-smi观察显存和 SM 利用率。5.2 量化后模型回答质量明显下降甚至胡言乱语质量下降是量化部署里最让人头疼的问题。先按概率排序排查几个常见原因校准数据集与推理域不匹配如果量化时用的校准语料和线上 prompt 风格相差十万八千里量化区间根本不对质量自然血崩。建议用业务真实数据重新校准。量化参数设置不合理比如 Group Size 设成了 32 或 256而不是默认的 128也会引入额外误差。可以尝试把 Group Size 调小。模型本身太大强行用 3 比特或 2 比特量化现在 70B 模型量化到 3 比特质量损失会非常明显如果有条件优先用 4 比特。还有一个比较隐蔽的问题如果模型是经过指令微调的比如 Chat 版本量化时使用的校准数据集最好包含指令格式的样本否则模型虽然能生成文本但“遵循指令”的能力会明显退化。5.3 模型崩溃、重复输出、输出乱码这种问题往往不是量化本身的锅而是部署链路里某个环节没对齐。常见原因包括模型文件下载不完整尤其在网速不稳定的时候建议核对 SHA256 校验值。vLLM 版本和模型量化配置不兼容比如你用新版 vLLM 加载老版本的 AWQ 模型可能出现奇怪的输出。解决方法是升级 vLLM 版本或者重新用当前版本支持的量化算法量化一次。模板prompt template错误。量化模型通常和原版模型共用同一个模板如果模板里的特殊 token 写错模型就会越生成越乱。5.4 框架兼容性速查表当前主流量化格式与推理框架这块单独放一张表方便大家快速对照选择。量化格式推荐框架主要场景说明GPTQvLLM, ExLlama, TransformersGPU 推理、高并发服务生态成熟4 比特性价比高AWQvLLM, AutoAWQ, SGLangGPU 推理、精度敏感场景对重要通道有保护量化速度快GGUFllama.cpp, Ollama, LM StudioCPU/混合设备、本地部署量化粒度丰富跨平台兼容INT8W8A8vLLM, TensorRT-LLM服务端高吞吐精度损失小但显存节省不如 4 比特这张表是我平时项目选型时的参考实际情况还要结合你的硬件条件和业务负载来定。比如在 A100 集群上做高并发 OpenAI 兼容 API 服务我首选 vLLM AWQ/GPTQ在自己的笔记本上验证模型效果Ollama GGUF 最省事。6. 部署之后还可以做的优化量化与其他推理优化手段的叠加6.1 量化和 KV Cache 量化的关系量化不仅可以用在模型权重上KV Cache 本身也能量化。KV Cache 的大小和序列长度、batch size 线性相关在长上下文场景下它的显存占比可能比模型权重还大。vLLM 从某个版本开始支持 KV Cache 的 FP8 量化V100 以下的老卡不适用可以在几乎不损失质量的前提下把 KV Cache 显存占用减半这意味着同样显存能支撑更长的上下文或者更大的并发。这给我们一个启示推理优化不是单点作战而是系统工程。先量化权重再把 KV Cache 量化再加上 PagedAttention、连续批处理才能在有限硬件上压榨出最大吞吐。6.2 蒸馏 量化让小模型无限逼近大模型另一个常见的叠加玩法是“蒸馏 量化”。先用大模型对大量业务数据做标注生成高质量的训练语料再用小模型比如从 70B 蒸馏到 7B去拟合这个语料最后对小模型做 INT4 量化。这一套组合拳下来一个 5GB 不到的 7B 模型在特定垂直任务上的表现可能比 140GB 的 FP16 70B 模型还要好。当然蒸馏需要训练资源不是所有团队都有条件做。如果你的场景是标准问答、文本摘要这类通用任务直接用开源量化模型就行但如果是非常垂直的业务比如法律文书解析、医疗报告结构化蒸馏自研模型再量化部署是一条值得投入的路线。7. 聊聊实践中的一些经验体会做推理优化这几年我最大的体会是量化不是“模型变笨”的代名词而是“在约束条件下达成目标”的工程艺术。每当你抱怨模型太大跑不动先别急着上多卡集群想想能不能把模型“瘦身”一下。一张 4090 跑 7B INT4 模型配合 vLLM 的连续批处理能扛住一个中小型内部工具的并发量这在三年前是想都不敢想的。最后分享一个我自己调试时很受益的小习惯每次部署完量化模型先把原始 FP16 模型跑同样的 prompt把两份输出并排放在一起对比。不是所有差异都是问题但如果量化模型输出了明显错误的逻辑、或者漏掉了关键信息就说明量化方案有问题需要回头检查校准数据或者量化参数。这个习惯让我避开了很多“模型能跑但结果完全不能用”的尴尬事故。如果在实际部署中遇到任何新问题欢迎在评论区把你的硬件配置、模型版本、量化方式发出来我也很好奇现在社区里大家在跑什么新组合。
返回列表