【StableDiffusion】よわよわMacBookでもAIに絵を描かせたい！

# はじめに

最近AIが絵を描いてくれるツール流行っていますよね。  
Stable Diffusionがすごいとかなんとか・・  
無料で使えるサービスもあるのですが（[DreamStudio](https://photoshopbook.com/2022/10/03/dream-studio/), [お絵描きばりぐっどくん](https://page.line.me/877ieiqs)など）、すぐ制限にかかってしまい使えなくなってしまいます。  
  
じゃあローカルで実行できるようにしよう！  
ってことで </br>
→ ネットの記事を調べてみる </br>
→ 大抵がGPUを使う前提の記事 </br>
→ 自分のよわよわ intel CPU じゃ使えないのか..😭 </br>
→ **「ん?そもそも本当にGPUありじゃないと使えないのか？よわよわPCでもいけるんじゃない？」**  </br>
ということを検証してみようと、この記事を書くに至りました。

# 記事の対象者
GPUが搭載されていない/機械学習向きでないPCで無料でStable Diffusionを使うことを検討している人。

# 筆者の環境

<img alt="環境" src="https://user-images.githubusercontent.com/59855529/196094272-fd9ff9d3-ebf7-463d-b905-1693c9562412.png">

# Stable Diffusionついて
Stable Diffusionとは、キーワードに沿って人間が描いたような画像を生み出すAIのことです。  
Stable Diffusionを用いた技術としては下記のようなものがあります。  
- txt2img(text to image) ... テキストから画像を生成
- img2img(image to image) ... テキストと画像から新たな画像を生成
- inpainting ... 指定範囲をテキストで指示して画像修復


# 様々な環境で実行して比較してみた
今回は特に txt2img に絞って、様々な環境で速度や完成度を比較してみました。
1. 公式のStable Diffusionをローカルで実行
2. CPU最適化されたStable Diffusionをローカルで実行
3. 公式のStable DiffusionをGoogle Colab (無料)上で実行

txt2imgに渡すテキスト（呪文）は下記。
チームラボプラネッツの作品名をそのまま使ってみました。
https://planets.teamlab.art/tokyo/jp/ew/universe_fireparticles/
```
Universe of Fire Particles on the Water’s Surface art by teamLab
```
ステップ数は 3, 5, 10, 50 の4つで試しました。
ステップ数が多い方が精度は高くなりますが、その分時間はかかります。


## 1. 公式のStable Diffusionをローカルで実行
まずは、試しに公式の Stable Diffusion をインストールして動かしてみます。  
python の実行環境を整え、[diffusers](https://github.com/huggingface/diffusers) というライブラリを利用します。  
以下のようなコードを書きます。

```python
import os
from diffusers import StableDiffusionPipeline

dir_name = "images"
prompt = "Universe of Fire Particles on the Water's Surface art by teamLab"
steps = 50

if not os.path.exists(dir_name):
    os.mkdir(dir_name)

pipe = StableDiffusionPipeline.from_pretrained(
    "CompVis/stable-diffusion-v1-4",
    revision="fp16",
    use_auth_token=os.getenv("SD_TOKEN")
).to("cpu")

file_name = f"{dir_name}/{prompt}-step_{steps}.png"
print(file_name)
image = pipe(prompt, num_inference_steps=steps)["sample"][0]
image.save(file_name)
```

`SD_TOKEN` には [Hugging Fase](https://huggingface.co/) から取得したトークン入れます。  
↓の画像を出力するのに 25分以上かかりました。

![Universe of Fire Particles on the Water's Surface art by teamLab-step_50-25m33s](https://user-images.githubusercontent.com/40657211/196025673-3f2dafc4-123a-4266-9177-1ecb8cd2ff5a.png)

生成された画像について表にまとめます。画像は縮小しています。
| ステップ数 | 生成された画像 | 実行時間 |
| ---------- | ---------- | ---------- |
| 3  | <img width="240" alt="generated" src="https://user-images.githubusercontent.com/59855529/196084071-17e0bf32-dfc1-49af-b29d-40d8021384cc.png"> | 2分 |
| 5  | <img width="240" alt="generated" src="https://user-images.githubusercontent.com/59855529/196097415-d9653232-6725-41a0-b5cd-2a693e22c190.png"> | 3分 |
| 10 | <img width="240" alt="generated" src="https://user-images.githubusercontent.com/59855529/196083954-52852a25-edfa-4680-9984-4ad473921ab5.png"> | 5分27秒 |
| 50 | <img width="240" alt="generated" src="https://user-images.githubusercontent.com/59855529/196083866-95bed627-96b2-422e-8298-f2e87f36b675.png"> | 25分18秒 |


## 2. CPU最適化されたStable Diffusionをローカルで実行

下記リポジトリを使って進めていきます。
OpenVINOを使っており、Intel CPUでもStable Diffusionが行えるよう最適化されています。
https://github.com/bes-dev/stable_diffusion.openvino  

### 1. 環境構築

1. Python 3.8 以上をインストールしておく
2. 下記コマンドで環境構築
```
git clone git@github.com:bes-dev/stable_diffusion.openvino.git
cd stable_diffusion.openvino
python3 -m venv venv
source venv/bin/activate
pip3 install -r requirements.txt
```

### 2. ステップ数を変えて実行

実行コマンド：
```
python3 demo.py --prompt "Universe of Fire Particles on the Water’s Surface art by teamLab" --num-inference-steps 10
```
上記の`--num-inference-steps`でステップ数を調整します。


各ステップごと生成された画像は下記。画像は縮小しています。

| ステップ数 | 生成された画像 | 実行時間 |
| ---------- | ---------- | ---------- |
| 3  | <img width="240" alt="generated" src="https://user-images.githubusercontent.com/59855529/196084842-562da720-a3c7-475c-a210-ec89d04f3043.png"> | 27秒 |
| 5  | <img width="240" alt="generated" src="https://user-images.githubusercontent.com/59855529/196084849-de57b373-3524-40ab-a83d-e59797a1671d.png"> | 39秒 |
| 10 | <img width="240" alt="generated" src="https://user-images.githubusercontent.com/59855529/196084852-ffd4b00a-7588-4ed0-86f4-24f6189c83fa.png"> | 1分19秒 |
| 50 | <img width="240" alt="generated" src="https://user-images.githubusercontent.com/59855529/196084853-fe9b112a-d5a4-476c-b399-4a1b12978f31.png"> | 6分43秒 |

## 3. 公式のStable DiffusionをGoogle Colab (無料)上で実行

下記をColabノートに書いていきます。
### 1. 事前準備

TOKEN にはHugging Faceで発行したトークンを指定します。

```python
!pip install transformers scipy ftfy diffusers

import torch
from torch import autocast
from diffusers import StableDiffusionPipeline

TOKEN = "{{Hugging Faceで発行したトークン}}"

pipe = StableDiffusionPipeline.from_pretrained(
    "CompVis/stable-diffusion-v1-4",
    revision="fp16", 
    torch_dtype=torch.float16,
    use_auth_token=TOKEN
).to("cuda")
```

### 2. 実行
`prompt` に呪文を指定します。
`steps` にステップ数を指定します。

```python
import os
import time

dir_name = "images"
prompt = "Universe of Fire Particles on the Water’s Surface art by teamLab"

os.mkdir(dir_name)

steps = 3
os.mkdir(f"{dir_name}/{steps}steps")
for i in range(5):
    print("i: ", end="")
    with autocast("cuda"):
        time_sta = time.time()
        image = pipe(prompt, guidance_scale=7.5, num_inference_steps=steps)["sample"][0]
        elapsed = round(time.time() - time_sta, 1)
        image.save(f"{dir_name}/{steps}steps/{i}it_{elapsed}seconds.png")
        print(elapsed)
```

各ステップごと生成された画像は下記。画像は縮小しています。

| ステップ数 | 生成された画像 | 実行時間 |
| ---------- | ---------- | ---------- |
| 3  | <img width="240" alt="generated" src="https://user-images.githubusercontent.com/59855529/196085237-8947cfbf-838b-44d1-8068-69ff27ac741d.png"> | 1.6秒 |
| 5  | <img width="240" alt="generated" src="https://user-images.githubusercontent.com/59855529/196085241-893cece2-f7d9-47f6-9e4f-d5f149286102.png"> | 2.2秒 |
| 10 | <img width="240" alt="generated" src="https://user-images.githubusercontent.com/59855529/196085244-6d6b2d8c-9e2a-45e0-b067-b055cd40aa30.png"> | 3.8秒 |
| 50 | <img width="240" alt="generated" src="https://user-images.githubusercontent.com/59855529/196085246-23acf4d1-db10-47c2-86ea-0b302e8dc8bb.png"> | 15.6秒 |


## 結果比較

| ステップ数 | 公式 | OpenVINO | Google Colab | 精度 |
| ---------- | ---------- | ------------ | ------------ | ------------ |
| 3  | 2分      | 27秒    | 1.6秒 | 抽象画のようになる |
| 5  | 3分      | 39秒    | 2.2秒 | ステップ数3近い |
| 10 | 5分27秒  | 1分19秒  | 3.8秒 | 比較的リアルになった |
| 50 | 25分18秒 | 6分43秒  | 15.6秒 | ステップ数10よりさらにリアルになった |
 
 
# 所感
おそらく Stable Diffusion 自体は GPU を使用することを前提に設計されており、これをそのまま CPU で使おうとするととんでもない時間がかかってしまいました。  
Intel CPU で Stable Diffusion を使いたい場合は OpenVINO を使うのが良さそうです。  
1枚画像を生成するのにかかる時間が約 1 / 5 ぐらいになりました。  
幸い OpenVINO で Stable Diffusion を実装したリポジトリがあったので、それを使えばコマンド一発で画像生成できて便利でした。  

また、ステップ数がデフォルトで 50 になっていますが、生成にかかる時間を短くするにはここを調整する選択肢もあると思います。  
ステップ数を下げた分だけ質も落ちてしまいますが、例えばステップ数を 10 にすると OpenVINO で 1分程度で出力できるので、試行錯誤のループが早くなって良いこともあります。

このように色々な工夫をすることで Intel CPU でも画像生成させることが可能ではありました。  
ただ、まあ実際あえて CPU を使うメリットもあまりないので、よわよわ PC しか持っていない方は普通に Google Colab を使う方が良いと思います。