この記事で理解してほしいこと
- ジョブを動かすマシンを選ぶのは「配膳係」のような裏方で、見ているのは 「CPU・メモリ・GPU が何個あるか」という数だけ。
- ジョブが動かない原因には2種類ある:数が足りないときは動き出す前に止まる、GPU のメモリ(VRAM)が足りないときは動き出してから落ちる。
- マシン候補を順位づけて並べても、Batch は中身を考えて賢く選ぶのではなく、上から順に試して、ダメなら次に進むだけ。
- だから 「マシンには載せられたのに、動かしたら落ちる」 ことが起こる。GPU のメモリにモデルが収まるかは、Batch は見てくれない。
- いろんな種類の GPU を候補にするなら、そのどれでもモデルがちゃんと動くかを、自分で実際に動かして確かめる。
はじめに
AWS Batch で GPU ジョブを動かしていて、こんな経験はないでしょうか。
- ジョブがずっと
RUNNABLEのまま動き出さない - あるいは、動き出したのに CUDA out of memory(OOM) で落ちる
この2つは、どちらも「リソースが満たせていない」ように見えますが、まったく別物です。前者は AWS Batch が起動前に気づく問題、後者は AWS Batch には防げない実行時の問題です。
本記事では、この「2種類の満たせない」を、社員食堂の厨房にたとえながら整理します。仕様の細部を暗記するより、仕組みの形をイメージで掴むことを狙いとします。
登場人物を「社員食堂」にたとえる
AWS Batch の構成要素を、社員食堂に置き換えます。
| AWS Batch | 社員食堂 | 役割 |
|---|---|---|
| ジョブ定義 | レシピ | 何を・どんな材料で作るかの指示書 |
| ジョブ | 食券 | 「このレシピで1つ作って」という注文 |
| ジョブキュー | 食券を並べる列 | 注文を並べて優先順位をつける |
| コンピューティング環境 | 厨房 | 実際に料理を作る場所と設備 |
| スケジューラ | 配膳係 | 食券を、作れる厨房に運ぶ判断をする人 |
特に重要なのが、最後の 配膳係(スケジューラ) です。「どの厨房で作るか」を実際に判断して食券を運ぶのは、この配膳係の仕事です。
ジョブが料理になるまでの流れ
食券(ジョブ)には「GPUコンロ1台・火力(CPU)2・作業台(メモリ)4GB ください」のような 必要量 が書かれています。これは AWS Batch では resourceRequirements にあたります。
"resourceRequirements": [
{ "type": "VCPU", "value": "2" },
{ "type": "MEMORY", "value": "4096" },
{ "type": "GPU", "value": "1" }
]
配膳係(スケジューラ)は、この必要量を見て、それを作れる厨房に食券を運びます。ここで大事なのは、配膳係が見ているのは「厨房の設備一覧表(カタログ上のスペック)」だけだということです。「GPUコンロが何台あるか」「火力は足りるか」といった、表に書いてある数字で判断します。
1つめの「満たせない」:設備表を見た時点でわかる(起動前)
まず、配膳係が 厨房に運ぶ前に 気づくタイプの「満たせない」です。
配膳係は、第一希望の厨房(order 1)から順に、2つのことを確認します。
-
その厨房は今日ちゃんと営業しているか?(コンピューティング環境が
VALIDか)。ガス停止中・閉鎖中のような状態(INVALID)なら、その厨房は使えないので次へ。 - 設備表を見て、この料理を作れる調理台があるか?(インスタンスのスペックが要求を満たすか)。
たとえば「GPUコンロ4台要る料理」なのに、その厨房の調理台が最大でも1台しか積めないなら、設備表を見た時点で「ここでは無理」とわかります。だから次の厨房(order 2)へ向かいます。
キューに複数の厨房がある場合
1つの列(ジョブキュー)に複数の厨房(コンピューティング環境)を order で紐づけている場合、配膳係は番号の小さい順に試します。
new batch.JobQueue(this, 'GpuQueue', {
computeEnvironments: [
{ computeEnvironment: g5Env, order: 1 }, // まず g5 厨房
{ computeEnvironment: g6Env, order: 2 }, // 作れなければ g6 厨房
],
});
ここで誤解しがちなのが、これは 配膳係が食券の中身を見て「賢く g6 厨房を選んだ」のではない という点です。第一希望の厨房から順に試して、設備が足りなかったから次に回った、というだけです。必要量が効くのは「どの厨房を選ぶか」ではなく、「選ばれた厨房の中でどの調理台を使うか」のほうです。
どこにも運べないとき
すべての厨房が「営業していない」か「設備が足りない」だと、配膳係は食券を運べません。食券は調理待ちのまま、つまりジョブは RUNNABLE(準備はできているが、まだ厨房に載っていない)のまま、どこかが空くまで待ち続けます。
2つめの「満たせない」:調理を始めて初めてわかる(実行時 / OOM)
ここからが本題で、ハマりやすいほうです。
配膳係は、設備表を見て「GPUコンロが1台ある厨房」を見つけ、そこに食券を運びました。設備表どおり要求は満たしているので、配膳係の仕事は成功しています。 AWS Batch でいえば、割り当ては正常に完了しています。
ところが、料理人が実際に調理を始めると——その GPUコンロ(GPU)の上に、料理(モデル)が物理的に乗りきらなかった。鉄板が小さすぎて、具材があふれてしまった。これが CUDA out of memory(OOM)、つまり VRAM 不足です。
ここで効いてくるのが、配膳係は設備表(カタログ上の数)しか見ていないという事実です。設備表には「GPUコンロが1台ある」とは書いてあっても、「そのコンロの上に、この特定の料理が乗りきるか(VRAM が足りるか)」までは書いていません。それは料理人が調理を始めて初めてわかることなので、配膳係には事前に防げないのです。
2つの「満たせない」を並べる
| 設備が足りない | 鉄板に乗らない(OOM) | |
|---|---|---|
| たとえ | 設備表に「作れる調理台が無い」 | 調理台はあるが鉄板が小さい |
| いつわかる | 厨房に運ぶ前(設備表で) | 調理を始めた後 |
| 配膳係が見るもの | 設備表(カタログ上の数) | (見ていない・見られない) |
| 症状 |
RUNNABLE のまま止まる |
起動後に OOM で落ちる |
| AWS Batch は防げる? | 防げる(次の order へ / 待つ) |
防げない(管轄外) |
| 誰の責任 | AWS Batch が面倒を見る | 人間が事前に確認する |
なぜこれが本番で怖いのか
特に複数世代の GPU を候補にしている場合(例:g5 と g6)、この2つめが厄介なバグになります。
平常時は order 1 の g5 厨房で問題なく作れていたとします。ところが g5 厨房が満席(在庫切れ)になった瞬間、配膳係は order 2 の g6 厨房に食券を運びます。もし g6 の鉄板(VRAM)に料理(モデル)が乗りきらなければ、その時だけ OOM で落ちる。
在庫切れは滅多に起きないので、「普段は動くのに、たまにだけ落ちる」 という、最も原因究明が難しいパターンになります。しかも AWS Batch のログ上は「正しく厨房に運んだ(割り当てた)」ように見えるため、Batch の設定をいくら見直しても原因にたどり着けません。
対策:人間が確認すべきこと
配膳係(AWS Batch)は設備表の数しか見ないので、「その鉄板に料理が乗るか」という質は人間が保証するしかありません。複数世代の GPU を候補にするなら、最低限これを確認します。
- 使うモデルが必要とする VRAM 量を把握する
- 候補に入れたすべての世代の GPU の VRAM が、それを上回るか確認する
- フォールバックで当たりうる世代も含めて、実際に動かして検証する
まとめ
- 食券(ジョブ)を厨房(環境)に運ぶのは、配膳係(スケジューラ)。配膳係は 設備表(カタログ上の数) を見て判断する。
- 「満たせない」には2種類ある。
-
設備が足りない:厨房に運ぶ前に配膳係が気づく。
RUNNABLEで止まる、または次のorderへ。 - 鉄板に乗らない(OOM):調理を始めた後に落ちる。配膳係の管轄外で、防げない。
-
設備が足りない:厨房に運ぶ前に配膳係が気づく。
- 後者があるため、「割り当ては成功、でも処理は失敗」 が起こりうる。
- 複数世代の GPU を候補にするなら、全世代の VRAM にモデルが乗るかを 人間が確認する。
AWS Batch は「設備表の数」を合わせてくれる便利な配膳係ですが、「その厨房で本当に料理が完成するか」までは保証しません。その境界線を理解しておくことが、GPU ジョブを本番で安定させる第一歩です。
主な参照:Compute environments for AWS Batch、ResourceRequirement - AWS Batch、Run GPU jobs - AWS Batch、Jobs stuck in RUNNABLE status