AMD の GPU(ROCm)で PyTorch の生成モデルを動かす技術検証の途中で、VRAM が 21 GB 空いているのに 256 MB の確保で OOM(メモリ不足)になりました。OOM を見るとまず VRAM が足りないと考えて、解像度を下げたり、モデルを量子化したり、層を退避したりしたくなりますが、このときの原因は容量ではなく、環境変数1つでした。

結論

  • PYTORCH_HIP_ALLOC_CONF=expandable_segments:True が立っていると、21 GB 空いていても 256 MB の確保で OOM になりました。見た目は「VRAM が足りない」ときと同じです。
  • この変数は設定しません。OOM を見たら容量より先にこの変数を疑い、env -u PYTORCH_HIP_ALLOC_CONF で走らせ直します。
  • 本当に足りない OOM もあります。VRAM 20 GiB に FLUX.2-klein-4B(7.83 GiB)と MOSS-SoundEffect v2.0(16.59 GiB)は一緒に載りません。モデルは1つずつ読み、使い終わったらプロセスごと終えます。
  • 変数は人やエージェントの注意に任せず、生成を起こすスクリプトの中で消しておきます。

試した環境

  • GPU: AMD Radeon RX 7900 XT(gfx1100、VRAM 20 GiB=約 21.5 GB)
  • OS と ROCm: Ubuntu、ROCm 7.2.4
  • ライブラリ: torch 2.13.0+rocm7.2、diffusers 0.40.0.dev0、transformers 5.15.0
  • モデル: FLUX.2-klein-4B(画像)、MOSS-SoundEffect v2.0(効果音)、Qwen-Image-Edit-2511(画像編集)ほか

21 GB 空いているのに 256 MB で落ちる

生成を走らせると、256 MB を確保するところで OOM になりました。そのとき VRAM は 21 GB 空いていました(20 GiB は約 21.5 GB なので、ほとんど使われていない状態です)。エラーの形は容量が足りないときと同じなので、素直に読むと「モデルが大きすぎる」「解像度が高すぎる」と考えます。けれども原因は別の所にあるので、そちらへ手を入れても直りません。

環境には PYTORCH_HIP_ALLOC_CONF=expandable_segments:True が立っていました。この組み合わせ(ROCm 7.2.4、torch 2.13.0+rocm7.2、gfx1100)では、この設定が確保そのものを壊していました。それからは、この変数を設定せず、OOM を見たら真っ先にこれを見るようにしました。

並んだスイッチのうち向きの違う1つを戻そうとする人と、使わずに済んだ脚立や部品の山の絵

どう確かめるか

OOM が出たら、まず今のシェルや、生成を起こす設定に、この変数が立っていないかを見ます。立っていたら、外して同じコマンドを走らせ直します。

env | grep PYTORCH_HIP_ALLOC_CONF
env -u PYTORCH_HIP_ALLOC_CONF python <生成のスクリプト> ...

外して通るなら、原因はこの変数です。外しても落ちるなら、そこで初めて容量を疑います。次の図は、私たちが OOM を見たときに確かめる順です。

OOM を見たときに確かめる順

変数を外しても落ちるときだけ、モデルの大きさと載せ方の話に進みます。

本当に足りない OOM

こちらは正しい OOM です。FLUX.2-klein-4B は読み込むと 7.83 GiB、MOSS-SoundEffect v2.0 は 16.59 GiB を使います。合わせると 20 GiB を超えるので、片方を読んだまま2つ目を読むと落ちます。

FLUX.2-klein-4B の 7.83 GiB と MOSS-SoundEffect v2.0 の 16.59 GiB を合わせると 24.42 GiB で、VRAM の容量 20 GiB を超えることを示す横棒グラフ

私たちは、モデルを1つずつ読み、使い終わったらプロセスごと終えるようにしました。1つでも VRAM に載らない物もあります。たとえば Qwen-Image-Edit-2511 の transformer は bf16 で 40.9 GB あり、これは diffusers の層単位の退避で回しました。

変数はスクリプトの中で消す

検証では、生成を AI のエージェントにも任せました。「この変数を設定しない」と手順書やプロンプトに書いても、守られませんでした。そこで、生成は薄いシェルの入口からだけ起こすことにし、入口の中で毎回この変数を消すようにしました。

# 設定しないこと。確保そのものを壊す
unset PYTORCH_HIP_ALLOC_CONF || true

こうしておけば、外から何が渡ってきても、生成のプロセスにはこの変数が届きません。人が手で打つときも同じ入口を通せば、端末に変数が残っていても生成には届きません。

確かめていないこと

  • gfx1100 以外の GPU や、ほかの ROCm・PyTorch の版で同じことが起きるかは試していません。

おわりに

ROCm で OOM を見たら、モデルの大きさを疑う前に PYTORCH_HIP_ALLOC_CONF を見てください。外しても落ちるときに初めて、1つずつ読む・層を退避するといった載せ方を考えれば足ります。

※ ROCm と PyTorch の振る舞いは執筆時点の版(ROCm 7.2.4、torch 2.13.0+rocm7.2)で見た物で、いまは変わっている可能性があります。