把 7440 亿参数塞进 25GB 内存:MoE 流式卸载的账本

2026-11-04T07:11:22+08:00 | 7分钟阅读 | 更新于 2026-11-04T07:11:22+08:00

@
把 7440 亿参数塞进 25GB 内存:MoE 流式卸载的账本

一台 12 核、25GB 内存的笔记本,跑 GLM-5.2,7440 亿参数。colibri 的 README 第一句就是「这不快」,作者实测 0.05 到 0.1 tok/s,一个 token 要等十几二十秒。他也没打算掩饰,社区跑分表里连自己撤回过的一次测量错误都标了出来。

这个项目今天在 GitHub 趋势榜上拿了 675 颗星。0.05 tok/s 本身没什么用,值得看的是它把一件正在发生的事提前摊开了:前沿模型的权重已经装不进内存,于是硬盘被当成第三层内存来用。

一、MoE 给的这个口子是怎么开的

7440 亿参数里,一个 token 只激活大约 400 亿。这 400 亿里真正随 token 变化的只有约 110 亿,也就是被路由器选中的那些专家。注意力、embedding、共享专家、输出头这层骨架约 170 亿参数,int4 量化后 9.9GB,可以老老实实常驻内存。剩下两万多个路由专家,int4 之后整个池子约 370GB,全躺在盘上,谁被选中谁上来。

colibri 就是用这个结构,把 744B 的模型拆成了「常驻的一小块」加「按需流式加载的一大堆」。

二、一个 token 要读多少字节

75 个 MoE 层,每层取 8 个专家,一个 token 大约触发 600 次专家读取。单次读取约 19MB,冷启动时一个 token 要从盘上拉 11GB 左右。

这个数字决定了后面所有的争论。你手上那块盘的顺序读大概是 6GB/s,那么一个 token 光是等数据就要快两秒。想把速度做上去只有两条路:让读的字节变少,或者让要读的东西已经在内存里。

三、三层内存怎么分工

colibri 把 VRAM、RAM、磁盘当成一套受管的内存层次,没有割开看。VRAM 放最热的专家,RAM 做宽松的缓存,磁盘是冷数据源。替换策略用 LFU 和 LFRU 的混合,另外加了 25% 的迟滞,防止两个专家来回抢同一个槽位。

最有用的一招是 .coli_usage:它把每一轮对话的路由记录存下来,下次启动按历史热度把最常用的专家钉在空闲内存里。作者自己打的比方是 JIT,编译器不会把整个程序都编译一遍,它看哪条路径跑得热,只编译热的那部分。colibri 对权重做同样的事,于是同一台机器用得越久,命中率越高,出字越快。

这个设计有个常被忽略的边界。内存只有 24GB 时,引擎会自动把每层缓存压到 2 个槽位,盘再快也救不回来。小内存机器上卡脖子的是内存本身,不是 SSD。

四、反方算了一笔账

robotnurse 那篇分析是这条路上少见的冷水,而且先把参数全列出来,方便别人反驳。

他在 M3 Ultra 上回归 decode 时间和搬运的权重字节,得到 798GB/s 的等效带宽,是芯片标称值的 99.8%。也就是说 decode 已经贴着内存带宽的天花板在跑,没有余量。盘这边,顺序读一块 147GB 的专家池花了 25 到 30 秒,折算 5 到 6GB/s。

两个数一比,从盘上读 1 个字节的时间,够从内存读 130 个字节。

再从目标倒推。要 10 tok/s,一个 token 只有 100ms,其中常驻部分占 35ms,留给盘的 65ms 在 6GB/s 下只能读 0.4GB。V4.1-Flash 的 fp4 专家每 token 要走 4.5GB,那么至少 91% 的专家得常驻。按 215GB 的可用预算算,专家池上限约 236GB。

结论不客气:流式卸载只能救那些差一点就装下的模型,大概差一成以内。真差一倍,估算是 0.8 到 1.4 tok/s。而那一成,用更低的位宽去补,比写一套流式管线便宜得多。

这组数字只对那台机器和那几个 DeepSeek 类模型成立,方法倒是可以搬。它至少说明一件事:讨论能不能跑之前,先把「每 token 要多少专家字节」和「盘能给你多少带宽」写下来。

五、比带宽更早爆的三个地方

prefill 先撑不住。 2048 个 token 的一块 prompt 会把每一层的每个专家都碰一遍。74% 常驻的情况下,光读盘就是 12 秒一块,prefill 上限被按在 170 tok/s 左右。对话第一句就要等这么久,体验是断的。

预取治不了带宽。 74% 常驻时,一层要读 30MB,I/O 花 5ms,计算只花 0.7ms。预测得再准,也只有 0.7ms 能藏,剩下 4.3ms 干等。预取解决的是延迟,这里的瓶颈是带宽。

批量和投机都在放大读取。 4 个 token 一批,碰到的专家接近 4 倍。投机解码验证草稿还要多读专家,等于拿最稀缺的资源换吞吐,在磁盘这一层非常不划算。

六、但确实有人跑通了

唱衰归唱衰,实测里跑通的也不少,而且各自踩对了不同的点。

SSD-LLaMA 那篇论文在单张 RTX 5090、32GB 内存上跑万亿参数 MoE,decode 超过 1 tok/s。它的立论是硬件到了拐点:PCIe 5.0 SSD 顺序读能到 14.8GB/s,已经超过单通道 DDR3-1600 的 12.8GB/s,逼近 DDR4-1866 的 14.9GB/s;容量成本上,拿 SSD 替掉大容量 DRAM 能省九成。这并不等于说 SSD 就是内存,延迟和随机读差得远,但作为「放得下」的那一层,它够格了。

MoE-Direct 在 32GB 内存加一张 RTX 5080 上跑 Qwen3.5-122B,专家部分 72.8GB,5.59 tok/s,比同一个二进制走 plain mmap 快 2.3 倍。更值钱的是另一个结果:同一个引擎跑 gpt-oss-120b,12 条贪心输出和原始读路径逐 token 一致。这条比速度更能说明卸载没有动模型。

llama.cpp 有个讨论串点出了一个容易忽略的数字。GGUF 把 128 个专家交错存在一个张量里,mmap 取 1 个专家要碰 6912 个页,放大 111 倍。重排成专家连续之后是 192 个页,降到 36 倍。同一个模型、同一块盘,只因为文件布局,每层 I/O 从 263MB 压到 31MB。很多人觉得是机器慢,其实是格式在收过路费。

FreeToken 换了个角度:缓存没命中时别让 GPU 停着,按实时互联带宽把当前 token 的计算在 CPU 核和 GPU 张量核之间分掉,再用双缓冲把 PCIe 传输盖在计算下面。FlashMoE 则把缓存替换交给一个小模型,命中率比 LRU 和 LFU 高出 51%,整体快 2.6 倍。

七、我自己的判断

分三档看。

能用的:模型在内存的 1.5 到 2 倍以内,专家粒度小,比如 30B-A3B 那种 128 个专家每层只激活 8 个;单用户、离线、对延迟不敏感。这种配置下 2 到 5 tok/s 是能读的,尤其你只是让它夜里跑一批长任务,慢点没关系。

勉强能看的:几百 B 的模型配 64GB 内存加一张像样的显卡。能出字,一个 token 几秒,适合验证想法、跑一次评测,不适合日常干活。

别指望的:并发服务、长 prompt 的 RAG、需要 prefill 速度的文档处理。还有一类最反直觉,共享专家多、路由均匀的模型。共享专家看着是省参数的好设计,可它恰恰削弱了专家缓存赖以生存的路由局部性,路由越均匀,缓存越没用。

真正要判断的只有一件事:这台机器上,专家池的常驻比例能不能撑到九成以上。撑不到,速度就掉到另一个数量级,所有优化加起来也只是在这一档里挪动。

八、动手之前先做的三件事

先量再写代码。两个数,半天能测完:一是 90%、75%、50% 常驻下 miss fraction 各是多少,二是专家粒度的随机读在队列深度 1、8、24 下各是多少。这两个数能直接否掉一个月的开发。

顺手查一下 PCIe 链路。有人用 M.2 转接卡,结果只接了两条 lane,盘速从 3.5GB/s 掉到 1.5GB/s,排查了几天都在怀疑模型。

如果格式是交错的,先做专家连续化重排。这一步零成本,收益比大多数内核优化都大。

九、这条线的意义

这条路真正难的地方,不在把权重放到盘上。难的是让盘上的字节尽量少被需要。所有工程都在这一个不等式上做文章:每 token 需要的专家字节,除以可用的盘带宽,必须小于你能接受的每 token 时间。

分母这几年在涨,PCIe 5.0、双盘 RAID0、大容量 QLC 都在帮忙。分子也在涨,模型一年比一年大。所以它不会有一个「彻底解决」的结局,只会长期存在一条分界线,划在「本地能跑」和「本地能用」之间。

对个人来说,这件事的价值大概不在省钱,也不在替代 API。它是在断网、断供,或者就是你不想把数据发出去的那一天,你桌上还有一台能开口说话的机器,哪怕它一分钟只吐二十个字。


参考来源

Me

Cut out summary from your post content here.

The remaining content of your post.