著者 | ピエール・リアンハート 編纂者:岳陽 前回の記事では、キーバリュー(KV)キャッシュの最適化手法について考察しました。この記事では、機械学習モデルの速度に影響を与える可能性のある様々なパフォーマンスボトルネックに焦点を当てます。ここで紹介する内容は、あらゆる機械学習モデル(学習用、推論用を問わず)に広く適用できます。ただし、理解を容易にするため、ここでは大規模言語モデル(LLM)を用いた推論シナリオを例に挙げます。 この記事を読む前に、この記事に多大なインスピレーションを与えた参考文献[1] (https://horace.io/brrr_intro.html)を読むことを強くお勧めします。 01 モデルパフォーマンスのボトルネックの4つの主な種類モデルの現在のパフォーマンスに満足しておらず、最適化に時間をかける覚悟がある場合、最初のステップはボトルネックの種類を特定することです。パフォーマンスのボトルネックは主に4つのカテゴリに分類でき、そのうち3つはハードウェアの制限に関連し、1つはソフトウェアに関連しています。 まず、ハードウェア関連のボトルネックについて説明します。各ボトルネックは、特定の動作状態またはモードに対応しています。
図 1 – 計算依存プロセス。計算プロセスとデータ転送プロセスはそれぞれ黄色と青で強調表示されています。
図 2 – メモリ帯域幅が制限されたプロセス。計算プロセスとデータ転送プロセスはそれぞれ黄色と青でマークされています。
図 3 – 通信バウンド プロセス。計算プロセス、データ転送プロセス、ネットワーク通信プロセスはそれぞれ黄色、青、緑でマークされています。 注意: これらの概念は、CPU、GPU、カスタム チップ (Google の TPU、AWS の Neuron Core など) など、あらゆるタイプのチップに適用されるため、「チップ」という用語を使用しています。 現在のコンピューティングハードウェアとAIフレームワークは高度に最適化されており、計算タスクとデータ転送タスクが同時に発生することがよくあります(図4参照)。本稿では、説明を簡潔にするため、これらのタスクは順次実行されるものと仮定します。 図 4 — データ転送が他の操作 (計算など) と同時に発生する可能性がある通信依存のプロセス。
図 5 – オーバーヘッド バウンド プロセス: 計算、データ転送、ソフトウェア実行に費やされる追加時間は、それぞれ黄色、青、紫でマークされています。 実行モデルの順方向伝播または逆方向伝播は、複数のカーネル関数またはプログラムセグメントをGPU上で並列に実行することを伴います。通常、すべてのカーネルを同じメカニズムで実行することは不可能です。したがって、どのメカニズムが多くの時間を消費しているかを特定することが鍵となります。次に、この主要なパフォーマンスボトルネックの最適化を優先し、次に影響の大きいボトルネックを特定する、というように進めていきます。 パフォーマンスボトルネックの種類を正確に特定することは非常に重要です。パフォーマンスの問題ごとに異なる解決策が必要です。診断が誤っていると、最適化対策を実施しても効果は大幅に低下し、間違いなく時間の無駄になります。 02 システムパフォーマンスを制限する主な要因を特定する本稿ではこの話題には深く立ち入りませんが、参考文献[1]では、オーバーヘッド制約がある場合、消費時間は計算量やデータ転送量の増加に比例して増加しないことが強調されています。つまり、計算能力やデータ転送能力を高めても、プログラムの実行時間がそれに応じて増加しない場合は、そのプログラムはオーバーヘッド制約を受けている可能性が高いです。そうでない場合、プログラムのパフォーマンスはハードウェアのボトルネックに遭遇する可能性がありますが、計算ボトルネックとメモリ帯域幅のボトルネックを区別するには、FLOP数(システムまたはアルゴリズムが1秒間に実行できる浮動小数点演算の数)やデータ転送量などの指標を使用する必要があります。つまり、パフォーマンスプロファイラを使用してそれらを区別する必要があります。 LLM(大規模言語モデル)に戻ると、学習と推論の事前充填フェーズは通常、計算量に制限があり、推論のデコードフェーズは多くのハードウェアのメモリ帯域幅によって制約されることを覚えておいてください。したがって、学習プロセスを主にターゲットとした最適化(低精度行列乗算など)は、推論レイテンシの大部分がデコードフェーズに起因しているため、全体的な推論レイテンシを大幅に削減できない可能性があります。 03 さまざまなタイプのパフォーマンスボトルネックを最適化して、レイテンシを削減します。計算能力が限られている場合は、次のことが可能です。
メモリ帯域幅が制限されている状況の場合は、次の操作を実行できます。
図6 — CNNモデルにおける水平方向と垂直方向の様々なメモリ操作の融合、初期状態(上)と最終状態(下)[8] 通信が制限される状況では、次のことをお勧めします。
例えば、参考文献[10]のテンソル並列レイアウトでは、計算の進行に伴って重みシャードは変更されずに、アクティベーションシャードが異なるプロセッサまたは計算デバイス間を移動する。参考文献[9]は、事前充填段階および非常に大きなデータシーケンスを扱う場合、アクティベーションのサイズが重みのサイズよりも大きくなる可能性があることを指摘している。したがって、通信の観点からは、「重み収集」パーティショニング戦略のように、アクティベーションを移動または調整せずに重みシャードのみを移動する方が効率的である。これは、重みを異なるデバイス間で移動する際に特定のデバイスのアクティベーションを固定する可能性のある他のパーティショニング戦略とは逆である。 頭上境界にある場合は、次のことが推奨されます。
モデル コンパイラを使用すると、計算グラフをさらに最適化できます。 いずれにせよ、トレース/コンパイルではテンソルのサイズや型などのパラメータが静的である必要があり、実行時に変更されないため、柔軟性とオーバーヘッドの削減を犠牲にしていることになります。if-else文などの制御フロー構造は、このプロセスで失われることがよくあります。 動的テンソル形状や制御フローなど、事前(AOT)コンパイル(通常はすべてを静的に修正し、実行時に柔軟な調整を不可能にする)と互換性のない柔軟性要件については、ジャストインタイム(JIT)コンパイラが実行前にモデルコードを動的に最適化できます(ただし、AOTコンパイラほど徹底的ではありません)。例えば、PyTorch 2.xはTorchDynamoと呼ばれるジャストインタイム(JIT)コンパイラを提供しています。TorchDynamoを使用するにはPyTorchプログラムを変更する必要がないため、JITコンパイラを使用する際のオーバーヘッドを削減しながら、高品質なPython開発エクスペリエンスを維持できます。 余談ですが、モデルオプティマイザーと(AOT)コンパイラーには違いがあるのでしょうか?私にとって、その区別は少し曖昧です。ここでは、この2つの用語を概念的に区別する方法を説明します。 まず、どちらも事前(翻訳者注:プログラムは実際に実行する前にコンパイルまたは最適化されます)。古典的な AOT コンパイラのワークフローは次のとおりです。サポートされている AI フレームワーク(PyTorch、TensorFlow、MXNet など)からコードをトレースし、コンピューティング グラフを中間表現(IR)(ソース コードとターゲット コード間の抽象表現、汎用的で言語およびプラットフォームに依存しない表現)に抽出し、ハードウェアに依存しない最適化手法(代数書き換え、ループ展開、演算子融合など)を使用して最適化されたコンピューティング グラフを生成し、最後にハードウェア固有の最適化手法(最適なコンピューティング カーネルまたはアルゴリズムの選択、コンピューティング デバイス(GPU、TPU など)とメモリ間でのデータの移動方法の最適化)を使用して、ターゲット ハードウェアに展開可能な成果物を作成します。AOT モデル コンパイラの例には、PyTorch の TorchInductor、XLA、Meta の Glow などがあります。 モデル オプティマイザーは、事前 (AOT) コンパイルを含むツール スイートですが、通常は特定のハードウェア (Intel ハードウェアの場合は OpenVINO、NVIDIA ハードウェアの場合は TensorRT および TensorRT-LLM など) 向けに最適化されており、モデルの量子化やモデルのプルーニングなどの追加のトレーニング後最適化を実行できます。 これまでは、レイテンシ(単一のリクエストを処理するのに必要な時間)の場合のみに焦点を当ててきました。次に、コンピューティング能力とメモリ帯域幅が限られている場合を詳しく検討し、スループット(単位時間あたりに処理できるリクエスト数)をこの記事の論理的枠組みに再導入してみましょう。 04 ボトルネック(性能ボトルネック) = f(ハードウェア(ハードウェア構成), 演算強度)興味深いことに、同じアルゴリズムで同じ入力を処理する場合、計算能力の限界とメモリ帯域幅の限界という2つのシナリオが発生する可能性があります。どちらのシナリオが当てはまるかは、アルゴリズムの演算強度、つまりアクセスされるメモリのバイトごとに実行される演算回数によって異なります。 我々は、より費用対効果の高い計算能力制約の範囲内、あるいはその近傍の演算強度値を目指しています。演算強度値が増加するにつれて、スループットと費用対効果も向上することがわかります。しかし、演算強度を向上させる方法によっては、レイテンシが減少する可能性があります。したがって、システムを設計する際には、レイテンシとスループットのトレードオフを考慮し、適切なアルゴリズムや手法を選択する必要があります。 b は各プログラム実行中にメモリに(またはメモリから)転送されるデータのバイト数、p は各プログラム実行中に実行される浮動小数点演算(FLOP)数を表します。BW_mem(TB/s)はハードウェアメモリ帯域幅、BW_math(TFLOPS)はハードウェアの数学演算帯域幅(ピークFLOPSとも呼ばれます)です。t_mem はデータの移動に費やされた時間、t_math は算術演算の実行に費やされた時間を表します。 簡単に言えば、「計算能力が限られている」とは、計算タスクを実行するときに、データ転送よりも算術演算の実行に多くの時間がかかることを意味します (図 7)。 図7 – コンピューティング帯域幅とメモリ帯域幅の制約条件の比較。コンピューティング時間とデータ転送時間はそれぞれ黄色と青で示されています。 したがって、計算タスクを実行する際には制限があります。 Aはアルゴリズムの演算強度を表し、バイトあたりの浮動小数点演算(FLOP)で測定されます。データ転送中に各バイトで実行される演算回数が多いほど、演算強度は高くなります。 式が示すように、計算量が制限された条件下でアルゴリズムが機能するには、その演算能力がハードウェア依存のピークFLOPSとメモリ帯域幅の比率を上回る必要があります。逆に、演算能力がこの比率を下回る場合、アルゴリズムはメモリ帯域幅によって制限されます(図8)。 図8 – メモリ帯域幅または計算能力によって制限される場合の判断境界 NVIDIA® ハードウェアで半精度行列乗算 (つまり、Tensor コアを使用) を使用した場合の実際のデータを見てみましょう (表 1)。 表1 – LLMトレーニングおよび推論サービスで一般的に使用されるNVIDIA®データセンターGPUの仕様 これは何を示しているのでしょうか。NVIDIA A10 を例にとると、帯域幅比が 208 ということは、その特定のハードウェアで 1 バイトのデータを移動することが、約 208 FLOP (浮動小数点演算) を実行することとほぼ同等であることを意味します。したがって、NVIDIA A10 で実行されるアルゴリズムが、転送されるデータ 1 バイトあたり少なくとも 208 回の浮動小数点演算 (または転送される半精度浮動小数点数あたり少なくとも 416 回の浮動小数点演算) を実行できない場合、データの移動にかかる時間は必然的に計算時間を超えます。つまり、メモリ帯域幅によって制限されます。言い換えると、ハードウェア帯域幅比 (特定のハードウェアで 1 バイトのデータ転送に必要な時間と 1 FLOP を実行するために必要な時間の比) よりも低い演算強度を持つアルゴリズムは、メモリ帯域幅によって制限されます。 LLM推論プロセスのデコードフェーズは演算負荷が低いため(詳細は次のブログ記事を参照)、ほとんどのハードウェアではメモリ帯域幅の制約を受けます。NVIDIA H100と比較すると、NVIDIA H200の帯域幅比は、このような低負荷ワークロードに適しています。NVIDIAがH200を「生成型AI推論のスーパーチャージ」と宣伝しているのは、まさにこのためです。H200のハードウェア設計は、メモリ制約のあるシナリオに特化しています。 ここで、演算能力とレイテンシおよびスループットの関係を見てみましょう。 注:ここでのスループットは1秒あたりのリクエスト数ではなくTFLOPSで表されていますが、両者は比例関係にあります。さらに、スループットがTFLOPSで表されているという事実は、ハードウェア使用率およびコスト効率との関係を強調しています。この関係をより明確にするために、スループットは、各チッププロセッサが1秒間に処理できるリクエストまたはタスクの数としてより正確に表すことができます。つまり、チッププロセッサが各リクエストに必要なチップ秒数が短いほど、スループットが高く、コスト効率が高くなります(文献[9]のセクション4を参照)。 演算能力をX軸に、スループット(最大達成可能値)を従属変数としてY軸にプロットすると、いわゆる(初期)ルーフラインモデル(コンピュータプログラムのパフォーマンスを評価するために使用されるグラフィカルモデルで、パフォーマンスのボトルネックを特定して最適化するのに役立ちます)[12](図9)が得られます。 図9 - ルーフラインモデル 図9に示されているスループットの数値が、なぜ達成可能な最大値を示しているのか、簡単な思考実験を通して理解してみましょう。計算能力が限られている場合、これは明白です。計算能力を最大限に活用することを妨げるものは何もなく、ハードウェアのピーク容量によってのみ制限されるからです。メモリ帯域幅が限られている場合、1秒間に取得できるデータの最大量は、ハードウェアのメモリ帯域幅、BW_memによって決まります。アルゴリズムの演算能力をAとすると、1秒間に実行できる浮動小数点演算の最大回数は、BW_mem * Aとなります。 アルゴリズムの演算強度を高めるとどのような影響があるでしょうか?次の3つのケースが考えられます(図10参照)。 図10 – アルゴリズムの演算強度を高めるための3つのシナリオ シナリオ1:演算能力の向上はメモリ帯域幅の制限を克服するには小さすぎるものの、スループットは比例して向上します。システムは依然としてメモリ帯域幅によって制限されるため、レイテンシへの影響は、この演算能力がデータ転送の速度と効率にどの程度影響するかによって異なります。 シナリオ2:演算能力の向上により、システムは計算能力が制限された状態になります。スループットはハードウェアのピークスループットまで上昇します。システムは計算能力が制限された状態となり、レイテンシへの影響は、演算能力の向上がアルゴリズムの全体的な計算負荷にどの程度影響するかによって決まります。 シナリオ3:既に限られた計算能力と既に達成されているピークスループットを考慮すると、演算強度を高めてもスループットの向上は見込めません。レイテンシへの影響は、演算強度の向上がアルゴリズムの総計算コストにどの程度影響するかによって決まります。 具体的にどのように演算強度を高めるべきでしょうか?これは個々のアルゴリズムによって異なります。次の記事では、Transformerデコーダーブロックの演算強度を決定する主要なパラメータを検証します。これにより、バッチサイズを増やすことで特定の演算の演算強度がどのように向上するかを理解できるようになります。 前述の最適化手法の中には、演算強度を向上させ、スループットとリソース利用率を向上させるものもあります。Transformerモデル(デコードフェーズがメモリ帯域幅によって制限される)の場合、演算強度の向上は主に演算融合(複数の演算(行列乗算、加算など)を1つの大きな演算に統合することで、演算とデータ転送間のギャップを減らす)とデータ(重み行列、KVキャッシュ)の量子化によって実現され、データ転送回数とサイズを削減します。 ここでは、アルゴリズムがハードウェアリソースを最大限に活用できるという重要な仮定を立てています。例えば、データ送信時には、アルゴリズムがハードウェアの理論上のメモリ帯域幅を100%活用できると仮定しています。しかし、現実には明らかにそうではありません(ただし、一部のアルゴリズムは最適なリソース利用率に近づいています)。リソース利用率が最適ではない場合、これまでの分析結果にどのような影響を与えるでしょうか? 簡単に言えば、上記の帯域幅データは、現実に達成可能なデータに置き換える必要があります。最適ではないシステム(アルゴリズム実装がハードウェアリソースを十分に活用できない状況)では、最適なルーフライン曲線よりも低いルーフライン曲線が示されます(図11を参照)。具体的には、スループットを向上させるには、演算能力の向上と、ハードウェアの計算能力、メモリ帯域幅、その他のリソースをより効率的に活用するようにアルゴリズムを最適化するという2つの方法があります。 図11 — リソース利用が最適ではないルーフラインモデル 最後に、アルゴリズム最適化の実例を挙げてまとめましょう。バージョン2.2より前のFlashAttentionは、デコード段階で効率が悪く、パフォーマンスが非常に低かったです。以前のデータロード実装では、デコード段階でのカーネルのメモリ帯域幅の利用効率が大幅に低下していました。さらに悪いことに、バッチサイズが大きくなるにつれて帯域幅の利用率はさらに低下しました。そのため、メモリ制約により、より小さなバッチを必要とする長いシーケンスのパフォーマンスが最も影響を受けました。FlashAttentionチームはこの問題を解決し(主にKVキャッシュからデータをロードする際にシーケンス長の次元を並列化していなかったため)、推論プロセスのデコード段階に最適化されたカーネルであるFlashDecodingをリリースしました。これにより、より長いシーケンスの入力を処理する際のレイテンシが大幅に削減されました[13]。 05 要約この記事では、モデルのレイテンシに影響を与える可能性のある4種類のパフォーマンスボトルネックについて考察しました。それぞれのボトルネックには、適切な最適化戦略が必要となるため、モデルのレイテンシを引き起こす主な要因を特定することは非常に重要です。 簡潔にするため、この記事では分散環境は考慮しません。分散環境の場合、実際のハードウェア操作は計算能力またはメモリ帯域幅のいずれかによって制限されます。カーネルの演算能力が、どのパフォーマンスボトルネックになるかを決定します。演算能力が低く、メモリ帯域幅が限られている場合、達成可能な最大スループットは演算能力に比例します。一方、計算能力が限られている場合、スループットはハードウェアのピークハードウェアFLOPSによって制限されます。これは、演算能力に影響を与える要因に大きく依存します。演算能力を向上させることで最大スループットを向上させることができ、理想的には計算能力が制限されているシステムのパフォーマンスレベルに到達できる可能性があります。ただし、演算能力の向上はレイテンシに悪影響を与える可能性があります。 次のブログ投稿では、この新しい知識を活用して、Transformer デコーダーブロックの演算強度をより詳細に検証します。お楽しみに! 読んでくれてありがとう! ——— ピエール・リアンハート GenAI ソリューションアーキテクト @AWS - 意見と誤りは私自身のものです。 終わり 参考文献
|