Stable Diffusionのオリジナル開発陣が発表した画像生成AIモデルFLUX.1([dev]/[schnell])をMacBook(M2)で動かしてみた

[Supership](https://supership.jp/)の名畑です。[逃げ上手の若君](https://nigewaka.run/)はジャンプでも読んでいるのですが、アニメも[OP](https://www.youtube.com/watch?v=XmpgKUcm2nI)と[ED](https://www.youtube.com/watch?v=VNl4J9b_xhE)までを含め期待を上回る出来で毎週楽しみに見ています。余談ですがEDを歌っている[ぼっちぼろまる](https://www.boromaru.tokyo/)さんの[タンタカタンタンタンタンメン](https://www.youtube.com/watch?v=1T0XtlM_8QQ)は昔から好きです。

## はじめに

[Black Forest Labs](https://blackforestlabs.ai/)のニュースが話題になっています。

> 画像生成AIの「Stable Diffusion」などの開発に携わったAI研究者が、新しいAI開発企業の「Black Forest Labs」を立ち上げました。さらに、Black Forest Labsはパラメーターサイズが120億のオープンソース画像生成AIモデル「Flux」も発表しています。
>
> 参考：[Stable Diffusionのオリジナル開発陣がAI企業「Black Forest Labs」を立ち上げ独自の画像生成AIモデル「Flux」をリリース - GIGAZINE](https://gigazine.net/news/20240802-black-forest-labs-image-ai-flux/)

> 画像生成AIモデル「Stable Diffusion」の共同開発者たちによって設立されたベンチャー企業「Black Forest Labs（BFL）」は8月1日（現地時間）、高品質な画像生成能力と多様な出力が特徴の最新の画像生成AIモデル「FLUX.1」を発表した。
> 
> 参考：[ASCII.jp：「Stable Diffusion」開発者たちが新たな画像生成AI「FLUX.1」を発表　迷走するStability AIと対照的な展開に](https://ascii.jp/elem/000/004/213/4213683/)

ということで、画像生成AIモデルである**FLUX.1**を手元のMacBook(M2)で動かした過程を記事に残します。

コードはすべて**Python**です。

## FLUX.1について

詳しくは公式アナウンスである「[Announcing Black Forest Labs &#x2d; Black Forest Labs](https://blackforestlabs.ai/announcing-black-forest-labs/)」をご覧いただければと思いますが、以下の3つのモデルがあります。

- **FLUX.1 [pro]**
	- 最先端のパフォーマンスを持つ画像生成モデルで、API経由でアクセス可能。
- **FLUX.1 [dev]**
	- 非商用アプリケーション向けのモデルで、Hugging Faceで入手可能で、商用利用の場合は問い合わせが必要。
- **FLUX.1 [schnell]**
	- ローカル開発や個人使用向けの高速モデルで、Apache2.0ライセンスの下で公開されている。Hugging Faceで入手でき、推論コードはGitHubおよびHugging FaceのDiffusersで見つけることができる。ComfyUIとの統合もサポートしている。

本当は **FLUX.1 [pro]** を試したかったのですが、[API](https://docs.bfl.ml/)は現時点(2024.8.5)ではまだ「**Accounts are only activated for selected partners.**」ということで招待制です。
[**Replicate**](https://replicate.com/)や[**Fal.ai**](https://fal.ai/)を経由すれば呼べるのでしょうが、今回はローカルで生成できる最も高品質なモデルである **FLUX.1 [dev]** を用いることにします。
記事の最後に **FLUX.1 [schnell]** での生成例も載せます。

「**とりあえずどんな画像が生成されるかだけ自分で試してみたい**」という方は以下のリンク先にてWeb上で生成可能です。有料なものもありますのでご注意ください。

- **FLUX.1 [pro]**
	- [Replicate](https://replicate.com/black-forest-labs/flux-pro)
	- [Fal.ai](https://fal.ai/models/fal-ai/flux-pro)
- **FLUX.1 [dev]**
	- [Hugging Face](https://huggingface.co/spaces/black-forest-labs/FLUX.1-dev)
	- [Replicate](https://replicate.com/black-forest-labs/flux-dev)
	- [Fal.ai](https://fal.ai/models/fal-ai/flux/dev)
- **FLUX.1 [schnell]**
	- [Hugging Face](https://huggingface.co/spaces/black-forest-labs/FLUX.1-schnell)
	- [Replicate](https://replicate.com/black-forest-labs/flux-schnell)
	- [Fal.ai](https://fal.ai/models/fal-ai/flux/schnell)

## 私の環境

[MacBook Pro(Apple M2 Proチップ / メモリ16GB)](https://support.apple.com/kb/SP889?locale=ja_JP)です。
OSは[macOS 14 Sonoma](https://www.apple.com/jp/macos/sonoma/)です。

パッケージとしては[diffusers](https://github.com/huggingface/diffusers)、[sentencepiece](https://pypi.org/project/sentencepiece/)、[t5](https://huggingface.co/docs/transformers/model_doc/t5)、[torch](https://pytorch.org/)、[transformers](https://huggingface.co/docs/transformers/index)が必要です。**diffusers**については[公式の手順](https://huggingface.co/black-forest-labs/FLUX.1-dev#diffusers)に従い、githubからのインストールとします。
まとめると以下コマンドです。**torch**は後述の理由でバージョンを絞っています。

```shell-session
$ pip install sentencepiece torch==2.3.1 transformers git+https://github.com/huggingface/diffusers.git
```

私の環境でのバージョンはそれぞれ以下です。

```shell-session
$ pip list | grep -e diffusers -e sentencepiece -e t5 -e torch -e transformers
diffusers                    0.30.0.dev0
sentencepiece                0.2.0
t5                           0.9.4
torch                        2.3.1
transformers                 4.43.3
```

torchは現時点(2024.8.5)の最新は**2.4.0**なのですが、**2.3.1**にダウングレードしました。
最初は**2.4.0**で進めていたのですが、生成画像のノイズがひどく、なぜか検索してみるとダウングレードでうまくいったという情報が見つかったためです。因果関係は調べきれていませんが、解決はしています。

ちなみにノイズがひどい画像というのは以下のようなものです。

![flux-4.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/f1c982cb-5725-8fea-5606-4f1a2fef9fc6.png)

## アクセス権の取得

今回は[Hugging Face](https://huggingface.co/)経由でモデルを入手して実行します。
そのためにまずは**Hugging Face**のアカウントを作成します。

アカウントを作成してログイン後[FLUX.1-devのページ](https://huggingface.co/black-forest-labs/FLUX.1-dev)に行くと規約への同意が求められます。

![flux_1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/1fc1257b-fdba-283c-7918-3f8fcc3ea550.png)

規約を読んで納得した上で**Agree and access repository**を押します。

以下のようにアクセス権が得られたことが確認できます。

![flux_2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/11b077b4-8e37-f07c-9710-bedcb3d4f501.png)

## アクセストークンの作成

モデルをダウンロードする際のユーザー認証のため、**Hugging Face**のアクセストークンを作成します。

**Hugging Face**で[Settings](https://huggingface.co/settings/profile)に移動し、さらに[Access Tokens](https://huggingface.co/settings/tokens)に移動します。

ここで**Create new Access Token**を押します。

読み取り権限があればいいので**Read**を選び、好きな名前を指定して生成してください。

![flux_3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/10849c3a-d2cd-2909-7eb9-01e292c1958a.png)

ハードコーディングを避けるため、環境変数にセットします。

まず設定ファイルを開きます。私の環境では**zshrc**です。

```shell-session
$ open ~/.zshrc
```

生成したアクセストークンの値を記録します。
私は**HUGGING\_FACE\_TOKEN**という名前にしました。

```shell-session
export HUGGING_FACE_TOKEN=ここにアクセストークンの値を書く
```

## PYTORCH\_MPS\_HIGH\_WATERMARK\_RATIOの指定

メモリ16GBマシンなので当たり前ではありますが、私の環境ではメモリが不充分なためか、そのまま実行すると以下のエラーが出ました。

> RuntimeError: MPS backend out of memory
> Use PYTORCH\_MPS\_HIGH\_WATERMARK\_RATIO=0.0 to disable upper limit for memory allocations (may cause system failure).

**MacBook**の**GPU**である**MPS**の容量不足です。

指示通り、環境変数として以下の指定をしました。こうすることで**MPS**の使用上限がなくなります。

```shell-session
export PYTORCH_MPS_HIGH_WATERMARK_RATIO=0.0
```

ただし、メモリ使用のリミットをはずすことでメモリ枯渇によるPC停止もありえますのでご注意ください。

最初は0.0ではない値にしようかと思ったのですが、以下のエラーが出るので断念して0.0としました。

> RuntimeError: invalid low watermark ratio 1.4

[torch.mps.empty_cache()](https://pytorch.org/docs/stable/generated/torch.mps.empty_cache.html#torch.mps.empty_cache)で**MPS**のキャッシュをクリアできますので、こちらを適宜呼ぶことでメモリ容量の不足を回避することができるのであれば、その方が良いですね。

## transformer_flux.pyの修正

このまま実行すると、まだエラーが発生します。

> scale = torch.arange(0, dim, 2, dtype=torch.float64, device=pos.device) / dim
> TypeError: Cannot convert a MPS Tensor to float64 dtype as the MPS framework doesn't support float64. Please use float32 instead.

**float64**の代わりに**float32**を使うようにというエラーです。[transformer_flux.pyの該当箇所](https://github.com/huggingface/diffusers/blob/a054c784955023385cf91e792db10970d00ca281/src/diffusers/models/transformers/transformer_flux.py#L41)を以下のように変更すれば回避できます。

```python
# scale = torch.arange(0, dim, 2, dtype=torch.float64, device=pos.device) / dim
scale = torch.arange(0, dim, 2, dtype=torch.get_default_dtype(), device=pos.device) / dim
```

GitHubのissueでも「[flux does not work on MPS devices](https://github.com/huggingface/diffusers/issues/9047)」として上がっていますので、近いうちに対応される可能性はあります。
[ComfyUI](https://github.com/comfyanonymous/ComfyUI)でも「[FLUX Issue | MPS framework doesn't support float64 ](https://github.com/comfyanonymous/ComfyUI/issues/4165)」というissueがありました。

## コード

[公式のサンプルコード](https://huggingface.co/black-forest-labs/FLUX.1-dev#diffusers)のままでは動かないため、以下を変更しています。

1. アクセストークンの指定
2. **MacBook**の**GPU**を使用するために**device**として**mps**を指定
3. **enable\_model\_cpu\_offload**の呼び出しを削除
	- 呼び出すと**CUDA**前提の処理が流れるため「**AssertionError: Torch not compiled with CUDA enabled**」が起こります。

コードは以下です。公式サンプルコードからの変更箇所はコメントに記載済みです。

```python
import torch
from diffusers import FluxPipeline
import os  # 環境変数読み込みのために追加

hf_token = os.getenv("HUGGING_FACE_TOKEN")  # Hugging Faceのトークンを取得
pipe = FluxPipeline.from_pretrained("black-forest-labs/FLUX.1-dev",
                                    torch_dtype=torch.bfloat16,
                                    token=hf_token  # Hugging Faceのトークンを指定
)
pipe.to(torch.device("mps"))  # deviceとしてMPSを指定する
# pipe.enable_model_cpu_offload()  # 呼び出し削除

prompt = "A cat holding a sign that says hello world"
image = pipe(
    prompt,
    height=1024,
    width=1024,
    guidance_scale=3.5,
    output_type="pil",
    num_inference_steps=50,
    max_sequence_length=512,
    generator=torch.Generator("cpu").manual_seed(0)
).images[0]
image.save("flux-dev.png")
```

品質は後回しでとりあえず生成を試すだけなら、時間を短縮するために**num\_inference\_steps**を小さくする方がいいかもしれません。
シード値の調整は**generator**で行えます。
呼び出し時のパラメータについて詳しくは[api reference](https://huggingface.co/docs/diffusers/main/en/api/pipelines/flux#diffusers.FluxPipeline.__call__)をご覧ください。

モデルに対して「**A cat holding a sign that says hello world**」というプロンプトで画像を生成しています。
訳すと「**hello worldという看板を持った猫**」ですね。

初回はモデル等のダウンロードが必要となります。30GB以上あるので、環境によってはかなり時間がかかるかと思います。

## 結果

![flux-5.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/f647e41a-7b45-42e2-2c8e-2f368b2316fb.png)

気になるところはあれど、かなり綺麗で、そして「**Hello World**」という文字もきっちり示せています。プロンプトを忠実に再現していますね。

また、せっかくなので別プロンプトでも試してみました。

```python
prompt = "anime style, Japanese moe heroine"
```

「**anime style, Japanese moe heroine**」なので、訳すと「**アニメスタイル、日本の萌えヒロイン**」です。

その結果は以下でした。

![flux-6.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/063f07b7-c564-05c1-b08b-12dc80d94568.png)

なにを以て**萌え**とするかはここでは論じませんが、こちらもプロンプトを忠実に再現した高品質な画像と感じます。

ちなみに[過去記事](https://qiita.com/nabata/items/52a25e3f2bac99a2527d)の際に同一プロンプトを用いて**Stable Image Ultra**で生成した画像は以下でした。

![flux-sd-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/97e18462-f44a-3c38-5603-c65bf46935e6.png)
<!--![flux-sd-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/3dad4f37-d993-8cf2-8a8d-7f7c94185781.png)-->
<!--![flux-sd-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/22a283ee-41a2-d436-763b-f422f623e9b7.png)-->

比較してみると、**FLUX.1**の方が萌えヒロインという言葉に近い、かな？

## FLUX.1 [schnell]でも試してみた

高速モデル、つまり少ないステップ数で画像の生成が可能である **FLUX.1 [schnell]** においても[公式のサンプルコード](https://huggingface.co/black-forest-labs/FLUX.1-schnell#diffusers)を元にして画像生成をしてみました。

```python
import torch
from diffusers import FluxPipeline
import os  # 環境変数読み込みのために追加

hf_token = os.getenv("HUGGING_FACE_TOKEN")  # Hugging Faceのトークンを取得
pipe = FluxPipeline.from_pretrained("black-forest-labs/FLUX.1-schnell",
                                    torch_dtype=torch.bfloat16,
                                    token=hf_token  # Hugging Faceのトークンを指定
)
pipe.to(torch.device("mps"))  # deviceとしてMPSを指定する
# pipe.enable_model_cpu_offload()  # 呼び出し削除

prompt = "A cat holding a sign that says hello world"
image = pipe(
    prompt,
    guidance_scale=0.0,
    output_type="pil",
    num_inference_steps=4,
    max_sequence_length=256,
    generator=torch.Generator("cpu").manual_seed(0)
).images[0]
image.save("flux-schnell.png")
```

こちらも初回は30GB以上あるモデル等のダウンロードが行われますので時間がかかります。

結果は以下となります。

![flux-7.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/f2568369-b5be-0a8b-c29d-5faff6273653.png)

「**anime style, Japanese moe heroine**」だと以下です。

![flux-8.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/869934/8f829b43-f9ea-1511-1a03-beda02dcd943.png)

さすがに **FLUX.1 [dev]** と比べて落ちる感はあれど、両方ともプロンプトをきちんと汲んだ綺麗な画像ですね。
ちなみに、少ないステップ数で生成できるため、本記事のコードであれば **FLUX.1 [dev]** と比べて時間は数分の一です。

## 最後に

早くAPIも使いたい。

> Today we release the FLUX.1 text-to-image model suite. With their strong creative capabilities, these models serve as a powerful foundation for our upcoming suite of competitive generative text-to-video systems. Our video models will unlock precise creation and editing at high definition and unprecedented speed. We are committed to continue pioneering the future of generative media.
> 
> 参考：[Announcing Black Forest Labs &#x2d; Black Forest Labs](https://blackforestlabs.ai/announcing-black-forest-labs/)

動画生成も可能になるとのことで、本当に今後が楽しみです。

## 宣伝

[SupershipのQiita Organization](https://qiita.com/organizations/supership-inc)を合わせてご覧いただけますと嬉しいです。他のメンバーの記事も多数あります。

Supershipではプロダクト開発やサービス開発に関わる方を絶賛募集しております。
興味がある方は[Supership株式会社 採用サイト](https://supership.jp/recruit/)よりご確認ください。