
2025年,有一件事让做GPU编程的人挺不是滋味的:一个叫cudaLLM的模型,砸了128块H100显卡去训练,结果在KernelBench Level 1这个基础测试集上,十次尝试里也就八成能对。
这是什么概念?
你花了相当于几十万美元的算力,训出来的模型,写十个GPU程序,还有两个是错的。而这些还只是最简单的单算子任务,比如卷积、矩阵乘法这类基础操作。
问题出在哪?不是模型不够聪明,是喂给它的"练习题"出了问题。
这篇来自中国科学院计算技术研究所的论文,叫KernelZero,给出了一个挺巧妙的解法。它不是又去堆更多算力,而是换了一种训练的"节奏"。
难写的不是代码,是"合适的练习题"
先说说GPU内核(也就是用CUDA或者Triton这类语言写的、直接在显卡上跑的高性能代码)这件事到底难在哪。
CUDA*:英伟达为GPU设计的编程语言,能让开发者直接控制显卡的并行计算能力。
Triton*:一种更高层的GPU编程语言,由OpenAI主导开发,写起来比CUDA简单,但性能损失较小。
写这类代码需要的不只是会写Python,你得懂显卡的内存怎么分层、线程怎么调度、数据怎么搬运才不浪费时间。这是一门交叉了计算机体系结构的手艺活。
用大语言模型来自动生成这些内核,思路听起来很直接:拿一堆"PyTorch模块对应CUDA实现"的样本喂给模型,让它学着翻译。但这里有个致命的坑。
如果训练数据要么太简单,模型闭着眼睛都能写对,学不到什么;要么太难,模型怎么写都是错的,梯度信号一片混乱,训练根本没法收敛。这就好比教一个刚学会加减法的孩子做微积分题,他不会从中学到任何有用的东西,只会越做越懵。
论文里还提到了另一层矛盾,这个矛盾更微妙:正确性和性能之间的拉扯。
如果只奖励"代码跑得对",模型学会的往往是最保守、最笨拙的写法,能对但慢得要命;如果一味追求"跑得快",模型就敢乱来,为了省一点时间,直接破坏了计算逻辑的等价性,跑起来是快了,但答案错了。
这两个问题揉在一起,就是这篇论文要解决的核心矛盾:既要有"刚刚好难度"的训练题,又要让模型学会"先保证对,再追求快"的正确顺序。
用一个模型出题,另一个模型解题
KernelZero的解法,说穿了就是搞了两个角色,让它们互相"练拳"。
一个叫Proposer(提议者),专门负责出题:给定一批PyTorch的API(比如卷积层、归一化层、激活函数这些),它要生成一个能跑起来的PyTorch模块,也就是一道"翻译题"。
另一个叫Coder(编码者),专门负责解题:拿到这个PyTorch模块,把它翻译成对应的CUDA或Triton内核代码。
Proposer*:论文中负责生成训练题目(PyTorch模块)的模型角色。
Coder*:论文中负责把PyTorch模块翻译成GPU内核代码的模型角色。
这个设计的巧妙之处在于,Proposer出题时不是拍脑袋随便出,而是紧盯着Coder当前"不会做的题"。具体来说,系统会把Coder做错的模块里用到的API组合抽出来,喂给Proposer,让它围绕这些"薄弱环节"继续出题。
这就好比一个私教发现你总是卧推卡在80公斤这个重量上,他不会天天让你举20公斤的哑铃(太轻松,没有训练效果),也不会直接上120公斤(你根本举不起来,还容易受伤),而是让你在80到85公斤之间反复磨,一点点把这个瓶颈往上顶。如果私教只会让你举你已经很擅长的重量,你的力量永远停在原地;如果直接让你挑战极限重量,你大概率会受伤或者彻底放弃训练。真正有效的训练,永远发生在"够得着但够得有点吃力"的那个区间。
论文里管这个叫Frontier Reward(前沿奖励):
Frontier Reward*:一种奖励机制,让Proposer生成的题目难度刚好卡在Coder当前能力的边界上,也就是让Coder在多次尝试中大约一半正确、一半错误的难度。
具体的数学设计也挺直白。给定一个Proposer生成的模块,系统会让Coder采样一组(比如4到5个)候选答案,计算这些答案里正确率是多少。如果正确率刚好接近50%,说明这道题难度正合适,Proposer就能拿到满分奖励;如果正确率太高(题目太简单)或太低(题目太难),奖励就会往下掉。
这个50%的设定并非拍脑袋,它背后其实有个统计学的直觉:一道题如果正确率是50%,说明它对模型来说信息量最大,模型的每一次尝试都在提供有价值的区分信号。这和强化学习里"探索与利用平衡"的思路是一脉相承的。
但光出好题目还不够,出的题目还得靠谱,不能是些逻辑不通、跑不起来的废题。为此,Proposer生成的每个模块都要过三道关卡:先用抽象语法树检查代码结构是否和要求的API匹配,再实际跑一遍看会不会报错,最后检查输出里有没有NaN或者无穷大这类数值异常。三关都过了,这道题才算合格,才能进入训练池。
先学会走,再学会跑
解决了"出题"的问题,接下来是"怎么让Coder学会既对又快"这件事。
论文提出了一个叫CA-GRPO(正确性感知的分组相对策略优化)的训练方法,核心思路可以用六个字概括:先对,再快。
CA-GRPO*:Correctness-Aware Group Relative Policy Optimization的缩写,一种改进的强化学习算法,只有当模型的正确率达到某个门槛后,才会开始奖励代码的运行速度。
GRPO*:Group Relative Policy Optimization,一种强化学习优化算法,不需要额外训练一个价值网络,而是通过对比同一批采样结果的相对好坏来计算优势值,是DeepSeek系列模型常用的训练方法。
具体怎么做的?Coder针对同一个模块生成一组候选内核(比如5个),系统先看这组里有多少个是正确的,算出一个组内正确率。如果这个正确率没达到设定的门槛(论文里最终用的是0.5,也就是至少一半正确),那么这组样本只按对错给分,不去管快慢;只有当正确率达标了,系统才会在"对"的样本里比较速度,跑得快的给更高奖励。
这个设计其实是在给训练过程装了一道"安全阀"。
想象一个新手司机刚拿到驾照,教练不会一上来就说"你现在给我飙到120码",而是先让他把车稳稳当当开到目的地,等他连续几次都能安全抵达了,才开始教他怎么在保证安全的前提下开快一点。如果反过来,一开始就鼓励他追求速度,结果很可能是他为了快而闯了红灯,或者压根开错了路,跑得越快,错得越离谱。CA-GRPO里那个"正确率门槛",就是这道安全阀,它确保速度优化这件事,永远建立在"至少一半的答案是对的"这个地基之上。
论文的消融实验也印证了这个设计的必要性。他们试了不同的门槛值:如果门槛设成1.1(意味着速度奖励永远不会被激活,模型只学正确性),最终的正确率反而是四个方案里最高的(74.85%),但速度表现却是最差的,只有9.75%的样本能达到1.5倍加速;而门槛设成0.5的版本,虽然正确率略低一点,但在实际测试的六个代表性算子上,全部拿到了最好的加速效果,比如在一个叫Tensor-MM的任务上,从冷启动阶段的0.12倍加速直接跳到了4.42倍。这组数据挺直观地说明了:把安全阀完全拿掉不行,把阀门关得太死也不行,0.5这个中间值才是那个恰到好处的平衡点。
在正式开始强化学习之前,KernelZero还给Coder做了一次"预习",叫做冷启动蒸馏。
冷启动蒸馏*:在强化学习开始前,先用一个更强的教师模型生成大量高质量的示范代码,让待训练的模型先模仿学习,打下基础后再进入强化学习阶段。
这次预习的内容很讲究,论文总结了四条GPU优化的基本功:分块(把数据切成小块塞进片上高速内存,减少访问显存的次数)、融合(把连续的运算合并成一个内核,省掉中间结果来回搬运的开销)、流水线(让数据搬运和计算同时进行,别让计算单元干等着数据)、重排序(调整循环和线程的执行顺序,让内存访问更连贯)。这四条原则被用来提示一个教师模型(gpt-oss-120B)生成带有详细推理过程的代码示范,最终筛出4万多条CUDA样本和近6万条Triton样本,用来给Coder打地基。
这就好比让一个刚入行的厨师先跟着大厨的菜谱一步步照做几十遍,把火候、刀工这些基本功先练熟,然后才放他自己上灶台去创新菜式。如果没有这个预习阶段,直接让模型从零开始靠试错摸索复杂的GPU优化技巧,那训练效率会低得多,甚至可能永远也摸不到门道。
出题的AI自己也在进化
这里有个容易被忽略但其实很关键的设计:整个系统不是"Proposer出题、Coder做题"这么一锤子买卖,而是两个模型轮流训练,交替进化。
具体的做法是,先让Proposer训练20步(生成的题目质量会越来越贴近Coder的能力边界),然后固定住Proposer,让Coder针对这批新题目训练20步(解题能力提升),接着再回过头继续训练Proposer(因为Coder变强了,之前的题目对它来说可能变简单了,需要出更难的题)。这样交替进行4轮,总共80步。
论文专门做了个对照实验,验证这个"轮流进化"是不是真的有必要:一组是让两个模型一直这样交替训练下去,另一组是在第40步的时候把Proposer冻结住,之后Coder只能在一批固定不变的题目上反复练习。
结果很清楚。持续更新Proposer的那组,在CUDA的Level 2任务上,正确率(pass@1,也就是模型第一次尝试就答对的比例)从64.4%涨到了69.6%;而Proposer被冻结的那组,只能停留在原地打转,没有明显进步。更有意思的是,这个差距在难度更高的Level 2任务上比Level 1更明显,这说明当Coder变得越来越强的时候,它越需要不断升级的新题目来继续突破,一批一成不变的旧题目,很快就会被它"刷穿",失去训练价值。
这背后其实藏着一个挺深的道理:如果出题的人不进步,那么答题的人迟早会把题库摸得一清二楚,练习就变成了应付考试,而不是真正的能力提升。这也是为什么很多培训项目效果有限,因为题库是死的,学生练着练着就只是在背答案,而不是在锻炼解决新问题的能力。KernelZero用两个AI互相较劲的方式,让"出题的难度"始终跟得上"解题的水平",这种动态平衡才是持续进步的关键。
成绩单:7B的小模型打赢了千亿级大模型
说了这么多设计思路,最终效果到底怎么样?
论文用的评测基准是KernelBench,这是个专门评估大模型GPU代码生成能力的测试集,Level 1包含100个单算子任务(比如单独一个卷积、一个矩阵乘法),Level 2包含100个融合模式任务(比如"矩阵乘法接一个Sigmoid激活"这种组合操作)。
KernelBench*:一个用来评测大语言模型生成GPU内核代码能力的标准测试基准,分为不同难度级别,涵盖单算子和多算子融合任务。
评测用了两个核心指标:pass@k(在k次采样里至少有一次正确的比例)和fast_p@k(不仅正确,还要比PyTorch原生实现快p倍以上的比例)。
结果显示,KernelZero-7B这个只有70亿参数的模型,在CUDA生成任务上,Level 1的pass@1达到75.8%,pass@10更是干到了满分100%;Level 2的pass@1是69.6%,pass@10达到97%。作为对比,参数量大得多的Claude-4.5-Sonnet在Level 1的pass@1是76.4%,两者几乎打平,但KernelZero在pass@5和pass@10这些多次采样指标上反而更胜一筹。
在Triton生成任务上,KernelZero的表现更亮眼:Level 1的pass@1达到77.2%,超过了参数量高达1.6万亿的DeepSeek-V4-Pro(后者只有49.7%)和744亿参数的GLM-5.2(66.7%)。
这里有个数字值得多说一句:DeepSeek-V4-Pro的参数量是KernelZero-7B的两百多倍,但在Triton这个具体任务上,反而被这个小模型甩开了近28个百分点。这说明什么?说明在特定垂直任务上,针对性的训练方法,有时候比单纯堆参数规模更管用。这也是这篇论文最有说服力的地方之一。
模型 参数量 CUDA Level1 pass@1 CUDA Level1 pass@10 Triton Level1 pass@1
Claude-4.5-Sonnet 未知 76.4% 97% 不适用
DeepSeek-V4-Pro 1.6T 不适用 不适用 49.7%
GLM-5.2 744B 不适用 不适用 66.7%
KernelZero-7B 7B 75.8% 100% 77.2%
除了正确率,速度表现也值得一看。KernelZero生成的Triton代码在Level 1任务上,有43.9%的样本能达到1倍以上加速(也就是比PyTorch原生实现更快),而CUDA代码这个数字只有17.6%。这个差异背后的原因挺实在:Triton提供了更高层的编程抽象,编译器会自动处理很多底层优化细节,而生成的CUDA代码完全靠手写,还不能调用cuDNN、cuBLAS这类英伟达官方的高性能库。很多Level 2任务里包含卷积或矩阵乘法,PyTorch的原生实现直接调用了这些经过多年打磨的官方库,纯手写的CUDA代码想要超过它们,难度本身就更大。
写在后面
读完这篇论文,最触动我的其实不是那些漂亮的准确率数字,而是"用AI给AI出题"这个思路本身。
我们平时训练模型,默认的做法都是先攒一个静态的数据集,然后拿去训练,训练完就结束了。但KernelZero提醒了一件事:如果数据集是死的,而模型是活的、在不断进步的,那么这个数据集迟早会和模型的真实水平脱节,要么变得太简单,要么(如果任务本身难度分布不均)某些部分永远太难。
这个思路其实不只适用于GPU代码生成。任何一个需要"生成"和"评判"两种能力配合的AI训练场景,理论上都可以借鉴这种"左右手互搏"的结构。比如让一个模型出数学题,另一个模型解题,出题的模型根据解题模型的表现动态调整难度,这在教育类AI产品的自适应学习系统里,其实已经有类似的影子。
还有一个细节我觉得值得单独拎出来说:论文里那个"50%正确率是最佳训练难度"的设定,其实和人类学习心理学里的一个概念很像,叫"最近发展区",就是维果茨基提出的,指一个人"自己做不到但在别人帮助下能做到"的能力区间。教育学里早就发现,最有效的学习任务,永远发生在这个区间里,太简单没有成长,太难会产生挫败感直接放弃。KernelZero用一个冷冰冰的数学公式,重新发现了一个教育学里的老道理,这挺有意思的。
论文里没细说、但我挺好奇的一点是:这套"Proposer出题、Coder解题"的框架,能不能反过来用?比如让Coder的解题失败模式,反过来指导人类研究者去优化Proposer本身的架构设计,而不只是喂给它更多训练数据。如果这个反馈回路能建立起来,或许整个训练系统能进化得更快。
一个70亿参数的模型,靠着"会出题"这一招,打平甚至打赢了参数量大它两百倍的对手。这件事本身,可能比论文里任何一个具体的技术细节都更值得琢磨。
Q&A
Q1:KernelZero是什么?
A:KernelZero是中科院计算所提出的一个GPU内核代码生成框架,通过两个AI模型(Proposer负责出题、Coder负责解题)互相配合、交替训练,让模型能持续学会生成又对又快的CUDA和Triton代码。
Q2:KernelZero只有7B参数,为什么能打赢参数量大得多的模型?
A:因为它用了针对性的训练方法,比如让出题模型始终生成难度刚好卡在解题模型能力边界的题目,并用CA-GRPO算法确保先学会写对代码再追求速度,这种精准训练比单纯堆参数规模更有效。
Q3:CA-GRPO是什么,它解决了什么问题?
A:CA-GRPO是一种改进的强化学习算法,只有当一组生成代码的正确率达到设定门槛后才会开始奖励运行速度,解决了"追求正确会导致代码保守、追求速度会导致代码出错"这一训练矛盾。







