1. 概要
2025年12月21日(日)に開催予定の第10回 岐阜AI勉強会のため、Black Forest Labs の FLUX.1 [schnell]を動かしました。今回は Google Colab PRO で A100 GPU を選択して実行しました。
コードの処理内容の調査を目的として、Hugging Face のdiffusers の GitHub リポジトリを Git Clone してデバッガでステップ実行する手順を試しました。
2. ブレイクポイントをセットしてデバッグ実行
2.1. Google Drive に Hugging Face の diffusers の GitHub リポジトリを Git Clone
Google Drive for Desktop を Windows にインストールし、Windows にインストールした Git Bash で下記のコマンドを実行しました。G ドライブの「マイドライブ」フォルダに diffusers の GitHub リポジトリを Git Clone しています。
$ cd /g/マイドライブ/ $ git clone https://github.com/huggingface/diffusers.git
上記のコマンドを実行すると、Google Drive 側からは /content/drive/MyDrive/diffusers/src で diffusers の Python スクリプトを参照できます。
2.2. diffusers のソースコードにブレイクポイントをセット
Google Colab でも利用可能な ipdb を使用してデバッグ実行しました。Windows 側で diffusers の Python スクリプトを開き、ブレイクポイントをセットしたい箇所に下記の行を追加します。
import ipdb; ipdb.set_trace()
下記のスクリプトの FluxTransformer2DModel の forward メソッドの先頭に
src/diffusers/models/transformers/transformer_flux.py
下記のようにブレイクポイントをセットして試しました。
If `return_dict` is True, an [`~models.transformer_2d.Transformer2DModelOutput`] is returned, otherwise a
`tuple` where the first element is the sample tensor.
"""
+ import ipdb; ipdb.set_trace()
+
if joint_attention_kwargs is not None:
joint_attention_kwargs = joint_attention_kwargs.copy()
lora_scale = joint_attention_kwargs.pop("scale", 1.0)
2.3. FLUX.1 [schnell] による画像生成を実行し、ブレイクポイントで停止させる
こちらのリンク先に用意した Google Colab のページの下記のコードセルを順に実行します。
2.3.1. Google Drive のマウント
Google Drive をマウントします。
from google.colab import drive
drive.mount('/content/drive')
2.3.2. git clone した diffusers のソースコードの優先参照
git clone した diffusers のソースコードを優先して参照するようにします。
import sys sys.path.insert(0, "/content/drive/MyDrive/diffusers/src")
2.3.3. git clone した diffusers のソースコードが実行されることの確認
pip 等でインストールされたコードではなく、git clone した diffusers のソースコードが実行されることを確認します。
import diffusers print(diffusers.__file__)
git clone した diffusers のソースコードが参照されていれば下記のように出力されます。
/content/drive/MyDrive/diffusers/src/diffusers/__init__.py
2.3.4. diffusers を使用して FLUX.1 [schnell] を実行する際に必要なパッケージのインストール
下記のコードセルを実行し、diffusers を使用して FLUX.1 [schnell] を実行する際に必要なパッケージをインストールします。
!pip install torch torchvision torchaudio !pip install transformers accelerate safetensors !pip install sentencepiece protobuf einops
2.3.5. Python デバッガ ipdb をインストール
!pip install ipdb
2.3.6. FLUX.1 [schnell] を使用した Pipeline を用意
import torch
from diffusers import FluxPipeline
pipe = FluxPipeline.from_pretrained(
"black-forest-labs/FLUX.1-schnell",
torch_dtype=torch.float16
).to("cuda")
2.3.7. FLUX.1 [schnell] を使用して画像を生成
FLUX.1 [schnell] は 4 step で画像を生成できるため、num_inference_steps=4 のようにステップ数 4 を指定しています。
prompt = 'The phrase "Gifu AI Study Group" formed from small colorful geometric shapes.'
image = pipe(
prompt,
guidance_scale=0.0,
num_inference_steps=4,
max_sequence_length=256
).images[0]
image.save("Gifu-AI-study-group.png")
2.4. ipdb によるステップ実行
上記 2.3.7. のコードセルを実行すると上記 2.2. でセットしたブレイクポイントにヒットします。
下記のように表示されるので Google Colab 上で ipdb> の後に c (continue) と入力して Enter キーを押します。c と入力して Enter キーを押す操作を 4 回繰り返すとコードセルが最後まで実行されて画像が生成されます。
> /content/drive/MyDrive/diffusers/src/diffusers/models/transformers/transformer_flux.py(680)forward()
679
--> 680 if joint_attention_kwargs is not None:
681 joint_attention_kwargs = joint_attention_kwargs.copy()
ipdb> c
もう一度同じコードセルを実行すると、また上記の箇所でブレイクポイントにヒットします。c と入力して Enter キーを押す操作を 3 回繰り返し、画像生成の直前まで処理を進めます。
ここで Google Colab 上で ipdb> の後に w (where) と入力して Enter キーを押すと下記のようにスタックトレースが表示されます。
ipdb> w
[... skipping 21 hidden frame(s)]
/tmp/ipython-input-3053860109.py(8)<cell line: 0>()
7 prompt = "A cat holding a sign that says hello world"
----> 8 image = pipe(
9 prompt,
/usr/local/lib/python3.12/dist-packages/torch/utils/_contextlib.py(120)decorate_context()
119 with ctx_factory():
--> 120 return func(*args, **kwargs)
121
/content/drive/MyDrive/diffusers/src/diffusers/pipelines/flux/pipeline_flux.py(944)__call__()
943 with self.transformer.cache_context("cond"):
--> 944 noise_pred = self.transformer(
945 hidden_states=latents,
/usr/local/lib/python3.12/dist-packages/torch/nn/modules/module.py(1775)_wrapped_call_impl()
1774 else:
-> 1775 return self._call_impl(*args, **kwargs)
1776
/usr/local/lib/python3.12/dist-packages/torch/nn/modules/module.py(1786)_call_impl()
1785 or _global_forward_hooks or _global_forward_pre_hooks):
-> 1786 return forward_call(*args, **kwargs)
1787
/usr/local/lib/python3.12/dist-packages/accelerate/hooks.py(175)new_forward()
174 else:
--> 175 output = module._old_forward(*args, **kwargs)
176 return module._hf_hook.post_forward(module, output)
> /content/drive/MyDrive/diffusers/src/diffusers/models/transformers/transformer_flux.py(680)forward()
679
--> 680 if joint_attention_kwargs is not None:
681 joint_attention_kwargs = joint_attention_kwargs.copy()
Google Colab 上で ipdb> の後に u (up) と入力すると呼び出し元フレームへ移動します。u と入力して Enter を押す操作を 4 回繰り返すと pipeline_flux.py の下記の呼び出し元に移動します。
ipdb> u
...
ipdb> u
...
ipdb> u
...
ipdb> u
> /content/drive/MyDrive/diffusers/src/diffusers/pipelines/flux/pipeline_flux.py(944)__call__()
943 with self.transformer.cache_context("cond"):
--> 944 noise_pred = self.transformer(
945 hidden_states=latents,
Google Colab 上で ipdb> の後に n (next) と入力すると関数の中に入らないで次の行へ進みます。n と入力して Enter を押す操作を何回か繰り返し、pipeline_flux.py の下記の行まで実行します。
ipdb> n
...
ipdb> n
...
ipdb> n
> /content/drive/MyDrive/diffusers/src/diffusers/pipelines/flux/pipeline_flux.py(1004)__call__()
1003 else:
-> 1004 latents = self._unpack_latents(latents, height, width, self.vae_scale_factor)
1005 latents = (latents / self.vae.config.scaling_factor) + self.vae.config.shift_factor
下記の例のように Google Colab 上で ipdb> の後に p latents と入力すると latents の内容が表示されます。p は print です。また、p latents.shape と入力すると多次元配列 (tensor) の各軸のサイズが表示されます。
ipdb> p latents
tensor([[[ 1.0859, 0.1621, 0.1572, ..., -1.6406, -2.0781, -1.8125],
[ 0.2773, 0.2148, -0.4512, ..., -1.7500, -2.1250, -2.0000],
[ 0.2441, 0.2598, -0.1777, ..., -1.7344, -2.0000, -1.9922],
...,
[-0.4922, -0.0186, -0.0430, ..., -1.5938, -1.7500, -1.3125],
[ 0.4531, -0.0596, -0.1523, ..., -2.0000, -1.6406, -1.4688],
[-0.4102, -0.4062, -0.0442, ..., -1.7578, -1.3906, -1.3438]]],
device='cuda:0', dtype=torch.bfloat16)
ipdb> p latents.shape
torch.Size([1, 4096, 64])
下記の例は、Google Colab 上で ipdb> の後に n と入力し、次の行まで実行を進めてから更新された latents と image の各軸のサイズを表示する操作を繰り返した例になります。
ipdb> n > /content/drive/MyDrive/diffusers/src/diffusers/pipelines/flux/pipeline_flux.py(1005)__call__() 1004 latents = self._unpack_latents(latents, height, width, self.vae_scale_factor) -> 1005 latents = (latents / self.vae.config.scaling_factor) + self.vae.config.shift_factor 1006 image = self.vae.decode(latents, return_dict=False)[0] ipdb> p latents.shape torch.Size([1, 16, 128, 128]) ipdb> n > /content/drive/MyDrive/diffusers/src/diffusers/pipelines/flux/pipeline_flux.py(1006)__call__() 1005 latents = (latents / self.vae.config.scaling_factor) + self.vae.config.shift_factor -> 1006 image = self.vae.decode(latents, return_dict=False)[0] 1007 image = self.image_processor.postprocess(image, output_type=output_type) ipdb> p latents.shape torch.Size([1, 16, 128, 128]) ipdb> n > /content/drive/MyDrive/diffusers/src/diffusers/pipelines/flux/pipeline_flux.py(1007)__call__() 1006 image = self.vae.decode(latents, return_dict=False)[0] -> 1007 image = self.image_processor.postprocess(image, output_type=output_type) 1008 ipdb> p image.shape torch.Size([1, 3, 1024, 1024])
下の表は ipdb 及び pdb でよく使用されるコマンドをまとめた表になります。
実行制御系
| 省略形 | 正式名 | 意味 |
|---|---|---|
| c | continue | 次のブレークポイントまで実行 |
| n | next | 次の行へ進む(関数には入らない) |
| s | step | 次の行へ進む(関数に入る) |
| 省略形なし | until | 指定行まで実行 |
| r | return | 現在の関数から戻るまで実行 |
| q | quit | デバッガを終了 |
スタック・位置確認系
| 省略形 | 正式名 | 意味 |
|---|---|---|
| w | where | スタックトレース(コールスタック)を表示 |
| u | up | 呼び出し元のスタックフレームへ移動 |
| d | down | 呼び出し先のスタックフレームへ移動 |
表示・確認系
| 省略形 | 正式名 | 意味 |
|---|---|---|
| l | list | 周辺のソースコードを表示 |
| p | 変数を表示 | |
| pp | pretty print | 変数を整形して表示 |
| a | args | 現在の関数の引数を表示 |
| whatis | whatis | 変数の型を表示 |