文章

才华把我埋葬于明天

昨天中午我还在和 GPT 商量,手头这台昇腾 910B4 跑 Qwen3.8-Flash-Next 下一步该怎么继续抠性能。把前两天刚做好的 14 页测试 PDF 发过去之后,我顺嘴多问了一句:我们现在用的是 vLLM 0.26.0,要是直接升到 0.31.0rc 或者刚出的 0.32.0rc,会不会比我们自己去查问题、写算子优化更有用?

GPT 去翻了一圈仓库,告诉我前一天刚推出来的 vllm-ascend 0.32.0rc 已经把 A2 加进支持表了,连我们这周自己手搓的好几个改动也进了主线。

下午两点多,我在服务器上另外四张空闲的 910B4 上拉起了 0.32.0rc 的镜像。启动脚本里我没挂过去一周攒下来的 /deployment、/native、/cachepack 补丁目录,也没加那些自定义的环境变量,只把 Qwen3.8-Flash-Next 的 W8A8 权重只读挂进去,加上官方新给的 --engram-config '{"cpu_offload":true,"dp_shared_memory":false}',按旧线上的同一套输入跑了一遍测试。

结果出来的时候我盯着终端看了一会儿,真有点不知道说啥好。同样是四张 64G 的 910B4,TP4+EP4,不开 MTP,保留多模态图片输入。我在 0.26.0 上打了一堆补丁、折腾了整整一周的版本,4K 单并发 prefill 是 1414 tok/s,而这个一行本地代码都没改的 0.32.0rc 直接跑到了 8079 tok/s,快了 5.7 倍。256K 满上下文差得更离谱,旧版首字要等 559.7 秒,九分多钟才吐出第一个字,新版直接降到了 54.8 秒,快了十倍还不止。单并发 decode 在没开 MTP 的情况下,也从 18.6 tok/s 提到了 26.2 tok/s。

就在两个小时前,我还在认真算怎么去抓四卡对齐的 trace,想着下一轮要是能把每步 53.6ms 的耗时压掉 8ms、把 decode 推到 22 tok/s 就算很不错了。结果换个昨天才发的 RC 镜像,直接就比我定的目标还高出一截。我切回聊天窗口,只敲了一句:

靠,官方补丁上来了就是不一样……过去几天白干了。

折腾了一周的 0.26.0

我现在打开本地整理好的 ascend-qwen3.8 文件夹,里面有 39 个按日期归档的阶段目录、18382 个文件,差不多 2G 的日志、补丁、JSON 数据和五份 PDF 报告,从服务器往回迁的时候还挨个核对了 SHA-256。这一个礼拜的时间基本全砸在里面了。

Qwen3.8-Flash-Next 这个模型结构比较特殊,是还未发布的 Qwen4 模型的前瞻架构,里面有很多业界没有见过的新特性,125B 的 MoE 主干,每层 512 个专家激活 10 个,48 层里混着 36 层 GDN 和 12 层 QSA 稀疏注意力,另外还带一张 51B 参数、BF16 占 95.37 GiB 的 PLE(n-gram)词表和视觉编码器。十月底刚部署的时候,vllm-ascend 文档里只有 Atlas A3 八卡的教程。我们的机器是八张 910B4(A2),我想用四张卡(TP4+EP4)把它跑起来,省出一半的卡干别的,还得保住图片输入和 4 路 256K 并发。

在使用 0.26.0 时上干这事到处都在报错。十月三十一号第一天,往容器里迁 A2 算子包和 FLA,修分块 prefill 把前一个 chunk 误判成外部前缀缓存命中的 bug,一直搞到半夜,看到测试页正常输出 391 和 782 才松口气。后面几天又去保 GDN 递归状态的 FP32 精度,修量化加载改坏的 INT64 哈希缓冲区,再把带图片的请求单独分去走 eager 路由,省得纯文本开 ACLGraph 加速的时候一发图就把进程搞崩。

到了十一月三号,又发现 0.26.0 里混合缓存被拆成了 39 个组,对齐浪费了很多空间,每张卡只能分到 748 个块。那天 cache-packing 连着返工三次,改成六区域共享块池之后才把每卡块数提到 2244。同一天还跑了几十组数据试 MTP1 和 MTP3,同步异步都测了一遍,结果这个模型在日常中文问答下预测准确率太低了,开同步 MTP 反而慢了 14%,最后只能全关掉。

最折磨人的还是八卡缩四卡。四张 64G 的卡一共 256G 显存,95.37 GiB 的 PLE 词表直接放卡上根本留不出多少空间给长上下文。后来去调 CANN 的 aclrtMallocHost 和 aclrtHostRegisterV2,把词表切成四份锁进主机内存,让 NPU 直接按行读取,每张卡才腾出 23.84 GiB。结果第一次跑 4 路 256K 满窗压测,跑到第 459 秒还是爆显存挂了,看日志是框架自动给 KV 池划了 25.46 GiB,运行中途临时张量要 1.88 GiB,卡上只剩 1.41 GiB。就差那四百多兆,前面七分半钟白等。最后手动把 KV 预算限制在 20 GiB,十一月五号晚上才把四卡四路 256K 全跑下来。

当时生成完基线 PDF 我还挺高兴的,虽然 512 短输入 prefill 掉了四成,256K 首字也很慢,但总觉得在官方没适配的 A2 四卡上跑通这套配置挺不容易。结果十一月六号 0.32.0rc 更新,PR #20467 合入了 QSA 按长度分流 FIA 和 GBSA,PR #20560 合入了原生 BF16 PLE 主机内存卸载,底下的 CANN 和 ops-transformer 算子包也升了版本。十一月七号下午拉镜像一测,前七天写的那些启动补丁、内存映射脚本和缓存池打包代码一下就全没用了,打了个 .tgz 包收起来再也没挂过。

GPT 还安慰我说,前几天做的那套固定输入和四路满窗验收脚本还是有用的。有用确实有用,昨天拉完 0.32.0rc,直接拿这套脚本跑了一遍,几十分钟就把新版本比我快多少倍给算出来了。

软件上的活越来越留不住

九月份的时候,DeepSeek 做核心算子的刘胜与(interestingLSY)发过一篇很火的文章,叫《我不得不把才华埋葬在昨天》。他刚写完 DeepSeek V4.1 的核心 Attention 算子,在文章里提到一件事:算子工程师把底层优化得越快,模型迭代就越快,AI 学会自己写底层算子、反过来替代人类算子优化师的那一天也就来得越早,以后写代码的人都会慢慢变成调度 AI Agent 的人。

那会儿看这篇文章,我还觉得这是顶尖 GPU 算子作者才需要操心的事,毕竟我平时主要做工程部署和落地调优,离手写顶级算子还远。但经过这一周,我发现自己干的这一摊活其实也差不了多少。

我现在本地目录里就放着一堆给 Codex 写的 ascendc、triton、昇腾 profiling 和精度性能测试 skill。这周碰到性能异常,我基本都是先把测试 PDF 丢给 GPT Pro 去查主线 commit 和 issue,再让 Agent 连上服务器跑对照实验、核对哈希、生成报告。昨晚试 0.32 的前缀缓存 APC 也是这样,Agent 自动跑完 36 批测试,测出来 4K 单并发冷 decode 掉了 6.505%,超过了我事先定的 6% 回退线,就直接回滚配置了。靠着 AI,一周确实干完了以前要摸索一两个月的工作量,但我自己真正动手写代码的时间越来越少。而且每次我把排障经验整理成 SKILL.md 塞给 Agent,让它下次干得更顺手的时候,心里也明白下次就更用不上我自己了。

除了 AI 在替掉人工调优,现在自己花时间做出来的东西也太容易被别人超过了。以前花一周查明白一个冷门 bug,写篇博客记下来,至少能管用大半年。现在模型隔几周就换结构,推理框架几天发一个 RC,官方团队和社区里到处都是挂着好几个 Agent 连轴转的人。我这边刚在 568afb3a 上把主机卸载和缓存池凑合跑通,回头一查才看到,Ascend-SACT 十一月五号就已经基于同一个 commit 放出了改过 136 个文件的 v7 部署包,ModelScope 上也有人把同款模型的四卡 W4A8 传上去了。

昨天下午我还想着,之前有人给 DeepSeek V4.1 做过 1.6G 的去审查补丁,要不我也给这个 Qwen 搞个 Heretic 无审查版。动手前让 GPT 去 Hugging Face 搜了一圈,结果别人早就把完整的 heretic-2 权重和提取好的 409KB 43 层拒答方向向量 .npz 传上去了,连怎么在专家求和之后只做一次投影、省得改两千多个专家矩阵的办法都写好了。我最后连脚本都没写,直接把现成的 .npz 下回来挂到另外四张卡上就跑起来了。

硬件适配也一样容易被替掉

这次在 910B4 上折腾得这么累,很大一部分原因也是 A2 在硬件支持里已经往后排了。Qwen3.8-Flash-Next 出来的时候官方先给的是 A3(910C)教程,这阵子社区里提的新算子 PR,不是默认只开 A3,就是在 950DT、A5 上测的。

手头拿的是旧一档的卡,很多所谓的深度调优其实就是硬凑硬件条件。单卡只有 64G 显存装不下那张 95G 的词表,就只能往主机内存里搬。MoE 每层 512 个专家,分块小了每个专家分不到几个 token,昇腾的 Cube 单元跑不满,又得去调分块阈值和通信融合,中间我连 NPU0/1 在 NUMA6、NPU2/3 在 NUMA4 会不会拖慢读内存都去查了一遍。

查这些底层细节挺费精力的,但做完了真的留不下什么。上游隔几天腾出手补个 A2 兼容,发个新镜像就能把这些手动改动全替掉。等以后机器换上显存更大、带宽更高的新卡,当初为了省那四百多兆显存折腾出来的配置就更没人关心了。

最后的感伤

今天早上起来,我花了一上午把服务器上的容器重新整理了一遍,把 New API、Nginx 反代和 Docker 的请求内容日志全关了,免得平时测试瞎聊的内容一直留在服务器硬盘上,顺便修了一下反代容器重启后 IP 变动导致的公网 502。另外四张卡上挂着的 Heretic 分支也调通了工具调用和图片输入,单并发稳定在二十四五 tok/s。

现在机器上的服务比前两天快得多,想要的功能也都配齐了,但我坐在电脑前面还是觉得挺失落的,有点替自己感伤。

把这篇博客起名叫《才华把我埋葬于明天》,是反着改了一下刘胜与那篇的标题。真正写核心算子的大佬说“把才华埋葬在昨天”,是因为人家确实有硬核的算子功底,过去那几年手写底层优化的日子也真的算数。放到我自己身上,原本以为看懂新模型结构,顺着报错一路查进 CANN 和显存池,熬几个晚上把没人给现成方案的四卡 256K 跑下来,多少也算一点本事。可在现在模型、推理框架、硬件和 AI 一起飞快更新的速度面前,这点东西实在不够看。

我今天费半天劲才搞明白的东西,到了明天可能就被一个刚发的 RC 版本、社区里动作更快的人、更强一点的 Agent,或者一张新出的卡给替掉了。今天刚弄明白 GDN 和 QSA 在 B4 上怎么跑顺,说不定下个月新模型又换一套混合结构,一切又得重来。

服务器上那个跑了一周的 0.26.0 容器现在还没删,状态停在 Exited。我在 baseline.md 里写着留它做回退兜底,其实只要 0.32 一直稳着,我大概再也不会去 docker start 它了。硬盘里那 2G 挨个核对过哈希的补丁、日志和 PDF 报告也是一样,彻底跑通的第二天就已经用不上了。

本文由作者按照 CC BY 4.0 进行授权