Qwenベースの画像生成モデルをローカルで動かそうとして、VRAM不足に悩んでいる方も多いと思います。
今回は Diffusers の transformer_qwenimage.py(QwenTransformer2DModel)を改造してTransformerブロックをCPUにオフロードする ことで、8GBのGPUでも動かすことに成功したので、その方法の一端を共有します。
問題:Transformerブロックが多すぎてVRAMが足りない
Qwenの画像生成モデルは内部に大量のTransformerブロックを持っています。すべてをGPU(CUDA)上に乗せたまま推論しようとすると、VRAM 8GBでは当然アウトです。
解決策は単純で 「使うときだけGPUに持ってきて、終わったらCPUに戻す」 という逐次オフロードです。
改造内容:forward() メソッドのブロックループ部分
transformer_qwenimage.py の forward() メソッド内、Transformerブロックをループ処理している箇所を以下のように変更します。
変更前(すべてのブロックがGPU常駐)
for block in self.transformer_blocks:
encoder_hidden_states, hidden_states = block(
hidden_states=hidden_states,
encoder_hidden_states=encoder_hidden_states,
encoder_hidden_states_mask=encoder_hidden_states_mask,
temb=temb,
image_rotary_emb=image_rotary_emb,
joint_attention_kwargs=attention_kwargs,
)
変更後(CPUオフロード対応版)
# まずすべてのブロックをCPUに逃がしてVRAMをクリア
for block in self.transformer_blocks:
block.to('cpu')
torch.cuda.empty_cache()
# ブロックを1つずつGPUに持ってきて処理し、終わったらCPUへ
for block in self.transformer_blocks:
if self.is_cuda:
block.to("cuda")
encoder_hidden_states, hidden_states = block(
hidden_states=hidden_states,
encoder_hidden_states=encoder_hidden_states,
encoder_hidden_states_mask=encoder_hidden_states_mask,
temb=temb,
image_rotary_emb=image_rotary_emb,
joint_attention_kwargs=attention_kwargs,
)
block.to('cpu')
torch.cuda.empty_cache()
ループの末尾に block.to('cpu') と torch.cuda.empty_cache() を追加してキャッシュをクリアしていますが不要かもしれません。
コードの仕組みを図で理解する
┌─────────────────────────────────────────────────────┐
│ GPU (VRAM 8GB) │
│ │
│ hidden_states ──▶ [ Block N ] ──▶ hidden_states │
│ ↑ │
│ .to("cuda") │
│ (処理前) │
└─────────────────────────────────────────────────────┘
↕ .to('cpu') / .to("cuda") を繰り返す
┌─────────────────────────────────────────────────────┐
│ CPU (RAM) │
│ │
│ Block 0, Block 1, Block 2, ..., Block N (待機中) │
└─────────────────────────────────────────────────────┘
追加で必要な設定:is_cuda フラグ
コード中に self.is_cuda が登場します。これはモデルクラスの初期化時(__init__)に自前で設定したフラグです。GPUが使用可能かどうかを判定するために使っています。
# __init__ 内に追記
self.is_cuda = torch.cuda.is_available()
あるいはモデルロード後に外から設定しても構いません。
model.is_cuda = torch.cuda.is_available()
速度とトレードオフ
CPUオフロードには当然デメリットもあります。
| 通常(GPU常駐) | CPUオフロード | |
|---|---|---|
| VRAM使用量 | ❌ 非常に多い | ✅ 1ブロック分のみ |
| 推論速度 | ✅ 速い | ⚠️ 遅くなる(PCIe帯域が律速) |
| 動作可否(8GB環境) | ❌ OOM | ✅ 動く |
速度は落ちますが、CPUだけの場合よりは5倍ほど早くなります。
まとめ
transformer_qwenimage.py の forward() に手を加えるだけで、VRAM 8GB環境でもQwenベースの画像生成モデルが動くようになります。
Diffusers の公式APIである enable_model_cpu_offload() はモデル全体に対して動作しますが、今回のようにブロック単位で細かく制御する方法はより柔軟で、特に独自モデルや改造モデルに有効です。
同じ問題で詰まっている方の参考になれば幸いです。
動作確認環境
GPU: VRAM 8GB
ライブラリ: PyTorch + Diffusers
対象ファイル: transformer_qwenimage.py(QwenTransformer2DModel)
またこの実験ではQwen-Image-Edit-2511-SDNQ-uint4-svd-r32 モデル(uit4ビット 量子化)を使用しています。最も安定動作する計量版Qwenモデルかと思います。


