# Patch Notes – ZeroGPU Blackwell 対応 ZeroGPU のハードウェアが **A100 → Half NVIDIA RTX Pro 6000 Blackwell** に変更されたことに伴い、 PyTorch 2.11 / CUDA 13.0 環境で動作するよう以下の修正を適用した。 --- ## 1. `requirements.txt` – torchao バージョン固定を解除 **問題:** `torchao==0.11.0` が固定されていたが、最新の PEFT が `torchao>=0.16.0` を要求するため起動時に `ImportError` が発生していた。 ```diff -torchao==0.11.0 +torchao>=0.16.0 ``` --- ## 2. `app.py` – AOTI コンパイル処理の削除 **問題:** `spaces.aoti_capture / aoti_compile / aoti_apply` は ZeroGPU 独自の実験的 API で、新しい Blackwell ハードウェア上で CUDA キャッシュアロケータのアサート失敗が発生していた。 ``` RuntimeError: NVML_SUCCESS == r INTERNAL ASSERT FAILED at "CUDACachingAllocator.cpp":1165 ``` **対応:** `optimize_pipeline_` の import および呼び出しを削除。Lightning LoRA は 4 ステップ推論なので最適化なしでも実用速度を維持できる。 ```diff -from optimization import optimize_pipeline_ ... -optimize_pipeline_(pipe, image=[...], prompt="prompt") ``` --- ## 3. `app.py` – アテンションプロセッサを FA3 → SDPA に変更 **問題:** `QwenDoubleStreamAttnProcessorFA3` が `kernels-community/vllm-flash-attn3` カーネルを使用しているが、このカーネルは Blackwell アーキテクチャ向けにコンパイルされておらず実行時に CUDA エラーが発生していた。 ``` CUDA error: no kernel image is available for execution on the device ``` **対応:** PyTorch 組み込みの `scaled_dot_product_attention`(SDPA)を使う新しいプロセッサ `QwenDoubleStreamAttnProcessorSDPA` に切り替えた(詳細は項目 5 を参照)。 ```diff -from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorFA3 +from qwenimage.qwen_fa3_processor import QwenDoubleStreamAttnProcessorSDPA ... -pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorFA3()) +pipe.transformer.set_attn_processor(QwenDoubleStreamAttnProcessorSDPA()) ``` --- ## 4. `qwenimage/pipeline_qwenimage_edit_plus.py` – `pos_embed` 呼び出しを新 API に合わせる **問題:** diffusers の `QwenEmbedRope.forward` の引数順が変更されていた。 | | 旧 API(ローカル版) | 新 API(diffusers) | |---|---|---| | 引数 | `(video_fhw, txt_seq_lens, device)` | `(video_fhw, device=None, max_txt_seq_len=None)` | 旧 API で呼び出すと `txt_seq_lens`(list)が `device` の位置に渡され、`lru_cache` がリストをハッシュしようとして `TypeError: unhashable type: 'list'` が発生していた。 **対応:** `max_txt_seq_len` としてバッチ内最大値を渡すよう修正。`pos_embed` の呼び出しは 2 箇所(通常パス・uncond パス)を両方修正した。 ```diff +max_txt_seq_len = max(txt_seq_lens) if txt_seq_lens is not None else 0 -image_rotary_emb = self.transformer.pos_embed(img_shapes, txt_seq_lens, latents.device) +image_rotary_emb = self.transformer.pos_embed(img_shapes, device=latents.device, max_txt_seq_len=max_txt_seq_len) +max_negative_txt_seq_len = max(negative_txt_seq_lens) if negative_txt_seq_lens is not None else 0 -uncond_image_rotary_emb = self.transformer.pos_embed(img_shapes, negative_txt_seq_lens, latents.device) +uncond_image_rotary_emb = self.transformer.pos_embed(img_shapes, device=latents.device, max_txt_seq_len=max_negative_txt_seq_len) ``` --- ## 5. `qwenimage/qwen_fa3_processor.py` – SDPA プロセッサを追加 **対応:** `QwenDoubleStreamAttnProcessorFA3` と同じ dual-stream 処理フローを保ちつつ、アテンション計算のみ SDPA に置き換えた `QwenDoubleStreamAttnProcessorSDPA` クラスを追加。 FA3 と SDPA でテンソルレイアウトが異なるため、入出力で transpose を行う: - FA3: `(B, S, H, D_h)` レイアウト - SDPA: `(B, H, S, D_h)` レイアウト ```python # FA3 (変更前) out = flash_attn_func(q, k, v, causal=False) # (B, S, H, D_h) # SDPA (変更後) out = F.scaled_dot_product_attention( q.transpose(1, 2), k.transpose(1, 2), v.transpose(1, 2), is_causal=False ).transpose(1, 2).contiguous() # back to (B, S, H, D_h) ``` 既存の `QwenDoubleStreamAttnProcessorFA3` クラスはファイルに残置(FA3 対応環境での利用余地)。 --- ## 変更しなかったもの - `pipe.transformer.__class__ = QwenImageTransformer2DModel` — dual-stream アーキテクチャ(`(img_output, txt_output)` タプル返却)に必要なため保持 - `qwenimage/transformer_qwenimage.py` — ローカル版の `QwenEmbedRope` は `pos_embed` インスタンスには使われないが、`QwenImageTransformer2DModel` の forward メソッドのために保持