H100を借りたのに、絵が1フレームも描けなかった — 計算GPUと描画GPUは別物
「GPU が必要」と言ったとき、実は 2 つの別々の話が混ざっています。
- 計算用: 学習・推論。CUDA が動けばよい
- 描画用: 3D レンダリング、ゲーム、映像制作。OpenGL / Vulkan / EGL が要る
同じ NVIDIA の GPU でも、片方しかできないものがあります。
3D アバターが動画配信プラットフォームへ 24 時間ライブ配信する、無人の AI アバター配信システムを作っていました。その過程で、この「計算用と描画用は別物」という壁に 2 回はまりました。CPU 描画で 1 回、MIG で 1 回。リソースが足りない話に見えて、実際には機能が無い話だった、という勘違いです。
以下は、実際にクラウド GPU を借りて測った結果から作った、描画用途の GPU 選定手順と、失敗の記録です。
やろうとしていたこと
構成はシンプルです。
ヘッドレス Chromium(3D アバターを WebGL で描画)
→ 画面と音声をキャプチャ
→ ffmpeg で H.264 + AAC にエンコード
→ RTMP で配信プラットフォームへ送出
LLM と TTS(音声合成)でアバターがしゃべり、それをブラウザで描画してエンコードし、そのまま流す。このうち「ヘッドレス Chromium で 3D を描く」部分をどこで動かすか、が最大の悩みどころでした。
ハズレ1: CPU 描画(SwiftShader)は解像度を下げても救えない
最初の設計では、renderer は CPU だけで動く前提でした。Chromium には SwiftShader という CPU 実装の WebGL バックエンドがあり、GPU がなくても WebGL は「動く」からです。
実測すると、確かに動きました。動いただけでした。素の WebGL は 60fps 出るのに、3D アバターのシーン(トゥーン系シェーダ + スキニング)は約 4fps。
普通ならここで「解像度を落として軽くする」を試します。試しました。720p でも 540p でも 360p でも、4fps のまま変わりません。解像度に比例しないということは、律速がピクセル処理ではなくシーン処理そのものだ、ということです。設計書に用意していた「重かったら 540p / 24fps に降格」という保険は、最初から無効でした。
CPU 描画は不成立。GPU を用意することになりました。
ハズレ2: MIG スライスは「取れた」が「描けない」
手元のクラスタには H100 があり、MIG(Multi-Instance GPU)で 1g.10gb のスライスに分割して、LLM 推論や音声推論に配っていました。MIG は 1 枚の GPU を複数のインスタンスに分割する仕組みで、推論サービスを詰め込むには非常に有効です。ここに 1 枚借りれば追加コストゼロ。そう考えて、そこにレンダラーを載せようとしました。
検証 Pod を立てた結果はこうです。
- Pod は正常にスケジュールされた(= スライスの空きはある)
- Pod 内の
nvidia-smiに H100 と MIG デバイスが見えている - それでも Chromium の WebGL は SwiftShader に落ちる
ここで「スライスが足りないのでは」と考えるのは自然ですが、違いました。Chromium のフラグをどう組み替えても、--use-gl=angle のバックエンドを egl にしても vulkan にしても、結果は同じ。Vulkan の ICD(ドライバ登録情報)を見に行くと、そもそも空でした。
原因は NVIDIA の公式仕様です。MIG は CUDA 計算専用で、グラフィックス API をサポートしていません。
これは性能の問題ではなく機能の有無の問題なので、スライスを何枚積んでも、最大の 7g.80gb を使っても、WebGL は 1 フレームも GPU で描けません。例えるなら、満車で停められないのではなく、そこは駐車場ではなく計算専用の部屋だった、という話です。空き枠を増やしても車は入りません。
「MIG を解除すればいいのでは」も筋が悪い
理屈の上では、MIG を解除して H100 を丸ごと 1 枚使えばグラフィックス API は通ります。ただし、データセンター向けの計算特化 GPU は、**描画に必要なユニットが削られています。**H100 の場合:
- グラフィックス用の TPC が 2 基しかない(AI 計算のために描画ユニットを削ぎ落としたアーキテクチャ)
- NVENC(ハードウェアエンコーダ)が非搭載
つまり、仮にグラフィックス API が通ったとしても描画性能は出ませんし、H.264 のハードウェアエンコードもできないので配信用途の旨みも薄い。運用上も、全スライスを推論サービスが使っている状態で MIG を解除するのは不可能でした。
カタログの CUDA コア数や VRAM 容量だけを見ても、この情報は出てきません。「高い GPU なら何でもできる」わけではない、というのがここでの学びでした。H100 は計算のための GPU で、絵を出すための GPU ではありません。
正解: 描画に対応した GPU をクラウドで借りる
最終的に、renderer だけをクラウドの描画対応 GPU に出しました。描画用途では、L4 / T4 / RTX 系のようにグラフィックスを想定して作られた GPUを選びます。RTX 4000 Ada / RTX 2000 Ada クラス(時間 $0.24〜0.28)で十分に 720p30 が出ました。高いほど良いわけではありません。
置き場所の設計はこうなりました。
| 処理 | 置き場所 | 理由 |
|---|---|---|
| LLM・TTS・アプリケーション | 手元クラスタ(H100 MIG) | 計算タスク。MIG の得意分野 |
| ブラウザ描画・エンコード | クラウドの描画対応 GPU | グラフィックス API が要る |
**同じ「GPU が必要」でも、計算と描画は別の在庫として扱う。**これが今回いちばん大きな設計変更でした。
コンテナから本当に見えているか
GPU が割り当てられていることと、グラフィックスのドライバが使える状態であることは別です。描画対応 GPU を借りても、コンテナの設定次第でドライバが見えません。以下を確認します。
- コンテナに
NVIDIA_DRIVER_CAPABILITIES=allを指定する(既定値だとグラフィックス系のライブラリがマウントされない) - EGL の ICD(
10_nvidia.json相当)が置かれているか。eglinfoで NVIDIA の EGL デバイスが列挙されるか - Vulkan の ICD(
icd.d/)が空でないか - libglvnd が入っているか
ここが揃っていないと、アプリケーションからは「NVIDIA の実装が存在しない」ように見えます。
「動いた」を信じない
これが実務上いちばん大事です。
**ヘッドレス Chromium は、GPU 描画に失敗すると黙って CPU 実装(SwiftShader)にフォールバックします。**エラーも警告も出ません。起動するし、WebGL コンテキストも取れるし、画面も出ます。遅いだけです。「動いている」を成功と読むと、本番直前まで気づけません。
判定は必ず出力側から取ります。
| 確認方法 | CPU に落ちている | 成立している |
|---|---|---|
GL_RENDERER の文字列 |
SwiftShader |
NVIDIA |
| 3D シーンの実測 fps | 約 4 | 57〜58 |
10 倍以上違うので、迷いません。最小のプローブページ(GL_RENDERER と fps を出すだけ)を先に作ると、切り分けが劇的に速くなります。このスタックは失敗時に沈黙するので、fps か GPU 使用率で裏を取る、という一手間が効きます。
体数を決めるのは、たいてい CPU
「1 枚に何本乗るか」を実測したら、意外な結果が出ました。
| 項目 | 実測 |
|---|---|
| 同時配信数 | 4 本(720p30、実時間維持) |
| そのときの GPU 使用率 | 26% |
| 先に飽和したもの | CPU(16 vCPU) |
GPU は 3 倍以上余っていました。理由は単純で、GPU の仕事は「描く」ところだけだからです。
| 処理 | どこ |
|---|---|
| 3D 描画 | GPU |
| フレーム取り出し | CPU / 転送 |
| H.264 エンコード | CPU(ソフトウェアの場合) |
| 音声のミックス・mux・送出 | CPU |
だから NVENC の有無が体数に直結します。ハードウェアエンコードに逃がせば CPU が空き、もっと詰め込めます。GPU を選ぶときに vCPU 数とエンコーダの有無を見る、というのはここから来ています。
借り方: コミュニティ型とセキュア型、そして Stop の罠
安価な GPU クラウドには、個人・事業者が余剰 GPU を貸し出すコミュニティ型と、事業者が運用するセキュア型があります。
コミュニティ型は安い代わりに、**当たり外れがあります。**同じイメージ・同じ設定で、あるホストは 10 分間無事故、別のホストは 60〜150 秒ごとにクラッシュ、という差を実際に観測しました。
使い分けと、必ず入れるべき対策はこうです。
- 開発中の実験 → コミュニティ型
- 本番配信・長時間検証 → セキュア型
- どちらでも、不良ホストを検知して引き直す仕組みを入れる(セキュア型でもホストは死にます)
もうひとつ、運用の罠を 1 つ。インスタンスを「Stop」すると、その GPU が他の人に取られて再開できなくなるサービスがあります。停止中も課金されるうえに再開できない、という最悪の状態になり得るので、使い終わったら Terminate が原則でした。
コストの出し方
時間 $0.28 × 720 時間/月 = $201.6/月(GPU 1 枚)
$201.6 ÷ 4 本 = $50.4/本 ≒ ¥7,600/本(150円/USD)
ここに乗る、見落としやすいものを挙げます。
- 上り帯域: 2.5Mbps の送出で 1 日約 27GB。egress 課金のあるクラウド($0.09/GB 前後)だと月 1 万円規模の追加。GPU 専業クラウドは通信費込みのことが多い
- 稼働時間の設計: 24 時間で ¥7,600/本、1 日 8 時間なら ¥2,500/本。3 倍違います。「常時稼働が必要か」ではなく「どの時間帯に動かすか」の設計問題として扱う
- 推論側のコスト: AI が 24 時間しゃべり続ける場合、LLM と TTS のコストがレンダラーを上回ることがあります
選定チェックリスト
描画用途で GPU を借りるとき、この順で確認しています。
- MIG か? → MIG ならグラフィックス API は使えない。検討終了
- graphics TPC と NVENC はあるか? → 計算特化 GPU(H100 など)は削られている。スペック表の「CUDA コア数」だけ見ても分からない
- vCPU は足りるか? → 体数を決めるのはたいてい CPU
- コンテナからドライバが見えるか? →
NVIDIA_DRIVER_CAPABILITIES=all、EGL/Vulkan の ICD、libglvnd - 本当に GPU で描いているか? →
GL_RENDERERと fps で裏を取る。「起動した」は証拠にならない - 不良ホストを引き直せるか? → コミュニティ型なら必須、セキュア型でも入れておく
- Stop ではなく Terminate になっているか? → 課金と再開可否を確認
まとめ
- GPU は計算用と描画用で別カタログ。CUDA コア数や VRAM では判断できない
- **MIG はグラフィックス API 非対応。**計算専用なので、スライス数に関係なく WebGL は動かない
- 計算特化 GPU(H100 等)は graphics TPC が極小で NVENC も無い。MIG を解除しても描画には向かない
- CPU 描画(SwiftShader)は 3D シーンでは実用にならず、解像度を下げても比例して軽くならない
- **失敗が沈黙する。**CPU フォールバックを疑い、
GL_RENDERERと fps で確認する - 体数を決めるのは CPU のことが多い。NVENC の有無が効く
- コミュニティ型には当たり外れがある。引き直す仕組みを前提に置く
- コストは稼働時間の設計で 3 倍変わる
「とりあえず一番強い GPU を借りる」が、いちばん外れやすい選択でした。用途に合った安いカードのほうが、速くて安いことがあります。「空きがなくて入らない」のか「そもそも入れない部屋なのか」を切り分けること。リソースが足りない話に見えて、機能が無い話だった、というのは GPU まわりでは案外よくある勘違いだと思います。