跳到主内容
精选85Hacker News Best(web_list)技巧与观点

用 Codex 自动研究实现内核 232 倍加速

原文
推荐理由

做 GPU 内核优化的同学必看,这篇复盘给出了完整的自动研究流程、分块 Householder 算法和 WY 更新的实现思路,还有跳出局部最优的实操技巧,值得收藏。

Auto-research with codex: How I achieved a 232x Faster Kernel over baseline with Codex in GPU Mode's qr_v2 problem

使用 codex 进行自动研究:我如何在 GPU Mode 的 qr_v2 问题中通过 Codex 实现比基线快 232 倍的内核

08 Jul, 2026

2026年7月8日

Table of Contents

目录

  • Intro
  • Contest in short
  • Problem intro
  • Why this problem is auto-research-able
  • Learning Enough to Ask Better Questions
  • (Optional) Math for QR decomposition: Householder reflections
  • Make serial work small with the help of the blocked Householder algorithm
  • Other challenges
  • Codex-maxxing
  • Kernel progress breakthroughs
  • Breakthrough ideas
  • Introducing idea diversity to escape the local maxima
  • Implementation Hints
  • What I could have done better
  • Conclusion
  • References
  • Acknowledgements
  • 引言
  • 竞赛简介
  • 问题介绍
  • 为什么这个问题适合自动研究
  • 学习足够知识以提出更好的问题
  • (可选)QR 分解的数学:Householder 反射
  • 利用分块 Householder 算法使串行工作变小
  • 其他挑战
  • 最大化利用 Codex
  • 内核进展突破
  • 突破性想法
  • 引入想法多样性以逃离局部最优
  • 实现提示
  • 我本可以做得更好的地方
  • 结论
  • 参考文献
  • 致谢

Intro

引言

Contest in short

竞赛简介

GPU Mode, in collab with Core Automation, recently hosted an auto-research themed contest. The problem statement was to implement batched square compact-Householder QR factorization aka QR decomposition. I placed 12th out of 183 participants, ending up with a 232x speedup over the baseline solution. This post is about how I got there. I will go through my approach, learnings, and bottlenecks I ran into during the contest. It was my first serious attempt at auto-research. Some people will call this "loop engineering", and honestly that is fine too.

GPU Mode 与 Core Automation 合作,最近举办了一场以自动研究为主题的竞赛。问题陈述是实现批量方形紧凑 Householder QR 分解,即 QR 分解。我在 183 名参与者中排名第 12,最终比基线解决方案实现了 232 倍的加速。这篇文章讲述了我如何达到这一目标。我将介绍我的方法、学到的经验以及竞赛中遇到的瓶颈。这是我第一次认真尝试自动研究。有些人会称之为“循环工程”,老实说,这也没关系。

Note that you don't need to go through the mathematics or the problem itself in detail to follow most of this blog post. I have focused on my approach while keeping the math and the problem itself secondary as most people who will read this won't have participated in the contest.

请注意,你不需要详细了解数学或问题本身就能理解这篇博客的大部分内容。我专注于我的方法,而将数学和问题本身放在次要位置,因为大多数阅读本文的人可能没有参加竞赛。

You can check out the full contest page here: Problem Link and Leaderboard

你可以在这里查看完整的竞赛页面:问题链接和排行榜

This contest was part of GPU Mode's Linear Algebra Kernels in the Age of Research series.

本次竞赛是 GPU Mode 的“研究时代的线性代数内核”系列的一部分。

Problem intro

问题介绍

We were given a batch of square FP32 CUDA matrices A with shape batch x n x n, and had to return the same compact Householder QR representation as torch.geqrf(A): an H matrix whose upper triangle is R and whose lower triangle stores Householder vectors, plus a tau vector of reflector coefficients. The checker rebuilt Q with torch.linalg.householder_product(H, tau), took R = triu(H), and verified:

我们得到一批形状为 batch x n x n 的方形 FP32 CUDA 矩阵 A,需要返回与 torch.geqrf(A) 相同的紧凑 Householder QR 表示:一个 H 矩阵,其上半部分为 R,下半部分存储 Householder 向量,以及一个反射系数 tau 向量。检查器使用 torch.linalg.householder_product(H, tau) 重建 Q,取 R = triu(H),并验证:

A≈QR,Q⊤Q≈I,Q⊤A≈R

A≈QR, Q⊤Q≈I, Q⊤A≈R

Among correct submissions, the leaderboard ranked runtime by geometric mean across shapes and conditioning cases. The important sizes were batched square matrices like 512 x 512, with larger 1024, 2048, and 4096 cases too. Low-bit FP16, FP8, or NVFP4 was allowed internally, but returned factors still had to satisfy FP32-style QR checks.

在正确的提交中,排行榜根据形状和条件数情况的几何平均值对运行时间进行排名。重要的尺寸是批处理的方形矩阵,如 512 x 512,也有更大的 1024、2048 和 4096 的情况。内部允许使用低比特 FP16、FP8 或 NVFP4,但返回的因子仍必须满足 FP32 风格的 QR 检查。

A tiny 3 x 3 example is:

一个小的 3 x 3 示例是:

A=[12−5146167−68−424−41]=[6/7−69/175−58/1753/7158/1756/175−2/76/35−33/35]⏟Q[1421−140175−700035]⏟R

A=[12−5146167−68−424−41]=[6/7−69/175−58/1753/7158/1756/175−2/76/35−33/35]⏟Q[1421−140175−700035]⏟R

Here Q is orthogonal, which means its columns are unit-length and perpendicular to each other, and R is upper triangular, which means everything below the diagonal is zero. The contest was not asking us to print dense Q and R directly; it asked for the compact Householder version that lets the checker reconstruct Q and read R from the upper triangle.

这里 Q 是正交的,这意味着它的列是单位长度且相互垂直,R 是上三角矩阵,这意味着对角线以下的所有元素为零。竞赛不是要求我们直接打印稠密的 Q 和 R;它要求的是紧凑的 Householder 版本,让检查器能够重建 Q 并从上半部分读取 R。

For the 3×3 example above, the very first reflector maps the first column (12, 6, −4) straight onto (−14, 0, 0) in one shot. The −14 becomes R11. How that works is in the math section.

对于上面的 3×3 示例,第一个反射器将第一列 (12, 6, −4) 一步映射到 (−14, 0, 0)。−14 成为 R11。其原理在数学部分说明。

Why this problem is auto-research-able

为什么这个问题可以自动研究

GPU Mode provides participants with the popcorn CLI making it agent-friendly. Agents can use this to test, benchmark, and submit to the leaderboard directly. The checker also provided shape-wise feedback along with the overall geometric mean timing.

GPU Mode 为参与者提供了 popcorn CLI,使其对智能体友好。智能体可以使用它进行测试、基准测试并直接提交到排行榜。检查器还提供了形状级别的反馈以及总体几何平均时间。

Astute observers will notice this is an apt setup for writing a loop. Agents yearn for tight feedback loops. They allow them to hill-climb to their heart's content.

敏锐的观察者会注意到,这是一个适合编写循环的设置。智能体渴望紧密的反馈循环。它们允许智能体尽情地爬山。

GPU Mode contests usually give you some way to iterate on kernels. Either you submit directly, or a sponsor like Modal chips in credits. Here the organizers basically allowed unlimited submissions as long as you spaced them out. If you didn't, the queues got long and everybody's runs timed out. At one point the workspace even ran out of Modal credits because everyone had been hammering submissions. It's a nice way to make learning accessible.

GPU Mode 竞赛通常会提供某种方式来迭代内核。要么直接提交,要么像 Modal 这样的赞助商提供积分。这里组织者基本上允许无限次提交,只要间隔开。如果不这样做,队列会变长,每个人的运行都会超时。有一次,工作区甚至用完了 Modal 积分,因为每个人都在猛击提交。这是一种让学习变得可及的好方法。

Over the course of 14 days, I made over 1500 submissions.

在14天的时间里,我提交了超过1500次。

Learning Enough to Ask Better Questions

学得足够多,才能提出更好的问题

I have known the basics of GPU kernel optimization (mainly in Triton with some understanding of CUDA) for a year, but haven't worked in this domain professionally. What I am trying to tell you is that I was an underdog among the people around me on the leaderboard. The person just above me on the leaderboard (CUDA Colonel) is a principal engineer at NVIDIA.

我了解GPU内核优化的基础知识(主要是Triton,对CUDA也有一些理解)已经一年了,但并未在这个领域专业工作过。我想告诉你的是,在排行榜上,我是周围人中的弱者。排行榜上排在我上面的人(CUDA上校)是NVIDIA的首席工程师。

Anyway aura farming aside, since I know the basics and had recently read about GatedDeltaNet, I was fresh on the general GPU kernel lingo.

不管怎样,抛开炫耀不谈,因为我了解基础知识,并且最近读过关于GatedDeltaNet的内容,所以我对GPU内核术语还算熟悉。

The better you know something, the better you can prompt the LLMs, because you convert unknown unknowns into known unknowns.

你对某件事了解得越好,就越能更好地向LLM提问,因为你把未知的未知转化为了已知的未知。

At the same time, it's worth noting that this contest was doable without domain knowledge - like you probably won't make it to the top 10, but you can get a respectable speedup over baseline by just relying on your harness/agent loop or whatever.

同时,值得注意的是,这个竞赛没有领域知识也能参与——你可能进不了前十,但通过依靠你的工具链或代理循环等,你可以获得比基线显著的加速。

My first steps in the contest were to learn what QR decomposition is and how it can be done. There are a bunch of ways to do it - like Gram-Schmidt and Householder reflections. The contest mandated Householder reflections. I went back and forth with Claude and watched a few YouTube videos to build intuition. After my discussions with Claude, it was clear that we needed to use the blocked Householder algorithm as the main architecture with the trailing WY-update. As it turns out, GPT-5.5 also had a good idea about this. QR decomposition is a fairly well known problem.

我在竞赛中的第一步是学习什么是QR分解以及如何实现。有很多方法可以做到这一点——比如Gram-Schmidt和Householder反射。竞赛要求使用Householder反射。我和Claude反复讨论,并观看了一些YouTube视频来建立直觉。在与Claude讨论后,很明显我们需要使用分块Householder算法作为主要架构,并采用尾随WY更新。事实证明,GPT-5.5对此也有很好的想法。QR分解是一个相当知名的问题。

I found the concept interesting as matrix decompositions show up in several modern optimizer variants for LLM training, especially in methods that use matrix preconditioning, such as Shampoo-style optimizers and related approaches. Muon (used by Kimi) is another good example: instead of treating a weight update as one giant flattened vector, it keeps the matrix structure around and orthogonalizes the momentum update, usually through a few Newton-Schulz iterations that approximate the polar factor.

我觉得这个概念很有趣,因为矩阵分解出现在LLM训练的几种现代优化器变体中,尤其是在使用矩阵预条件的方法中,比如Shampoo风格的优化器及相关方法。Muon(Kimi使用)是另一个好例子:它不将权重更新视为一个巨大的扁平向量,而是保持矩阵结构,并通过几次Newton-Schulz迭代来正交化动量更新,这些迭代近似于极因子。

(Optional) Math for QR decomposition: Householder reflections

(可选)QR分解的数学:Householder反射

I recommend skimming through this section if you are curious about the math otherwise feel free to skip. The only thing to note is that there is a sequential dependency in Householder QR which makes it problematic to do GEMM. We use blocked Householder to make it more matrix-multiplication shaped.

如果你对数学好奇,我建议浏览这一节,否则可以跳过。唯一需要注意的是,Householder QR中存在顺序依赖,这使得进行GEMM变得困难。我们使用分块Householder使其更符合矩阵乘法的形状。

The contract

合同

Quickly reviewing the contract: input is a batch of square FP32 matrices A; output is the compact (H, tau) format that torch.geqrf returns. The upper triangle of H is R. Below the diagonal, H stores the Householder vectors, and tau stores one scalar per column. The checker rebuilds Q from (H, tau) and verifies A ≈ QR.

快速查看合同:输入是一批方阵 FP32 矩阵 A;输出是 torch.geqrf 返回的紧凑格式 (H, tau)。H 的上三角部分是 R。对角线以下,H 存储 Householder 向量,tau 每列存储一个标量。检查器从 (H, tau) 重建 Q,并验证 A ≈ QR。

Mirrors

镜子

Forget matrices for a second. In a bathroom mirror, your reflection is exactly as far behind the glass as you are in front of it, straight through.

暂时忘掉矩阵。在浴室的镜子里,你的倒影在玻璃后面的距离,恰好等于你在玻璃前面的距离,直线穿过。

If x⟂ is the part of x sticking out perpendicular to the glass, reflection just subtracts that part twice:

如果 x⟂ 是 x 垂直于玻璃伸出的部分,反射只是减去那部分两次:

xreflected=x−2x⟂

x反射 = x − 2x⟂

So a Householder reflection is about finding the perpendicular part and subtracting it twice.

所以 Householder 反射就是找到垂直部分并减去两次。

Storing the mirror

存储镜子

A Householder vector is the mirror, stored compactly. In code, we don't carry around the whole mirror plane. We store one vector v sticking straight out of it. The mirror is everything perpendicular to v, and the reflection moves along v.

Householder 向量就是镜子,以紧凑形式存储。在代码中,我们不携带整个镜面。我们存储一个从镜面伸出的向量 v。镜面是垂直于 v 的一切,反射沿 v 方向移动。

The perpendicular part is just the shadow of x along v, which is v⊤xv⊤v copies of v. Plug that into the subtraction above:

垂直部分就是 x 沿 v 的投影,即 (v⊤x)/(v⊤v) 个 v。将其代入上面的减法:

ℋx=x−τv(v⊤x),τ=2v⊤v

ℋx = x − τv(v⊤x),τ = 2/(v⊤v)

So tau is just 2v⊤v: the factor of 2 and the length of v bundled into one precomputed number. v picks the mirror, tau scales the update. (I'll write the mathematical reflector as ℋj and reserve H for the compact output matrix.)

所以 tau 就是 2/(v⊤v):将因子 2 和 v 的长度捆绑成一个预计算的数字。v 选择镜子,tau 缩放更新。(我将数学反射器写为 ℋj,并保留 H 用于紧凑输出矩阵。)

Householder reflection in 2D tau = 0.00

二维 Householder 反射 tau = 0.00

x reflected x v x_parallel x_perp Mirror rule: keep x_parallel, flip x_perp. So reflected x = x - 2x_perp.

x 反射 x v x_parallel x_perp 镜子规则:保留 x_parallel,翻转 x_perp。所以反射的 x = x - 2x_perp。

更进一步:量化金融体系

看懂新闻只是起点——沿量化金融路径,把它变成能交付的工程能力

进入量化体系 →

相似阅读

另一事件,读法相近