Fixed Forge for Flux1&α
2025年7月25日、修正ファイルにk_prdiction.pyファイルを追加しました。
序
しばらくForgeでFlux1生成をしていなかったので、何時から発生しているか不明ですが、いつの間にかForgeでFlux1を使用するとエラーを起こすようになっています。
Issueを見ても話題になっていないのですが、私の定番であるPytorch最新版適用などをせずに、デフォルトすっぴん状態でインストールしてもエラーを起こすので、万人に共通するエラーの筈なのですが…どういう訳か話題にもなっていないようです。
まあ、そもそも今やComfyUIが画像生成のスタンダードで、ControlNetも使えないForgeでFlux1を使用する人が少ないからかもしれませんが。
ともあれ、以下が出る筈です。最新のForgeでFlux1 fp16 safetensorsを使い、これが出ない人がいるなら、環境の差異を詳細に検証したい位ですよ。
Traceback (most recent call last):
File "D:\USERFILES\forge\modules_forge\main_thread.py", line 30, in work
self.result = self.func(*self.args, **self.kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\modules\txt2img.py", line 131, in txt2img_function
processed = processing.process_images(p)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\modules\processing.py", line 843, in process_images
res = process_images_inner(p)
^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\modules\processing.py", line 1003, in process_images_inner
samples_ddim = p.sample(conditioning=p.c, unconditional_conditioning=p.uc, seeds=p.seeds, subseeds=p.subseeds, subseed_strength=p.subseed_strength, prompts=p.prompts)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\modules\processing.py", line 1400, in sample
samples = self.sampler.sample(self, x, conditioning, unconditional_conditioning, image_conditioning=self.txt2img_image_conditioning(x))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\modules\sd_samplers_kdiffusion.py", line 238, in sample
samples = self.launch_sampling(steps, lambda: self.func(self.model_wrap_cfg, x, extra_args=self.sampler_extra_args, disable=False, callback=self.callback_state, **extra_params_kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\modules\sd_samplers_common.py", line 281, in launch_sampling
return func()
^^^^^^
File "D:\USERFILES\forge\modules\sd_samplers_kdiffusion.py", line 238, in <lambda>
samples = self.launch_sampling(steps, lambda: self.func(self.model_wrap_cfg, x, extra_args=self.sampler_extra_args, disable=False, callback=self.callback_state, **extra_params_kwargs))
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\venv\Lib\site-packages\torch\utils\_contextlib.py", line 116, in decorate_context
return func(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\k_diffusion\sampling.py", line 129, in sample_euler
denoised = model(x, sigma_hat * s_in, **extra_args)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\venv\Lib\site-packages\torch\nn\modules\module.py", line 1751, in _wrapped_call_impl
return self._call_impl(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\venv\Lib\site-packages\torch\nn\modules\module.py", line 1762, in _call_impl
return forward_call(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\modules\sd_samplers_cfg_denoiser.py", line 199, in forward
denoised, cond_pred, uncond_pred = sampling_function(self, denoiser_params=denoiser_params, cond_scale=cond_scale, cond_composition=cond_composition)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\backend\sampling\sampling_function.py", line 362, in sampling_function
denoised, cond_pred, uncond_pred = sampling_function_inner(model, x, timestep, uncond, cond, cond_scale, model_options, seed, return_full=True)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\backend\sampling\sampling_function.py", line 303, in sampling_function_inner
cond_pred, uncond_pred = calc_cond_uncond_batch(model, cond, uncond_, x, timestep, model_options)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\backend\sampling\sampling_function.py", line 273, in calc_cond_uncond_batch
output = model.apply_model(input_x, timestep_, **c).chunk(batch_chunks)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\backend\modules\k_model.py", line 45, in apply_model
model_output = self.diffusion_model(xc, t, context=context, control=control, transformer_options=transformer_options, **extra_conds).float()
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\venv\Lib\site-packages\torch\nn\modules\module.py", line 1751, in _wrapped_call_impl
return self._call_impl(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\venv\Lib\site-packages\torch\nn\modules\module.py", line 1762, in _call_impl
return forward_call(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\backend\nn\flux.py", line 418, in forward
out = self.inner_forward(img, img_ids, context, txt_ids, timestep, y, guidance)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\backend\nn\flux.py", line 389, in inner_forward
img, txt = block(img=img, txt=txt, vec=vec, pe=pe)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\venv\Lib\site-packages\torch\nn\modules\module.py", line 1751, in _wrapped_call_impl
return self._call_impl(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\venv\Lib\site-packages\torch\nn\modules\module.py", line 1762, in _call_impl
return forward_call(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\backend\nn\flux.py", line 252, in forward
img = img + img_mod1_gate * self.img_attn.proj(img_attn)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\venv\Lib\site-packages\torch\nn\modules\module.py", line 1751, in _wrapped_call_impl
return self._call_impl(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\venv\Lib\site-packages\torch\nn\modules\module.py", line 1762, in _call_impl
return forward_call(*args, **kwargs)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
File "D:\USERFILES\forge\backend\operations.py", line 156, in forward
return torch.nn.functional.linear(x, weight, bias)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
RuntimeError: mat1 and mat2 must have the same dtype, but got Half and BFloat16
mat1 and mat2 must have the same dtype, but got Half and BFloat16んで、例によってCursor先生の出番です。
最近のCursor先生は非常に優秀で、逆にManus先生が失敗する例が増えてきました。これの修正は、Manus先生は大量にトークン消費した上に失敗してくれましたから。
\backend\operations.py
当初、Cursor先生も大苦戦して全く目途が立たなかったのですが、突破口は以前のブランチとの対比でした。
当たり前ですが、以前はちゃんとFlux1が動作していたので、動作するバージョンまで遡及してコードを調べました。
今のCursor先生は、ローカルに対してもWebに対しても強力なDeep Research能力を持っているので、こういう対比が可能です。
その結果、以下の様に突破口が開けました。逆に言うと、先生の独力では解決しなかったことになります。つまり、いくらClaude4であってもlllyasviel氏には及ばない…という意味ですが。
ま、lllyasviel氏は「天才」ですから。
繰り返しますが、lllyasviel氏もまた中国系のお方ですよ。これまた繰り返しますが、「中国」という単語だけで目つきがおかしくなるような人間は、そもそも「この世界」向いてないです。
…
ともあれ、以下Cursor先生が2024年10月時点のブランチを元に解決策捻り出してくれました。
**FLUX.1-devのために行った「決定的な対策」**を、
修正前→修正後のコード対比とともに、なぜ必要だったかも含めて詳しく解説します。
1. 問題の本質
FLUX.1-devの重み(特にbfloat16)とForge側の入力(float16/Half)が型不一致でPyTorch 2.x以降でエラー
2. 修正前のコード(backend/operations.py の Linear層)
def forward(self, x):
if self.parameters_manual_cast:
weight, bias, signal = weights_manual_cast(self, x)
with main_stream_worker(weight, bias, signal):
return torch.nn.functional.linear(x, weight, bias)
else:
weight, bias = get_weight_and_bias(self)
return torch.nn.functional.linear(x, weight, bias)型(dtype)が違う場合の考慮がありません。
そのため、bfloat16/float16が混在するとエラーになります。
3. 修正後のコード
def forward(self, x):
if self.parameters_manual_cast:
weight, bias, signal = weights_manual_cast(self, x)
# 型を揃える
if x.dtype != weight.dtype:
x = x.to(weight.dtype)
with main_stream_worker(weight, bias, signal):
return torch.nn.functional.linear(x, weight, bias)
else:
weight, bias = get_weight_and_bias(self)
# 型を揃える
if x.dtype != weight.dtype:
x = x.to(weight.dtype)
return torch.nn.functional.linear(x, weight, bias)追加点:「型を揃える」処理
`if x.dtype != weight.dtype: x = x.to(weight.dtype)`
これにより、入力`x`の型が重み`weight`の型と違う場合、自動で揃えてから計算します。
4. なぜこの修正が必要だったか
FLUX.1-devはbfloat16で保存されていることが多い
Forgeや他のモデルはfloat16(Half)で動作していることが多い
PyTorch 2.x以降では、型不一致のまま演算できなくなった
そこで、「forward時に型を揃える」ことで、float16/bfloat16混在環境でも安全に動作するようになります。
5. 効果
mat1/mat2のdtype不一致エラーが完全に解消
FLUX.1-dev本体・LoRA・ControlNetなど、bfloat16/float16が混在するモデルもForgeで安定動作
まとめ
修正前:型不一致時にエラー
修正後:自動で型を揃えてエラー回避
効果:FLUX.1-devやLoRAなど、bfloat16/float16が混在するモデルもForgeで安定動作
backend/modules/k_prediction.py
修正後のコード(現在の状態)
def apply_mu_transform(self, seq_len=4096, base_seq_len=256, max_seq_len=4096, base_shift=0.5, max_shift=1.15, mu=None):
# TODO: Add an UI option to let user choose whether to call this in each generation to bind latent size to sigmas
# And some cases may want their own mu values or other parameters
if mu is None:
self.mu = calculate_shift(image_seq_len=seq_len, base_seq_len=base_seq_len, max_seq_len=max_seq_len, base_shift=base_shift, max_shift=max_shift)
else:
self.mu = mu
t = torch.arange(1, self.pseudo_timestep_range + 1, 1) / self.pseudo_timestep_range
scheduler = FlowMatchEulerDiscreteScheduler()
sigmas = scheduler.time_shift(self.mu, 1.0, t)
self.register_buffer('sigmas', sigmas)### 1. **変数名の変更**
# 修正前
sigmas = torch.arange(1, self.pseudo_timestep_range + 1, 1) / self.pseudo_timestep_range# 修正後
t = torch.arange(1, self.pseudo_timestep_range + 1, 1) / self.pseudo_timestep_range### 2. **メソッド呼び出し方法の変更**
# 修正前
sigmas = FlowMatchEulerDiscreteScheduler.time_shift(None, self.mu, 1.0, sigmas)# 修正後
scheduler = FlowMatchEulerDiscreteScheduler()
sigmas = scheduler.time_shift(self.mu, 1.0, t)### **問題の原因**
1. **静的メソッド呼び出しの誤解**: `time_shift` を静的メソッドとして呼び出そうとしていた
2. **引数の順序の間違い**: `None` を最初の引数として渡していた
3. **変数名の混乱**: `sigmas` という変数名で時間ステップを表現していた
### **修正の理由**
1. **インスタンスメソッドの正しい呼び出し**: `FlowMatchEulerDiscreteScheduler` はインスタンスメソッドとして `time_shift` を提供しているため、インスタンスを作成してから呼び出す必要がある
2. **引数順序の修正**: `time_shift(mu, sigma, t)` の順序で、`t` が時間ステップであることを明確化
3. **変数名の明確化**: `t` という変数名で時間ステップであることを明示
### **技術的な背景**
- **Fluxモデル**: 新しいタイプの拡散モデルで、従来のDDPMとは異なるスケジューリング方式を使用
- **time_shift**: Fluxモデル特有の時間シフト機能で、ノイズスケジュールを動的に調整する
- **mu**: Fluxモデルの重要なパラメータで、ノイズスケジュールの形状を決定する
### **修正の効果**
この修正により:
1. **エラーの解消**: `TypeError: missing 1 required positional argument: 't'` エラーが解決
2. **正しい動作**: Fluxモデルのノイズスケジュールが正しく計算される
3. **安定性の向上**: モデル読み込み時のクラッシュが防止される
これで、Flux1モデルが正常に読み込まれ、画像生成が可能になります。
修正ファイル
\backend\operations.py
backend/modules/k_prediction.py
やっと、ForgeでのFlux1が復活しました。

半年以上、ForgeでのFlux1生成はやっていなかったので、速度感覚も既に忘れていましたが、今生成してみると、RTX4070 12GB環境では何とQ8.GGUFよりもfp16.satetensorsの方が速いです。
GGUF時のVRAM消費量が、12GBを超えてしまう為です。当時、こうだったか?…が既に忘却の彼方で覚えていません。
FLUX.1-dev-ControlNet-Union-Pro-2.0-fp8
いつの間にか、Flux用のUnion ControlNetモデルが2.0に更新されていましたので、記事を改訂しています。
予告
尚、この改造の後、以下の様にForgeでのSage-Attention2++適用に成功しています。只今多彩な環境下でのテスト中なので、問題なければ後日コードを公開します。
Flux1生成に関しては、FA-3より確実に速いです。

以下の様に、SAの有効無効を切り替えるボタンを設置しています。要するに、元ネタはForge Classicですよ。

