我把 Ollama 部署在 4 GB 移动端 GPU 上并跑出了 2.5——VRAM 数学计算详解 - DEV Community

4 阅读6分钟

Gemma 4 挑战赛:基于 Gemma 4 的作品提交

本文是 Gemma 4 挑战赛:基于 Gemma 4 进行构建 的参赛作品

📎 本文是我早前一篇文章的配套续篇:我两个月前就在生产环境中上线了本地 LLM 功能——但它从未真正运行过。同一个 gemma4:e2b,同一台机器——本篇是 GPU 卸载的后续实验

🔬 TL;DR

速度提升 2.5 倍,温度下降 10°C——跑在一块"理论上装不下这个模型"的 4 GB 笔记本 GPU 上。

| | 纯 CPU | GPU 混合 |

| Tokens / 秒 | 17 | 39 |

| 单次调用延迟 | ~5.5 s | ~2.0 s |

| 突发负载下 CPU 温度 | 发烫 | −10 °C |

| GPU 上的层数 | 0 | 35 / 36 |

相同的提示词,相同的模型,相同的硬件。唯一的变量是:是否允许 Ollama 调用显卡。

说实话:我原本期待更高的提升。本文末尾的数学分析会精确解释,为什么在 4 GB VRAM 上跑 Gemma 4,2.5 倍就是上限,以及想突破这个上限需要什么条件。

⚙️ 实验环境

| | |

| 模型 | gemma4:e2b(有效参数 2B,磁盘占用约 7.2 GB) |

| CPU | AMD Ryzen 5 4600H,6 核 / 12 线程 |

| GPU | NVIDIA GTX 1650 Ti Mobile,4 GB VRAM |

| 系统 / 运行环境 | Ubuntu + Docker,Ollama 0.23.1 |

| 提示词 | 来自我的阅读 App 的干扰项 + 提示 + 解析生成器——所有测试中固定不变 |

| 输出预算 | 每次调用约 60 个 token |

| 控制变量 | num_gpu=0 → 纯 CPU · num_gpu=999 → 让 Ollama 自动分配 |

| 预热 | 每种模式在计时采样前先丢弃一次调用结果 |

两种模式均在预热之后运行,因此数据反映的是稳态推理性能,而非首次加载的开销。每个 /api/generate 的响应以 NDJSON 格式返回,所以我直接从引擎中提取了 eval_counteval_durationtotal_duration——没有引入任何外部计时噪声。

📊 测试结果

| 指标 | 纯 CPU | GPU 混合(35/36 层在 GPU 上) | Δ |

| 平均每次输出 token 数 | 60 | 55 | 基本相同 |

| 平均推理延迟(仅 token 生成) | 3,506 ms | 1,411 ms | 快 2.49 倍 |

| 平均总延迟(提示词处理 + 生成) | 5,390 ms | 2,174 ms | 快 2.48 倍 |

| Tokens / 秒 | 17 | 39 | 快 2.29 倍 |

GPU 运行期间的 ollama ps

NAME SIZE PROCESSOR CONTEXT UNTIL gemma4:e2b 7.8 GB 74%/26% CPU/GPU 4096 Forever

生成过程中的 nvidia-smi

NVIDIA GTX 1650 Ti, used 1998 MiB, free 1909 MiB, util 32 %

⚠️ ollama ps 会误导你。 那个"CPU/GPU 74%/26%"的字符串表示的是内存分配比例,而非层的分配比例。Ollama 服务端日志才是唯一能告诉你哪些层真正被转移了的地方。我的日志显示的是 offloaded 35/36 layers to GPU。Transformer 几乎全部移到了 GPU——除了有一层至关重要。下面细说。

🧠 为什么是 2.5 倍而不是 10 倍

这个模型共有 36 个 Transformer 层。Ollama 将其中 35 层放在了 GPU 上。唯一留下来的是输出投影层——即将最终隐状态映射回 Gemma 词表的那一层。

Gemma 4 的词表非常庞大(约 256k 个 token)。那个输出层又密又重,其余部分迁移到 GPU 后,它会把 4 GB 中剩余的空间全部吃掉。所以 Ollama 只好将它留在 CPU 上。

这在稳态下带来了严峻的后果:

💡 每一个生成的 token,在最后都必须绕回 CPU 走一趟。 GPU 负责它所拥有的 35 层,速度很快;但管道在那一层 GPU 无法承接的地方就会卡住。对成千上万个 token 取平均,CPU 侧就成了性能下限。

这就是为什么是 2.5 倍而不是 10 倍的全部原因。混合推理的瓶颈在于两个设备中较慢的那个,而在这块显卡上,较慢的设备在每个 token 上都在做实实在在的工作。

值得加粗的结论:如果你只看 ollama ps,你对自己的配置实际在做什么会有完全错误的认识。 服务端加载日志才是哪些层去了哪里的唯一可信来源。

💡 2.5 倍提升实际带来了什么

在 App 里,一次保存操作——干扰项 + 提示 + 简短解析,约 60 个输出 token——以前需要 5.5 秒,现在只需要略超 2 秒

这把体验从"这是不是卡死了?"区间拉到了"好,它在跑"区间。这才是一个保存操作真正重要的门槛。

连续五次保存:

  • 之前: CPU 全力运转约 30 秒

  • 之后: 约 10 秒,负载由 CPU 和 GPU 共同分担

  • 额外收益: 该突发负载期间 CPU 峰值温度下降了约 10 °C

对于一台在小房间里用的轻薄本来说,这最后一个数字决定了风扇声是否会被你听到。

🚀 如何进一步提升

以下三个方案,按我的意愿程度排序:

  • 仅对输出层使用更小的量化精度。 如果该层能装进剩余的约 1.9 GB 空间,整个模型就能全部运行在 GPU 上,你就能看到其他文章里引用的那些 10 倍的数字。代价是输出分布上真实的质量损失——与其想当然,不如在你自己的提示词集上实测一下。

  • 换一块更大的 GPU。 16 GB 的显卡能轻松装下整个模型,还有余量。但本次实验的目的就是搞清楚"一块普通的笔记本 GPU 能做什么",所以一块 500 美元的台式机显卡并不在讨论范围之内。

  • 更换推理引擎。 llama.cpp 直接调用、vLLM 等均可。2 秒已经在这个模型所驱动的操作预算之内了。在"够快"之后继续优化,只会让你最终得到三套 benchmark 和零个用户。

🛠️ 复现方法

# 1. Pull the model ollama pull gemma4:e2b # 2. Force CPU only curl -s http://localhost:11434/api/generate -d '{ "model": "gemma4:e2b", "prompt": "Give me 5 distractors for the word \"warehouse\".", "stream": false, "options": { "num_gpu": 0 } }' | jq '{tokens: .eval_count, eval_ms: (.eval_duration/1e6), total_ms: (.total_duration/1e6)}' # 3. Let Ollama use the GPU curl -s http://localhost:11434/api/generate -d '{ "model": "gemma4:e2b", "prompt": "Give me 5 distractors for the word \"warehouse\".", "stream": false, "options": { "num_gpu": 999 } }' | jq '{tokens: .eval_count, eval_ms: (.eval_duration/1e6), total_ms: (.total_duration/1e6)}' # 4. Check what actually landed where docker logs ollama 2>&1 | grep -E "offloaded|layers" nvidia-smi --query-gpu = name,memory.used,memory.free,utilization.gpu --format = csv

每条 curl 跑几次以消除预热效应,然后对 eval_mstotal_ms 取平均值。真正有意义的数字是两者的比值,而非绝对延迟——绝对值会随你的 CPU 而变化。

✅ 结论

  • 4 GB VRAM 已经足够有用,即便模型"理论上"需要更多显存。只是别期待 10 倍的提升。

  • 混合推理的瓶颈在于较慢的那个设备。 如果有某个关键层留在 CPU 上,那就是你的性能下限。

  • 相信加载日志,而不是 ollama ps 那个漂亮的 CPU/GPU 百分比是内存分配,不是层数统计。

  • 2.5 倍的差距,就是 UX 感觉残缺与正常之间的分界线。 这已经足够了。

  • 一旦进入预算范围就停止优化。 "够快"永远胜过"最快"。

📖 完整报告(含所有加载日志的深度解析)发布在我的博客:vasyl.blog — 我把 Ollama 跑在 4 GB 移动 GPU 上,获得了 2.5 倍提升

⭐ 本文所驱动的阅读 App 已开源(AGPL-3.0):github.com/mrviduus/te…

使用 gemma4:e2bGemma 4 挑战赛 构建。如果你也在参赛,欢迎在评论区贴上链接——我很乐意拜读。

如需进一步操作,你可以考虑屏蔽此用户和/或举报滥用行为