[控场AI]
· 7 分钟阅读· 3,871 字

8GB显卡跑120B Nemotron:跳过零值,找真瓶颈

8GB显卡跑120B Nemotron:跳过零值,找真瓶颈

开发者用NVFP4和字节每token思路,在8GB显卡上以8.2 tok/s运行120B MoE模型,发现磁盘读取才是真瓶颈。

一位开发者与Claude协作,在RTX 5060(8GB显存)上运行120B参数的Nemotron-3.5-Super混合专家模型。关键思路是放弃“模型是否适合VRAM”的旧问题,转而计算每token需读取的专家字节数:该模型每token仅激活22个专家,约2.7GB/token,非路由部分6.6GiB常驻GPU,59GiB路由专家留在NVMe按需流式加载。引擎基于PyTorch+Triton构建,采用O_DIRECT磁盘块、LRU RAM缓存、下一层路由器预取,并利用ReLU²后92.5%神经元为零的特性重排down权重,仅传输活跃神经元组,提升12%速度。Nsight分析揭示真正瓶颈是NVMe读取(50-55ms/token)而非Python开销,将RAM缓存增至20GB后速度从7.3提升至8.2 tok/s。正确性通过PPL和贪婪匹配验证,平均KL≤0.003。

在8GB显存上运行120B参数的大模型?NVIDIA的Nemotron-3.5-Super给出了肯定答案,但前提是换一个思路:不纠结模型总大小,而是计算每个token需要读取多少专家权重。一位开发者(与Claude协作)在RTX 5060上实现了这一目标,并发现了预想之外的真正瓶颈。

8GB GPU运行120B模型

核心思路:字节每token才是关键

Nemotron-3.5-Super是一个混合专家(MoE)模型,总大小75GB(NVFP4格式),但每个token只激活512个专家中的22个(top-22)。关键在于NVIDIA将专家做得很小:它们在1024维的“潜在”空间中工作,而非完整的4096维。单个专家(up 2688×1024 + down 1024×2688)在NVFP4下仅3.10MB。

计算一下:22个专家 × 40层 × 3.10MB ≈ 2.7GB per token。这个数字介于Qwen(1.3GB/token)和DeepSeek广告(4.2GB/token)之间。而非路由部分——Mamba、注意力、共享专家、路由器等——共6.6GiB,常驻GPU。59GiB的路由专家则留在NVMe硬盘上,按需流式加载。

NVFP4 是 NVIDIA 在 Blackwell 架构上引入的 4 位浮点格式,专为低精度推理设计。与传统的 INT4 不同,它保留了浮点表示,包含 1 位符号、2 位指数和 1 位尾数,并采用两级缩放:每 16 个连续值共享一个 FP8 的块缩放因子,此外还有一个全局缩放因子。这种设计在极低精度下仍能维持较好的数值稳定性,使得 120B 级别的模型权重可以压缩到 75GB 左右。文中提到的“每 16 个连续值共享一个 scale”正源于此,这也是为什么不能直接按单个神经元跳过零值——破坏 16 值分组会丢失缩放信息。NVFP4 的硬件解压路径需要 Blackwell 及更新架构的 GPU 才能高效执行,这也是作者强调需要 Blackwell 显卡的原因之一。

混合专家(MoE)模型 的核心思想是将前馈网络拆分为多个“专家”,每个 token 通过路由器(router)选择性地激活其中少数几个。与稠密模型每个 token 都经过全部参数不同,MoE 的激活参数量远小于总参数量,因此推理时计算量可控。但 MoE 的显存挑战在于:虽然计算只涉及少量专家,所有专家的权重仍需存储。Nemotron-3.5-Super 采用 top-22 路由,即每个 token 激活 512 个专家中的 22 个,且专家在 1024 维的“潜在”空间中工作,维度低于完整的 4096 维,使单个专家仅 3.10MB。这种“小专家、多数量”的设计降低了每 token 需读取的专家字节数,是 8GB 显存能运行 120B 模型的前提。

引擎分步解析

作者没有现成运行时可用,于是基于PyTorch+Triton构建了引擎,以transformers的NemotronH代码为骨架。几个关键设计:

1. 磁盘块设计:每个专家的四个张量重写为一个3,096,576字节的块,正好756个4KiB页。一次pread加O_DIRECT读入固定内存。重打包59GiB约2.5分钟。

2. RAM缓存:LRU策略,32个读线程。路由集中度高,24%的专家在RAM中时,81-84%的查找命中。

3. 预取:在当前输入上运行下一层路由器,约72%猜对。猜错的在GPU忙碌时读取。

4. 跳过零值(新技巧):ReLU²后,92.5%的专家神经元对给定token为零。零神经元不需要其down列,因此不必通过PCIe搬运。但NVFP4每16个连续值共享一个scale,不能直接挑神经元。作者重新布局了磁盘上的down权重(纯字节排列),使每个神经元的4位值连续,scale按16个神经元分组。现在只将up(1.55MB)复制到GPU,down内核直接从固定内存读取,且只读包含活跃神经元的16神经元组。提升12%,6.6 → 7.3-7.6 tok/s。

5. 聊天服务器:OpenAI兼容API,支持流式输出,并有对话快照(约170MB)以便下条消息只处理新尾部。

O_DIRECT 是 Linux 的一项文件 I/O 标志,用于绕过内核页缓存,使数据直接从存储设备传输到用户空间缓冲区。在流式加载专家权重的场景中,使用 O_DIRECT 可以避免双重缓存(内核页缓存 + 用户空间缓存)浪费宝贵的内存,并减少 CPU 开销。但它要求读取偏移和长度对齐到设备块大小(通常为 4KiB),且缓冲区地址也需对齐。作者将每个专家重写为 3,096,576 字节的块,正好是 756 个 4KiB 页,正是为了满足 O_DIRECT 的对齐要求,实现一次 pread 完成整个专家的读取。配合固定内存(pinned memory),还能让 GPU 直接通过 PCIe 从主机内存异步拷贝,减少传输延迟。

真正的瓶颈:磁盘读取而非Python开销

达到7.3 tok/s时,每个token约137ms。作者原以为是Python启动开销,计划用CUDA图优化。但Nsight Systems分析显示:GPU忙碌约92ms,空闲约54ms;其中启动间间隙仅约13ms。CUDA图只能解决这13ms。

尝试的两个“明显”修复——重排工作让共享专家先于路由结果运行,以及提前复制预测的专家——都bit-for-bit正确,但都没帮助,推测性复制反而慢了7%,因为错误猜测堵在总线前面。

实际等待时间:NVMe读取(RAM缓存未命中)占50-55ms,Python缓存簿记17ms,等待路由选择11ms。磁盘才是最大等待。早期测量说“磁盘~3ms”是错的,那次运行关闭了GPU复制,掩盖了磁盘延迟。

修复很平淡:增大RAM缓存。离线模拟路由,选择20GB缓存,磁盘读取从136.9ms降至121.5ms,速度从7.3提升到8.2 tok/s。这留下约7GB RAM给32GB系统的其余部分。

视觉能力与正确性验证

Nemotron-3.5-Super-VL带一个1.3GB的视觉塔(C-RADIO)。引擎的6.6GiB加上视觉塔无法同时放入显卡,因此视觉塔权重放在固定内存中,逐层流式传输到GPU(每张图0.4-1.6秒,CPU上需10-31秒)。

在一张60行、15px字体的发票上测试:正常分辨率下,每字段10个中答对7-9个;NVIDIA最大分辨率(2204 tokens)下,三个字段全部10/10,总耗时116秒。

正确性方面,以CPU上的fp32 transformers实现为参考,使用原始检查点(非重打包版)和transformers自己的FP4解码。困惑度(PPL)对比:英文段落5.233 vs 5.280,TCP vs UDP问答6.592 vs 6.714,俄语问答5.873 vs 5.854。平均KL ≤ 0.003。贪婪答案匹配度:63/64和64/64,唯一差异是真正的平局(参考本身两个token分数差0.11,小于一个BF16步长)。

还做了必须失败的检查:交换每个字节的两个4位半部分,PPL跳到18,784——证明解码顺序是被测试的而非假设的。

困惑度(Perplexity, PPL) 是衡量语言模型预测能力的指标,定义为模型对测试文本中每个 token 的平均负对数似然的指数。PPL 越低,说明模型对文本的预测越准确。在量化或自定义推理引擎的验证中,通常将优化实现的 PPL 与参考实现(如 CPU 上的 fp32 transformers)对比,若差异很小(如文中 5.233 vs 5.280),则说明数值误差在可接受范围内。KL 散度 则衡量两个概率分布之间的差异,文中平均 KL ≤ 0.003 表示自定义引擎输出的 token 概率分布与参考实现高度一致。贪婪答案匹配(greedy match)进一步检查逐 token 生成结果是否相同,63/64 和 64/64 的匹配率说明差异仅出现在参考本身概率接近平局的情况。

什么没奏效

  • 将提示的专家放入RAM缓存——提示变慢,解码无收益。
  • 预取6个猜测而非4个——更多浪费读取。
  • 按单个神经元跳过零值——逐神经元重读scale比复制整个块更慢。按16神经元组有效。
  • 推测性提前复制——正确但更慢。
  • 将最近使用的专家保留在GPU——下一token有40%重复,但保存它们需要约2.7GB VRAM,8GB卡在6.6GB密集部分旁没有空间。

如何尝试

仓库包含引擎、Triton内核、服务器、重打包/验证工具和所有测量脚本。诚实提醒:尚未从全新克隆端到端运行过。需要Blackwell GPU(内核使用NVFP4硬件路径)、快速NVMe上约70GB空间、32GB RAM。

最重要的结论:对MoE模型,“是否适合VRAM”是错误的问题。计算字节每token,然后测量时间花在哪里再修复——因为明显的罪魁祸首(这里是Python启动开销)可能是错的。

#Nemotron-3.5-Super#8GB GPU#MoE模型#NVFP4#专家流式加载#Triton内核#ReLU²零值#RAM缓存
分享:

相关推荐