AI Pulse

两张64GB挖矿卡跑320B模型,384K下约90tok/s

背景

我在两张 64GB 的 CMP 170HX 显卡上折腾 GLM-5.3-Flash 有一阵子了,现在这套配置终于稳定下来,觉得可以拿出来分享。

我还拿它和同一台机器上一直在用的 Qwen3.8-Flash-Next 配置做了对比:vLLM + AWQ INT4 + FP8 PLE(PLE 是 Qwen3-Next 推理管线里的一个组件,这里保留原名)。

除了 PP/TG 基准测试(PP = Prefill,预填充;TG = Token Generation,生成),我还把两个模型都接上了 DSH(一个 Agent 任务执行框架),给它们同样的编码/Agent 小任务,看看原始推理速度到底如何转化为实际任务完成时间。

先说几个前提

* 这不是一次严格对等的量化对比(apples-to-apples)
* GLM 和 Qwen 用的是不同的推理引擎,以及不同的投机解码(speculative decoding,用一个小的草稿模型先提出候选 token、再由目标模型验证)配置
* 投机解码的速度高度依赖接受率(草稿 token 被目标模型采纳的比例)和实际生成的文本
* 编码任务只是几个实际例子,算不上严格的基准测试套件
* 下面提到的“Strata 风格”,指的是我之前用 Strata 时采用的 HBM-first/全驻留(full-residency)内存策略,并不是说这套配置跑的是 Strata 本身

仓库与可玩 Demo

GitHub:
https://github.com/Flun/glm53-flash-cmp170hx-exl3

硬件环境

CPURyzen 5 5600X
RAM80GB DDR4
GPU2x CMP 170HX 64GB
GPU 架构SM80
PCIeGen2 x8
GPU P2P不可用
OSUbuntu 24.04

两个模型都在同一台机器上测试。Agent 测试用 DSH 作为执行框架。

(为什么这一步重要:CMP 170HX 是 64GB HBM2e 的挖矿卡改推理卡,PCIe 只有 Gen2 x8 且没有 P2P,带宽非常有限。后面选 HBM-first 而不是频繁搬运权重,就是被这个硬件约束逼出来的。)

GLM-5.3-Flash 配置

目标模型:turboderp/GLM-5.3-Flash-exl3,3.05bpw(bpw = bits per weight,每个权重的平均位数)

引擎:ExLlamaV3 1.5.4(简称 EXL3)

当前配置:

* GLM-5.3-Flash EXL3 3.05bpw
* 目标权重约 125.2GB / 116.6GiB
* 目标权重完全驻留在两张 64GB 显卡上
* k_hcfuse
* DFlash2 EXL3 6bpw(DFlash2 是投机解码用的草稿模型)
* DFlash2 K7
* Q8 KV 缓存(8-bit 量化的 KV 缓存)
* 实际使用 384K 上下文
* 最大请求预算约 392,960 tokens

GLM-5.3-Flash 本身是一个总参数 320B、激活参数约 18B 的 MoE(Mixture of Experts,混合专家)模型。

这里的关键是目标权重始终驻留在 HBM(High Bandwidth Memory,高带宽显存)里,解码过程中不会持续从系统内存流式加载专家权重。

关于 3.05bpw 的量化质量

这大概是我最关心的部分。

乍一看,3.05bpw 听起来是一个相当激进的量化,尤其是和人们常用的 UD Q4 系列(UD = Unsloth Dynamic,Unsloth 的动态量化格式)相比。但 EXL3 并不是简单地把每个张量都压成 3-bit。

它使用 trellis(网格)量化方案,根据张量的不同分配不同的位数。3.05bpw 只是一个平均目标比特率。

该模型家族发布的量化配置也会让更敏感的部分保持更高精度。例如在 3.05bpw 分支中,lm_head 仍然保留 6-bit。

看同一模型家族的 4.05bpw 版本,经过检查各部分的位数大致如下:

* 路由专家(routed experts):K4
* 注意力层(attention):K6
* 共享专家(shared experts):K6
* 稠密 MLP(dense MLP):K5
* lm_head:K6
* embedding / norms / router:原精度(native)

所以整体思路是:对体量庞大的路由专家部分压缩得更狠,而在更小、更敏感的通路上投入更多位数。

对于这种 MoE 模型来说很有道理,因为绝大部分存储都花在专家权重上。

与常见 UD 量化的粗略对比

量化格式大小与 BF16 的 Top-1 一致率平均 KLD
UD-IQ3_XXS120.37GB81.63%0.28377
EXL3 3.05bpw(我的目标)125.18GB约 93.05%(根据公开的 3.0bpw 结果估计)约 0.050(根据公开的 3.0bpw 结果估计)
UD-IQ4_XS156.82GB88.18%0.11665
UD-Q4_K_XL199.71GB92.22%0.04929
UD-Q5_K_XL240.31GB94.35%0.02705

作为参考,公开的 GLM-5.3-Flash GGUF(llama.cpp 生态的模型量化格式)保真度数据大致如上表所示。

有一点值得指出:名为 Q4_K_XL 的量化并不是字面上“整个模型每个参数 4 bit”。对于一个 320B 模型来说,约 200GB 其实是混合精度量化,有效平均比特率远高于 4bpw。

另外还有一个公开的 GLM-5.3-Flash EXL3 3.0bpw 保真度测试,使用 51,175 个留出的(held-out)next-token 位置,结果如下:

* Top-1 一致率:约 93.0%
* 平均 KLD(Kullback-Leibler Divergence,KL 散度,衡量分布差异):约 0.0505

从数值上看,这与公开的 UD-Q4_K_XL 结果大致处于同一水平。

不过,我不会仅凭这些数字就宣称“EXL3 3bpw 比 UD-Q4_K_XL 更好”。它们不是通过完全相同的评估流程/语料测出来的,而且公开的 3.0bpw 产物也不是我正在跑的同一份量化权重。

我的结论很简单:3bpw 这一档的 EXL3 在同样的体积下能保留惊人的保真度,表现并不像一个朴素的 3-bit 量化。

对我的使用场景来说,把目标模型压到约 116.6GiB、同时保留可用的编码/Agent 质量,正是这套配置有意思的主要原因。

DFlash2 6bpw 只是草稿模型

为了避免混淆:3.05bpw 的模型才是真正的 GLM 目标模型;6bpw 的 DFlash2 模型只是投机解码用的草稿模型(drafter)。

草稿模型先提出候选 token,GLM 目标模型负责验证。所以这绝不是“3.05bpw 和 6bpw 平均质量”之类的配置。草稿模型的量化主要影响草稿速度、显存占用和接受效率。

HBM-first / “Strata 风格”的内存策略

这部分借鉴了我之前用 Strata 时的思路。再次说明:这里跑的不是 Strata。

我说的“Strata 风格”其实很简单:尽可能让模型常驻 HBM,避免运行时 CPU↔GPU 之间的权重搬运。

GLM 目标模型本身可以装进两张卡,所以我让目标模型完全驻留。我没有选择把专家权重换出(offload),而是把注意力放在减少随上下文增长的那部分显存占用:KV 缓存和投机解码草稿模型。

对于这台机器来说,这比在 PCIe 上不断搬运权重要合理得多。

DFlash2 与 384K 上下文

一开始我用的是 GLM 自带的 MTP d2 路径(MTP = Multi-Token Prediction,多 token 预测)。后来换成了 DFlash2。

我没有保留原始的 BF16 incoai/GLM-5.3-Flash-DFlash2 草稿模型,而是把它转换成兼容 ExLlamaV3 的 EXL3 6bpw 版本,转换后的草稿权重约 0.96GiB。

长上下文场景下更大的问题其实是草稿模型的 KV 缓存。如果目标模型跑 384K,草稿模型也跟着长 384K 的 KV 缓存,显存很快就不够用了。

所以我把草稿模型一侧改成固定 SWA(Sliding Window Attention,滑动窗口注意力)窗口 + GPU 环形缓存(ring cache,固定大小的循环缓冲区)。目标模型仍然看到完整的 384K 上下文,并保留完整的目标 KV;只有草稿模型的 KV 存储被限制在一个有界环形缓冲区里。

这样当前配置(DFlash2 K7 + Q8 KV + 384K 目标上下文)才能跑起来,草稿缓存不会膨胀到完整目标长度。实现代码和验证测试都在仓库里。

冷启动时间

我还测了从冷启动编译/启动到 API 真正就绪的时间。

模型就绪时间
GLM-5.3-Flash EXL3约 1 分 04 秒
Qwen3.8 Flash Next / vLLM约 3 分 50 秒

这其实不算模型大小对比。Qwen 的 vLLM 配置启动时要做的事多不少:

* PP(Pipeline Parallelism,流水线并行)worker
* 分布式运行时
* 模型放置
* MTP
* PLE
* GDN
* Triton(GPU kernel 编译器)编译
* 内存分析
* KV 分配

而 ExLlamaV3 的 GLM 路径相对静态。

推理基准测试

以下数据来自我仪表盘上的实际负载。再说一次,尤其是投机解码,不要把数字当作普适的模型速度——接受率和生成文本本身影响很大。

GLM-5.3-Flash / DFlash2 K7 / Q8 实测数据

输入长度PP(预填充 tok/s)Decode(生成 tok/s)
8K1,52995.6
40K1,62490.7
73K1,64790.6
106K1,65091.0
131K1,61194.4
385K1,53590.1

在这个特定负载下,DFlash 的接受率大约在 87% 左右。

换成旧的 MTP d2 路径时,同样的负载一般在约 60 tok/s。改用 DFlash2 K7 之后,这里到了约 90 tok/s。

Qwen3.8 Flash Next / vLLM 实测数据

Qwen 的配置是:AWQ INT4(Activation-aware Weight Quantization,激活感知的 4-bit 权重量化)+ FP8 PLE / PP2(流水线并行度 2)/ MTP3。

输入长度PP(预填充 tok/s)Decode(生成 tok/s)
8K5,513129.5
40K5,628123.6
73K5,466141.9
106K5,307141.5
131K5,183159.9
252K4,706149.4

所以从原始吞吐量看,Qwen 明显更快。在约 131K 输入时:预填充约 5.18K vs 约 1.61K,解码约 160 vs 约 94 tok/s。这一点没什么可争的。

对我来说有趣的是,当我真正让两个模型去做多步编码工作时发生的事。

为什么暂时止步 384K

我测了约 385K 输入,预填充仍然有约 1.5K tok/s。问题不是预填充性能崩掉,而是墙钟时间(wall-clock time,实际流逝时间)。

从头预填充约 385K 已经要大约 4 分钟。就算我能塞下 1M,以这个速度做完整的 1M 冷预填充,日常使用也不太现实。所以目前我把服务保持在 384K Q8。

不过我还是想看看能不能跑通 1M,主要是为了技术上的挑战。

小型 Agent 任务测试

本来我只打算让两个模型都做一个俄罗斯方块就收手。两个模型都接上 DSH,收到完全相同的请求。

1. 俄罗斯方块

提示词:“构建一个可玩的网页版俄罗斯方块游戏。”

模型完成时间
GLM-5.34 分 40 秒
Qwen3.85 分 30 秒

两个模型都给出了可运行版本,说实话差距不大,不够有意思。所以我又加了两个任务。

2. AI 迷你 PC 落地页

给两个模型的完全相同的提示词:“构建一个精美的单文件 HTML 落地页,面向 AI 迷你 PC,包含深色主题、规格、性能图表、定价、FAQ 和流畅滚动动画,不使用任何外部库。”

模型完成时间
GLM-5.310 分 05 秒
Qwen3.814 分 40 秒

3. Vampire-Survivors 风格游戏

提示词:“构建一个单文件 HTML 的 Vampire-Survivors 风格游戏,包含 WASD 移动、自动攻击、敌人波次、经验值、三选一升级、血量、游戏结束和重新开始,不使用任何外部库。”

模型完成时间
GLM-5.34 分 40 秒
Qwen3.824 分 10 秒

这个任务的差距比我预想的大得多。有一个明显的保留点:Qwen 版本加了音效,而 GLM 版本没有。提示词并没有要求音效,所以我也没有回头让 GLM 补上——我希望两次运行都保留在同一个一次性提示词(one-shot prompt)的结果上。

任务完成时间汇总

任务GLM-5.3Qwen3.8
俄罗斯方块4 分 40 秒5 分 30 秒
落地页10 分 05 秒14 分 40 秒
Vampire 风格游戏4 分 40 秒24 分 10 秒

我不会从三个例子中过度解读,这绝不是“GLM 编码强 5 倍”之类的证据。

我觉得有趣的只是:原始 tok/s 和端到端 Agent 完成时间之间的相关性并不好。Qwen 的预填充和解码吞吐量都高得多,但在这些特定任务上 GLM 往往更早完成。

对于 Agent 任务来说,规划、重试次数、文件重读、编辑次数,以及第一版实现离能跑通有多近,都很重要。所以我认为原始推理速度和实际任务完成时间值得分开看。

当前配置总结

我现在在用的 GLM 服务是:

* GLM-5.3-Flash EXL3 3.05bpw
* DFlash2 EXL3 6bpw K7
* Q8 KV
* 384K 上下文

这个配置我最喜欢的地方是显存/质量的取舍。目标模型装进约 116.6GiB 的 HBM,保持驻留;公开的 3bpw 档 EXL3 保真度数据也表明,这个量化的表现比我单看比特率时的预期好得多。

运行层面本质上就是 HBM-first 思路:让目标权重驻留,然后在草稿模型/KV 一侧省内存,而不是在解码过程中来回搬运专家权重。

完整配置、转换脚本、环形缓存改动、基准测试代码和原始结果都在这里:

GitHub:
https://github.com/Flun/glm53-flash-cmp170hx-exl3

如果有人在其他奇怪的 128GB 级 GPU 配置上跑 GLM-5.3-Flash,我也很想看看你们的数字。

接下来我想试的是 1M 上下文,不过到那个时候,预填充时间大概比“能不能塞下”更棘手。

阅读原文
📚 相关主题 大语言模型本地部署

订阅 AI Pulse

每天 08:00 · 12:30 · 18:30 · 23:50 更新