インフラ

数週間の常駐VRAMデータからのオンプレミスGPUのサイジング

スペックシートに記載されているのはカードのメモリであり、コンテナが待機状態で実際に保持するメモリ量ではありません。ここでは、数週間にわたる常駐VRAMの測定値から、単一のオンプレミスGPUのサイズをどのように決定したかを示します。

この記事は英語の原文をAIモデルが翻訳したものです。表現が原文と異なる場合があります。 英語の原文を読む

ML推論のワークロードをクラウドから単一のオンプレミスのマシンに移行する際、最初の疑問は1つのGPUで十分かどうかということです。スペックシート上の答えはここでは役に立ちません。それを決定するのは、コンテナがアイドル時に実際に保持しているメモリと、負荷時に到達するピーク値です。私は、数週間にわたって同じイメージを実行していた3つのクラウドGPUから常駐VRAMを読み取ることでオンプレミスGPUのサイジングを行い、その数値によって決定は明白になりました。

常駐メモリは最低ラインであり、スペックシートではない

起動時にモデルをロードする推論コンテナは、ジョブ間でそのメモリを解放しません。次のリクエストでコールドロードのコストを支払わないように、モデルセット全体を常駐させます。したがって、最低ラインを決める数値は、カードサイズでもリクエスト中のピークでもありません。それは、コンテナがアイドル状態でいる間の、安定した常駐フットプリントです。

そのフットプリントには3つのものが積み重なります。CUDAコンテキストは、ディスクから1つの重みも読み込まれる前に、プロセスあたり数百MiBを消費します。次にモデルの重みが来て、複数のモデルを提供する画像サービングでは、それが大部分を占めます。そしてアロケータです。PyTorchのようなフレームワークは、ドライバから取得した大きなブロックをキャッシュするため、解放されたテンソルはドライバではなくそのキャッシュに戻ります。外部から見ると、コンテナはメモリを全く返していないように見えますが、実際に返していません。

これが、常駐セットが起動時から静止しているのではなく、しばらく上昇してから横ばいになる理由です。より長い入力やより大きなバッチといった新しいリクエストのシェイプはそれぞれ、アロケータにまだ保持していなかったブロックを切り出させることがあり、そのブロックは保持され続けます。数日間の混合トラフィックの後、常駐セットは、プロセスが処理したすべてのシェイプの最高使用量近くで安定します。起動から5分後に測定されたコンテナは、まだそれらのシェイプに遭遇していないため、測定値は低くなり、見積もりは過小になります。

カードごとではなく、プロセスごとに測定してください。デバイス全体の使用量の数値には、これから削除するデスクトップセッションを含む、他のすべてのプロセスが混在しています。

# Per-process resident VRAM. This is the number that sizes the card.
nvidia-smi --query-compute-apps=pid,used_gpu_memory --format=csv
# Device totals, for the headroom check.
nvidia-smi --query-gpu=memory.total,memory.used,memory.free --format=csv

報告される合計値の時点で、スペックシートの記述は正確ではなくなります。24 GBとして販売されているカードは、24 GBのアドレス指定可能なメモリを公開しません。ドライバが一部を予約し、ECCが有効なパーツでは訂正ビットがより多くの容量を消費するためです。同じ24 GBという区分の2枚のカードでも、報告される合計値が1ギガバイト異なることがあり、これはマージンが数ギガバイトしかない場合には重要です。

測定結果が示したこと

クラウド上の3つのGPUが、それぞれ23 GBのカードで、同一のイメージを実行していました。アイドル状態の3つすべてで、推論コンテナの常駐VRAMを読み取りました。

GPU 常駐VRAM (アイドル時) 注記
A 15,322 MiB 単一の長時間実行プロセス、稼働時間6週間以上
B 17,382 MiB 観測された最大値
C 13,676 MiB 観測された最小値

同一イメージ間で見られる13.7 GBから17.4 GBへの広がりが断片化の影響です。これら3つのプロセス間で重みに違いは一切ありません。したがって、3,706 MiBという差全体がアロケータの履歴によるものです。つまり、各インスタンスがどの形状のリクエストを、どのような順序で処理したかということです。最大値は最小値より27パーセント高くなっています。

これが、平均が罠である理由です。3つの平均値は15,460 MiBであり、GPU Bが実際に保持している量より1.9 GB少なくなっています。6〜7ギガバイトのヘッドルームがあるカードで、平均に基づいてサイジングすると、最初のリクエストが到着する前にマージンの3分の1を消費してしまいます。

どの常駐メモリ量よりも重要なのは、起こらなかったことです。その常駐セットに加えて行われたピーク時の推論は、数週間の本番稼働を通じて23 GBのカード内に収まりました。メモリ不足による強制終了も、アロケータのリトライの嵐も、再起動もありませんでした。その一つの事実が、実際のユーザーが送信したすべてのリクエスト形状をカバーしています。それには、誰もベンチマークに含めないテールケースも含まれます。

ヘッドレスブートはデスクトップが奪ったものを取り戻す

オンプレミスのマシンはワークステーションであり、フルデスクトップで起動していました。ディスプレイマネージャーとそのコンポジターは、推論コンテナが起動する前から数百MiBのGPUメモリを確保していました。誰もログインしないワークステーションでは、それはまさにサイジングしようとしているリソースを占有する純粋な無駄です。

24GBのカードに対して数百MiBは丸め誤差のように聞こえ、そしてカードに対しては実際にそうです。ヘッドルームに対してはそうではありません。コンテナが最悪の場合に17.4GBを確保する場合、管理するマージンは6.6GBに近くなり、グリーターの500MiBはその8パーセントになります。無駄は、容量に対してではなくマージンに対して測定してください。

# Boot to a console, and stop the greeter from claiming VRAM.
sudo systemctl set-default multi-user.target
sudo systemctl disable --now gdm3   # or lightdm, sddm

切り替え後、GPUプロセスはinference containerのみに減少しました。想定するのではなく、検証してください。再起動して、compute-appsクエリのリストにエントリが1つだけ表示されることを確認してください。すべての測定は、マシンが実際に実行される状態で行ってください。なぜなら、デスクトップが起動した状態で測定された数値は、存在しないマシンを表すからです。

サイズ決定

オンプレミスのカードは24 GBのGPUで、ワークロードが収まることをすでに証明していた23 GBのクラウドカードより約1.5 GB大きかった。計算はこうだ。観測された最悪の常駐サイズは17,382 MiBであり、クラウドカードはそのコンテナを数週間、その上に約5.6 GBの余裕を持たせて実行し、カードを使い果たすことはなかった。オンプレミスのカードは1.5 GB多く報告するため、同じイメージは、デスクトップがリソースを消費しなくなったマシン上で、同じ最悪のケースに対して約7.1 GBの余裕を持つことになる。

論拠は予測ではなく、優位性である。私は推論のピークを測定したことはなく、その必要もなかった。新しいカードが、このワークロード、このイメージ、そして実際のトラフィックに数週間耐えてきたカードよりも厳密に大きいというだけで十分だった。以前収まっていたどのピークも、1.5ギガバイトの余裕を持って今も収まる。

コストの非対称性が、これを容易にした。2枚目のGPUは、単にカードの価格だけの問題ではない。空きスロット、電源のヘッドルーム、そして冷却が必要であり、それら3つのいずれも持たない可能性のあるシャーシに、加えて1つのデバイスを前提とするサービングパスを分割する作業も必要になる。逆にメモリが不足すると、本番環境の停止というコストがかかる。優位性の論拠があれば、どちらのリスクも見積もる必要はなかった。1枚のカードで十分であり、数週間のクラウドデータが、私が午後に実行できたであろうどんなベンチマークよりも高い確信度でそのことを示していた。

購入前に測定すべきこと

一般的な方法は、常駐メモリ使用量の多いあらゆる推論ワークロードで有効です。

  • 起動直後ではなく、数日間実際のトラフィックを処理したコンテナで、プロセスごとの常駐VRAMを読み取ります。同一インスタンス間での最大値を取得し、それを上限ではなく下限として扱います。
  • 本番環境で実績のあるカード内で、常駐メモリ使用量と推論時のピーク使用量の合計が収まっていることを確認します。購入しようとしているカードが、実績のあるカードよりも大きな合計メモリ量を報告する場合、サイジングは確定です。
  • マーケティング上の容量ではなく、報告されたmemory.totalを比較します。同じ価格帯の2つのカードでも、1ギガバイト異なることがあります。
  • マシンがワークステーションの場合は、ディスプレイマネージャーをオフにして測定します。これにより、デスクトップがあなたが当てにしていたヘッドルームを占有することがありません。
  • 最悪ケースの常駐メモリ使用量とピーク使用量の合計を余裕をもってクリアするサイズのカードを購入し、そこで止めます。必要のないGPUは、ラック内で最も高価な遊休ハードウェアです。

この方法は、ワークロードの常駐メモリ使用量が多く、そのフットプリントが安定しているという1つの仮定に基づいています。トレーニングはこの仮定を破ります。なぜなら、アクティベーションとオプティマイザの状態はバッチサイズとシーケンス長に応じてスケールするため、ピーク使用量がアイドル時の下限をはるかに超え、直接サイジングする必要があるからです。リクエストごとにモデルをロード・アンロードするサービスは、常駐セットがごくわずかで、ピーク使用量が全てを物語るため、別の側面からこの仮定を破ります。モデルセットが増え続けるマルチテナントサービングもこの仮定を破ります。なぜなら、今四半期の最悪ケースは来四半期の最悪ケースではないからです。イメージへのいかなる変更も同様です。新しいモデルやフレームワークのアップグレードは、下限を変動させ、測定値を無効にします。

よくある質問

サイズ設定は、平均と最大のどちらの常駐メモリ読み取り値に対して行うべきですか?

最大値に対して行い、さらにその上にマージンを残してください。同一インスタンス間のばらつきはアロケータの履歴に起因するため、最も高い読み取り値は、最も多様な形状のリクエストを処理したインスタンスのものになります。少数のインスタンスでは、その分布をサンプリングしたにすぎず、上限を定めたことにはなりません。

リクエストの形状が変化すると、常駐メモリの下限は変動しますか?

はい、変動します。下限は、プロセスが処理したすべての割り当て形状の最高水位標を追跡するため、最大バッチサイズやコンテキストウィンドウを引き上げると、そのプロセスの生存期間中、下限も押し上げられます。サイズ設定後にサービングパラメータを変更すると、以前の読み取り値は、もはや実行していないコンテナを記述したものになります。

より大きなカードを購入する代わりに、メモリに上限を設けることはできますか?

部分的には可能です。アロケータのチューニングによって断片化を削減し、プロセスがキャッシュする量を制限することで、常駐セットを引き下げることはできますが、重みを縮小することはできません。また、ブロックをドライバに強制的に戻すと、ヘッドルームと引き換えにスループットが犠牲になります。その差が数百MiBであれば、そのトレードオフは多くの場合、行う価値があります。ギガバイト単位であれば、より大きなカードか、より小さなモデルセットが必要です。

1つのGPUで2つの推論コンテナを実行するとどうなりますか?

それぞれの常駐セットは加算され、重複しません。各プロセスは数百MiBの独自のCUDAコンテキストを消費し、独自の重みのコピーを保持するため、15GBのイメージのコンテナを2つ実行すると、15GBではなく30GBが必要になります。1つのカードにプロセスを詰め込むことが有効なのは、各モデルが小さく、かつカードの容量がそれらの下限の合計よりもはるかに大きい場合に限られます。