☰
8GB显存跑35B大模型:量化、分层卸载与推理优化实战
2026/9/29 23:32:52 网站建设 项目流程

1. 先算明白账:8GB 显存为什么敢碰 35B

1.1 模型大小不是按“参数个数”估的

我们常说的“35B 模型”,指的是参数量在 350 亿左右。要估一个模型加载需要多少显存,最简单粗暴的公式是:参数量乘以每个参数的存储位数,再除以 8 转成字节。如果直接用半精度(FP16/BF16),每个参数占 2 字节,那么 35B 模型光权重就是 70GB。加上推理时的 KV cache、临时激活值,实际占用还要再往上走。这个差距非常大,8GB 显存连零头都不到。

但这块数字也让很多人误以为“8GB 跑 35B = 不可能”。真正让 8GB 显卡有机会上场的是量化推理,以及“部分计算放到内存里”的混合运行模式。需要注意,量化降低的是权重体积,而不是“模型必须全部塞进显存”这件事。

1.2 量化“压缩”了多少

目前最常见的开源量化格式是 GGUF(由 llama.cpp 生态推广),常见的有 Q2_K、Q3_K_M、Q4_K_M、Q5_K_M、Q8_0 等。粗略按“每参数占用”估算:

  • Q2_K:每个参数约 2.7 bit
  • Q3_K_M:每个参数约 3.5 bit
  • Q4_K_M:每个参数约 4.8 bit
  • Q8_0:每个参数约 8.5 bit

按 35B 参数估算,Q4_K_M 的权重大约是 21GB,Q3_K_M 大约是 15GB,Q2_K 大约是 12GB。哪怕把量化压到 Q2_K,单看模型体积也仍然超过 8GB。也就是说,只靠显存跑 35B 是没戏的,必须把一部分层放到内存里。这听起来像“作弊”,但实际正是 llama.cpp 这类框架设计好的能力:分层卸载(offload),显存放得下多少层就放多少层,放不下的留在内存,由 CPU/GPU 协同完成前向计算。

打个比方:显存是小水箱,内存是大水池,模型数据是被抽上来的水。出水速度取决于水管粗细和泵的功率。8GB 跑 35B 相当于用小水管慢慢抽,水能出来,但别指望流速很快。

1.3 “8GB 跑 35B”的本质是妥协

讲清楚上面的计算,你就能明白,“8GB 跑 35B”并不是什么神奇黑科技,而是在显存不足的情况下,用内存带宽和时间换取“能运行”的可能。用它能跑,不代表能用得舒服。后续所有调参、改造,都围绕一个问题展开:如何让少得可怜的显存被更高效利用,同时不让 CPU 端的内存带宽成为压倒性的瓶颈。

这里还要提一句:标题里的“35B”其实是指 30B 到 40B 这个参数档位。目前热门开源模型里 Qwen2.5-32B、Yi-34B 都属于这个区间,量化后体积和“35B”基本在同一档。下面的实操命令以 Qwen2.5-32B 为例,逻辑可以平移到其他同类模型。

2. 部署方案:为什么我选了 Ollama 而不是直接上 llama.cpp

2.1 不同工具怎么选

带动本地大模型现在有三个主流方向:一个是底层的 llama.cpp,另一个是封装好的 Ollama(底层仍然是 llama.cpp),还有 LM Studio 这类带界面的工具。如果你是想折腾技术细节,可以直接用 llama.cpp 去编译源代码,手动指定每个参数;如果你想快速复现一次“8GB 跑大模型”的实测,Ollama 是更省心的选择。它把模型拉取、量化格式、上下文处理都集成好了,几条命令就能进入交互界面。

我在这个项目里选了 Ollama 还有一层原因:它的日志对排查问题非常友好。跑起来之后,你能在日志里直接看到“已卸载多少层到 GPU”“KV cache 占了多少”这类关键信息。这对调试 8GB 显存这种极限场景特别重要。

2.2 我的机器配置与系统环境

  • 显卡:NVIDIA,8GB 显存(2060 或同级)
  • CPU:支持 AVX2 的 x86_64 处理器,8 核心
  • 内存:32GB DDR4 双通道
  • 系统:Ubuntu 22.04 + 官方驱动
  • Ollama 版本:0.1.32 以上

强调双通道内存,是因为 CPU 跑大模型时,内存带宽直接决定每秒能“喂”给模型多少参数。DDR4 双通道的实际带宽大约 20-30GB/s,单通道会直接减半,差距非常大。如果你手里是单根内存条,建议先别急着跑 35B,7B 模型会更现实。

2.3 这次用哪个模型

实测模型是 35B 这个档位里最常见的开源模型,我机器上跑得比较多的是 Qwen2.5-32B,量化格式为 Q4_K_M。Ollama 拉取时通常默认选择 Q4_K_M 版本,正好符合我在 8GB 显存场景下的预期。模型体积大约 20GB,加上 KV cache 和运行时 overhead,对内存的要求大约是 24-28GB。我的 32GB 内存刚好够用,但已经非常紧绷。

3. 完整实操:从拉取模型到调出可用配置

3.1 先用默认参数把模型拉下来

安装好 Ollama 后,我做的第一件事是直接默认参数跑起来。命令很简单:

ollama run qwen2.5:32b

这会把 Q4_K_M 量化版本拉到本地,并在终端进入聊天界面。我先输入“你好”,观察输出速度。第一次结果非常慢,而且通过 nvidia-smi 看显存占用只有大约 3GB,说明大部分层都跑在 CPU 上。这个状态能用,但生成速度只有 1.x token/s,用起来急死人。

于是我先退出交互,查看当前加载情况。Ollama 提供了一个很实用的命令:

ollama ps

输出里能看到当前加载模型的“PROCESSOR”列,如果显示 100% CPU / 0% GPU,就说明 GPU 没有参与计算。8GB 显存只用了 3GB,明显是默认策略太保守,导致模型完全跑在内存里。

3.2 手动指定 GPU 层数

Ollama 默认是根据显存安全冗余来判断放多少层到 GPU,所以它倾向于保守。这里需要手动干预。我新建了一个 Modelfile,内容如下:

FROM qwen2.5:32b PARAMETER num_ctx 2048 PARAMETER num_gpu 22

然后执行:

ollama create qwen32b-ngl22 -f Modelfile ollama run qwen32b-ngl22

这里 num_gpu=22 的含义是“把模型前 22 层放到 GPU”,剩余层留在 CPU。具体该设多少,没有标准答案,需要用显存占用倒着调。我的方法是先把 num_gpu 设为 20,跑一个比较长的回答让模型进入推理状态,再观察 nvidia-smi。如果显存峰值在 7.2GB 左右,说明还有余量,可以继续加 2 层;如果出现 CUDA out of memory 的报错,就减 4 层。

注意:不要一上来就设很大的 num_gpu,因为 KV cache 也会占显存,上下文越长,KV cache 越大。我把 num_ctx 固定在 2048,就是为了给 KV cache 留出余量,避免回答到一半显存爆掉。

3.3 把上下文长度降到合理范围

上下文长度(num_ctx)是很多“8GB 跑大模型失败或被卡死”的主要凶手。默认情况下,Ollama 可能使用 4096 甚至 8192 的上下文长度,这会为每个 token 在缓存中占一块空间。对 8GB 显存的机器来说,把上下文压到 2048,甚至 1024,能直接减少 1GB 左右的显存开销。

如果你希望温度等生成参数也能保留下来,可以把它们一并写进 Modelfile:

FROM qwen2.5:32b PARAMETER num_ctx 2048 PARAMETER num_gpu 22 PARAMETER temperature 0.7

这样一套配置下来,显存占用通常会到 6.5-7GB,处于 8GB 显卡的安全线内。注意,这个数字不是固定的,它由层数、上下文长度、量化格式共同决定。

3.4 看日志确认参数真的生效

Ollama 的日志在 Linux 上可以通过journalctl -u ollama或直接看/var/log/ollama.log查看。日志里会出现类似这样的行:

llama_model_load: ... offloaded 22/64 layers to GPU llama_kv_cache_init: ... CPU buffer size = ... decode speed: 3.1 tokens/s

这行“offloaded 22/64 layers to GPU”就是最关键的确认信息,说明我们的参数生效了。我从纯 CPU 的 1.x token/s,提升到 offload 22 层后的 3.x token/s,进步很明显。当然,如果继续加到 30 层,速度可能更快,但显存极可能不够,机器会直接抛错。

4. 实测数据与真实体验

4.1 不同参数下的速度对比

为了让你对速度差异有直观感受,我把同一台机器上不同 num_gpu 的实测数据整理成了一张表(不同机器数据会有差异,但趋势一致):

num_gpu显存占用生成速度结论
0约 2.2GB1.4 token/s纯 CPU,能跑但很煎熬
10约 3.8GB1.9 token/s略好一点,价值不大
22约 6.5GB3.1 token/s速度和显存比较均衡
38约 8.0GB4.6 token/s显存马上到红线,容易 OOM
满层大于 8GB无法启动不能直接用

从表里可以看到一个关键点:并不是把层数加到最大就一定最好。在 8GB 显卡上,22-30 层左右往往是最佳区间,再往上显存随时有溢出风险。一旦溢出,需要重启模型,反而更浪费时间。

4.2 生成速度的体感

3 token/s 是什么概念?每秒钟蹦出 3 个字。要输出一段 200 字的回答,需要一分多钟。如果模型带思维链,它在“思考”阶段也会以文字形式输出,你看着像在打字,但实际是模型在推理。体验虽然远不如云端 API,但作为本地测试和隐私优先场景,已经可用了。

更让人难受的不是“慢”,而是“看起来像卡死”。因为模型先对用户输入做 prompt processing,这个阶段速度很快,几十 token/s 很正常,然后进入生成阶段,突然掉到 3 token/s。你盯着终端,错觉就是模型没反应了。我后来习惯写一个带计时的小脚本,或者直接看终端右侧时间,等待时心里有底。

4.3 显存和内存的实时占用

跑起来后,我同时开了两个终端,一个在跑模型,另一个在轮询显存:

watch -n 1 nvidia-smi

实际观察结果:GPU 显存占用约 6.5GB,内存占用约 24GB。这里有个容易被忽略的问题:当模型很大部分在 CPU 上时,内存带宽被打满,CPU 占用也居高不下。如果你边跑模型边做其他计算,整个机器都会变得卡顿。所以实测时我基本关掉了浏览器和其他后台任务,专心等一个回答。

5. 常见问题与排查技巧实录

5.1 模型启动后系统内存直接爆掉

这是我第一次用 8192 上下文启动时遇到的问题。模型还没完全加载完,Linux 的 OOM Killer 直接把 ollama 进程杀了。原因很简单:权重 20GB 已经压在内存上,再加上 KV cache 和系统其他开销,32GB 内存根本不够。解决办法是降低 num_ctx 到 1024 或 2048,也可以考虑用更小的量化版本,比如 Q3_K_M。千万不要以为 32GB 内存很充裕,35B 模型默认配置分分钟把它耗尽。

5.2 明明改了 num_gpu,显存却不动

修改 Modelfile 后一定要重新执行ollama create生成新模型,再运行新名字。有几个版本对 Modelfile 的参数校验不严格,如果直接沿用旧的模型名,可能读到缓存配置。可以用ollama ps再确认一次当前进程的处理器分配,如果还是 CPU,检查日志里是否显示 offload 层数。这个坑我踩过两次,后来养成了“每次改参数就换一个模型名”的习惯。

5.3 回答到一半,速度突然变得极慢

如果机器开始疯狂读写磁盘,基本可以判断是发生了内存交换(swap)。原因是某些配置下,内存占用超过了实际物理内存,系统把部分数据换到磁盘。由于模型权重每次生成时都要重新读取,如果被换到磁盘,速度会跌到 0.5 token/s 以内,基本不可用。解决办法是打开free -g看可用内存,关掉不必要的大进程,或者把上下文继续调小。

5.4 换到 Q2_K 后模型“降智”太严重

我曾试图用更小的 Q2_K 量化来获得更快速度,结果回答质量明显下降。35B 的 Q2_K 虽然能省出更多内存空间,但模型的常识连贯性和逻辑都打了折扣。建议如果显存只有 8GB,还是优先保 Q4_K_M 或 Q3_K_M,别用 Q2_K。毕竟我们费这么大劲跑本地模型,是为了推理质量,而不是单纯的数字游戏。

5.5 为什么别人说 8GB 能跑“很大”的模型

网上很多人说 8GB 显存能跑 70B 甚至更大,其实都是同一套逻辑:大权重放内存,GPU 只做部分加速。这与“完全在显存内运行”是两码事。作为技术测试可以玩,但真实项目里我更推荐按任务需求选模型:写代码和翻译用 7B-14B 已经足够流畅,跑 35B 主要是为了获得更强推理能力,但必须接受它的慢。

我个人在实际操作中最深的感受是:这个实验让我真正理解了显存、内存带宽和大模型推理之间的物理边界。以前看论文觉得量化很抽象,亲手把 35B 压到一台 8GB 显卡上跑起来之后,才知道每一步参数调整都是在跟硬件极限做交换:少一点上下文就多一分稳定,多一些 GPU 层就快一点点,但风险也随之上升。如果你也想试,建议先用 Q4_K_M 默认跑一遍纯 CPU 版本,记录速度,再逐步增加 num_gpu 找到自己的最佳点。亲手试一次,比看任何教程都更容易上手。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询