在 M1 Max 上运行 2.8T 参数的 Kimi K3:Deltafin 项目实现 0.0687 token/s 推理
在 M1 Max 上运行 Kimi K3
Deltafin 项目成功在 64 GB M1 Max 上运行了 2.8T 参数的 MoE 模型 Kimi K3,当前中位推理速度为 0.0687 token/s(14.6 秒/token)。完整安装需约 1.7 TB 本地磁盘,流式模式仅需 215 GB 但推理速度降至 3 分钟以上/token。项目提供 OpenAI 兼容 API 服务器,支持聊天和代码补全,但建议客户端超时设为小时级别。
这是个在 M1 Max 上跑 2.8T MoE 的工程 hack,把不可能变成可能,虽然慢得只有聊天室节奏,但玩法足够硬核,玩硬件的看完会想开 issue 贡献数据。
在一台 Apple Silicon Mac 上运行 Kimi K3(2.8T 参数)的实验
Deltafin 是一个小型研究项目,它运行的 Mixture-of-Experts 模型远大于其所运行的机器。目前精确路径的中位数为 0.0687 token/s(14.6 秒/token),测试环境是我们的 64 GB M1 Max。迄今为止所有已发布的运行结果都来自那一台第一代机器——并非更新的 Max 或 Ultra——而能力门控路径加上自动 RAM 预算机制,将同一引擎延续到更新的 Apple Silicon Mac 上。
安装
三条命令,然后你就可以开始生成了。唯一真正需要做决定的是第 3 步。
# 1. environment (Python 3.12+, and Xcode CLT for clang)
python3 -m venv venv
./venv/bin/pip install torch numpy safetensors tiktoken ml_dtypes blobfile \
"transformers==4.56.2" einops tokenizers
# 2. build the fused MXFP4 kernel
clang -O3 -mcpu=native -shared -DNO_MAIN -o tools/libmxfp4gemv.dylib tools/fused_gemv.c
# 3. download the model (see the two modes below)
./venv/bin/python tools/setup_k3.py --full
两种模式
--full(推荐) | --stream | |
|---|---|---|
| 所需磁盘空间 | ~1.7 TB | ~215 GB |
| 下载时间 | 5–10 小时,可断点续传 | ~30 分钟 |
| 之后的速度 | 中位数 14.6 秒/token,在我们的 M1 Max 上 | 对于任何尚未缓存的内容,约 3 分钟以上/token |
| 推理时的网络 | 无 | 恒定 |
每个 token 都要读取 16 个专家 × 92 层 = 25.8 GB 的专家数据。从本地磁盘读取大约需要 4 秒;通过网络则需要数分钟。这单一事实就是两列之间的全部差异。
运行 setup_k3.py 时不带任何标志,它会在磁盘允许时选择 --full,否则回退到流式传输,并准确告诉你需要释放多少空间。
从流式传输开始,之后再升级
流式传输是试用 Deltafin 而无需投入 1.7 TB 的好方法。每当你想获得速度时,一条命令就能完成升级——无需重装、无需重新配置,而且它会自动接续任何已缓存的内容:
./venv/bin/python tools/fetch_experts_all.py # resumable, run anytime
./venv/bin/python tools/fetch_experts_all.py --dry-run # just show the numbers
./venv/bin/python tools/fetch_experts_all.py --layers 1-40 # partial is fine too
对于流式安装,空闲时间预热器可以根据记录的路由器追踪来对缺失的专家进行排序。其默认是只读计划;网络获取需要显式启用,并且它可以将旧版 .npz 条目原子性地转换为原始快速格式:
./venv/bin/python tools/warm_expert_cache.py
./venv/bin/python tools/warm_expert_cache.py --convert-npz --fetch 128
Deltafin 在启动时会打印一条提醒——无论是 CLI 还是 API 服务器——只要它仍处于流式模式,就会显示池中有多少是本地资源,以及完成全部处理需要多少成本。
可选:int8 主干
将非专家权重的每 token I/O 减半,在我们的检查中没有明显的质量变化。只需几分钟:
./venv/bin/python tools/convert_spine_int8.py
用法
# ask a question; generates until the model finishes its answer
./venv/bin/python tools/kimi_run.py --chat --prompt "What are the three largest moons of Saturn?"
# raw completion (no chat template); runs until you press Ctrl-C, or cap it
./venv/bin/python tools/kimi_run.py --prompt "The capital of France is" --max-new 16
Token 在生成时即打印出来,因此你始终能看到文本的实时输出。Ctrl-C 可在任意时刻干净地停止,并打印到目前为止的结果;--max-new N 限制长度。一个坦诚的提醒:K3 在回答之前会先思考,而以大约每分钟 4.1 个 token 的速度,一次完整的对话回答可能需要一段时间——观看它流式输出本身就是体验的一部分。
将 K3_TRACE=buffered 设置为把路由器的选择记录到 router_trace.jsonl,以便离线研究。性能测试运行时不开启追踪。
兼容 OpenAI 的服务器
Deltafin 可以提供标准的 OpenAI API,因此聊天界面、openai SDK 和编码智能体只需更改 base URL 即可使用它:
./venv/bin/python tools/serve_openai.py --port 8000
curl http://127.0.0.1:8000/v1/chat/completions -H 'Content-Type: application/json' \
-d '{"model": "deltafin-kimi-k3",
"messages": [{"role": "user", "content": "Hello!"}]}'
from openai import OpenAI
client = OpenAI(base_url="http://127.0.0.1:8000/v1", api_key="none")
r = client.chat.completions.create(
model="deltafin-kimi-k3",
messages=[{"role": "user", "content": "Hello!"}])
print(r.choices[0].message.content) # the answer
print(r.choices[0].message.reasoning_content) # K3's thinking, when present
/v1/chat/completions、/v1/completions 和 /v1/models 已实现,流式传输("stream": true)也可用。大多数读取 OPENAI_BASE_URL 和 OPENAI_API_KEY 的工具,只要将这些指向该服务器即可正常工作。
在把任何自动化程序指向它之前,请先阅读以下注意事项:
- 时间。答案什么时候到就什么时候到——把客户端的超时设成小时级,而不是秒级。省略
max_tokens可以让模型把答案写完(推荐);原始补全永远不会自行结束,默认值为 256。运维人员可以用K3_SERVER_MAX_TOKENS设置硬性上限。 - 流式安装在这里要慢得多。一个聊天模板提示词就有 60 个 token 甚至更多,而预填充每层都要触及大量专家,所以在缓存只填了一部分的情况下,一个聊天请求可能要花好几个小时来抓取。如果安装完整,那就只是正常的(缓慢的)推理。当你处于流式模式时,服务器会在启动时打印一条警告。
- 仅支持贪心解码。
temperature和top_p会被接受但被忽略,并且一次只运行一个请求(第二个并发请求会收到 429)。 - 智能体只是个新奇玩意儿,不是工作流。编程助手原则上可行,但它们冗长的系统提示词让预填充变得很昂贵。
配置
一切无需配置即可运行:Deltafin 会在有 GPU 时选择 GPU,在 int8 主干已构建时选择它,并在启动时说明自己的选择。以下变量用于覆盖这一行为:
| 变量 | 默认值 | 含义 |
|---|---|---|
K3_DEV | 自动 | GPU(mps)可用时使用,否则使用 cpu |
K3_SPINE | 自动 | 构建时使用 int8(推荐),否则使用 bf16 |
K3_INT8_LM_HEAD | 1 | 在支持时使用打包的 MPS int8 输出头;精确的稠密回退方案仍然可用 |
K3_SPEC | 1 | n-gram 推测(无损) |
K3_TEMPLATES | 1 | 模板层缓冲区复用 |
K3_PRELOAD / K3_PREFETCH | 1 | 后台层加载 / 专家预取 |
K3_METAL_POSITION_BATCH | 0 | 精确的可选启用 T>1 位置优先 Metal MoE;在已接受的投机推理通过上实测提升 +2.0%,且应按每台 Mac 重新调优 |
K3_MOE_TOP_K | 16 | 明确的质量/速度调节旋钮;更少的路由专家可减少专家字节数,并可能改变输出 |
K3_CPU_MOE_BATCH | auto | 精确的持久化 CPU MXFP4 工作线程环;填充计数器在八线程下实测提升 +3.6% |
K3_ASYNC_CACHE_WRITE | 0 | 可选启用的缓存未命中写入重叠;K3_CACHE_WRITE_QUEUE(4)限制未完成缓冲区的数量,K3_CACHE_WRITE_WORKERS(1)可按每台 Mac 重新调优 |
K3_APPROX | 0 | fp16 数值精度;在接近平局时不可复现 |
K3_RAM_GB / K3_PIN_LAYERS | 自动 | 覆盖 RAM 预算 |
K3_PROFILE | 0 | 每一轮的按阶段计时 |
K3_TRACE | off | buffered 每一轮写入一个 router-trace 块;sync 立即写入每一层 |
DELTAFIN_ROOT | 仓库根目录 | 缓存和权重所在位置 |
K3_HF_HOST / K3_HF_PATH | Hugging Face | 将专家拉取指向镜像 |
K3_SERVER_MAX_TOKENS | 无限制 | 可选的服务器生成硬性上限 |
K3_RESPONSE_MEMO_ENTRIES | 32 | 针对相同确定性 API 请求的精确进程内重放缓存;0 可将其禁用 |
环境要求
- 一台 Apple Silicon Mac。所有已公布的数据均来自同一台第一代 M1 Max,配备 64 GB 内存——这是目前唯一进行过基准测试的 Mac。更大的内存会被自动利用(128 GB 的机器会固定加载数倍于该规模的模型),而更新的芯片可以带来更高的内存带宽、更多的 GPU 资源和更快的存储。参见 为什么更新的 Mac 应该更快。
- Xcode Command Line Tools,用于
clang(xcode-select --install)。 - Python 3.12 或更新版本。
- 磁盘:完整安装约需 1.7 TB,流式加载约需 215 GB(参见 安装)。
- 需要能够访问 Hugging Face 的网络连接。
工作原理
K3 的权重总计约 1.56 TB,超过了这台机器的可用磁盘空间,更不用说内存了。而让本地推理仍然可行的观察是:混合专家模型每个 token 只会触及自身的一小部分。
- 常驻主干(约 114 GB:注意力、共享专家、潜在投影、嵌入向量)只需下载一次,之后每个 token 都从本地 NVMe 逐层读取,量化为 int8 并在 GPU 上计算。
- 82,432 个路由专家(约 1.45 TB)。对于每个 token,K3 的路由器每层挑选 16 个专家,只有这些专家会被读取。如果可以的话,把它们全部安装到本地(推荐);否则 Deltafin 会按需从 Hugging Face 获取它们——每个专家一次 HTTP range 请求——存入不断增长的磁盘缓存。
- 前向传播运行的是 Moonshot 自己的建模代码,未经修改。一个小的纯 PyTorch 垫片替代了它所期望的仅限 CUDA 的
fla内核。
flowchart LR
subgraph HF["Hugging Face CDN"]
W[("96 safetensors shards<br/>1.56 TB · MXFP4")]
end
subgraph MAC["MacBook (M1 Max, 64 GB)"]
subgraph DISK["NVMe"]
SP[("resident spine<br/>114 GB bf16 → 60 GB int8")]
EC[("expert cache<br/>raw shard spans")]
end
subgraph TOK["per token"]
R{"router<br/>top-16 of 896<br/>× 92 layers"}
L["93 decoder layers<br/>2 shared GPU templates"]
K["fused MXFP4 GEMV<br/>NEON"]
end
end
W -- "one range request<br/>per missing expert" --> EC
SP -- "double-buffered<br/>layer loader" --> L
EC -- "mmap" --> K
R -- "selected experts" --> K
K --> L
L -- "logits" --> R
预期表现
以下所有当前数字均是在一台 M1 Max(10 核 CPU、32 核 GPU、64 GB、内置 NVMe)上测得的,模型完整安装在本地,int8 常驻权重和输出头,Metal MoE,精确 fp32 数值,贪心解码,并禁用 tracing。
当前这一列汇总了来自平衡 ABBA/BAAB 测试活动的六次精确的全模型运行。每次运行都使用了五 token 提示词The capital of France is,验证了三 token 补全 Paris. The,并在报告稳态吞吐量之前丢弃了第一个解码步骤。数值为中位数;范围显示了这一 I/O 密集型工作负载即使在同一台安静机器上也有多大波动。
| 指标 | 首个可用版本 | 当前 M1 Max 基准测试 | 变化 |
|---|---|---|---|
| 预填充 / 首 token(5-token 提示词) | 2,429 s | 中位数 28.0 s(24.9–37.9 s) | 约 87× |
| 稳态解码,专家本地 | 约 20 分钟/token | 0.0687 token/s(14.6 s/token);运行范围 0.0503–0.0779 token/s | 约 82× |
| 精确三 token 生成,模型时间 | — | 中位数 56.5 秒 | — |
| 同一轮运行的冷启动进程墙钟时间 | — | 中位数 64.1 秒 | — |
| 解码,专家流式加载 | 约 20 分钟/token | 约 3 分钟/token | 受网络带宽限制 |
这就是“寒酸的 M1”结果:一台老化的第一代 M1 Max,而非更新的 Max 或 Ultra。这是一个保守的参考基准,而非跨 Mac 的对比测试。我们预计更新、更高带宽和更大内存的系统会有更好的表现,但当有人实测这些数据时,我们会单独标注。
近期精确路径改进
以下最新测量结果是在同一台 M1 Max 上进行的均衡 A/B 对比。每次全模型运行都检查了 token oracle。
| 变更 | 实测结果 | 发布行为 |
|---|---|---|
| 打包的 MPS int8 输出头 | +17.3% 稳态解码中位数,+23.1% prefill,以及 +26.8% 整体吞吐量;常驻头存储从 4.7 GB 降至 1.17 GB | 在算子和 int8 权重可用时启用,并带有异常保护的稠密回退 |
| 仅引用的推测性快照 | 0.001 ms 而非 3.56 ms,且无需约 475 MB 的状态克隆 | 默认启用;重放和部分接受测试保留了精确的未来序列 |
| 面向已接受草稿的按位置为主的 Metal MoE | 在真实 T=2 层上 +4.7%,全模型汇总吞吐量 +2.0% | 通过 K3_METAL_POSITION_BATCH=1 精确选择启用,待按 Mac 逐台调优 |
| 128 字节对齐的 CPU 工作线程计数器 | +0.2%(四线程)和 +3.6%(八线程) | 在持久化 CPU 回退中自动生效 |
中位数大约为 每分钟 4.1 个 token。一个具有代表性的 M1 Max 性能剖析主要由以下部分构成:
| 等待常驻主干读取(53 GB) | 约 5 秒 |
| 读取每层选中的 16 个专家(25.8 GB) | 约 4.3 秒 |
| 应用主干(传输 + 反量化) | 约 3 秒 |
| 注意力与归一化(93 层) | 约 2 秒 |
| MoE 专家矩阵乘法 | 约 1 秒 |
解码现在受限于常驻主干部分的磁盘带宽。那 53 GB 每生成一个 token 都要重新读取,而在此访问模式下约 7 GB/s 的持续速度意味着,在 14.6 秒的中位数耗时中约占 7.5 秒——除非增加内存(足以容纳主干部分而不挤占专家读取所需的页缓存),或者缩小主干部分,否则无法避免。
为什么更新的 Mac 应该更快
上述每一行都受制于随 Apple Silicon 代际变化的硬件。没有任何路径会被 M1 的结果硬性禁用,但这里测得的若干回退值;更新的机器应当根据自身的算力、运行时、内存和存储指纹重新调优这些值:
- 内存带宽。M1 Max 为 400 GB/s。M3/M4 Max 明显更高,而 Ultra 大约翻倍——这直接作用于主干部分加载和专家 matmul。
- GPU。更多核心以更快的速度执行相同的 Metal kernel;反量化 shader 和注意力路径都随之扩展。
- SSD。专家读取是最大的单一环节,其速度取决于内置硬盘的吞吐。后续 Mac 配备更快的 NVMe。
- RAM。这一点最为关键。53 GB 的主干无法与其余所有内容一起塞进一台 64 GB 的机器,因此每生成一个 token 都要从磁盘重新读取——约占总耗时的一半。而在 128 GB 的机器上,它可以直接留在页缓存中,这项开销基本就消失了。Deltafin 还会自动把更多模型固定在内存中,无需任何标志参数。
运行时选择基于 Metal 特性族和算子能力检查,而非芯片名称字符串。这样一来,更新的特性族——包括 M5——就能进入 M1 无法执行的路径,同时每条可选的原生路径都保留了精确的回退方案。
我们只在那台 M1 Max 上做过基准测试。如果你在 M3、M4 或 M5、Ultra,或者一台 128 GB 及以上的机器上尝试,我们真心希望看到你的数据——请提交一个 issue,附上 K3_PROFILE=1 的输出以及你的芯片型号。
当 n-gram 推测接受一份草稿时,一次前向传播会输出两个 token,因此重复性文本的运行速度会成比例地加快。推测是无损的:被接受的草稿会精确复现参考序列,被拒绝的草稿则逐比特恢复模型状态。
两行解码数据之间的差距,就是完整安装(见上文)的全部理由:当专家网络位于本地时,每个提示词都以顶行的速度运行,而不只是那些专家恰好被缓存的提示词。
输出是贪心且可复现的:相同的提示词每次运行都会产出相同的 token。
The capital of France is→Paris. The Eiffel Tower is located in Paris. The Louvre Museum is also in Paris. The Louvre has…
需要明确说明其局限性:这是一个研究性产物,而非实用的聊天配置。14.6 秒的中位 token 延迟距离交互式体验还差得很远,而且长提示词成本高昂,因为预填充会触及大量专家。我们认为它的价值主要在于作为一个存在性证明,以及作为流式推理技术的试验平台。
技术
以下每项技术都是在真实权重上经过测量后才被保留的。其中很少有真正新颖的东西;大部分是将下方所鸣谢项目中的思路适配到 K3 的特定形态上。
I/O 与流式传输
- 合并专家抓取。每个专家的六个张量恰好连续存放在分片文件中(我们检查了全部 82,432 个),因此整个专家就是一次 17.55 MB 的范围请求,通过一小组 keep-alive 连接完成。实测比逐个抓取张量快约 6.4 倍。
- 原始区间磁盘缓存。缓存文件就是分片字节的原样存储——没有容器格式,没有解析。
- 并行专家读取。 一层的 16 个被选中的专家由一个线程池通过
pread配合F_NOCACHE一起读取,而不是在内核计算时逐页按需缺页加载。实测冷启动:缺页加载为 0.87 GB/s,而读取为 6.85 GB/s。仅读取路径上,这就将每 token 耗时从 40 s 降至 4.3 s,并且F_NOCACHE避免了每 token 25 GB 的专家流量驱逐主干所需的页缓存。 - 双缓冲层加载。 一个工作线程在当前层计算时读取下一层的主干数据。
- 前序 token 预取。 在去重后的留出集上,连续 token 会复用约 31% 的专家选择,因此每个 token 的专家集合会在后台为下一个 token 预取。
计算
- 融合 MXFP4 反量化+GEMV(
tools/fused_gemv.c)——一个 NEON 内核,通过 16 项查表在一次遍历中完成反量化与乘法,并将 e8m0 缩放以整数运算作用于 fp32 指数。它与参考实现逐位一致,取代了此前慢得多的先反量化再做矩阵乘法路径。另有一个 Metal 版本作为已验证的原型存在。 - 模板层缓冲区复用。全部 69 个 KDA 层共享同一组张量形状,全部 24 个 MLA 层共享另一组,因此两个常驻 GPU 的“模板”层可以通过
copy_()接收每一层的权重。这避免了分配器频繁分配释放的开销——性能分析显示,这一开销在每 token 耗时中占了很大比例。 - int8 常驻主干。将每 token 的常驻 I/O 减半。在我们的检查中,前 5 个下一 token 候选保持了原有顺序,最高 logit 仅变动了 0.07%。
- 自定义 Metal 反量化 kernel。加载主干时,大部分时间花在一个行广播乘法上,MPS 运行该操作的速率为 43 GB/s,而同样字节的普通拷贝可达 334 GB/s。一个小的
compile_shaderkernel 将 int8→fp32、行缩放和拷贝融合在一起,达到 297 GB/s;配合常驻暂存缓冲区和从调度间隙中提升出来的传输,每层加载时间从 118 ms 降至 21 ms。位精确:每个张量上max|diff| = 0。 - 打包 int8 输出头。内置的 MPS 仅权重 matmul 直接消费现有的行 int8 checkpoint,避免了 4.7 GB 的 fp32 输出头及其反量化。能力检查和捕获到的稠密回退机制保证了跨 PyTorch 版本和 Apple GPU 系列的支持。
- 纯 PyTorch KDA shim(
tools/fla/)——Kimi Delta Attention 的递归、短卷积和门控归一化,从 fla-core 的语义移植而来。分块执行和逐步执行的结果一致到约 1e-9。在解码时,递归在 CPU 上运行,其小状态比一系列 GPU 调度更适合放在那里。
解码
- N-gram 推测。草稿通过对已有文本进行后缀匹配免费生成,并在一个双位置批次中验证,其固定开销得以分摊。这在这里之所以值得,正是因为常驻 I/O 和计算——而非专家获取——主导了一个热 token 的开销。在我们的测试中,被接受的草稿精确复现了参考序列。回滚保留旧的不可变状态对象,而不是克隆约 475 MB,然后在常数时间内恢复它们;重放测试保留了精确的未来序列。
sequenceDiagram
participant D as n-gram draft
participant M as model (one T=2 pass)
participant S as state snapshot
D->>M: [last_token, draft]
M->>M: 93 layers, shared cost
alt draft verified
M-->>D: 2 tokens accepted
else draft wrong
S-->>M: state restored (bit-exact)
M-->>D: 1 token, nothing lost
end
随 RAM 扩展
- 启动时,Deltafin 为操作系统预留内存(
max(10 GB, 18%)),并在剩余允许的范围内固定尽可能多的常驻层。一台 128 GB 的机器无需任何配置就能比 64 GB 的机器多固定数倍,而专家缓存还额外受益于任何空闲的页缓存。
未来可能的方向
大致按顺序:Metal 专家内核(已制作原型)、一个完善的质量测试框架——针对官方 API 的平均 NLL——以便有损的速度/质量权衡可以被测量而非争论、更智能的专家预取,以及最终一个秉承 ds4 精神的原生引擎,届时剩余的大部分开销都应消失。
致谢
Deltafin 大量依赖他人公开发布的工作。大致按影响力排序:
- colibri(JustVugg,Apache-2.0)——它展示了 744B MoE 可以运行在 25 GB 内存中,我们也是在这里了解到了 router-lookahead 预取、学习式专家固定(learned expert pinning)、
F_NOCACHE以及 macOS 上的F_RDADVISE纪律,还有逐分片转换模式。它的 M5 Max 性能报告——CPU 自旋等待抢占了 GPU 的共享功耗预算——改变了我们调度工作的方式。 - ds4 / DwarfStar(Salvatore Sanfilippo,MIT)——这是我们研究过的最清晰的专家流式设计方案:零拷贝专家缓冲区、掩码调度、基于选择的缓存淘汰、会话持久化,以及一套我们直接采纳的质量评估方法(对照官方 API 输出的平均 NLL)。它所声明的理念——正确性优先于速度,把 I/O 隐藏在计算背后——是明智的,我们也努力遵循它。
- Moonshot AI——感谢其公开 K3 的权重并附上可读的建模代码,Deltafin 直接运行了这些代码;也感谢 Kimi Delta Attention 设计,其小巧的循环状态正是让长上下文在笔记本上运行成为可能的关键。
- flash-linear-attention(fla-org,MIT)——我们的 KDA 适配层是从其内核和参考实现中移植语义而来的。
- llama.cpp / ggml——内核内反量化和 MXFP4 处理的先行工作,也是本地推理社区大部分知识的基础。
- PyTorch、Transformers、ml_dtypes(我们针对 e2m1 的位精确参考实现)以及 tiktoken。
许可证
Deltafin 自身的代码采用 MIT 许可证。本仓库中有两样东西不属于我们:
tools/fla/是对 flash-linear-attention(MIT,© 2023–2026 Songlin Yang、Yu Zhang、Zhiyuan Li)语义的纯 PyTorch 移植。该署名在文件头部以及 LICENSE 中均有重复说明。- Kimi K3 的权重和建模代码归 Moonshot AI 所有,并依据 Moonshot 自己的许可证分发。它们在安装时下载,绝不在此处内置——使用前请阅读该许可证。
Deltafin 是一个独立项目,与 Moonshot AI 没有任何关联。
来源:Hacker News 热门(buzzing.cc 中文翻译) · github.com