CUDA Agent: Large-Scale Agentic RL for High-Performance CUDA Kernel Generation

Paper: arXiv:2602.24286 Code: BytedTsinghua-SIA/CUDA-Agent Code reference: main @ 473025c8 (2026-03-02)

1. Motivation (研究动机)

CUDA kernel 优化是深度学习系统的底层瓶颈:同一个 PyTorch operator 或 operator sequence,能否被融合、是否避免中间 tensor 落到 global memory、线程块/共享内存/向量化访问如何安排,都会直接决定训练与推理吞吐。传统上这类优化依赖 CUDA 专家、profiling 工具和反复调参;而通用 LLM 虽然在普通软件工程任务上很强,但在 KernelBench 这类高性能 CUDA 生成任务上仍经常只能写出“能跑但不快”的 kernel,甚至无法稳定超过 torch.compile

Figure 0 解读:这张图给出论文的核心动机证据:通用模型在 Pass Rate 上可以接近可用,但 Faster Rate vs. torch.compile 明显不足;CUDA Agent 的目标不是只提高 correctness,而是把“生成可编译 kernel”推进到“稳定生成比 compiler baseline 更快的 kernel”。

现有方向主要有两类不足。第一类是 test-time search / refinement,例如多 agent 调试、evolutionary editing、retrieval-augmented search,它们依赖基础模型已有 CUDA 能力,主要在推理时搜索更好的 patch;如果模型本身不懂 memory coalescing、shared-memory tiling、kernel fusion,搜索空间会被强烈限制。第二类是固定执行反馈循环上的微调,它能让模型适应“写代码—运行—修复”的交互格式,但未必真正提升模型的内在 CUDA 优化策略,尤其对长上下文、多轮工具调用、稀有 CUDA token 的 RL 稳定性没有系统处理。

本文要解决的具体问题是:如何把 CUDA kernel generation 变成一个可大规模训练的 agentic RL 问题,使模型在一个受控的 CUDA 开发环境里反复编译、验证、profiling,并从可靠 reward 中学习到可迁移的 CUDA 优化能力。这个问题值得研究,因为一旦模型能稳定超过 torch.compile,LLM-based system agent 就可以从“辅助写代码”进一步进入底层系统优化:自动融合 operator、自动写 custom extension、在复杂模型子图上发现 compiler 规则覆盖不到的硬件特定实现。

2. Idea (核心思想)

核心 insight 是:CUDA 优化不是单轮 code generation,而是一个带验证器、profiling、错误反馈和性能目标的工程闭环;因此模型需要在“真实 CUDA 开发环境”中通过 agentic RL 学会迭代调试和性能优化,而不是只在静态答案上做 SFT。

CUDA Agent 的创新可以压缩为三点:先构造 6,000 个可执行、去污染、难度适中的 PyTorch reference operator 作为 RL 任务;再把 CUDA 开发规则、工具和 anti-hacking 约束封装成 skill-integrated agent loop;最后用 robust reward、RFT actor warm-up 和 value pretraining 解决长上下文 agentic PPO 的训练崩溃问题。与 STARK、CudaForge、EvoEngineer 这类 training-free 系统相比,CUDA Agent 的本质差异是把 execution feedback 从推理时启发式搜索信号变成训练时 reward 信号,直接改变模型参数和 CUDA prior。

一个直观理解是:普通模型像“临时查资料写 CUDA 的程序员”,遇到编译错误和 profiler 结果时只能在当前任务内修补;CUDA Agent 试图把大量这样的修补轨迹压缩进模型权重,使下一次遇到类似 operator fusion、memory layout 或 binding 问题时,它一开始就更像有经验的 CUDA 工程师。

更具体地说,本文把“agent 能使用工具”与“模型能从工具反馈中学习”区分开来:前者只是推理时能力,后者才是训练后的内在能力。CUDA Agent 的 novelty 在于把可执行任务、不可篡改评测、profiling latency 和多阶段 RL 串成一个闭环,使 reward 不是人工偏好或单元测试通过率,而是同时包含 correctness 与硬件速度目标的工程信号。

它与普通代码 RL 的差别还在于 reward 的粒度和任务结构:普通代码题往往只看测试是否通过,CUDA kernel 任务则必须同时通过数值正确性、编译、性能 profiling 和 baseline-relative speedup。本文把这些工程约束做成训练环境后,模型学习到的不只是某个 kernel 模板,而是“先定位瓶颈、再选择融合/tiling/vectorization/binding 策略、最后用 profiler 反馈迭代”的过程性策略。这个过程性策略正是 Code & SWE Agent 方向的关键:agent 的价值来自能在真实工具链里闭环优化,而不仅是一次性生成文本。 这也是本文区别于纯 benchmark leaderboard paper 的地方。

3. Method (方法)

3.1 Overall framework:数据、环境、RL 三段式闭环

CUDA Agent 的整体框架由三部分组成:数据合成管线提供可执行 PyTorch reference operators;agent loop 提供 CUDA 开发工作区、工具、verification/profiling 和 reward;稳定 RL 训练管线先 warm up,再用 PPO 做 long-context agentic RL。

Figure 1 解读:Figure 1 展示三阶段数据管线:从 torch / transformers 抓取 seed operators;用 LLM 把多个 torch operator 顺序组合成 fused task;再用执行过滤去掉不可运行、随机、退化输出、过易或过重的样本。这里的关键不是“合成更多题”,而是让训练任务逼迫 agent 学会跨 operator 的融合与内存布局决策。

Figure 2 解读:Figure 2 对应 skill-integrated agent loop:模型在 ReAct-style 循环中读写文件、运行 shell、编译 extension、查看错误和 profiler 结果。环境把 model.py 作为 PyTorch reference,把 model_new.pykernels/ 作为 agent 的工作区,并通过 verification/profiling 脚本把 correctness 和 latency 转成可训练 reward。

Figure 3 解读:Figure 3 展示训练顺序:先做 single-turn RL warm-up,让模型具备基础 CUDA 生成能力;再收集 agent trajectories 并用 RFT 初始化 actor;同时用 trajectory state 和 outcome reward 预训练 critic;最后进入 agentic PPO。这个顺序针对的是 long-context tool-use RL 的分布错配问题,而不是普通 PPO 的超参数微调。

3.2 Scalable Training Data Synthesis Pipeline

每个训练样本是一个自包含 PyTorch operator task:一个 torch.nn.Module 子类、__init__forward,以及 get_init_inputs()get_inputs()。这种格式的优点是 execution-based RL 可以直接实例化模型、生成输入、跑 eager/compile/reference 对照,并给 agent 一个清晰的目标:在不改 reference 的前提下写出更快的 custom CUDA extension。

数据合成有三个阶段:

  • Seed problem crawling:从 torchtransformers 中挖掘高质量 reference operators。论文避免从零散个人 repo 抓代码,因为这些实现质量和维护状态不稳定,会污染 reward 与训练任务。
  • Combinatorial construction:LLM 从 torch operator classes 中采样最多 5 个,并顺序堆叠成一个 computational layer。组合后的任务不等价于逐个 kernel 优化后串联,因为融合会改变中间内存 materialization、register/shared-memory 约束、occupancy 和 downstream layout。
  • Execution filtering:样本必须在 eager 与 torch.compile 下都能执行;排除随机 operator;排除不同输入输出几乎不变的退化任务;eager runtime 限制在 1 ms 到 100 ms;再用 AST 相似度去掉与 KernelBench evaluation 过近的样本。

Figure 6 解读:Figure 6 展示两类训练 operator:transformers 模块代表高层语义 operator,组合 torch operator 代表可控的 operator fusion 任务。前者提供真实模型结构感,后者提供可扩展的复杂度梯度。

Figure 7 解读:Figure 7 是 decontamination 的证据:训练样本与 evaluation programs 的最大 AST similarity 分布被压在阈值以下,论文使用 0.9 作为移除阈值,避免模型靠记忆 KernelBench 测试样本获得高分。

最终数据集为 CUDA-Agent-Ops-6K,共 6,000 个训练样本。附录 Table 3 给出的组成是:torch operators ×1 为 3.40%,×2 为 83.77%,×3 为 7.62%,×4 为 2.80%,×5 为 1.23%,transformers operator 为 1.18%。这说明主体不是单 operator,而是二元组合任务;它们足够常见以稳定训练,又能覆盖 fusion 的主要收益来源。

3.3 Skill-Integrated Agent Loop 与 anti-hacking 环境

Agent loop 对齐 OpenHands 风格:提供 Bash、Read/Write、Edit/MultiEdit、Glob、Grep、NotebookEdit、BashOutput、KillBash 等工具,让策略在本地开发环境中执行“读代码—改代码—编译—验证—profiling—再改”的循环。CUDA-specific 部分以 SKILL.md 形式给出,要求 agent 先用 profiling 分析 native PyTorch baseline,再在 model_new.pykernels/ 中实现 custom ops,最后通过 GPU sandbox 编译、验证并比较 torch.compile

论文的 anti-hacking 设计很重要,因为 RL 如果直接奖励速度,很容易学会破坏评测脚本或绕过计算。CUDA Agent 做了五类约束:verification/profiling 脚本用权限保护;禁止在执行时 fallback 到 torch.nn.functional;每题用 5 个随机输入做 correctness check;profiling 有 device synchronization、warm-up 和重复测量平均;不给 agent web search 或外部检索工具。这样 reward 更接近“真实 kernel 更快”,而不是“评测被绕过”。

Released code 在 main@473025c8 中没有公开完整 RL trainer,但公开了 agent workdir 的核心环境。utils/verification.py 初始化 ModelModelNew,复制 state_dict,把输入搬到 CUDA,并在 block_torch_functional() context 下运行 ModelNew,对 5 次随机输入做 torch.testing.assert_close(atol=1e-2, rtol=1e-2)utils/profiling.py 分别 benchmark PyTorch baseline、torch.compile 和 CUDA extension,默认 warm-up 5 次、benchmark 10 次,用 CUDA profiler event 的 device_time 求平均。

import torch
import torch.nn.functional as F
from contextlib import contextmanager
 
@contextmanager
def block_torch_functional(excludes=None):
    excludes = excludes or set()
    originals = {}
    for name in dir(F):
        fn = getattr(F, name)
        if callable(fn) and not name.startswith("_") and name not in excludes:
            originals[name] = fn
            setattr(F, name, lambda *a, __name=name, **kw: (_ for _ in ()).throw(
                RuntimeError(f"torch.nn.functional.{__name} is not allowed")
            ))
    try:
        yield
    finally:
        for name, fn in originals.items():
            setattr(F, name, fn)
 
 
def verify_cuda_extension(Model, ModelNew, get_init_inputs, get_inputs, checks=5):
    torch_model = Model(*get_init_inputs()).eval().cuda()
    cuda_model = ModelNew(*get_init_inputs()).eval().cuda()
    cuda_model.load_state_dict(torch_model.state_dict())
    with torch.no_grad():
        for _ in range(checks):
            inputs = [x.cuda() for x in get_inputs()]
            expected = torch_model(*inputs)
            with block_torch_functional():
                actual = cuda_model(*[x.clone() for x in inputs])
            torch.testing.assert_close(actual, expected, atol=1e-2, rtol=1e-2)
    torch.cuda.synchronize()

3.4 Robust Reward Scheduling

论文没有直接用 raw speedup ratio 作为 reward,因为不同 operator 的优化难度差异很大,raw ratio 会偏向容易题,也容易被 outlier latency 放大。CUDA Agent 使用离散 milestone reward:先要求 correctness,再看是否显著快于 eager 和 compile。 其中 是生成 kernel 的运行时间, 分别是 PyTorch eager 与 torch.compile runtime, 表示相对 baseline 至少快 5%。注意论文正文把解释文字中的 baseline 写成 ,而公式里是 ;这里按上下文统一理解为 PyTorch eager baseline。

import torch
 
 
def benchmark_model(model, inputs, warmup_iters=5, run_iters=10):
    with torch.no_grad():
        for _ in range(warmup_iters):
            _ = model(*inputs)
        with torch.profiler.profile(
            activities=[torch.profiler.ProfilerActivity.CUDA],
            record_shapes=False,
            with_stack=False,
        ) as prof:
            torch.cuda.synchronize()
            for _ in range(run_iters):
                _ = model(*inputs)
            torch.cuda.synchronize()
    return sum(e.device_time for e in prof.events() if e.device_type.name == "CUDA") / run_iters
 
 
def cuda_agent_reward(correct, t_agent, t_eager, t_compile):
    if not correct:
        return -1
    faster_eager = (t_eager - t_agent) / t_eager > 0.05
    faster_compile = (t_compile - t_agent) / t_compile > 0.05
    if faster_eager and faster_compile:
        return 3
    if faster_eager:
        return 2
    return 1

3.5 Stable Agentic RL:为什么需要 RFT 与 Value Pretraining

论文报告初始 RL trial 只能稳定训练 17 steps 就崩溃。根因被归结为 domain distribution mismatch:CUDA code token 在通用预训练数据中占比低于 0.01%,长达 150 turns 的 tool-call / code trajectory 会产生大量低概率 token;如果 rollout/inference 与 training engine 的数值精度不同,例如 FP16/BF16,接近概率下限的 token 会让 importance ratio 波动甚至爆炸。

因此训练管线先做 single-turn PPO warm-up,再在 agent loop 中采样 trajectories,用 RFT 过滤并初始化 actor。过滤标准有两条:outcome filtering 只保留 的轨迹;pattern filtering 删除冗余多轮循环、违反 tool-call schema 的幻觉等无效行为。RFT 目标是标准行为克隆: Critic 也不能冷启动。论文用采样 trajectory 的 state sequence 与 outcome reward 做 Value Pretraining。令 ,最终 token 得到 outcome reward ,前面 token reward 为 0;用 GAE 计算 target: 实验中 。随后用 PPO clipped objective 优化 actor: 其中 ,并且只在 agent 生成 token 上计算 loss,mask 掉环境反馈 token。

import torch
import torch.nn.functional as F
 
 
def rft_actor_update(policy, trajectories):
    kept = []
    for traj in trajectories:
        if traj.reward > 0 and not traj.has_redundant_loop and traj.tool_schema_valid:
            kept.append(traj)
    loss = 0.0
    for traj in kept:
        logp = policy.log_prob(actions=traj.agent_tokens, states=traj.states)
        loss = loss - logp.sum()
    return loss / max(len(kept), 1)
 
 
def value_pretrain_loss(value_fn, states, final_reward, gamma=1.0, lam=0.95):
    values = value_fn(states)
    rewards = torch.zeros_like(values)
    rewards[-1] = final_reward
    next_values = torch.cat([values[1:], values.new_zeros(1)])
    deltas = rewards + gamma * next_values - values
    adv = torch.zeros_like(values)
    running = 0.0
    for t in reversed(range(len(states))):
        running = deltas[t] + gamma * lam * running
        adv[t] = running
    target = values.detach() + adv
    return 0.5 * F.mse_loss(values, target)
 
 
def ppo_clip_loss(policy, old_policy, states, actions, advantages, mask,
                  eps_lower=0.2, eps_higher=0.28):
    ratio = torch.exp(policy.log_prob(actions, states) - old_policy.log_prob(actions, states))
    unclipped = ratio * advantages
    clipped = torch.clamp(ratio, 1 - eps_lower, 1 + eps_higher) * advantages
    token_loss = -torch.minimum(unclipped, clipped)
    return (token_loss * mask).sum() / mask.sum().clamp_min(1)

Figure 4 解读:Figure 4a–4b 显示去掉 RFT 后 reward 快速 collapse,同时 actor entropy 上升。作者的解释是:没有 RFT 的行为先验,policy 在 tool-call / CUDA code 空间中变得发散,输出越来越不结构化,PPO 更新会强化错误分布。

Figure 5 解读:Figure 5a–5b 显示去掉 Value Pretraining 后 critic explained variance 长期接近 0,且 response length clipped ratio 更高。也就是说,critic 冷启动会给 actor 提供噪声 advantage,长 trajectory 训练更容易把更新推向不稳定区域。

3.6 Released code 与 paper-to-code mapping

论文公式与 released code 实现差异:公开 repo main@473025c8 没有包含完整 RL 训练 launcher、PPO trainer、RFT 数据过滤脚本或训练配置;公开内容是 CUDA-Agent-Ops-6K 说明、agent workdir、CUDA skill、verification/profiling/compile utilities 和一个 AXPBY custom kernel 示例。因此上面的 RL pseudocode 是按论文公式整理;环境 pseudocode 与 mapping 则来自 released repo。训练超参数也只能从论文 §4.1 读取,不能从公开 repo 的 launch config 复核。

Code reference: main @ 473025c8 (2026-03-02) — pseudocode and mapping based on this commit

Paper ConceptSource FileKey Class/Function
Dataset / project releaseREADME.mdCUDA-Agent-Ops-6K, agent workdir overview
CUDA coding skill constraintsagent_workdir/SKILL.mdforbidden torch fallback, allowed CUDA/cuBLAS/cuDNN workflow
Reference operator task formatagent_workdir/model.pyModel, get_inputs, get_init_inputs
Optimized model interfaceagent_workdir/model_new.pyModelNew.forward calling cuda_extension.axpby_forward
Binding infrastructureagent_workdir/binding.cpp, binding_registry.hPYBIND11_MODULE, REGISTER_BINDING
Example custom CUDA kernelagent_workdir/kernels/axpby.cu, agent_workdir/kernels/axpby_binding.cppaxpby_kernel, axpby_launcher, axpby_forward
Compilationagent_workdir/utils/compile.py, compile.shsource discovery, torch.utils.cpp_extension.load
Correctness verificationagent_workdir/utils/verification.pyblock_torch_functional, check_equal, 5 checks
Performance profilingagent_workdir/utils/profiling.pybenchmark_model, PyTorch vs torch.compile vs extension
RFT / PPO / value pretrainingnot released in repopaper §3.3 formulas; no public training config at this ref

4. Experimental Setup (实验设置)

Training data and evaluation data. 训练数据是 CUDA-Agent-Ops-6K,包含 6,000 个合成 operator tasks;其构成见 §3.2。评估使用 KernelBench Level 1–3,总计 250 个 tasks,其中 Level 1 为 100 个 single operator tasks,Level 2 为 100 个 operator-sequence tasks,Level 3 为 50 个更复杂的 module-level tasks。训练数据还用 AST similarity 与 evaluation set 去污染,超过 0.9 的相似样本会被移除。

Baselines. 论文比较 Seed1.6 base model、GLM 4.6、Kimi K2、Gemini 3 Pro、Claude Opus 4.5,以及 PyTorch eager / torch.compile 作为 runtime baselines。所有模型在同一个 agent loop 下评估,以减少交互环境差异。

Metrics. Pass Rate 表示生成 kernel 能编译并通过 correctness check 的 task 比例;Faster Rate 分别统计正确 kernel 中快于 PyTorch eager 和 torch.compile 的 task 比例;Speed-up 是相对 eager / compile 的 geometric mean speed-up,只在正确解上计算。每个 task 取 agent trajectory 中相对 torch.compile speed-up 最大的解作为最终结果。

Training config. Base model 是 Seed1.6 MoE,23B active / 230B total parameters。RL global batch size 为 1024,online PPO mini-batch size 也为 1024;actor learning rate 为 ,critic learning rate 为 ;single-turn RL context window 为 32,768,agentic RL context window 为 131,072;training rollout 最多 150 agent turns,evaluation 放宽到 200 turns;训练 150 steps。Sandbox 是 CPU–GPU decoupled 架构:Docker terminal sandbox 处理编译等 CPU 任务,verification/profiling 分发到 128 NVIDIA H20 96GB GPUs(即 128 张 NVIDIA H20 96GB GPU) 的 sandbox pool,并做 process-level isolation / exclusive resource allocation。注意:这些训练配置来自论文 §4.1;released GitHub main@473025c8 未公开对应训练 launch script 或 experiment config。

5. Experimental Results (实验结果)

Main KernelBench results. Table 1 的 Overall 结果显示 CUDA Agent 达到 98.8% Pass Rate、98.4% Faster Rate vs. eager、96.8% Faster Rate vs. compile、2.60× geomean speed-up vs. eager、2.11× speed-up vs. compile。最强 proprietary baselines 仍有明显差距:Claude Opus 4.5 Overall 为 95.2% Pass Rate、66.4% Faster Rate vs. compile、1.46× speed-up vs. compile;Gemini 3 Pro 为 91.2%、69.6%、1.42×。

SubsetModelPass RateFaster vs. EagerFaster vs. CompileSpeed-up vs. EagerSpeed-up vs. Compile
OverallCUDA Agent98.8%98.4%96.8%2.60×2.11×
Level 1CUDA Agent100.0%99.0%97.0%2.48×1.87×
Level 2CUDA Agent100.0%100.0%100.0%3.27×2.80×
Level 3CUDA Agent94.0%94.0%90.0%1.80×1.52×

Level-wise 结果说明:Level 2 的 operator sequence 最受益于 learned fusion policy,CUDA Agent 相对 torch.compile 达到 100.0% Faster Rate 和 2.80× speed-up;Level 3 最难,但仍达到 90.0% Faster Rate vs. compile,约比 Claude Opus 4.5 / Gemini 3 Pro 的 50.0% / 52.0% 高约 38–40 个百分点。

Ablations. Table 2 证明每个核心模块都必要。去掉 agent loop 后 Overall Pass Rate 降到 77.1%,Faster Rate vs. compile 只有 14.1%,Speed-up vs. compile 只有 0.69×,说明单轮输出很容易退化成不快甚至更慢的 kernel。去掉 robust reward 时 Pass Rate 仍有 96.8%,但 Faster Rate vs. compile 降到 60.4%,说明 raw speed-up reward 没有正确对齐“稳定超过两个 baseline”的目标。去掉 RFT 时 Faster Rate vs. compile 为 49.8%、Speed-up vs. compile 为 1.05×;去掉 Value Pretraining 为 50.9% 与 1.00×,并且这些数值来自 collapse 前的最后 validation step。

VariantPass RateFaster vs. EagerFaster vs. CompileSpeed-up vs. EagerSpeed-up vs. Compile
w/o Agent Loop77.1%43.5%14.1%0.89×0.69×
w/o Robust Reward96.8%90.4%60.4%1.70×1.25×
w/o RFT95.6%82.0%49.8%1.56×1.05×
w/o Value Pretraining98.6%85.0%50.9%1.49×1.00×
CUDA Agent98.8%98.4%96.8%2.60×2.11×

Limitations. 作者明确承认两点限制:第一,没有与 TVM 等更复杂 compiler framework 比较,因为这些系统的调参和部署成本很难嵌入数千 rollout 的大规模 RL loop;第二,训练依赖大规模隔离 GPU pool,工程和算力成本很高,限制了社区复现和扩展,后续需要更高效的训练策略。

Overall conclusion. CUDA Agent 的结果说明,LLM 生成 CUDA kernel 的瓶颈不只是“缺少更多 test-time search”,而是缺少可训练、可验证、可稳定优化的 CUDA agent 环境。数据合成解决任务规模,skill-integrated loop 解决真实反馈,robust reward/RFT/value pretraining 解决 RL 稳定性;三者合起来才把 correctness、performance 和 long-horizon tool-use 训练同时推上去。