元鉴
返回中文阅读流

NVIDIA Developer Blog

用 AI Agent 自动化 GPU Kernel 翻译:从 cuTile Python 到 cuTile.jl

NVIDIA CUDA Tile(cuTile)是一种基于 tile 的编程模型,使开发者能用 tile 级操作编写 GPU kernel。

中文内容

已翻译official company source英文原文2026-05-26

NVIDIA CUDA Tile(cuTile)是一种基于 tile 的编程模型,使开发者能够以 tile 级操作——加载、存储和矩阵乘加——来编写 GPU kernel,而无需手动协调线程、warp 和共享内存。

cuTile.jl 将同样基于 tile 的方法带到了动态编程语言 Julia。用户无需下探到 NVIDIA CUDA C++,即可编写自定义 GPU kernel。在 Julia 的科学计算生态中,自定义 kernel 往往至关重要,涵盖微分方程、概率编程和物理仿真等领域。

cuTile Python 拥有一个不断增长的优化 kernel 库,用于 GPU 加速。将这些 kernel 翻译为 cuTile.jl 的能力,使 Julia 生态能够立即访问经过实践检验的实现,而不必从头重写每一个。

本文介绍跨领域特定语言(DSL)的 GPU kernel 翻译,即从 cuTile Python kernel 移植到 cuTile.jl(Julia)。文章展示如何:

  • 在 cuTile Python 与 cuTile.jl 之间翻译 GPU kernel:并排讲解一个完整的矩阵乘法示例。
  • 避免会破坏朴素翻译的语义陷阱:索引、广播、内存布局和循环形式在这两种 DSL 之间都存在差异,而静默的不匹配会产生错误结果,而不是编译器错误。
  • 构建可重复、由技能驱动的 AI 工作流:翻译知识被封装为 TileGym 中的一个 LLM skill,可一次性生成经过验证的 Julia kernel,将一次性的移植工作系统化。

跨 DSL GPU kernel 翻译

cuTile Python 和 cuTile.jl 前端共享同一种 tiled 抽象,因此翻译在很大程度上是算法化的。然而,两种语言在表层上的累积差异并不简单,如表 1 所示。

CategoryPython (cuTile)Julia (cuTile.jl)Indexing0-based (ct.bid(0))1-based (ct.bid(1))BroadcastingImplicit (a + b)Explicit dot syntax (a .+ b)Memory layoutRow-majorColumn-majorKernel definition@ct.kernel decoratorPlain function ... endConstantsparam: ct.Constant[int] in signatureparam::Int in signature, ct.Constant(val) at launchType conversiontile.astype(ct.float32)convert(ct.Tile{Float32}, tile)Matrix multiplyct.mma(a, b, acc=acc)muladd(a, b, acc)
表 1. 在 Python 与 Julia 中编写 tile 代码的高层差异

这些翻译在概念上都不难,但如果漏掉一个本应为 ct.bid(1) 的 ct.bid(0),就会导致静默数据损坏。使用 * 而不是 .* 进行逐元素乘法时,Julia 会静默执行矩阵乘法。这类 bug 会耗费数小时。

共享抽象加上一组有限且反复出现的陷阱,非常适合 AI 辅助工作流——前提是模型被教会要注意什么。

将 cuTile Python 翻译为 cuTile.jl

这个过程最好通过实际代码来理解。以下示例来自 TileGym,团队在其中将一组 cuTile Python kernel 移植到 cuTile.jl,并将其打包为一个自包含的 Julia 子项目。

矩阵乘法示例

贯穿示例使用 matmul,它足够复杂,能够展示关键翻译挑战。除了基本语法差异外,翻译还必须处理循环结构、TF32 tensor core 转换,以及从行优先布局到列优先布局的转换。

正文:cuTile Python:

@ct.kernel
def matmul_kernel(A, B, C, tm: ct.Constant[int], tn: ct.Constant[int],
                  tk: ct.Constant[int]):
    bid_m = ct.bid(0)
    bid_n = ct.bid(1)

    num_k = ct.num_tiles(A, axis=1, shape=(tm, tk))
    acc = ct.full((tm, tn), 0, dtype=ct.float32)

    dtype = ct.tfloat32 if A.dtype == ct.float32 else A.dtype

    for k in range(num_k):
        a = ct.load(A, index=(bid_m, k), shape=(tm, tk),
                    padding_mode=ct.PaddingMode.ZERO)
        b = ct.load(B, index=(k, bid_n), shape=(tk, tn),
                    padding_mode=ct.PaddingMode.ZERO)
        a = a.astype(dtype)
        b = b.astype(dtype)
        acc = ct.mma(a, b, acc)

    acc = ct.astype(acc, C.dtype)
    ct.store(C, index=(bid_m, bid_n), tile=acc)

正文:cuTile.jl(Julia):

function matmul_kernel(A::ct.TileArray{T,2}, B::ct.TileArray{T,2}, C::ct.TileArray{T,2},
                      tm::Int, tn::Int, tk::Int) where {T}
    bid_m = ct.bid(1)
    bid_n = ct.bid(2)

    num_k = ct.num_tiles(A, 2, (tm, tk))
    acc = zeros(Float32, tm, tn)

    U = T === Float32 ? ct.TFloat32 : T

    for k in Int32(1):num_k
        a = ct.load(A; index=(bid_m, k), shape=(tm, tk), padding_mode=ct.PaddingMode.Zero)
        b = ct.load(B; index=(k, bid_n), shape=(tk, tn), padding_mode=ct.PaddingMode.Zero)
        a = convert(ct.Tile{U}, a)
        b = convert(ct.Tile{U}, b)
        acc = muladd(a, b, acc)
    end

    acc = convert(ct.Tile{T}, acc)
    ct.store(C; index=(bid_m, bid_n), tile=acc)
    return
end

除了基本语法变化外,请注意以下几点:

  • 布局会翻转:Python 中行优先的 A(M,K) 在 Julia 中变为列优先的 A_jl(K,M)。累加器、加载索引和存储索引都会相应改变。如果累加器形状弄错——例如使用 (TM, TN) 而不是 (TN, TM)——就会得到错误结果,且没有编译器警告。
  • ct.mma → muladd:cuTile.jl 将矩阵乘加映射为 Julia 标准的 muladd,而 ct.PaddingMode.ZERO 变为 ct.PaddingMode.Zero(PascalCase)。

Softmax 示例

Softmax 进一步增加了复杂度。Julia 中实现了三种策略——tensor memory accelerator(TMA)单 tile、online 和 chunked——以处理不同张量大小。在 matmul 模式之外,softmax 函数还引入了广播点语法(ct.exp(ct.sub(a, b)) → exp.(a .- b))、重命名的归约(ct.max → maximum、ct.sum → sum、axis +1),以及逐元素 ct.maximum(a, b) → max.(a, b)。

但真正的挑战并不是语法,而是在翻译过程中保持正确的运行中 max/sum 统计。

使用 agent skill 生成工作流

该项目的主要成果并不是翻译后的 kernel,而是用于生成它们的 skill。

A six-step workflow laid out left to right for producing a reusable GPU kernel, with labeled stages: Analyze Source Kernel, Load Rules and API Mappings, Reference Worked Examples, Generate CuTile.jl Kernel, Validate and Test, and Produce ReA six-step workflow laid out left to right for producing a reusable GPU kernel, with labeled stages: Analyze Source Kernel, Load Rules and API Mappings, Reference Worked Examples, Generate CuTile.jl Kernel, Validate and Test, and Produce Re
图 1. 转换 skill 将翻译规则、API 映射、示例、验证和测试打包为一个可复用工作流

在此语境下,skill 是位于代码仓库中的结构化知识目录,可由 LLM agent 读取。这个特定 skill 的路径是:.claude/skills/converting-cutile-to-julia/。

.claude/skills/converting-cutile-to-julia/
├── SKILL.md                           # Entry point: workflow overview, top pitfalls
├── translations/
│   └── workflow.md                    # Step-by-step conversion with checklists
├── references/
│   ├── api-mapping.md                 # Bidirectional Python↔Julia API table
│   ├── critical-rules.md              # 17 rules (indexing, broadcasting, loops, ...)
│   ├── debugging.md                   # Error diagnosis for MethodError, IRError, etc.
│   └── testing.md                     # Test patterns, tolerances per dtype
├── scripts/
│   └── validate_cutile_jl.py          # Static checker for common anti-patterns
└── examples/
    ├── 01_add/                        # Python→Julia for vector addition
    ├── 02_matmul/                     # Python→Julia for matrix multiply
    └── 03_softmax/                    # Python→Julia for softmax (3 strategies)

仅 critical-rules.md 就记录了团队遇到的 17 个陷阱。表 2 详细列出了最常见的陷阱及其对应修复方法。

#PitfallFix1max(a, b) on tiles → IRErrorUse max.(a, b) (broadcast dot)2ct.load with order — index positions wrongorder remaps BOTH shape AND index
表 2. 一些较常见问题中遇到的陷阱及其对应修复方法

此外还有一个静态验证脚本,可在 GPU 上运行之前捕获残留的 ct.bid(0)、kernel 内部的 for 循环以及 Python 风格类型名称等问题。具备这些内容后,模型不必每次都重新发现转换规则。它读取 skill,遵循检查清单,并应用规则。

TileGym 中的 AI agent skill

具体交付物是 TileGym 中 julia/ 目录下的一个 Julia 子项目,该项目是开源的:

julia/
├── Project.toml                # Dependencies: CUDA.jl, cuTile.jl, NNlib.jl, Test
├── kernels/
│   ├── add.jl                  # 1D element-wise with alpha scaling
│   ├── matmul.jl               # 2D tiled MMA with column-major layout
│   └── softmax.jl              # 3 strategies: TMA, online, chunked
└── test/
    ├── runtests.jl             # Test runner
    ├── test_add.jl
    ├── test_matmul.jl
    └── test_softmax.jl

这三个 kernel 是有意选择的。Kernel add 是用于测试完整翻译面的最简单方法。Matmul 增加了循环结构、tensor core 和布局翻转。Softmax 引入了多遍算法,其中的不变量必须在翻译后仍然成立。每个 kernel 都有测试,会按各 dtype 容差与 CPU 参考实现进行比较,包括维度无法对齐到 tile 大小的边界情况。

结果与经验教训

有了 skill 后,每个 kernel 的工作流如下:

  1. 预检:扫描源代码,查找需要特殊处理的模式(for 循环、ct.mma、order= 等)。
  2. 转换:应用 API 映射和关键规则。
  3. 验证:运行静态检查器。
  4. 测试:针对参考实现运行 Julia 测试。
  5. 修复:如果出现失败,使用调试指南进行修复,然后重新运行。

对于一个具有代表性的通用矩阵乘法(GEMM)转换,在一个前沿 LLM 上,该过程耗时约 4 分钟,使用约 78K tokens,且没有人工干预。后续 kernel 更快,因为示例和规则已经在仓库中。

表 3 列出了移植过程中导致 bug 的陷阱,这些现在都已在 skill 中自动处理。

PitfallSymptomRoot causect.bid(0) left unchangedWrong tile loaded, silent corruption0-based versus 1-based indexinga * b for element-wise multiplyMatrix multiply instead of element-wiseJulia * is matmul; need .*Accumulator shape (TM, TN)Wrong results in matmulColumn-major needs (TN, TM)ct.PaddingMode.ZEROUndefVarErrorJulia uses PascalCase: .Zero
表 3. 将 tile 代码从 Python 移植到 Julia 时导致 bug 的常见陷阱、症状和根因

要点并不是 AI 编写了代码,而是能够把学到的东西捕获下来,使模型下次可以复用。一个提示词可以说:“注意索引。”一个 skill 可以说:“这里列出了会出错的 17 个具体事项、检查方法,以及一个能自动捕获它们的脚本。”

现在,未来的移植可以从一个已经拥有可工作示例、经过测试的 API 映射、静态验证器和调试指南的仓库开始。每一次所需工作量都会少于上一次。

更广泛的启示是,在系统工作中使用 AI 的挑战并不在于代码生成,而在于在编译器无法捕获语义错误的领域中生成正确代码。将领域规则与其描述的代码一起编码进版本控制,是应对这一问题的一种方式。

开始使用 agent skill 将 Python kernel 翻译为 Julia

使用以下代码尝试 Julia 子项目和转换 skill:

cd TileGym

# Explore the Julia kernels
ls julia/kernels/     # add.jl, matmul.jl, softmax.jl

# Explore the conversion skill
ls .claude/skills/converting-cutile-to-julia/

# Install Julia dependencies (requires Julia 1.12+, CUDA 13.1+ driver)
julia --project=julia/ -e 'using Pkg; Pkg.instantiate()'

# Run the Julia kernel tests
julia --project=julia/ julia/test/runtests.jl

要求:

  • Julia 1.12+ 和 NVIDIA CUDA 13.1+ driver
  • NVIDIA Ampere、NVIDIA Ada 或 NVIDIA Blackwell GPU(compute capability 8.x、10.x、11.x、12.x)
  • 具备文件系统访问权限的 LLM agent(例如 Claude Code)。若要将转换 skill 用于你自己的 kernel,请将 LLM agent 指向 .claude/skills/converting-cutile-to-julia/SKILL.md,提供一个 cuTile Python kernel 作为输入,然后开始将 Python kernel 翻译为 Julia。
Like

标签

原文标题

Automating GPU Kernel Translation with AI Agents: cuTile Python to cuTile.jl