Qwen-Image-Edit-2511 の transformer は 20B・bf16 で 40.9 GB(38.1 GiB)あり、VRAM 20 GiB の GPU には載りません。それでもこの画像編集モデルを ROCm で回せないかを技術検証した際、diffusers の層単位の退避(enable_group_offload)を使ったところ、メインメモリを食い尽くして swap を使い切り、6 分半待っても1枚も出ませんでした。
結論
enable_group_offloadにnon_blocking=True・use_stream=Trueを付けると、pinned メモリの複製ができて RSS が 61〜66 GB に達し、swap を使い切りました。付けなければ 17〜37 GB で済みました。num_blocks_per_groupは 1 のままにしました(2 以上は未検証)。この版の diffusers では、stream を使うと 1 に戻るので「まとめて運ぶ」と「転送を計算に重ねる」は両立できません。device_map="auto"とenable_sequential_cpu_offload()などの退避を併用すると、meta テンソルのエラーになります。どちらか一方にします。- transformer は量子化せず、bf16 のまま退避します。bitsandbytes の int8 では絵にならず、NF4 では平坦な面に粒が出ました。NF4 にするのは text_encoder だけです。
試した環境
- GPU: AMD Radeon RX 7900 XT(gfx1100、VRAM 20 GiB)
- OS と ROCm: Ubuntu、ROCm 7.2.4
- ライブラリ: torch 2.13.0+rocm7.2、diffusers 0.40.0.dev0、transformers 5.15.0、bitsandbytes 0.50.1
- モデル: Qwen-Image-Edit-2511(画像編集)、Qwen-Image(画像)
何が起きたか
non_blocking=True と use_stream=True を付けて層単位の退避を動かすと、プロセスの RSS が 61〜66 GB まで膨らみ、swap を使い切りました。Qwen-Image-Edit-2511 では 6 分半経っても1枚も出ず、Qwen-Image では重みを読み込むだけで 353 秒かかりました。2つの引数を外すと、RSS は 17〜37 GB に収まりました。
use_stream は、転送を計算に重ねるための引数です。名前から速くなりそうに見えるので付けたくなりますが、この環境では逆に、メモリを使い切る原因になっていました。
なぜか
non_blocking=True・use_stream=True を付けると、pinned メモリの複製が作られます。これが RSS を 61〜66 GB まで押し上げていました。外すと複製は作られず、同じモデルを 17〜37 GB で回せます。

num_blocks_per_group は 1 のまま
num_blocks_per_group は、一度にいくつのブロックをまとめて運ぶかの値です。diffusers がこの値を 1 に戻すのは、use_stream=True のときだけです。転送を計算に重ねるには stream が要り、stream を使うと 1 に固定されます。つまりこの版(0.40.0.dev0)では、「まとめて運ぶ」と「重ねる」を両立できません。
検証では stream を使いませんでした。stream を使わなければ num_blocks_per_group を 2 以上にもできますが、そのときの VRAM と速さは測っていないので、1 のままにしました。
pipe.transformer.enable_group_offload(
..., # 載せる先・退避する先など
num_blocks_per_group=1, # 1 のまま
# non_blocking=True と use_stream=True は付けない
)
この設定で Qwen-Image-Edit-2511 は、Lightning の 8 手で 1枚 140〜145 秒、1枚目は 197 秒で作れました。
device_map と退避を併用しない
device_map="auto" でモデルを読み、さらに enable_sequential_cpu_offload() などの退避を重ねると、meta テンソルのエラーになりました。載せ方を決める手段はどちらか一方だけにします。エラーの文面からは原因が併用だと分かりにくいので、meta テンソルの話が出たら、まず両方を使っていないかを見ます。
transformer は量子化で縮めない
VRAM に載らないなら量子化で小さくする手もありますが、bitsandbytes の量子化は拡散モデルの transformer では使えませんでした。int8 にすると絵にならず、NF4(4bit)にすると平坦な面に粒(モザイク)が出ました。bitsandbytes では int8 が使えないので、選べるのは NF4 か bf16 の2つで、間の段はありません。ほかの量子化の方式は確かめていません。
検証では transformer を bf16 のまま層単位で退避し、NF4 にするのは text_encoder だけにしました。なお ROCm で bitsandbytes を使うには、PyTorch が wheel に同梱する ROCm とは別に、システムの ROCm(/opt/rocm)が要りました。
確かめていないこと
num_blocks_per_groupを 2 以上にしたときの VRAM と速さ。
おわりに
diffusers の層単位の退避でメモリが溢れたら、まず non_blocking と use_stream を外してみてください。私たちの環境では、それだけで RSS が 61〜66 GB から 17〜37 GB に下がりました。
※ diffusers と bitsandbytes の振る舞いは執筆時点の版(diffusers 0.40.0.dev0、bitsandbytes 0.50.1)で見た物で、いまは変わっている可能性があります。


