NVIDIA CUDA.computeでGPU MODEカーネルリーダーボードをトップに
NVIDIAのCUDA.computeがGPU MODEカーネルリーダーボードで最高性能を達成したことを紹介する技術記事。
キーポイント
NVIDIA cuda.computeは、Python開発者がC++の知識なしに高度に最適化されたCUDAカーネルを利用できる新たなフレームワークを提供
GPU MODE Kernel Leaderboardで複数GPUアーキテクチャにおいて首位を獲得し、CUB実装が他手法より2~4倍高速な性能を示した
JITコンパイルによる迅速な開発サイクルと、カスタムデータ型・演算子の柔軟なサポートにより、生産性と性能を両立
CCCLチームの「速度限界」実装アプローチが、標準プリミティブ向けカスタムカーネルの開発期間を大幅に短縮する可能性を示唆
影響分析・編集コメントを表示
影響分析
この技術は、機械学習研究と実装の間にある重要な障壁を解消し、より多くのPython開発者がGPUのフルパフォーマンスを活用できるようになる。AI/機械学習分野全体の開発効率と性能最適化の民主化を促進する可能性がある。
編集コメント
PythonとGPUパフォーマンスの長年の課題に実用的な解決策を提供する画期的な進展。AI研究の実装ハードルを下げ、より広範なイノベーションを促す可能性が高い。
機械学習分野ではPythonがその使いやすさから支配的ですが、真に高速なGPUコードを書くことは、これまでC++に降りてカスタムカーネルを書き、Pythonへのバインディングを維持することを意味してきました。ほとんどのPython開発者や研究者にとって、これは大きな参入障壁です。
PyTorchのようなフレームワークは、CUDA C++でカーネルを実装することでこの問題に対処しています。手書きのカーネルもあれば、NVIDIA CUDA Core Compute Librariesのようなライブラリを活用する場合もあります。手書きのカーネルは時間がかかり、深い低レベルアーキテクチャの専門知識を必要とします。CCCL内のC++ライブラリであるCUBを使用する方が、多くの場合優れています。そのプリミティブはアーキテクチャごとに高度に最適化され、厳密にテストされているからです。しかし、CUBをPythonに公開するには、従来はバインディングの構築と維持、そして固定された型と演算子によるC++テンプレートの事前インスタンス化が必要でした。これはPython側での柔軟性を制限します。
NVIDIA cuda.compute
cuda.compute
NVIDIA CCCLチームは、高レベルの抽象化を通じてGPUアーキテクチャ全体で並列プリミティブの「光速」(SOL)実装を提供することに焦点を当てています。テストされたGPUアーキテクチャ(NVIDIA B200、NVIDIA H100、NVIDIA A100、NVIDIA L4)全体で、最も多くの1位を獲得しました。
このブログでは、私たちがどのようにしてリーダーボードで高い順位を獲得できたかについて、より詳細に共有します。
CUDA Python: GPUパフォーマンスと生産性の融合
CUBは、GPU MODE競技で注目された一般的な並列操作を含む、高度に最適化されたCUDAカーネルを提供します。これらのカーネルはアーキテクチャ的に調整されており、光速に近い実装として広く認識されています。
cuda.compute
cuda.compute
Pythonでの高速で構成可能なCUDAワークフロー: Python内で直接、効率的でモジュール化されたCUDAアプリケーションを開発できます。
カスタムデータ型と演算子: C++バインディングを必要とせずに、カスタムデータ型と演算子を利用できます。
最適化されたパフォーマンス: 実績あるCUBプリミティブを通じて、アーキテクチャを意識したパフォーマンスを実現します。
迅速な反復: JITコンパイルにより開発を加速しつつ、CUDA C++レベルのパフォーマンスを維持します。JITコンパイルは、パフォーマンスを損なうことなく開発者が必要とする柔軟性と迅速な反復サイクルを提供することで、開発サイクルを加速します。
リーダーボードの結果
cuda.compute
ソートのようなアルゴリズムでは、CUBの実装は次点の提出よりも2倍から4倍高速でした。これがCCCLの約束の実践です:標準的なプリミティブにおいて、数ヶ月かけて構築するようなカスタムカーネルを上回る、SOLクラスのアルゴリズムです。
1位を獲得できなかった場合、その差は通常、特定のGPUに対するチューニングポリシーを持っていなかったことに起因します。いくつかの例では、私たちの実装はより一般的な解決策でしたが、より上位の提出は特定の問題サイズに特化したものでした。
他のケースでは、1位の提出はすでにCUBまたはcuda.compute
これは勝つことについてではない
リーダーボードの結果は副産物です。真の目的は、コミュニティと共に学び、透明性を持ってベンチマークを行い、高性能GPU作業におけるPythonの力を実証することです。
私たちの目標は、手書きのCUDAカーネルを妨げることではありません。カスタムカーネルには正当なケースがたくさんあります。新しいアルゴリズム、緊密な融合、特殊なメモリアクセスパターンなどです。しかし、標準的なプリミティブ(ソート、スキャン、リダクション、ヒストグラムなど)については、最初の選択肢は実績のある高性能な実装であるべきです。cuda.compute
これは、次のCuPyやRAPIDSコンポーネント、あるいはカスタムのPython GPUアクセラレーションライブラリを構築しているすべての人にとって素晴らしいニュースです:純粋なPythonに留まりながら、より速い反復、より少ない接着層、そしてプロダクショングレードのパフォーマンスをすべて実現できます。
cuda.compute
GPUプログラミングを学ぶ際に誰もが最初に書く例の一つは、ベクトル加算です。cuda.computeを使用すると、デバイス全体のプリミティブを呼び出すことで、純粋なPythonを使ってこれを解決できます。
import cuda.compute
from cuda.compute import OpKind
ビルド時テンソル(呼び出し可能オブジェクトを特殊化するために使用)
build_A = torch.empty(2, 2, dtype=torch.float16, device="cuda")
build_B = torch.empty(2, 2, dtype=torch.float16, device="cuda")
build_out = torch.empty(2, 2, dtype=torch.float16, device="cuda")
JITコンパイルによる変換カーネル
transform = cuda.compute.make_binary_transform(build_A, build_B, build_out, OpKind.PLUS)
GPU MODE競技に提出するには custom_kernel の定義が必要
def custom_kernel(data):
# 入力データに対して変換操作を呼び出す
A, B, out = data
transform(A, B, out, A.numel())
return out
原文を表示
Python dominates machine learning for its ergonomics, but writing truly fast GPU code has historically meant dropping into C++ to write custom kernels and to maintain bindings back to Python. For most Python developers and researchers, this is a significant barrier to entry.
Frameworks like PyTorch address this by implementing kernels in CUDA C++—either handwritten or by leveraging libraries like the NVIDIA CUDA Core Compute Libraries. Handwritten kernels are time-consuming and require deep, low-level architectural expertise. Using CUB, a C++ library within CCCL, is often better, since its primitives are highly optimized per architecture and are rigorously tested. But exposing CUB to Python traditionally means building and maintaining bindings and pre-instantiating C++ templates with fixed types and operators—limiting flexibility on the Python side.
The NVIDIA cuda.compute
Using cuda.compute
The NVIDIA CCCL team focuses on delivering “speed-of-light” (SOL) implementations of parallel primitives across GPU architectures through high-level abstractions. It achieved the most first-place finishes overall on the tested GPU architectures: NVIDIA B200, NVIDIA H100, NVIDIA A100, and NVIDIA L4.
In this blog we’ll share more details about how we were able to place so high on the leaderboard.
CUDA Python: GPU performance meets productivity
CUB offers highly optimized CUDA kernels for common parallel operations, including those featured in the GPU MODE competition. These kernels are architecturally tuned and widely considered near speed-of-light implementations.
The cuda.compute
With cuda.compute
Fast, composable CUDA workflows in Python: Develop efficient and modular CUDA applications directly within Python.
Custom data types and operators: Utilize custom data types and operators without the need for C++ bindings.
Optimized performance: Achieve architecture-aware performance through proven CUB primitives.
Rapid iteration: Accelerate development with JIT compilation while maintaining CUDA C++ levels of performance. JIT compilation accelerates the development cycle by providing the flexibility and rapid iteration cycles that developers need without compromising performance.
The leaderboard results
Using cuda.compute
For algorithms like sort, the CUB implementation was two-to-four times faster than the next best submission. This is the CCCL promise in action: SOL‑class algorithms that outperform custom kernels for standard primitives you’d otherwise spend months building.
Where we didn’t take first place, the gap typically came down to us not having a tuning policy for that specific GPU. In some instances, our implementation was a more general solution, while higher-ranked submissions were specialized to specific problem sizes.
In other cases, the first place submission was already using CUB or cuda.compute
This isn’t about winning
Leaderboard results are a byproduct; the real objective is learning with the community, benchmarking transparently, and demonstrating the power of Python for high-performance GPU work.
Our goal isn’t to discourage hand-written CUDA kernels. There are plenty of valid cases for custom kernels—novel algorithms, tight fusion, or specialized memory access patterns—but for standard primitives (sort, scan, reduce, histogram, etc.), your first move should be a proven, high-performance implementation. With cuda.compute
This is great news for anyone building the next CuPy, RAPIDS component, or a custom Python GPU accelerated library: faster iteration, fewer glue layers, and production-grade performance all while staying in pure Python.
How cuda.compute
One of the first examples any person writes when learning GPU programming is a vector addition. Using cuda.compute we can solve this using pure Python by calling a device-wide primitive.
import cuda.compute from cuda.compute import OpKind # Build-time tensors (used to specialize the callable) build_A = torch.empty(2, 2, dtype=torch.float16, device="cuda") build_B = torch.empty(2, 2, dtype=torch.float16, device="cuda") build_out = torch.empty(2, 2, dtype=torch.float16, device="cuda") # JIT compiling the transform kernel transform = cuda.compute.make_binary_transform(build_A, build_B, build_out, OpKind.PLUS) # Defining custom_kernel is required to submit to the GPU MODE competition def custom_kernel(data): # Invoking our transform operation on some input data A, B, out = data transform(A, B, out, A.numel()) return out
関連記事
今日のまとめ
AI日報で今日の重要ニュースをまとめ読み