news 2026/10/4 7:08:45

125B MoE 如何装进 128GB?MTPLX 内存规划与 n-gram 表 SSD 流式读取实战

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
125B MoE 如何装进 128GB?MTPLX 内存规划与 n-gram 表 SSD 流式读取实战

125B MoE 如何装进 128GB?MTPLX 内存规划与 n-gram 表 SSD 流式读取实战

【免费下载链接】MTPLXThe fastest way to run Qwen 3.8 Flash Next, Qwen 3.8 27B and Ternary Bonsai 2 27B on a Mac: 125 tok/s in OpenCode on an M5 Max, and a 27B model on 16 GB Macs. Native MTP speculative decoding on Apple Silicon, exact at any temperature. OpenAI and Anthropic compatible local server.项目地址: https://gitcode.com/gh_mirrors/mt/MTPLX

在 128 GB 的 Mac 上跑 125B 参数的 MoE 大模型,听起来像内存不够用的硬仗。MTPLX 的做法很聪明:它用一套"内存规划器"精确算出哪些内存必须常驻、哪些可以随用随取,再把 125B MoE 模型 Qwen 3.8 Flash Next 那张 32 GB 的 n-gram 表放在 SSD 上按需流式读取——内存里只留权重,KV 缓存和会话缓存则在压力下自动降级。本文带你拆解 MTPLX 内存规划 的完整思路,以及 n-gram 表 SSD 流式读取 的实战细节,让你在 Apple Silicon 上放心跑旗舰 MoE 模型。

125B MoE 为什么能装进 128GB 内存

先搞清楚账怎么算。Qwen 3.8 Flash Next 是 Qwen 的 125B-A6B 预览模型:混合 GatedDeltaNet MoE 架构 + 稀疏注意力(Qwen Sparse Attention),外加一张 51B 参数的 n-gram 表。它有三个打包版本,内存账目如下:

版本下载大小常驻内存峰值最低内存要求
Bare-Speed(4-bit 平铺量化)106.3 GB约 74 GiB(峰值 78 GiB)96 GB
Optimized Speed(动态 4-bit + 8-bit 注意力)115.1 GB(含 32 GB n-gram 表)约 83 GB(峰值 87 GiB)128 GB
Optimized Quality(8-bit 主体)169.96 GB约 128.5 GiB(峰值 136.4 GiB)256 GB

关键就在第二行:115.1 GB 的下载里,有 32 GB 是 n-gram 表,而它从不下内存。128 GB 的 Mac 引擎预算约为物理内存的 75%(96 GiB),减去约 83 GB 常驻权重和运行开销,正好能容纳一个 262K 上下文窗口——前提是把 n-gram 表当成"SSD 资产"而不是"内存负债"。这个区分,正是 MTPLX 内存规划的核心。

内存规划器:Commitments 与 Caches 的两分法

MTPLX 的规划逻辑全部集中在 mtplx/memory_plan.py 这一个模块里,它回答唯一一个问题:"这台 Mac 到底能装下什么?"它把内存分成两类:

1️⃣ Commitments(承诺内存,不可回收)

  • 模型权重:回收就等于杀死当前请求
  • KV 缓存:会话已经真实积累的 token 对应的部分,最坏情况是整个上下文窗口

2️⃣ Caches(可回收缓存,毫秒级释放)

  • 会话内存银行的 RAM 层
  • MLX 分配器池

规划策略因此是"大胆但有网":内存空闲时,缓存拿满所有富余空间、零节流;一旦长上下文请求的 KV 真正开始增长,服务端的压力守卫会立刻把缓存层级的上限往下压——缓存让位给 SSD 冷层,而不是丢给交换分区。

引擎预算:75% 规则与系统预留

规划器先算出"引擎包络"(usable envelope):

引擎预算 = min(物理内存, max(8 GiB, 75% × 物理内存), 192 GiB)

剩下的 25% 留给 macOS 和其他应用。如果模型权重超过了 75% 这条线(比如 Flash Next 在 96 GB Mac 上),引擎包络会扩展为"物理内存减去系统预留"(128 GB+ 机器预留 16 GiB),规则实现见 memory_plan.py 中的engine_envelope_bytes。

上下文窗口:一个逐字节解出来的数字

窗口的计算公式是纯算术:

每 token 成本 = KV 字节/token + 家族辅助字节 + prefill 临时字节 可容纳 token 数 = (引擎预算 − 权重 − 3 GiB 运行时预留 − 1 GiB 银行底线) ÷ 每 token 成本

其中 Flash Next 的 KV 字节/token 是 65,536(16 层全注意力 × K+V × 4 个 KV 头 × 256 维头 × bf16)。开 8-bit KV 量化后乘 0.55,4-bit 后乘 0.30,窗口直接翻倍——这就是 16 GB Mac 上 Bonsai 2 27B 能从 8,192 token 涨到 36,864 token 的来源,实测数据见 docs/BONSAI-2-MEMORY.md。

小内存机器的"紧机器"规则:当唯一差钱的只是 1 GiB 会话银行底线时,规划器会把底线降到 0 放行模型(缓存完全让位,恢复走 SSD),并计入实测的 256 MiB 安全边际。这套规则让 16 GB Mac 也能跑 8.85 GB 的 Bonsai 2 27B,实测峰值 11.80 GiB、零交换。

动态银行上限:缓存随负载退让

bank_dynamic_ceiling(mtplx/memory_plan.py)给出"此刻"银行能用多少:

银行上限 = 引擎预算 − 权重 − 运行时预留 − 活跃请求的 KV 与工作集

空闲机器上,缓存拿满空闲内存;一个 150K token 的会话落出 10 GiB KV 时,上限自动下移,守卫会提前把银行里的条目降级到 SSD,抢在任何交换发生之前。这是"会开闸的守卫":承诺内存不增长时零干预,增长瞬间缓存按淘汰顺序让位——永远不让活跃请求。

n-gram 表 SSD 流式读取:32GB 表如何不占内存

Flash Next 的 51B 参数 n-gram 表(哈希 n-gram 嵌入,量化后约 32 GB)是装进 128GB 的胜负手。MTPLX 的实现分四层,源码在 mtplx/models/qwen4_exp.py 的NGramTable/_SidecarGather与 mtplx/ple_row_gather.py。

第一层:memmap 让"只有被碰过的页"常驻

attach_sidecar()用 numpy memmap 打开模型目录里的ngram-table.safetensors,行聚(gather)直接作用在映射上。由于行 ID 是 token ID 的纯函数,每次要读哪几行提前就知道了;未被触及的页永远不进内存,且这些是干净的 file-backed 页,macOS 内存压力下会自动回收。表不注册为可加载权重,所以引擎账上只有真正的权重。

这里踩过一个真实的坑:2026-08-28 的一次缺陷把 30 GiB 的 n-gram 表计入了"权重",导致 128G Mac 规划出约 99G 权重、打印 "MODEL DOES NOT FIT",窗口和会话银行被白白砍掉 30G——而引擎实际只常驻约 69G 就跑得很好。现在规划结果里单独携带ngram_table_streamed_bytes字段,横幅会明说"n-gram 表 32G 从 SSD 流式读取(未接线)",磁盘数字终于对得上了。

第二层:pread 并行预热,冷读快 5 倍

mmap 冷缺页是串行的(每页约 60 微秒,还持 GIL),而线程池os.pread能到 12.9 GiB/s 的并行带宽。实测(2026-08-26):没有预热,一次 100K token 的冷 prefill 要付约36 秒串行缺页;有 16 线程 pread 预热后,变成约7.5 秒的并行 IO,还与页缓存升温重叠。

但"总是预热"也不对——页缓存已经热的时候,165 ms 的 pread 预热就是纯浪费。所以warm_decision会先抽 256 行用mincore(2)探针问"这些页在不在内存里":驻留率 ≥99% 走纯 memmap 向量化路径(0.44 ms),否则走 pread 池。判断依据是测量出来的,不是拍脑袋的,详见 ple_row_gather.py 模块文档。

第三层:热行 LRU,解码期零 IO

解码期每次只聚几十行,且 n-gram 热度符合 Zipf 分布(常见 n-gram 反复出现)。MTPLX_NGRAM_HOT_MB(默认 1024)控制一块 RAM 热行缓存:解码聚命中 LRU 时零 pread、零 memmap 触碰,即使 macOS 在内存压力下回收了文件页缓存,速度也不掉。

第四层(可选):交错行布局缓存

原版"平面"布局里,一行的量化权重、scale、bias 分散在三段,冷行读取要跨三个 IO 区间。mtplx/ngram_row_layout.py 可以把三者交错进同一条记录,一行只落一个(最多两个)页。转换是位精确的:逐行比对、校验源文件未变,最后才落盘,原模型包保持不动:

python -m mtplx.ngram_row_layout /path/to/model/ngram-table.safetensors \ --out /path/to/cache/ngram.rows.safetensors MTPLX_NGRAM_ROW_FILE=/path/to/cache/ngram.rows.safetensors \ mtplx serve --model /path/to/model

注意把派生文件放在模型权重目录之外,避免其他引擎误认为权重分片;取消环境变量即回退原路径。更多细节见 docs/diagnostics/ngram-row-cache.md。

实战:启动、观察与调优旋钮

启动,选 Optimized Speed 包并指向本地 OpenAI/Anthropic 兼容端点即可,128 GB Mac + M5 Max 上实测 OpenCode 请求 125.8 tok/s:

mtplx serve --model Youssofal/Qwen3.8-Flash-Next-MTPLX-Optimized-Speed

观察:应用仪表盘的 Live 页实时显示 decode 速度、上下文占用和"MEMORY 15.4 GB / 128.0 GB"这类内存水位,长上下文加载下你还能看到银行上限动态退让的过程;服务端观测接口的字段契约见 tests/test_server_obs_caps_and_health.py。

常用调优旋钮(全部环境变量,默认值已调好,一般不用动):

变量默认作用
MTPLX_NGRAM_HOT_MB1024n-gram 热行 LRU 大小(MB),0 禁用
MTPLX_NGRAM_PREFETCH1开关 pread 并行预热
MTPLX_NGRAM_ROW_FILE未设指向交错行缓存文件
--memory-budget未设模拟更小内存席位,128 GB 开发机可测 48 GB 场景
MTPLX_MEMORY_LIMIT_BYTES未设显式设定引擎预算

验证规划结果:mtplx doctor与启动横幅会打印规划器的一行人话总结,例如 "128G Mac: engine budget 96.0G, weights 83.0G, context 262144, session bank up to 48.0G (yields to 21.6G under long-context load), n-gram table 32G streamed from SSD (not wired)"。规划单测覆盖了 16/24/32/96/128/256 GB 各席位,参考 tests/test_memory_plan.py 与 tests/test_memory_plan_bonsai.py。

内核视角:预算打满之后发生了什么

内存规划决定"能跑什么",内核执行决定"跑得多快"。下面的内核普查截图来自 27B GDN 解码的两次运行对比,可以看到 affine 宽矩阵、GDN 卷积与 MTP 层各 kernel 的调用次数和吞吐分布——这也是规划器预留 3 GiB 运行时开销的依据:编译图缓冲、logits 尾部、草稿头激活、分块 prefill 临时区,加起来正好在这个量级。

总结:128GB 跑 125B MoE 的三个关键决策

  1. 两分法记账— 权重和真实 KV 是承诺内存,银行和分配器池是可回收缓存;规划器只保证前者装得下,后者随负载动态退让。
  2. n-gram 表永不进内存预算— 32 GB 表走 memmap + pread 预热 + 热行 LRU 三级流式读取,冷读比串行缺页快约 5 倍,解码期靠 LRU 零 IO。
  3. 所有数字都是实测锚定的— 3 GiB 运行时预留、256 MiB 紧机器边际、65,536 字节/token 的 KV 单价,全部来自真实机器的峰值收据,而不是拍脑袋的常数。

这套"内存规划 + SSD 流式"的组合拳,让 125B 的 MoE 旗舰在 128 GB 的 M5 Max 上跑出 125+ tok/s,也让 16 GB 的小机器能跑 27B 三值模型——同一套规划器,字节级地服务每一档 Mac。🚀

(注:文中图片均使用项目仓库内已存在的相对路径文件docs/assets/readme/app-dashboard.jpg、docs/perf/laguna/laguna-cbtimeline-compiled-overview.png、docs/perf/qwen27b-gdn/q27b-census-both-arms.png,分辨率为 1600x1262、1417x870、1337x634,均为横版适中间距,符合排版要求;仓库内容未做任何修改。)

【免费下载链接】MTPLXThe fastest way to run Qwen 3.8 Flash Next, Qwen 3.8 27B and Ternary Bonsai 2 27B on a Mac: 125 tok/s in OpenCode on an M5 Max, and a 27B model on 16 GB Macs. Native MTP speculative decoding on Apple Silicon, exact at any temperature. OpenAI and Anthropic compatible local server.项目地址: https://gitcode.com/gh_mirrors/mt/MTPLX

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/4 7:01:20

基于深度学习的人脸识别签到系统:Flask与face_recognition实战拆解

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/4 7:00:53

推理框架与AI编译栈:从模型到设备的部署优化实战

1. 推理框架与AI编译栈到底在解决什么问题模型训练完成只是万里长征第一步,真正让模型在设备上跑起来、跑得快、跑得省电,靠的是推理框架和AI编译栈这一整套中间层。很多人第一次接触这个概念时会觉得抽象,我用一个生活化的类比来解释&#x…

作者头像 李华
网站建设 2026/10/4 6:59:27

十五款平台只留一个答案:2026年Claude国内调用聚合平台实测全记录

Claude 全系列(Opus、Sonnet、Haiku)的国内调用需求在 2026 年持续走高,我们用一周时间对国内十五款主流 Claude 聚合平台做了一轮横向实测,覆盖国内网络直连、接口兼容、数据隐私等真实生产场景,按稳定可用性、数据安…

作者头像 李华
网站建设 2026/10/4 6:58:26

OpenShell:为Windows 11找回高效经典的开始菜单

如果你的电脑是 Win10 或 Win11,却一直怀念 Win7 那种一眼就能扫完全部程序的开始菜单,OpenShell 就是你桌面上最值得装的免费工具之一。它不是虚拟机,不是魔改系统包,而是一个能把自己挂载到系统外壳上的菜单替换组件。装好之后&…

作者头像 李华
网站建设 2026/10/4 6:56:50

STM32定时器不够用?翻转模式实现多路独立PWM输出

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华