ARTICLE DETAIL

资讯详情

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

量化+蒸馏:如何在8GB显存上运行大模型?

量化+蒸馏:如何在8GB显存上运行大模型? 先抛一个有点反常识的结论单纯靠量化不可能把 700GB 的大模型塞进 8GB 显存。这个说法不是劝退而是先把账算清楚。700GB 的模型参数按目前最常见的 INT4 量化来算压缩率差不多是 4 倍也就是还要 175GB 左右距离 8GB 还有二十多倍差距。真正能解决问题的路径是两条腿走路蒸馏负责把模型“变小”量化负责把变小后的模型“塞进”显存。这篇文章我会把两条路分别拆开讲透结合我自己在 8GB 显卡上跑大模型的实际经验给你一套可以直接照着做的方案。先交代一下我自己的环境一张 8GB 显存的消费级显卡平时主要玩本地大模型部署、微调和推理加速。这种卡在 2024 年之后越来越尴尬因为新出的模型动辄 70B、上百 B显存却一分钱没涨。但尴尬归尴尬真要用起来也不是没有办法关键看你愿不愿意把“大模型”的定义放宽一点。1. 先把话放这700G 不是“塞进”显存而是“缩”到能用1.1 显存里到底存了什么参数、KV缓存、临时张量很多人以为显存只装模型权重这是最普遍的误解。实际跑推理时显存里至少同时放着三类东西。第一类是模型权重也就是模型文件里的那些浮点数。700GB 的模型文件光权重就要占掉 700GB这是最基本的开销。第二类是 KV 缓存每个 token 在生成时都需要把之前所有 token 的 Key 和 Value 保存下来用来算注意力权重。KV 缓存的大小取决于模型层数、注意力头数、上下文长度这部分会随着对话变长持续增长。第三类是中间激活值前向传播过程中每一层的输出都要临时保存在显存里方便反向传播或继续算下一层虽然单次占用不大但峰值时刻很容易成为 OOM 的元凶。推理阶段如果不需要反向传播中间激活值会在每层算完后释放所以显存压力主要是两个权重和 KV 缓存。你盯着任务管理器看的那个显存占用其实是这两者加在一起的结果。1.2 成本账从 700GB 到 8GB压缩率到底有多夸张直接做算术。700GB 模型权重假设原始精度是 FP16也就是每个参数占 2 字节那这个模型大概有 3500 亿参数。350B 是什么概念目前开源社区能公开下载的最大模型也基本在这个量级附近。如果做 INT8 量化每个参数占 1 字节总体积降到 350GB。再做 INT4 量化每个参数占 0.5 字节总体积降到 175GB。依然不够 8GB。所以纯量化的极限压缩率大约是 8 到 16 倍但 700GB 到 8GB 需要的是接近 90 倍的压缩。这个量级靠精度压缩根本做不到只能靠蒸馏先把参数量从千亿砍到几十亿甚至十几亿。换句话说蒸馏负责把大象变成狗量化负责把狗装进笼子。两个动作缺一不可顺序也不能颠倒。1.3 拆解后的正确路线蒸馏负责缩量化负责抠如果你的终极目标是“在 8GB 显存上跑一个强到离谱的模型”那我得泼冷水目前没有任何一条公开路径能把 700GB 这种体量的模型无损压到 8GB。但换个角度想你真正的诉求并不是“必须跑某个 700GB 模型”而是“希望在本地硬件上得到接近大模型的效果”那就有操作空间了。我推荐的路线是四步走。第一步选择一个开源的大模型作为“教师”可以是 70B 级别甚至是 API 形态的更大模型。第二步用蒸馏技术把教师模型的推理能力迁移到一个 7B 或者 3B 的小模型上。第三步对蒸馏后的小模型做 INT4/INT8 量化。第四步在 8GB 显卡上用 llama.cpp 或 Ollama 部署量化后的模型。每一步都有成熟的工具难点不在选型而在理解每步到底在干什么。2. 量化最容易见效的显存“减重”手段2.1 量化在做一件什么事精度换体积的底层逻辑量化这件事本质上是把连续分布的浮点数映射到离散的整数区间。原始模型权重大多数是 FP16 或 BF16 格式数值范围宽、精度高但每个数字都要占 2 字节。量化之后权重变成 INT81字节或 INT40.5字节显存直接砍半甚至砍到四分之一。但问题也出在这里。量化不是简单地把大数变小而是要保证“离散化”之后模型的输出分布尽量接近原始分布。如果直接四舍五入那些数值很小的权重会被直接抹成 0模型推理结果会产生大量噪声严重时整段输出都是乱码。所以业界提出了很多量化算法本质都是在解决同一个问题如何通过一个量化缩放系数和零点偏移让有限位宽的整数能最大程度地表示原来的浮点数值范围。你可以把它理解成把一张高清照片压缩成 JPEG压缩率越高肉眼可见的画质损失越明显但好的压缩算法会更聪明地保留人眼敏感的信息。2.2 主流量化类型与工具PTQ、GPTQ、AWQ、GGUF/llama.cpp目前实际部署中最常用的量化方案可以分成两大类。第一类是训练后量化PTQ拿已经训练好的模型不需要重新训练直接用校准数据算出量化参数。GPTQ 和 AWQ 都属于这一类它们各自有不同的权重处理策略。GPTQ 最早是针对 GPU 推理设计的基于二阶信息做逐层误差补偿量化后模型能用 Transformers 库直接加载。AWQ 则是根据激活值的重要程度来保护敏感权重AWQ 在低 bit 下通常比 GPTQ 保留更多模型能力尤其是对话和代码生成任务。第二类是 GGUF 格式加 llama.cpp 生态。GGUF 是 llama.cpp 定义的一种模型封装格式它把模型权重、分词器、超参数打包在一起并内置了多种量化等级。你在 Hugging Face 上看到的 Q4_K_M、Q5_K_S、Q8_0 这些后缀全部来自 GGUF 的量化命名体系。GGUF 系列的优点是兼容 Ollama、llama.cpp、LM Studio 等各种本地推理工具且内存管理做得非常细支持 CPU、GPU 混合推理。选型建议只有一个如果要在 8GB 显卡上跑优先找 GGUF 格式的模型从 Q4_K_M 或 Q5_K_M 开始试。如果你是为了追求最低延迟、不想套 GGUF 这层壳再用 GPTQ/AWQ 的 4bit 版本。2.3 量化后的显存怎么算一个公式快速估算关于显存估算我给一个偏保守但很好用的公式权重显存 模型参数量 × 每参数字节数 实际部署显存 权重显存 × 1.2 KV缓存每参数字节数按量化等级查FP16 是 2 字节INT8 是 1 字节INT4 是 0.5 字节。GGUF Q4_K_M 大体接近 0.55 到 0.6 字节因为它的量化块里还混了一些更高精度的分量。举例一个 7B 模型70亿参数用 Q4_K_M 量化权重大约 70亿 × 0.55 字节 ≈ 3.85GB。加上 KV 缓存和其他临时开销8GB 显卡在 2048 token 上下文长度下是能跑起来的实测显存占用大约在 5GB 到 6.5GB 之间。再举个例子13B 模型 Q4_K_M 量化后大约 7.2GB加载后 8GB 卡就非常紧张了几乎没给 KV 缓存留空间稍微加长一点上下文就会直接 OOM。所以你也别迷信“7B 一定能跑”模型能不能上要看“量化后体积 目标上下文长度对应的 KV 缓存”是否同时落进 8GB。2.4 实际跑起来以后量化模型的质量与速度经验先说我测试过的一组数据。同一个 7B 模型FP16 下显存占用约 14GB生成速度大概 15 token/s这个速度依赖具体显卡量化到 Q8_0 后显存占用约 7.5GB速度提升到 22 token/s 左右再量化到 Q4_K_M 后显存占用约 4GB速度能到 30 token/s 以上。速度提升来自两方面一是权重体积变小显存带宽压力下降二是更多层能完整放下 GPU不需要反复搬运到 CPU。从质量角度看Q8_0 和 FP16 的差异在绝大多数场景下几乎感觉不出来Q5_K_M 损失也非常小日常对话、文本摘要这种任务完全够用。但到 Q4_K_S 之后尤其是代码生成和数学推理任务错误率会有可感知的上升。如果你要跑的是知识问答或者创意写作Q4 完全能忍但如果是写代码或者做结构化输出我建议至少用 Q5_K_M。这个现象背后的原因不难理解代码和数学对数值精度更敏感权重量化会破坏某些关键 token 的预测概率分布有时候一个小数点级别的误差就把整段推理带偏了。3. 蒸馏把大模型的“内功”传给小模型3.1 为什么直接量化和蒸馏不能互相替代量化是把参数精度降下来模型的参数量和网络结构完全不变蒸馏则是重新训练一个参数量更小的模型让它的输出模仿大模型。从效果上看量化不改变模型的知识容量只改变参数存储和计算方式所以当压缩率过高时知识会因为表达能力不够而丢失。蒸馏则不然它是让小模型把大模型“已经学会的知识”重新学一遍虽然知识容量天生有限但在特定任务上可以做到很高的逼近程度。这就引出一个策略组合当你手中的大模型大到量化也无法塞进目标显存时不要死磕量化先把模型变小当你完成蒸馏之后再用量化进行最后一轮压缩。很多开源社区的小模型就是这么产出的一个 7B 模型蒸馏自 70B 模型再量化成 Q4部署在笔记本上。3.2 知识蒸馏的基本流程教师模型、学生模型、KL散度知识蒸馏这个概念最早由 Hinton 在 2015 年提出核心思想用一个比喻就能讲明白教师模型像是一个经验丰富的厨师学生模型像是一个刚入行的学徒。学徒光看菜谱原始训练数据学得慢但如果能有师傅在旁边指导火候和调味进步会快得多。具体到技术上蒸馏过程不是让学生模型直接学大模型的正确答案hard label而是让学生模型去拟合大模型输出的概率分布soft label。教师对每个 token 的输出分布里不仅包含正确答案还包含错误选项之间的相对概率关系这些“软信息”才是学生真正要模仿的精华。蒸馏损失函数一般由两部分组成学生模型与真实标签的交叉熵加上学生模型与教师模型输出分布之间的 KL 散度。KL 散度衡量两个概率分布的差异数值越低说明学生的预测越接近教师。你可以把 KL 散度理解成师生之间的距离度量蒸馏训练的过程就是不断缩小这个距离。实战中蒸馏一个 7B 模型的成本并不低哪怕是在单张 24GB 显卡上也需要数天时间。所以如果你是个人玩家我更推荐直接使用社区已经蒸馏好的小模型而不是自己从零蒸馏。3.3 实用蒸馏姿势收集高质数据、利用 API 蒸馏如果你确实需要定制蒸馏又受限于硬件最实用的姿势是用 API 作为教师来进行数据蒸馏也叫“模型自举”。具体分三步第一步准备一个高质量种子数据集可以是你业务场景里的真实问题也可以从公开数据集中抽取。第二步把这些问题发送给大模型 API让教师模型输出详细回答。为了让回答质量更高我会在提示词里要求模型给出推理步骤、结论和可能的边界条件。第三步用这些“问题-回答”对来微调一个开源小模型这个过程叫 SFT监督微调本质上是让学生模型记住教师模型的表达风格和推理路径。为了提升蒸馏效果你可以借鉴更强的思路让教师模型同时输出多个候选回答再从中挑选最优答案作为训练目标这比单次输出的噪声更小。另外一个细节是不要把原始 prompt 直接丢给教师模型而是要经过精心设计比如加一句“请详细解释你的推理步骤”这样得到的回答包含更多中间逻辑学生模型能学到的东西更多。3.4 蒸馏之后的小模型为什么更容易量化蒸馏对小模型还有一个隐形好处它的输出分布通常比从零训练的小模型更平滑、更集中。这个特性对量化极其友好因为量化误差主要发生在那些数值尺度差异过大的权重上而经过蒸馏输出的模型很多层都已经学会了用更简洁的表示来解决同一类问题权重分布更均匀量化时信息损失就会更小。我在实际测试中发现同一个 7B 架构如果训练数据来自从零训练INT4 量化后准确率可能下降 3% 到 5%但如果是蒸馏自 70B 教师模型的 7BINT4 量化后准确率下降通常能控制在 1% 到 2%。这说明蒸馏和量化之间确实存在正向协同效应蒸馏后的模型不仅仅是“更小”它在量化后也能保留更多有效知识。4. 实操路线8G 显存机的完整选择与部署4.1 先做一道减法题不同规模模型对应的量化后体积设备是 8GB所以推理时大概率还要留出一些显存给图形界面和其他程序。根据我长期压测的经验模型加载后的总占用最好控制在 6GB 以内留 2GB 给系统缓存和临时峰值否则在对话过程中极易触发 OOM。给你一张可以直接对照的表按不同参数的模型和量化等级估算一下“加载后模型权重体积”模型参数量FP16体积Q8_0体积Q5_K_M体积Q4_K_M体积1.5B3.0GB1.5GB0.95GB0.85GB3B6.0GB3.0GB1.9GB1.7GB7B14GB7.0GB4.3GB3.9GB8B16GB8.0GB5.0GB4.5GB13B26GB13GB8.2GB7.2GB从这张表能直接得出结论想在 8GB 显存上留足上下文空间首选 7B 量级模型配 Q4_K_M 或者 Q5_K_M或者 3B 模型配 Q8_0。13B 模型即使量化到 Q4_K_M加载后权重已经 7.2GB几乎把显存占满了KV 缓存稍微变长就会溢到 CPU速度断崖式下跌。4.2 部署工具链选择与安装Ollama / llama.cpp GGUF本地部署这块我的常用组合是 GGUF 格式加 llama.cpp或者直接用 Ollama。Ollama 本质上是对 llama.cpp 的封装安装简单命令友好。下载模型后一条命令就能启动交互式对话。它的优点是省心适合用来快速验证一个量化模型能不能跑缺点是它的底层参数暴露得不够多如果你想精细控制 KV cache 和 GPU 层数还是要回到 llama.cpp。llama.cpp 的使用思路是先从 Hugging Face 下载 GGUF 文件然后用 llama-cli 加载。如果你改了量化等级也可以用 llama.cpp 自带的 convert 脚本重新量化。不过个人建议直接在 HF 上找别人量化好的 GGUF社区量化版本的质量通常经过大范围测试比自己量化更稳。4.3 加载模型时的关键参数ctx长度、KV cache与层数分配8GB 显存环境下要盯住的参数有三个上下文长度、GPU 层数和 Flash Attention。上下文长度决定 KV 缓存的大小。KV cache 的粗略公式是2 × 层数 × 注意力头维度 × 上下文长度 × 每字节数。以 7B Q4 模型为例假设 32 层、KV cache 用 FP16上下文 2048 tokenKV cache 大约占 0.5GB 到 1GB。如果拉到 8192这部分会涨到 2GB 以上稍不留神就把显存吃光了。所以我的经验是8GB 显卡跑 7B 模型上下文长度先设 2048能跑通以后再加长。不要一上来就追求 32K 上下文大概率换来的是 OOM 或者无限等待。GPU 层数决定模型计算有多少放在显卡上。llama.cpp 支持-ngl参数指定 GPU 加载的层数。对 8GB 卡可以先从 ngl32 试起把一部分层加载到显存如果 OOM就降 ngl 到 24 或 16剩余层由 CPU 计算。混合推理的速度不快但总比完全跑不起来强。提示Ollama 环境里可以直接在模型文件里设置参数比如num_ctx控制上下文长度num_gpu控制 GPU 层数。用/set parameter命令可以临时设置重启后失效。4.4 我的实战配置参考不同任务怎么选量化等级我自己跑过的组合里有三个配置比较满意。日常聊天和内容创作我用的是 7B 模型的 Q5_K_M 版本上下文 4096GPU 层数全开首 token 延迟大约 0.8 秒流畅度可以接受。代码生成和结构化输出我换成了 Q8_0 版本的 3B 模型显存占用更少精度更高生成的代码格式更稳定不会经常出现缩进错乱或函数名拼写错的情况。如果只是偶尔跑一些简单任务比如文本摘要、邮件润色我会直接用 1.5B 蒸馏模型的 Q4_K_M加载速度快显存占用不到 1GB可以跟其他程序共存。虽然能力有限但胜在轻巧。5. 常见问题与避坑记录5.1 为什么量化后输出全是噪声或胡言乱语量化模型输出乱码90% 的情况是权重没有正确加载比如模型文件不完整或者 GGUF 格式与 llama.cpp 版本不匹配。另外如果你用的是自己转换的 GGUF 文件转换前一定确认原始模型格式是 Hugging Face transformers 结构并确保分片文件下载完整。从头开始检查时先去跑一个官方示例模型比如 LLaMA 或 Qwen 的官方 GGUF确认工具链没问题再排查自己下载的文件有没有对齐分片。我在早期犯过这种错下载 70B 模型时少下了一个分片文件加载却顺利通过直到推理输出中文变成乱码才发现。5.2 8G显存加载小模型还是OOM优先检查上下文长度如果你加载 3B 模型 Q4 还 OOM那大概率不是权重放不下而是上下文长度设置太大了。很多 Ollama 用户的默认上下文是 4096 甚至 8192KV cache 和中间激活值很容易把显存塞满。解决办法很简单先把上下文调到 1024确认能跑通再逐步往上加。同时可以开 Flash Attention它能减少 KV cache 的显存占用4 到 8GB 显存环境下收益特别明显。5.3 量化程度越高越省显存不一定还得看速度与质量Q4 一定比 Q8 省显存这是对的但并不代表 Q4 一定更好用。量化等级越低占用的显存越少但推理速度不一定线性提升因为现代显卡更依赖带宽但也会受解码开销影响低 bit 量化需要额外的反量化计算。实测中 Q4_K_M 和 Q5_K_M 的速度差异不大但 Q4 的质量损失却更明显。所以在不追求极限显存的情况下我会优先选择 Q5_K_M。它比 Q4_K_M 只重几百 MB但回答质量和稳定性高了不止一个档次这是性价比极高的一次取舍。5.4 蒸馏需要多少数据才够这个问题没有标准答案取决于任务复杂度。我给一个参考区间如果你的任务是让一个小模型模仿大模型的对话风格5000 到 20000 条高质量对话数据就够了如果是做复杂推理或代码生成可能需要 5 万条以上并且数据质量比数量更重要。另外蒸馏过程不要盲目追求多个 epoch。小模型参数量有限过度训练容易过拟合到训练数据反而会在未见过的任务上表现更差。我在跑蒸馏实验时一般先训 1 到 2 个 epoch用验证集观察 loss 曲线一旦验证 loss 不再下降就及时停止。6. 写在最后几个实用心得这些年在低显存设备上折腾大模型最深的感受是显存不够不等于玩不了大模型但它会倒逼你更清楚地理解大模型的存储结构和推理机制。量化让你懂模型权重在说什么蒸馏让你懂模型能力是怎么传递的这两样搞明白之后再回头看不带量化的原版模型你对性能瓶颈的理解会完全不一样。最后分享一个我自己踩过多次的坑下载 GGUF 模型时一定要仔细核对文件名中的量化等级不要混淆了 Q4_K_M 和 Q4_K_S。这两个体积对比差距不大但 Q4_K_S 的质量损失明显更高。如果你不确定该选哪个记一个简单规律手头显存够就上 Q8_0显存紧张就选 Q5_K_M只有极度紧张才用 Q4_K_MQ4_K_S 能不用就不用。对了如果你跑 Ollama 时遇到模型推理速度很慢先看一眼是不是模型被完全放到了 CPU 上。Ollama 默认会根据系统显存自动分配加载层数但在某些环境下它可能过度保守。手动加一行num_gpu 999让模型尽量全量加载到显卡速度会有质的飞跃。
返回列表