連続バッチ処理における非同期性の解放
本記事では、CPUとGPUのワークロードを分離することで推論性能を大幅に向上させる方法を解説します。連続バッチ処理はバッチを密に詰めることでGPU利用率を高めますが、同期動作によりCPUとGPUが交互に待機し、全実行時間の約4分の1を無駄にします。非同期バッチ処理では、デフォルト以外のCUDAストリームとイベントを使用してCPUとGPUを並列動作させ、待機時間を排除し、24%の無料高速化を実現します。記事では、CUDAストリーム、イベント、およびそれらを連続バッチ処理に適用する方法を詳しく説明し、transformersライブラリでの実装コードを紹介します。
記事インテリジェンス
要点
- 同期連続バッチ処理では、GPUがCPUを待つために約24%の時間が無駄になる。
- 非同期バッチ処理では、デフォルト以外のCUDAストリームとイベントを使用してCPUとGPUを並列化する。
- H2D、計算、D2Hの3つのストリームとイベント同期により、非同期パイプラインを構築する。
- 新しいカーネルやモデル変更は不要で、スケジューリングの最適化のみで実現できる。
重要な理由
このニュースが重要なのは、同期連続バッチ処理では、GPUがCPUを待つために約24%の時間が無駄になるためです。
技術的影響
モデル選定、推論コスト、プロダクト能力、評価基準に影響する可能性があります。
AI推論において、GPUの稼働率は重要です。H200インスタンスは1時間あたり約5ドル、1日で140ドルかかるため、GPUを常に稼働させなければなりません。連続バッチ処理はパディングによる無駄を削減しますが、同期モードではCPUとGPUが交互に待機するという新たな無駄が生じます。本記事では、非同期バッチ処理によりこの問題を解決します。
同期バッチ処理のループでは、CPUがバッチを準備する間GPUはアイドル状態になり、GPUが計算する間CPUはアイドル状態になります。実際の分析では、バッチサイズ32、8Bモデルで8Kトークンを生成するタスクにおいて、総処理時間300.6秒のうち24.0%がGPU待機時間でした。これはCPUオーバーヘッドを排除すれば、生成時間が228秒に短縮されることを意味し、24%の無料高速化が可能です。この最適化には新しいカーネルやモデル変更は一切不要で、ハードウェアの調整のみで実現できます。
非同期バッチ処理の鍵はCUDAストリームの使用です。デフォルトストリームは同期動作をするため、デフォルト以外のストリームを使用する必要があります。記事では操作をホストからデバイス(H2D)転送、計算、デバイスからホスト(D2H)転送の3つに分類し、それぞれに独立したストリームを割り当てます。しかしストリーム間のデータ依存性を解決するために、CUDAイベントを使用した同期が必要です。イベントはストリームに記録できるマーカーであり、他のストリームはそのイベントが完了するまで待機できます。例えば、計算ストリームはH2D転送が完了するまで待機します。
具体的な実装では、CPUはH2D転送を発行後イベントを記録し、計算ストリームはそのイベントを待ってから計算を開始します。計算完了後さらにイベントを記録し、D2Hストリームがそれを待って転送を開始します。すべての操作はCPUから非同期に発行され、実際の実行はGPUがスケジュールします。これにより、CPUは現在のバッチ実行中に次のバッチの準備を開始でき、パイプライン並列が実現します。記事では、デッドロックを避けるための正しいイベント使用法や、transformersライブラリへの統合方法についても議論しています。非同期バッチ処理はtransformersライブラリの連続バッチ処理に実装されており、コードはオープンソースです。最終的にGPU稼働率はほぼ100%に向上し、スループットが大幅に改善されます。また、CPU起動オーバーヘッドの概念や、ストリームとイベントによる正確な同期方法についても詳しく説明されており、非同期バッチ処理の動作原理を深く理解できます。