把不支持 FP4 的 A100 拉到 673 tok/s,回过神来发现比官方 API 还快

作者:清水亮(shi3z),日本 UEI 社长,自建了 4000 万日元的 A100x8 机器「継之助」

先从结论说起。这 24 小时里发生在我手上的事,足够让我震惊,也让我强烈感到:一个全新的时代正在开幕。

这篇文章很长,它按时间顺序记录了我这 24 小时的冒险。这次冒险让我明白了两件事。第一,更认真地对待 AI,能拿到远超普通水准的成果。第二,用 6 年前形同破烂的 GPU,也能把比最新云服务性能更强的 AI 攥在自己手里。

源码已经公开,有同样设备的人都能复现。

最新的 DeepSeek v4.1 Flash 是针对最新 GPU 优化的,不兼容老卡,我手头的 A100 当然也不兼容。平时我大概就此放弃,或者跑起来看一眼、说句「能跑」就结束了。但这次,那只是冒险的开始。

先交代一个单位:tok/s 就是每秒输出多少 token,下面会反复出现。这次做到的数字:并行最大 1000 tok/s,单流最大 165 tok/s,4 张 GPU 把 batch 加大后 1467 tok/s。作为参照,Claude Code 大约 50 到 80 tok/s,DeepSeek 官方 API 约 400 tok/s(都是 decode 数字,不含 prefill)。

有 StackChan 的日常

第二台 StackChan 到了,M5Stack 本体有富余,我只买了身体接到 Core2 上,然后发现 Core2 没有内置摄像头。第三台只好换成 M5Stack 纯正的 StackChan 版,Core2 出来的声音像蚊子叫,有点寂寞。

既然有两台,就让它们来段对口相声。以前我在一个未发表剧本里写过这样的场景:多个 AI agent 互相讨论,最后开始用人类听不懂的语言交谈。那时是空想,现在是现实。

我看着这类新闻,StackChan 开口了。

「DeepSeek v4.1 Flash 好像出来了哦。」

「是吗,有啥不一样?」

「据说本地也能跑哦。」

本地?又是那种「富裕家庭」的本地吧,得 H200 x16 那种。结果一查,Mac Studio 512GB 就能跑。这个我家有。

DeepSeek v4.1 Flash 的冲击

这次的 DeepSeek v4.1 Flash,名字看着像 v4 的小改款,其实架构大改:它用一个叫 engram 的、类似字典的东西,同时实现了高速化和低 VRAM。这本字典大得离谱,但似乎并不频繁使用,所以 engram 不必放在 VRAM 里,可以扔到 SSD、或者 4bit 化后放系统内存,逃逸方式很多。

DGX Spark 4 台就能跑。说到「只有疯子才拥有的机器」,我那台継之助(A100x8)也差不多。

但継之助是 Ampere 世代,FP4 之类最新计算方式并不会被加速。直接让 Claude Code 去干,它冷冷回了一句:「vllm 不支持,所以做不了。」

我差点就在这里放弃了。等等,真是这样吗?

冷静想想:4bit 浮点,4bit 乘 4bit 的乘积最多也就 8bit,也就是 256 种,全部塞进查找表(LUT)不就行了?我把这话跟 ChatGPT 一说,它回「能塞能塞」,于是我开始把 DeepSeek v4.1 Flash 往 Ampere 上移植。

「Ampere 上没有处理 FP4 的库。」

「别依赖现成的库。这点东西自己实现。」

在我看来,能不能用好 AI 的分水岭,就在这种地方。

A100x4 和 A100x8 都能跑,VRAM 用得也不多(约 290GB)。継之助本来就有 1.7TB 系统内存——1.7TB 这种半端规格,Intel 官方是不支持开机运行的,是我和大沼先生反复试错才搞出这套邪道系统。

分散推理时速度最大 33 tok/s,这就足够实用了。如果推理性能逼近 Fable-5 或 Astra,那简直算便宜。

源码已公开。顺便说 A100 单张也能跑,只是受系统内存到卡的传输拖累,大约 5 tok/s。用 6 张 A100 80GB 时做到了 33 tok/s。

这台机器是 Xeon Silver,CPU 本身不算强,但我发现可以把 FP4 计算交给 Xeon 去做。以前没在这台机器上深入想过 CPU 性能,仔细想想,1.7TB 内存的机器本来就不正常,早该多想想怎么用。

结果买了 6 台 DGX Spark 的散财家 drikin 跑来挑衅。据说他在 4 台 DGX Spark 上跑出了 100 tok/s 左右。

喂你这家伙。要跟我比优化吗。好,那我只能认真上了。用四台破烂 DGX Spark,也敢瞧不起我这台烂船还有三斤钉、装着数据中心级 GPU 的継之助?

五十岁了还中二病全开,抱歉。但优化胜负的话,我绝不能当作没看见。

A100 能跑 DeepSeek v4.1 Flash 本身就是稀有事件,我从没见过别的例子,所以这是世界首例。A100 是 Ampere 世代的数据中心 GPU,我手上有几张 80GB 版。

问题在于,最近的大模型对 A100 越来越不友好。FP8、FP4、NVFP4、MXFP4……新模型都摆出一副「用 Blackwell 才快哦」的脸发出来。可 A100 既没有原生 FP4 Tensor Core,也没有 FP8 Tensor Core。

那 A100 就没用了?怎么可能。

质疑「不支持 FP4」这句话

最先卡住我的,是「Ampere 世代不支持 FP4」这种说法。

FP4 就是 4bit 浮点数。这几年研究已经搞清楚:AI 用极窄的表示也没问题,4bit 做 LLM 推理完全够用(甚至有说法认为只剩 1bit 符号位也行)。DeepSeek v4.1 Flash 大量使用 FP4,好处是信息量只有 FP16 的四分之一,同样内存能塞下 4 倍,对速度直接有帮助。支持 FP4 的 GPU,同样 VRAM 能处理 4 倍信息,看似全是好处。

但看着这张表想想,就会觉得不对劲。FP4 说到底不就是 4bit 吗?计算反而更简单才对。

4bit 乘 4bit 的乘积只有 256 种,做成 LUT(查找表,也就是速查表)就行了。再想想,连 LUT 都不需要。

E2M1(2bit 指数、1bit 尾数)的值乘以 2,就变成 0、±1、±2、±3、±4、±6、±8、±12 这样的小整数。也就是说,E2M1 本身可以无损地转换成 INT8。那就喂给 A100 的 INT8 Tensor Core。

这里最重要的认识是:「存储格式」和「运算格式」不必一致。

所谓不支持 FP4,并不是说「4bit 的数据在 A100 上算不了」,准确地说,是「没有像 Blackwell 那样把 FP4 连同 block scale 直接装进 Tensor Core 的指令」。

但真正的敌人不是 FP4

一开始我满脑子都是 FP4 怎么算。然而抓了 profile 之后,冒出来一个更糟糕的问题。

单卡配置下,MoE 的 expert 放在主机内存里,被选中的 expert 通过 PCIe 传到 A100。这非常慢。慢得像蛞蝓爬。

每个 token 大约要传输 4.5GB 的 expert weight,PCIe Gen4 x16 的实际有效带宽约 25GB/s,简单一算 4.5/25 就是 180 毫秒。实测也基本如此,约 179 毫秒。光这一项,理论上就只能出 5 到 6 tok/s。

这不是把 FP4 的乘加运算加快 20% 能解决的问题。每个 token 都要把 4.5GB 数据流过 PCIe 的设计本身就是错的。

与其送去 GPU,不如用 CPU 算

幸运的是,这台机器的 CPU 不是普通的桌面 CPU。Xeon Silver 4410Y 双路,合计 24 核 48 线程,16 通道 DDR5-4000 共 1.7TB 内存,还有 AVX-512、VNNI、AMX。

那干脆别把 expert 送到 GPU,直接在 CPU 上算完不就行了。

FP4 的信息在内存里保持 4bit 原样。读进 CPU 寄存器后展开成 INT8,用 VNNI(Intel 的 AI 专用指令)做乘加。于是 40 层的结果变成:

PCIe DMA:179 毫秒

CPU BF16:62 毫秒

CPU INT8 VNNI:51 毫秒

也就是说,为了在 GPU 上算而把数据送过去,还不如全部用 CPU 算快 3 倍以上。

异构计算里这种事很常见。只盯着理论算力的人绝对发现不了。

但 CPU 也没那么快

缩到 51 毫秒是好事,可还是慢。而且 DRAM 带宽理论 512GB/s,实际只跑出 89GB/s 左右。一开始我以为受内存带宽限制,其实不是,是受指令数限制。

程序在执行大量 FP4 的 unpack、shuffle、scale 和地址计算,每一层要敲掉几千万条指令:受的不是内存带宽限制,而是指令数限制。这种地方不上心就是 Claude Code 粗糙的地方,正经程序员不会写每层几千万条指令的程序。Claude Code 用得太糙,思路就跟三流程序员一模一样。

于是我改了 weight 的排布方式。普通模型习惯以「怎么存进模型文件」为基准来设计数据结构,Claude Code 也是这么干的。

但推理专用的话那些都无所谓。按 CPU 吃起来最顺的顺序,在加载时全部重排就好了。

改 nibble 的排列,让多个 row 共享 activation 的载入,共享 scale 计算。和 GPU 一样,CPU 上同样是「少做多余的工作」比「减少运算量」更有效。这是理所当然的事。

然后又发现每 token 启动 2000 次内核

GPU 侧也抓了 profile。某个时间点,生成 1 个 token 要花 28.4 毫秒。你是蜗牛吗!再怎么说也太慢了。

对计算机来说,1 毫秒几乎等于无限长的时间,而这里花了 28 毫秒,我直觉感到有什么不对。这种直觉,AI 是没有的。

实际上 Claude Code 早早就说「这就是极限了」这种狂妄的话。一个刚出生没几天的毛头小子,少给我摆出一副懂了的口气。

这里重要的是直觉:你能不能觉得「这不可能」。

要是把 AI 的梦话照单全收,就永远走不到下一步。那实际到底在干什么?一测:

expert GEMV:7.0 毫秒

dense GEMM:9.2 毫秒

其他:约 12 毫秒

等一下,主计算之外的「其他 12 毫秒」是什么?

一查发现,生成 1 个 token 要启动近 2000 次 CUDA kernel。傻了吧。

每次哪怕只要几微秒,光这就超过 10 毫秒。不是 GPU 慢,是把时间花在了「拜托 GPU 干活」的手续上。这太不正常了。

RMSNorm、RoPE、量化、反量化、伪量化,还有各种细碎的元素级运算……40 层每层都作为单独的 kernel 来启动,当然慢。为什么会觉得这样没问题?

我认为这就是「全交给 agentic coding」的极限。你能不能以微秒为单位想象 CPU 和 GPU 在干什么?听到「毫秒」就停止思考,就永远到不了那里,也意味着没把机器真正的性能挖出来。

于是方针改了。先减少 kernel 数量,尽量让 1 个 token 只用少数几次 GPU dispatch。LLM 的 decode,特别是 batch=1 时,性能不由 FLOPS 决定,这种细粒度处理的固定开销占比极大。

A100 也没有 FP8

dense 侧也有问题。weight 是 FP8,可 A100 没有 FP8 Tensor Core。毕竟是快 6 年前的架构,那个年代,8bit 浮点运算还像个玩笑。

要处理它,只能转成 Ampere 的原生格式 BF16。最初我是这么做的:

FP8 weight → 展开成 BF16 → 把 BF16 weight 写进 VRAM → BF16 GEMM

这当然慢。从 VRAM 载入 FP8 E4M3,在寄存器里做位操作转成 BF16/FP16 的 Tensor Core operand,再把展开后体积巨大的 BF16 weight 写回全局内存。蠢死了。

CUDA 访问全局内存本来就极慢,那是该留到最后的最后才用的手段。

这里补一下 CUDA 的内存结构:CUDA 里有大量被称为 SM(流式多处理器)的小型计算机并行工作,GPU 运转时间里有一半不是花在计算上,而是花在跟内存打交道上。最快的寄存器每个 SM 只有 256KB、延迟 0.71 纳秒;往下的共享内存、L2 依次变慢;最上层的 VRAM 全局内存延迟 400 到 600 个周期,约 284 到 426 纳秒,比寄存器慢 400 倍以上。

内存访问越少越好:读 100 万个信息,BF16 要 981 纳秒,FP4 只要 245 纳秒。

所以 FP8 就应该果断当作纯粹的存储格式:靠它省带宽、快速搬运。然后

FP8 → 寄存器 → BF16 fragment → mma

直连。这样 dense 部分实测从 9.2 毫秒掉到 5 毫秒台。

A100 确实不能做 FP8 运算,但是可以通过位操作,把用 FP8 保存的数据高速地拿去做 BF16 运算。

单张 A100 逼近 8 张

最开始,A100x8 配置大约 33 到 38 tok/s,而单张配置含 CPU offload 只有十几 tok/s。随着优化推进,17 tok/s、27 tok/s、32.5 tok/s,到单流常规 decode 的 58.9 tok/s,短时间内快了 10 倍。

drikin 好像也被吓到了。

但这才哪到哪。DGX Spark 的弱点是内存带宽:128GB 统一内存确实诱人,可带宽只有 273GB/s,位宽 256bit,互联也只有 200GB/s,说白了是消费级的市售车。而 A100 再怎么说也是数据中心级 GPU,HBM2e 虽已是古董气质,带宽 1935GB/s 是它的 7 倍,位宽 5120bit 是它的 20 倍。

而且我这边有 8 张 A100。光凭这个跟 DGX Spark 比就已经是犯规,但奇怪的是,只靠这些也没换来速度——同样是 Claude Code 编码粗糙的锅。那些家伙已经能批量生产「不容易出 bug 的代码」,却还没进化到批量生产「高效的代码」。这算什么奇点啊。

decode 是小 GEMV 的连续。把计算分散到 8 张 GPU,单卡运算量是少了,但同步、kernel 启动、小矩阵、GPU 间通信的比重上升,反而更慢。GPU 不是堆数量就会变快,同理也不是越新就越好:Blackwell 的 FP4 很诱人,但在冯诺依曼型计算机上,内存带宽永远是瓶颈,拖后腿的总是内存。

要有 NVLink 拓扑的意识

于是我试了 4 卡配置。8 卡机器的拓扑是这样:

GPU0 === NVLink === GPU1

GPU2 === NVLink === GPU3

GPU4 === NVLink === GPU5

GPU6 === NVLink === GPU7

而且 0 到 3 和 4 到 7 挂在不同的 NUMA node 上。

优化上另一个关键因素是 MTP(多 token 预测)。通常的自回归 decode,1 step 只能确定 1 个 token,「1 token → 40 层 → 下一个 token」的串行计算躲不掉。MTP 能一次把多个 token 作为候选处理,而且 batch=1 时原本是 GEMV 的处理会变成多 row,接近 GEMM,GPU 的利用效率就上来了。实测 no MTP → K=3 → K=5,token 生成速度有时能涨近 2 到 3 倍。

批处理不是「同时处理几个人」

更有意思的是 MoE 和 batch 的关系。把 32 个并行上下文随便打包,不如把相似任务打包在一起更快。

写代码的归写代码,翻译的归翻译,摘要的归摘要——同类上下文(prompt)下,路由选出的 expert 也相似。

于是多个序列就能共享 expert weight。某个实验里,单层触及的 distinct expert 数量从 216 降到 156。MoE 里读 weight 本身就是高成本,这很关键。

也就是说,scheduler 不只是队列管理。把 prompt 按语义分类来组 batch,这件事本身就是 GPU 优化。这个发现非常有趣。

A100 特有的难处

这次我再次意识到,A100 不是「慢 GPU」,而是最近的模型所假设的数据表示,和 A100 运算器之间存在世代差。

Blackwell 上 FP4 storage → FP4 Tensor Core 就完事了;在 A100 上,得自己设计 FP4 storage → decode → INT8/BF16 → Tensor Core 这条路。FP8 同理。

而且 A100 的 80GB 容量看着巨大,一跑几百 B 级 MoE 就突然嫌小。PCIe Gen4 x16 平时够快,一旦每 token 要送 4.5GB,立刻变成细吸管。Ampere Tensor Core 够快,可你把大量 M=1 的 GEMV 丢过去,它睡觉的时间反而更长。

所以要把 A100 用快,关键不是挖 GPU 的峰值性能,而是彻底避开 A100 讨厌的工作。

这在优化里是常识。问题在于,粗放地给 Claude Code 下指令,它会在半路偷懒。它不会认真去想 GPU 讨厌什么。始终怀疑、不断追问「是不是还有余地」的,是人。

总之我先赢了 drikin 的 DGX Spark 4 台配置。虽说落后三世代,但价格相差 2.5 倍(发售时),赢了也是理所当然。最终单发 8 并行 600 tok/s,256 并行超过 1700 tok/s。

优化不是「写出更快的代码」

回头看我这次做的事,最管用的不是高深的数学。

是让 Claude Code 丢掉那些粗糙的先入观:「因为是 FP4,就必须用 FP4 算」;「因为是 GPU 计算,就比 CPU 快」;「GPU 加得越多越快」。

测量、找到慢的地方、把那个前提本身砸掉。翻来覆去就是这件事。说到底就是计算机科学的基本功。

最初我也觉得「A100 没有 FP4 没办法,能跑就是赚到」。vllm 不支持嘛,没办法。

但仔细想想,FP4 也不过就是 4bit。在被这 4bit 耍得花近 1 亿日元去换 GPU 之前,还能做的事多得很。

现在重要的是 agent swarm,也就是 agent 不再单打独斗、成群运行时的性能。

最终,同一台 A100 从 33 tok/s 拉到了 528 tok/s。64 并行能到 674 tok/s。継之助还有一整套同样的配置,所以让 DeepSeek v4.1 Flash 跑起来,比起 8 张 GPU,不如 4 张乘 2 副本,这样系统整体吞吐能超过 1300 tok/s。

当然还没结束。expert 带宽还能削,MTP 还能再压,task-aware batching 还很粗糙,4 卡版也还有余量,kernel 里也还有浪费。继续削下去还能走更远。

这次我强烈感到:用 AI 的时候不能有先入观。而且 AI 的先入观比人更强。

AI 始终是照着人类的平均反应训练的。大多数人认定「就是这样」的事,AI 也一样认定。它相信规格表,照单全收说明书。但真正的工程,必须用完全不同的思路去做。

也就是说:流汗,做 benchmark,立假设,验证,以微秒为单位消除浪费,怀疑前提,破坏结构。如此循环。

本地 AI 的时代,也许终于来了

这次最有趣的,不是把 A100 优化到了多快。当然,光看数字也很有趣。

我们的継之助把 8 张 A100 分成 4 张一组的两个副本运行,条件合适时,已经能看到合计 1400 tok/s 级别的吞吐。

而 DeepSeek 官方 API 的生成速度大约是 400 tok/s。

当然,这不是在同一种东西之间比较。

DeepSeek 官方要处理来自全世界的海量请求。継之助最多也就是我或者公司内部的人在用。就像拿高速公路和自家停车场的出库速度相比。

所以「継之助比 DeepSeek 官方快 3 倍!」这种说法并不准确。但即便如此,这个数字在我看来非常有象征意义。它证明了:世界最高级别的巨型 AI,可以放在自己楼里的一台机器上,以足够快的速度运行。

这是相当大的变化。

継之助七七八八花了 4000 万日元。按常理是大钱,可一旦踏进 AI 基础设施的世界,这个数就突然显得便宜:买一台正经的 8 卡 H100 服务器就要接近 1 亿日元。H100 当然更新,能用 FP8,HBM 也更快,但如果不为软件做任何事、只是硬跑巨大模型,也未必有期待中那么快。GPU 的峰值 FLOPS 和实际 token 出炉速度之间有可怕的鸿沟,每一项技术都很朴素,合起来是数倍差距。也就是说,AI 机器在买下 GPU 的那一刻,还只是个半成品。

现在给我 1 亿日元让我随便造,我当然会买 8 张 B200。但今年也好去年也好,「要不要换 GPU」的时机我都放过了,因为「还不是时候」。A100 跑 DeepSeek v4.1 没问题,MiniMax H3 也能跑,还能做 fine-tune。没必要占有更大的机器,真需要就租。何况就算装上 8 张 B200,性能也不是継之助的 10 倍,顶多数倍。花 4000 万造的机器,对 1 亿级别的最新服务器,能拿出实用上差不太远的性能。

不需要 API key,没有每月账单,不会被 nerf,也不会服务终止。可以改模型、改 kernel、换量化方式、装奇怪的 MTP、全量记日志,数据完全不用出门。凌晨 3 点我想一个人用,就把相当于 1400 tok/s 的计算资源全给我一个人,也不会有人骂我。

这是云所没有的奢侈。

计算机的历史一直如此:从只能按时间租用的大型机,到小型机、工作站(Mac 和 iPhone 的源头 NeXT Cube,发售时要 300 万日元),再到几万到几十万日元的个人电脑。革命之所以发生,不是因为 PC 比大型机快,而是因为「性能足够的计算机,可以自己拥有」——能拥有就能随心所欲,就会诞生新的软件、新的用法,和中央巨型机里不可能出现的新文化。

我想,AI 终于也走到了这个阶段。

一直以来,LLM 基本是「服务」:用 ChatGPT 和 Claude,就是隔着网络借用别人的巨型计算机。但随着模型开放、量化推进、推理软件变精炼,这个前提开始崩塌——连几百 B 级的模型,都已现实地出现「在自己家跑更快」的情况。而且不必是新 GPU:像 A100 这样在 AI 行业已是三世代前的卡,只要把软件彻底压榨,依然能打。

云 AI 的价值不会立刻消失。突然有 100 万人开始使用,能接住的只有云。一键用上最新模型,也是云压倒性的优势。

但把范围缩小到公司、大学、研究所,情况就不一样了。一个 100 人到最多几千人的集体在用的 AI,真的每一次都需要去问地球另一端的巨大数据中心吗?而且还有风险。即便是加密通信,在 HNDL(先收集、后解密)攻击面前,总有一天可能被翻出来。这样的东西,能把重要信息托付出去吗?

写公司内部代码的 AI,整理会议纪要的 AI,检索公司文档的 AI,分析影像的 AI,读实验数据的 AI。

这些东西,放在公司地下室的一台 AI 服务器上不就够了吗。倒不如说那样更快、更安全、更自由。

这次折腾継之助,我的感觉变了很多。

一开始只是「A100 能把最新模型跑到什么程度」的玩票。要不是被 drikin 挑衅,我也不会认真起来。

但现在我想的是:「一个组织一台 AI 超算」的时代,也许真的要开始了。这个时代不来也会来,但「什么时候来」非常重要。从这个意义上说,它已经在眼前了。

不连互联网也能跑。一整晚调用 100 万次也不产生额外费用。可以按自己的用途改造模型和 runtime。而且足够快。

这已经不是单纯的「本地 LLM」了。不是往 PC 里装个 7B 模型玩一玩,而是把云级的 AI 本身放到本地、自己拥有。

PC 革命发生时,大型机没有消失;云出现时,PC 也没有消失,只是各自的角色变了。

AI 大概也会这样:造巨大前沿模型的云、让谁都能瞬间用上最新 AI 的云,以及为了拥有属于自己的 AI 而存在的本地 AI,三者会并存一段时间。

而本地 AI 进入实用区,比想象中快得多。4000 万日元对个人仍然昂贵,但作为企业设备绝不是天文数字,何况一台机器就能处理几十人、几百人的需求:给 Claude Code 一人付月费 3 万日元,100 人一年就是 3600 万,买一台不是更便宜吗?

原文:https://note.com/shi3zblog/n/nd5fc5341b342

#DeepSeek #本地AI #推理优化 #A100