Hugging FaceのKernel Builderで本番向けCUDAカーネルを構築・拡張

Huggingface

カスタムCUDAカーネルは、機械学習モデルから最大の性能を引き出すことを目指す開発者にとって不可欠であり、速度と効率において大きな優位性を提供します。しかし、基本的なGPU関数から、実世界でのデプロイメントに対応できる堅牢でスケーラブルなシステムへの道のりは、複雑なビルドプロセスの操作から依存関係の迷宮の管理まで、多くの課題に満ちています。この複雑なワークフローを効率化するため、Hugging Faceはkernel-builderを導入しました。これは、多様なアーキテクチャにわたるカスタムカーネルの開発、コンパイル、配布を簡素化するために設計された専門ライブラリです。このガイドでは、現代のCUDAカーネルをゼロから構築するプロセスを深く掘り下げ、そして今日のエンジニアが直面する一般的な本番およびデプロイメントの課題に対処するための実践的な戦略を探ります。

kernel-builderによって促進される現代のCUDAカーネルプロジェクトは、その核において構造化された構成に従います。例えば、RGB画像をグレースケールに変換するために設計された実用的なカーネルを考えてみましょう。このようなプロジェクトは通常、ファイルを明確な階層に整理します。プロジェクトのマニフェストとして機能し、ビルドプロセスを調整するbuild.tomlファイル。GPU計算が展開される生のCUDAソースコードを格納するcsrcディレクトリ。特定の依存関係のバージョンをロックすることで完全に再現可能なビルド環境を保証するflake.nixファイル。そして、生のPyTorchオペレーターを公開するPythonラッパーを含むtorch-extディレクトリです。build.tomlファイルは、何をコンパイルするか、およびコンポーネントがどのように相互にリンクするかを定義し、PyTorchバインディング用のC++ファイルとカーネル自体のCUDAソースを指定し、多くの場合、テンソル操作のためのPyTorchライブラリなどの依存関係を宣言します。flake.nixファイルは、kernel-builderのバージョンとその依存関係を正確に固定することで、悪名高い「私のマシンでは動作する」問題を排除し、カーネルがどのマシンでも一貫してビルドできることを保証するために不可欠です。

実際のGPUの魔法はCUDAカーネルコード内にあり、img2gray_kernelのような関数は、2Dスレッドグリッドを使用してデータを処理するように定義されています。これは画像操作において本質的に効率的なアプローチです。各スレッドは単一のピクセルを処理し、輝度値に基づいてRGBからグレースケールへの変換を実行します。決定的に重要なのは、この低レベルのCUDA関数がC++バインディングを介してPyTorchエコシステムに公開され、ネイティブPyTorchオペレーターとして登録されることです。この登録は極めて重要です。なぜなら、これによりカスタム関数がPyTorch内でファーストクラスの市民となり、torch.ops名前空間の下で可視になるからです。この深い統合は2つの大きな利点を提供します。1つはtorch.compileとの互換性で、PyTorchがカスタム操作をより大きな計算グラフに融合させ、オーバーヘッドを最小限に抑え、パフォーマンスを最大化できるようにします。もう1つはハードウェア固有の実装を提供する能力で、PyTorchのディスパッチャが入力テンソルのデバイスに基づいて適切なバックエンド(例:CUDAまたはCPU)を自動的に選択できるようにし、それにより移植性を向上させます。最後に、torch-extディレクトリ内の__init__.pyファイルにあるPythonラッパーは、登録されたC++関数へのユーザーフレンドリーなインターフェースを提供し、ネイティブオペレーターを呼び出す前に、入力検証とテンソル割り当てを処理します。

カーネルの構築は、kernel-builderツールによって簡素化されます。反復的な開発のために、Nixシェルは必要なすべての依存関係がプリインストールされた分離されたサンドボックスを提供し、開発者が変更を迅速にコンパイルしてテストすることを可能にします。この環境は、特定のPyTorchおよびCUDAバージョンに合わせて構成でき、正確な互換性を保証します。次に、build2cmakeコマンドは、CMakeLists.txtpyproject.tomlsetup.pyなどの重要なビルドファイルを生成します。これらはCMakeによってカーネルのコンパイルに使用されます。Python仮想環境をセットアップした後、カーネルはpipを使用して編集可能なモードでインストールでき、すぐにテストできるようになります。簡単な健全性チェックスクリプトは、カーネルが正しく登録され、期待通りに機能することを確認し、開発中の迅速なイテレーションを可能にします。

カーネルが機能するようになったら、それをより広範な開発者コミュニティと共有することが次のステップです。配布する前に、開発成果物をクリーンアップすることをお勧めします。その後、kernel-builderツールは、サポートされているすべてのPyTorchおよびCUDAバージョン向けにカーネルをビルドするプロセスを自動化し、広範な互換性を確保します。これにより、さまざまな環境にデプロイできる「準拠カーネル」が生成されます。コンパイルされた成果物は、kernelsライブラリがそれらを見つけるための標準的な場所であるbuildディレクトリに移動されます。最後のステップは、Git LFSを使用してこれらのビルド成果物をHugging Face Hubにプッシュし、カーネルを簡単にアクセス可能にすることです。開発者は、Hubリポジトリからカスタムオペレーターを直接ロードして使用でき、ダウンロード、キャッシュ、登録が自動的に処理されます。

最初のデプロイメントを超えて、本番環境でカスタムカーネルを管理するには堅牢な戦略が必要です。バージョン管理は、APIの変更を適切に処理するための鍵です。Gitコミットのショートハッシュは基本的な固定形式を提供しますが、セマンティックバージョニング(例:v1.1.2)は、より解釈しやすく管理しやすいアプローチを提供します。kernelsライブラリはバージョン範囲の指定をサポートしており、ダウンストリームユーザーが定義されたシリーズ内で最新の互換性のあるカーネルを自動的に取得できるようにし、安定性とアップデートへのアクセスを両立させます。大規模なプロジェクトの場合、kernelsはプロジェクトレベルの依存関係管理システムを提供し、カーネルの要件はpyproject.tomlで指定されます。kernels lockコマンドはkernels.lockファイルを生成し、プロジェクト全体の特定のカーネルバージョンを固定します。これはバージョン管理にコミットして、すべてのユーザーの一貫性を確保できます。get_locked_kernel関数は、これらの固定されたバージョンをロードするために使用され、予測可能な環境を保証します。Dockerイメージなどのランタイムダウンロードが望ましくないシナリオでは、load_kernel関数を使用してプリダウンロードされたカーネルをロードでき、kernels downloadユーティリティはカーネルをコンテナイメージに直接組み込むのを容易にします。直接Hubダウンロードはバージョン管理と再現性における利点から推奨されますが、kernelsユーティリティは従来のPython wheelsの作成もサポートしており、あらゆるHubカーネルを、レガシーなデプロイメントニーズに対応する様々なPython、PyTorch、CUDA構成と互換性のあるwheelsのセットに変換できます。

この包括的なアプローチは、初期のカーネル開発とPyTorch統合から、高度なバージョン管理とデプロイメント戦略まで、開発者がかつてないほど簡単に高性能なカスタムCUDAカーネルを構築し、管理することを可能にします。kernel-builderやHugging Face Hubのようなツールを活用することで、コミュニティはオープンで協力的な開発を促進し、アクセラレーテッドコンピューティングにおけるイノベーションを推進することができます。