如何用 Agent 优化 CANN 算子?说人话
回复 群友 607: 先说结论:在 CANN 上用 Agent 优化算子,关键不是"让它帮你读代码",而是给它造一个能编译、能上板测、能记住经验的闭环。围绕这个闭环,现在有三条现实可走的路。 一、为什么 CANN 上的 Agent 特别难,这决定了你该往哪使劲 CUDA 是线程模型,网上开源 kernel 一抓一大把,模型预训练时"见过"。Ascend C 不是,它是显式数据流:你得自己把张量切成能塞进 UB 的 tile,自己用 TQue 做乒乓双缓冲让搬数据和算数据重叠,自己插同步屏障。任何一处错了——tile 边界、内存对齐、队列配对——就是编译失败或者运行期非法访存。 MultiKernelBench 的数字很直观:同样一次生成,CUDA 的 Pass@1 是 44% 到 52%,AscendC 不到 2.1%。所以昇腾上的第一矛盾是"能不能编译过",不是"跑得快不快"。更麻烦的是编译器报错往往指向内存对齐违规,不指向任何源码行,模型看不懂,于是卡在"改 → 编译失败 → 再改"的死循环里。这就是为什么下面所有有效做法,本质都在解决同一件事:把模型缺的那部分硬件常识补上。 二、最省事的一条:用官方现成的 CANN 官方已经有 MindStudio Agent(MsAgent),定位就是昇腾场景的一站式调试调优 Agent,沉淀的是昇腾工程师的调优经验,能自动做算子调优、精度调试、性能调优、量化、仿真建模、参数寻优,代码和用法都在昇腾社区。社区侧还有 CANNBot 和"昇腾 Agent-Skills"专栏,比如"轻松完成昇腾 910 到昇腾 310P 的 Ascend C 算子迁移"这类实操。如果你的诉求是"手上这个算子想调通、调快",先用这条,比自研划算得多。 三、学术和开源里已经被验证的两套思路,值得抄机制 第一套是华东师大的 AscendOptimizer。它在 101 个真实 AscendC 算子上平均 1.21× 加速,53% 的算子比参考实现更快。两个机制特别值得学: 一是 Optimization Rewind,反向拆解。它不去凭空生成快 kernel,而是从已经够快的实现出发,故意把某个优化手法一个个删掉,然后只留下"删了以后实测确实明显变慢"的那些。一个优化手法被这样验证过,就蒸馏成一条结构化经验(标题、瓶颈、适用条件、预期收益、代码 diff),攒成共享经验库。道理很朴素:没有现成语料,就用硬件实测自己造语料,让硬件告诉你哪行代码真的在干活。 二是 host 端 tiling 用硬件在环的进化搜索。因为 tiling 空间是不连续的,tile 大小或搬数据顺序改一点点,就从"合法且快"变成"非法",这类规则你想提前写全几乎不可能,只能编译、跑、测速,从实测结果里筛活下来的。 第二套是 AgenticCANN,核心是"先喂知识再写代码",而不是事后让模型猜报错。它把领域知识分了六层:编程模型、模式映射、硬件约束、分块策略、API 签名、已验证范例。LayerNorm 上的逐层消融很说明问题:什么都不给,可行性 0%;给编程模型 40%;补上"DataCopy 长度要 32 字节对齐、UB 预算 200KB 以内、AllocTensor 和 FreeTensor 必须配对"这类硬约束,跳到 60%;再加精选范例 80%;按进化阶段只注入该阶段的知识,到 90%,加速 2.71×。边际收益最大的一层恰好是硬件约束——也就是预训练语料里最缺的东西。 还有个反直觉的结论一定要记住:Agent 的自主性不是越高越好。让它自由读写文件、反复跑编译那套 Tool-Agent 模式,探索出一种 30.37ms 的 kernel 确实最快,但后续世代只拿到 +0.04% 的收益,烧掉 4.18M token;而固定小步修的 Fix-Loop 只花 350K token,跨世代拿到 +26%。所以正确姿势是:初始种子阶段放开让它探索,进入优化阶段就切成小步、保结构的收敛模式。 顺带说个端到端效果当参照:盘古 1B 推理里,生成出的 RMSNorm kernel 相比 PyTorch 原生算子快 6.65×,向量流水线利用率从 14.2% 拉到 81.6%,替换掉全部 53 个归一化层后端到端预计降 8% 到 10%。 四、自己搭的话,这几件事决定了成不成 第一,把硬件约束写成文件放进仓库,每次让 Agent 读,而不是等它踩坑。对齐规则、UB 内存预算、tiling 公式、队列配对检查清单,结构化、极简,别整本手册往里塞,上下文会被稀释。 第二,建三道闸门:编译过、数值对(拿 CPU 或参考实现比)、上板测速。三道缺一道,Agent 就会自我感动——改出一堆"看起来更优雅"的代码,实测没快。 第三,从一个规则算子开始,别一上来啃 attention。失败边界现在已经很清楚了:elementwise 和归一化能到 90% 到 100%,融合算子只有 56%,broadcast 是 0%,scaled dot-product attention 在八种配置下全军覆没,原因是中间矩阵 QK 转置的尺寸随序列长度平方涨,直接超过 UB 容量,需要块级分块加重算,模型没有显式算法指导想不出来。也别指望 Softmax 有惊喜,厂商编译器在标准 reduction 拓扑上已经优化得很凶,实测基本 0.98×,没什么空间。 第四,先算收益再动手。盘古那个例子里归一化占了端到端延迟大约 11%,所以值得投入;如果一个算子只占 1%,你优化到 2× 端到端也看不出来。优化顺序应该按端到端占比排,不按难度排。 第五,经验必须沉淀。把每次有效的改动存成条目,检索时按瓶颈症状找,不按算子名字找,这样才可能跨算子复用——按名字检索等于每次从零开始。 第六,最后一定留人工关:fp16/bf16 的累计误差、非对齐的尾块、极端 shape 和边界输入。这类东西 Agent 通常不会主动跟你交代,但它会让你的精度悄悄坏掉。 想继续追这个方向,可以收藏这份汇总,LLM 驱动 kernel 生成的论文、开源项目、benchmark 基本都在里面,昇腾相关的 AscendCraft、AscendKernelGen、AscendOptimizer 和 CANN Bench 都能从这儿找到入口:https://github.com/flagos-ai/awesome-LLM-driven-kernel-generation 你手上具体是哪个算子、用 Ascend C 还是走 MindStudio 那套?说一下我可以给你更具体的切入顺序。