DirectMLでStable Diffusionを動かしてみる

# はじめに
株式会社ピーアールオー（あったらいいな！を作ります） Advent Calendar 2022の4日目になります。
前日は 私の「[DirectMLで試す、非NVIDIA系GPUで機械学習](https://qiita.com/pro_matuzaki/items/8813ca3347c83fbeaade)」でした。

# DirectMLでもっといろいろ試してみたい
さて、前回の記事で動かすことができたDirectMLですが、せっかくなのでもっと試してみたいと思い、
2022年のAI界隈を賑わしたStable Diffusionを動作させてみることにします。

# Stable Diffusionを試す
## モデルのDL
まずは[hugging face](https://huggingface.co/)という学習モデルを公開しているサイトにアカウントを登録する必要があるようです。
次にAccount>settingからAccess Tokenを生成します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221091/a09c0a67-d37a-86d3-6e37-f6cb8821512b.png)

次にhuggingface用のライブラリをインストールし、loginを実行します。
```
pip install huggingface_hub
```

```
> huggingface-cli login

    _|    _|  _|    _|    _|_|_|    _|_|_|  _|_|_|  _|      _|    _|_|_|      _|_|_|_|    _|_|      _|_|_|  _|_|_|_|
    _|    _|  _|    _|  _|        _|          _|    _|_|    _|  _|            _|        _|    _|  _|        _|
    _|_|_|_|  _|    _|  _|  _|_|  _|  _|_|    _|    _|  _|  _|  _|  _|_|      _|_|_|    _|_|_|_|  _|        _|_|_|
    _|    _|  _|    _|  _|    _|  _|    _|    _|    _|    _|_|  _|    _|      _|        _|    _|  _|        _|
    _|    _|    _|_|      _|_|_|    _|_|_|  _|_|_|  _|      _|    _|_|_|      _|        _|    _|    _|_|_|  _|_|_|_|

    To login, `huggingface_hub` now requires a token generated from https://huggingface.co/settings/tokens .

Token:
Add token as git credential? (Y/n)
Token is valid.
Your token has been saved in your configured git credential helpers (manager-core).
Your token has been saved to C:\Users\owner\.huggingface\token
Login successful
```

前回も実施しましたが、以下を事前に実行しておく必要があります。
```
pip install diffusers==0.3.0
pip install onnx
pip install transformers
```

準備が整ったら以下コマンドで学習モデルをDLし、onnxに変換する必要があるそうです。
```
python convert_stable_diffusion_checkpoint_to_onnx.py --model_path="CompVis/stable-diffusion-v1-4" --output_path="./stable_diffusion_onnx"
```
残念ながら変換時にエラーが発生。実は参考にした[Stable Diffusion for AMD GPUs on Windows using DirectMLト](https://gist.github.com/harishanand95/75f4515e6187a6aa3261af6ac6f61269)にてonnxはnigtly buildを入れる必要があるよ、とあったんですが、理由がよくわからなかったのでスルーして進めてましたのですが、やっぱり必要な模様ですね。
```
Traceback (most recent call last):
  File "convert_stable_diffusion_checkpoint_to_onnx.py", line 266, in <module>
    convert_models(args.model_path, args.output_path, args.opset, args.fp16)
  File "C:\Users\owner\dlc\lib\site-packages\torch\autograd\grad_mode.py", line 27, in decorate_context
    return func(*args, **kwargs)
  File "convert_stable_diffusion_checkpoint_to_onnx.py", line 217, in convert_models
    safety_checker = OnnxRuntimeModel.from_pretrained(output_path / "safety_checker")
  File "C:\Users\owner\dlc\lib\site-packages\diffusers\onnx_utils.py", line 212, in from_pretrained
    **model_kwargs,
  File "C:\Users\owner\dlc\lib\site-packages\diffusers\onnx_utils.py", line 174, in _from_pretrained
    os.path.join(model_id, model_file_name), provider=provider, sess_options=sess_options
  File "C:\Users\owner\dlc\lib\site-packages\diffusers\onnx_utils.py", line 78, in load_model
    return ort.InferenceSession(path, providers=[provider], sess_options=sess_options)
NameError: name 'ort' is not defined
```

[ここ](https://aiinfra.visualstudio.com/PublicPackages/_artifacts/feed/ORT-Nightly/PyPI/ort-nightly-directml/overview/1.13.0.dev20220908001)からnightly buildを取得し、以下でインストール実行
```
pip install ./ort_nightly_directml-1.13.0.dev20220908001-cp37-cp37m-win_amd64.whl --force-reinstall
```

これでうまく変換できるようになりました。

## 実行
まずは上述の参考サイトにあったスクリプトを実行してみます。
```
from diffusers import StableDiffusionOnnxPipeline
pipe = StableDiffusionOnnxPipeline.from_pretrained("./stable_diffusion_onnx", provider="DmlExecutionProvider")
prompt = "a photo of an astronaut riding a horse on mars"
image = pipe(prompt).images[0] 
image.save("astronaut_rides_horse.png")
```
ちなみに、実行中はGPUに割り当てたメモリがフルで使用されていました。

PCの動作もかなり重くなるので、それなりにパワーのある環境じゃないと実行は厳しいかもしれません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221091/cd3c8302-a3c9-022c-269d-0ba0f7c01738.png)

私の環境で生成に要した時間は512x512で３分ほどでした。

無事生成された画像はこんな感じ。いいですね。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221091/09ac5ce5-9651-fe6d-675c-a46ed5d9674a.png)

せっかくだからいろいろと試してみました。

hugging faceの[prompt generator](https://huggingface.co/spaces/Gustavosta/MagicPrompt-Stable-Diffusion)ってのもあるようですが、まずはインターネットに転がっている呪文で生成してみました。
```
temple in ruines, forest, stairs, columns, cinematic, detailed, atmospheric, epic, concept art, Matte painting, background, mist, photo-realistic, concept art, volumetric light, cinematic epic + rule of thirds octane render, 8k, corona render, movie concept art, octane render, cinematic, trending on artstation, movie concept art, cinematic composition , ultra-detailed, realistic , hyper-realistic , volumetric lighting, 8k –ar 2:3 –test –uplight
```
で生成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221091/baf26e1d-4e54-a96e-031e-4c593634cae0.png)

```
beautiful concept art illustration of a one beautiful kawaii girl in fluttery white dress with wavy hair,symmetrical perfect face fine detail delicate features quiet gaze,a beautiful full body illustration,beautiful europian building background,High-angle shot by void/Re:era and wlop and makotoshinkai and greg rutkowski and krenz cushart and KanLiu and rossdraws and void/Re:era and @ribao_bbb and modare,atmospheric lighting,volumetric lighting,sdorica,reduce saturation,pretty-small-face,fine detailed face,Twice,volumetric top lighting,big kawii eye,bold line painting,soft shadow,kawaii girl,4k,8k,trending artstation,pixiv ranking 1st
```
で生成
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/221091/8c3ea1ee-7191-6fab-d5b2-6efdf57194ce.png)

確かにこれ面白いですね。
季節柄、年賀状のイラストとか生成させてみようかな。

# 最後に
生成に必要な時間は私の環境でだいたい2~4分程度かかるようです。
RTX3090などでは数秒～10秒程度で生成できるらしいので、性能差は歴然ですが、対してCPUのみで生成した場合にはCore i9などでも30分近くかかるなどの情報を見たことがあるので、まぁお試し程度で動かすには十分な性能と思います。
また、M1/M2のマックではちょうど最近になってApple純正のCore MLがStable diffusionに対応した[^1]という話があり、これを利用すればやはり数秒程度で画像を生成することができるらしいです。Apple Siliconすげー。

[^1]: https://gigazine.net/news/20221202-stable-diffusion-core-ml-apple/