[bug]: FLUX final-layer modulation LoRA layer is not converted (FLUX.1 diffusers: load fails, FLUX.2 BFL: layer skipped)

クローズ 初心者向け
#10,022 コメント 2 件 リアクション 0 件 担当者 0 名 GitHub で見る

メンテナーはふだん 2 日以内に返信

関連するプルリクエストがすでにマージされています。

  • #10052 @Pfannkuchensack による — マージ済み

評価

難易度
2/5
見積もり時間
1〜3時間
初心者へのやさしさ
75/100
issue の種類
バグ
明瞭さ
明確に書かれている
活発さ
活発
技術スタック
python, pytorch

調査の方向性

invokeai/backend/patches/lora_conversions/flux_diffusers_lora_conversion_utils.py の288行目のassertから始めて、norm_out.linear のルールを追加します。次に flux_bfl_peft_lora_conversion_utils.py の map を更新し、入れ替えた半分を持つ final_layer.adaLN_modulation.1 を含めるようにします。issueの再現スクリプトを実行して、AssertionErrorが消え、モジュール解決がTrueを返すことを確認してください。

索引モデルが issue の本文から書いたものです。

説明

bug
Is there an existing issue for this problem?
  • I have searched the existing issues
Install method

Manual (dev checkout)

Operating system

Windows

GPU vendor

Not GPU-specific (reproduced on CPU)

GPU model

No response

GPU VRAM

No response

Version number

main at 0ddc9df91b

What happened

The final-layer modulation (norm_out.linear in diffusers naming, final_layer.adaLN_modulation.1 in BFL naming) is not converted for FLUX:

  • FLUX.1, diffusers keys: the whole LoRA fails to load. lora_layers_from_flux_diffusers_grouped_state_dict (invokeai/backend/patches/lora_conversions/flux_diffusers_lora_conversion_utils.py) has no rule for norm_out.linear, so the closing assert len(grouped_state_dict) == 0 (line 288) fires. Diffusers-format LoRAs that train every linear layer contain this layer. OneTrainer's FLUX.1 LoRA preset trains every layer by default.
  • FLUX.2, BFL keys: the layer is skipped. The BFL→diffusers map in flux_bfl_peft_lora_conversion_utils.py has final_layer.linear → proj_out (line 111) but nothing for final_layer.adaLN_modulation.1. The key stays BFL-named and does not resolve on Flux2Transformer2DModel ("Failed to find module").

Both directions need the two output halves swapped. diffusers' AdaLayerNormContinuous splits the projection into (scale, shift), while BFL's LastLayer splits it into (shift, scale). The halves of lora_up / lora_B rows therefore swap on conversion.

What you expected to happen

norm_out.linear maps to final_layer.adaLN_modulation.1 for FLUX.1, and back for FLUX.2, with the halves swapped. The LoRA loads and the layer is applied.

How to reproduce the problem
import torch
from diffusers import Flux2Transformer2DModel

import invokeai.backend.model_manager.load  # noqa: F401
from invokeai.backend.patches.lora_conversions.flux_bfl_peft_lora_conversion_utils import (
    lora_model_from_flux2_bfl_peft_state_dict,
)
from invokeai.backend.patches.lora_conversions.flux_diffusers_lora_conversion_utils import (
    lora_model_from_flux_diffusers_state_dict,
)

# FLUX.1, diffusers names: norm_out.linear (3072 -> 6144)
sd = {"transformer.norm_out.linear.lora_A.weight": torch.randn(4, 3072), "transformer.norm_out.linear.lora_B.weight": torch.randn(6144, 4)}
try:
    lora_model_from_flux_diffusers_state_dict(sd, alpha=None)
except AssertionError:
    print("FLUX.1 diffusers: AssertionError (norm_out.linear left unconsumed)")

# FLUX.2 Klein 9B, BFL names: final_layer.adaLN_modulation.1 (4096 -> 8192)
p = "diffusion_model.final_layer.adaLN_modulation.1"
patch = lora_model_from_flux2_bfl_peft_state_dict({f"{p}.lora_A.weight": torch.randn(4, 4096), f"{p}.lora_B.weight": torch.randn(8192, 4)}, alpha=None)
with torch.device("meta"):
    model = Flux2Transformer2DModel(num_layers=8, num_single_layers=24, attention_head_dim=128, num_attention_heads=32, joint_attention_dim=12288)
for key in patch.layers:
    target = key.removeprefix("lora_transformer-")
    print("FLUX.2 BFL:", key, "-> module exists:", target in dict(model.named_modules()))

Output on main:

FLUX.1 diffusers: AssertionError (norm_out.linear left unconsumed)
FLUX.2 BFL: lora_transformer-final_layer.adaLN_modulation.1 -> module exists: False
Additional context

Once norm_out.linear passes, a full-layer FLUX.1 dev LoRA runs into #10023 next.

Found while checking every LoRA layout OneTrainer writes (b08db37) against main: OneTrainer's own savers run on meta-device models of the real architectures, then identification, LoRALoader and LayerPatcher module resolution on the InvokeAI model.

Discord username

No response

主要言語
TypeScript
スター
28.9k
フォーク
3.1k
平均マージ
4日 2時間
マージ済み PR(30日)
220

環境構築

  • Dockerfile・Docker Compose ファイルなし
  • プルリクエストのテンプレートあり
  • コントリビューションガイドなし

はじめの一歩

  1. issue を最後まで読み、次にプロジェクトのコントリビューションガイドを読みます。
  2. 着手することを issue にコメントします — 二人が同じ作業をするのを防げます。
  3. リポジトリをフォークし、ブランチを切って変更します。
  4. issue 番号を参照したプルリクエストを送ります。

invoke-ai/InvokeAI のほかの issue

invoke-ai/InvokeAI の issue をすべて見る

似ている issue

TypeScript の issue をもっと見る

新しい issue をメールで受け取る

初心者向けの GitHub issue を短くまとめたダイジェスト。