iOSとMacOSに🤖機械学習🤖を用いたテキスト入力に基づく描画を実現（Stable Diffusion + Core ML）

| Example 1 | Example 2 |
|---|---|
| ![スクリーンショット 2022-12-18 22.16.31.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/6d93e359-6f40-7ab5-6192-de93e129eb5c.png) | ![スクリーンショット 2022-12-18 22.19.25.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/de1882f6-0006-ff3f-ca55-e78751504892.png) |
| 春、ピンクの花、桜、暖かい、鮮やか、美しい、絵画、緑の草、青く澄んだ空、晴れた日、水墨画 | 山の中のハイテクな塔、ハイテク、サイエンス・フィクション、未来的、古寺、美しい |
| 注：AIは青空キーワードを無視した | 注：AIは古寺のキーワードを無視した |

## Stable Diffusion (AIはどうやって絵を描くのですか)

AIは、入力されたテキストをもとにアートを描くことができます。
これは、`Stable Diffusion` という機械学習モデルを使うことで可能になりました。

`Stable Diffusion` は、2022年に発表された ディープラーニング (Deep Learning) による
テキストから画像への変換モデルです。

https://stability.ai/blog/stable-diffusion-v2-release

https://github.com/CompVis/stable-diffusion

このモデルで使えるツールはPythonだけでした。
そして通常、Appleプラットフォームで実行するために最適化されていませんでした
（例えば、Apple Neural Engineは使用しません）

## 画質はいいんですか？

良い場合もあります。
そうでないときもある。

キャラクターよりも、背景画や環境を描くのに向いていると思います。
複数のオブジェクトを描かせると、そのうちの一つしか描かないことがあります。
また、文字の入力を一部無視することがあります。


:::note warn
研究用、アーティストの背景画作成用、アイデア出し用などに向いていると思います。
手描きを超えることはできないと思います。
:::

https://apps.apple.com/jp/app/画像生成ai-ローカル-stable-diffusion/id1658459595

## CoreMLツール

2022年12月、Appleは `Stable Diffusion` を CoreML モジュールに変換するツールを発表しました。
変換後のモジュールは、iOSとMacOSで直接使用することができます。

https://machinelearning.apple.com/research/stable-diffusion-coreml-apple-silicon

https://github.com/apple/ml-stable-diffusion


## 環境について

M1チップ搭載のiPad Proで、最新のMacOS（macOS Ventura 13.1）と最新バージョンのiOS (16.1) を使用して、モデル変換と画像生成を実行することを推奨しています。

## 既存のモデルをCore MLに変換する

Pythonを使って既存の `Stable Diffusion` モデルを CoreMLパッケージへ変換します。

これらのモデルを自分で変換したくない場合は、
Appleが既に変換しているものを使用することができます
次のセクション `Appleの変換済みモデルからダウンロードする` をお読みください。

### 環境設定

まず、`AnaConda` または `MiniConda` をインストールします。
bashスクリプトファイル（インストーラのバイナリを含む）をダウンロードし、それを実行します。

まず、インストーラをダウンロードします: 

https://docs.conda.io/en/latest/miniconda.html

MacOSでは

```bash
cd ~/Downloads
# M1
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-arm64.sh
# Intel
wget https://repo.anaconda.com/miniconda/Miniconda3-latest-MacOSX-x86_64.sh
```

その後、インストールスクリプトを実行します。

```bash
chmod +x Miniconda3-latest-MacOSX-arm64.sh
bash Miniconda3-latest-MacOSX-arm64.sh
```

一旦ターミナルを閉じ、再度開き、変更を反映させます。

その後，CoreMLツールの環境を構築します。

```bash
conda create -n coreml_stable_diffusion python=3.8 -y
conda activate coreml_stable_diffusion
```

CoreML ツールを使うとき、あるいはこの環境に新しいパッケージをインストールするときは、
必ず `conda activate coreml_stable_diffusion` を実行して環境を切り替えてください。
ターミナル行の最初に現在の環境が表示されます。

```bash
(base) test@MacBook-Pro ~ % conda activate coreml_stable_diffusion
(coreml_stable_diffusion) test@MacBook-Pro ~ % 
```

`(base)` --------> `(coreml_stable_diffusion)` なりました


Apple Core ML変換ツールのパッケージを `clone` して準備します。

```bash
git clone https://github.com/apple/ml-stable-diffusion.git
cd ml-stable-diffusion
pip3 install -e .
```

<details><summary>上記コマンドを実行する際、正しい環境が表示されていることを確認してください `(coreml_stable_diffusion)`</summary><div>

```bash
(coreml_stable_diffusion) test@MacBook-Pro ~ % git clone https://github.com/apple/ml-stable-diffusion.git
(coreml_stable_diffusion) test@MacBook-Pro ~ % cd ml-stable-diffusion
(coreml_stable_diffusion) test@MacBook-Pro ~ % pip3 install -e .
```

</div></details>

その他必要な工具 (`git-lfs`, `sentencepiece`, `rust`) を準備します。

```bash
brew install git-lfs
git lfs install

pip3 install sentencepiece

curl https://sh.rustup.rs -sSf | sh

pip3 install huggingface_hub
```

<details><summary>上記コマンドを実行する際、正しい環境が表示されていることを確認してください `(coreml_stable_diffusion)`</summary><div>

```bash
(coreml_stable_diffusion) test@MacBook-Pro ~ % pip3 install sentencepiece
(coreml_stable_diffusion) test@MacBook-Pro ~ % pip3 install huggingface_hub
```

</div></details>

Apple CoreMLツールでサポートされる `torch` の最新バージョンは2.0.0です。

Torch version 2.1.0.dev20230411 has not been tested with coremltools. You may run into unexpected errors. Torch 2.0.0 is the most recent version that has been tested.

```bash
pip3 install torch==2.0.0
```

<details><summary>上記コマンドを実行する際、正しい環境が表示されていることを確認してください `(coreml_stable_diffusion)`</summary><div>

```bash
(coreml_stable_diffusion) test@MacBook-Pro ~ % pip install torch==2.0.0
```

</div></details>

## HuggingFace.co

`Stable Diffusion` のモデルファイルは `Hugging Face` に格納されています。
また、AppleのCoreMLツールは、`HuggingFace.co` からモデルを取得します。
`HuggingFace.co` にアカウントを登録し、次のリンクを使ってアクセストークンを生成する必要があります: 
https://huggingface.co/settings/tokens

その後、以下のコマンドを実行してサインインしてください。

```bash
huggingface-cli login
```

### 既存のモデルを変換する

環境が `coreml_stable_diffusion` であり、`clone` した `ml-stable-diffusion` のディレクトリにいることを確認してください。
モデルID(hugging face websiteのリポジトリID)を指定して、以下のコマンドを実行します。

```bash
python -m python_coreml_stable_diffusion.torch2coreml --convert-vae-decoder -o <output-mlpackages-directory> --bundle-resources-for-swift-cli --attention-implementation SPLIT_EINSUM --model-version CompVis/stable-diffusion-v1-4

python -m python_coreml_stable_diffusion.torch2coreml --convert-unet -o <output-mlpackages-directory> --bundle-resources-for-swift-cli --attention-implementation SPLIT_EINSUM --model-version CompVis/stable-diffusion-v1-4

python -m python_coreml_stable_diffusion.torch2coreml --convert-text-encoder -o <output-mlpackages-directory> --bundle-resources-for-swift-cli --attention-implementation SPLIT_EINSUM --model-version CompVis/stable-diffusion-v1-4

python -m python_coreml_stable_diffusion.torch2coreml --convert-safety-checker -o <output-mlpackages-directory> --bundle-resources-for-swift-cli --attention-implementation SPLIT_EINSUM --model-version CompVis/stable-diffusion-v1-4
```

<details><summary>上記コマンドを実行する際、正しい環境が表示されていることを確認してください `(coreml_stable_diffusion)`</summary><div>

```bash
(coreml_stable_diffusion) test@MacBook-Pro ~ % python -m python_coreml_stable_diffusion.torch2coreml --convert-vae-decoder -o <output-mlpackages-directory> --bundle-resources-for-swift-cli --attention-implementation SPLIT_EINSUM --model-version CompVis/stable-diffusion-v1-4
(coreml_stable_diffusion) test@MacBook-Pro ~ % python -m python_coreml_stable_diffusion.torch2coreml --convert-unet -o <output-mlpackages-directory> --bundle-resources-for-swift-cli --attention-implementation SPLIT_EINSUM --model-version CompVis/stable-diffusion-v1-4
(coreml_stable_diffusion) test@MacBook-Pro ~ % python -m python_coreml_stable_diffusion.torch2coreml --convert-text-encoder -o <output-mlpackages-directory> --bundle-resources-for-swift-cli --attention-implementation SPLIT_EINSUM --model-version CompVis/stable-diffusion-v1-4
(coreml_stable_diffusion) test@MacBook-Pro ~ % python -m python_coreml_stable_diffusion.torch2coreml --convert-safety-checker -o <output-mlpackages-directory> --bundle-resources-for-swift-cli --attention-implementation SPLIT_EINSUM --model-version CompVis/stable-diffusion-v1-4

```

</div></details>

`-o <output-mlpackages-directory>` はモデルの出力先ディレクトリです．例えば /User/<名前>/Downloads/ConvertedModel

`--bundle-resources-for-swift-cli` は、MLパッケージファイルをコンパイルし、Swiftアプリケーションで使用できるようにすることをツールに依頼します。実行すると、`.mlmodelc` ファイルが生成され、`merges.txt` ファイルと語彙の `JSON` ファイルがダウンロードされます。

`--attention-implementation SPLIT_EINSUM` は、CPUとGPUだけでなく、Apple Neural Engineもアート生成処理に使用できるようにモードを設定します。

`--model-version CompVis/stable-diffusion-v1-4` は、使用するモデルを指定します。

よく使われるリポジトリ

`--model-version runwayml/stable-diffusion-v1-5`: 

https://huggingface.co/runwayml/stable-diffusion-v1-5

`--model-version stabilityai/stable-diffusion-2`: 

https://huggingface.co/stabilityai/stable-diffusion-2

`--model-version CompVis/stable-diffusion-v1-4`: 

https://huggingface.co/CompVis/stable-diffusion-v1-4

`--model-version stabilityai/stable-diffusion-2-1`: 

https://huggingface.co/stabilityai/stable-diffusion-2-1

上記モデルは英語入力にのみ対応しています。

### 日本語モデルについて

日本のモデルもあります。
`--model-version rinna/japanese-stable-diffusion`です。 

https://huggingface.co/rinna/japanese-stable-diffusion 

しかし、`japanese-stable-diffusion`をCore MLパッケージに変換する際に、
テキストエンコーダーサイズに関するエラー（`torch2coreml.py` のPythonコード内で `sample_text_encoder_inputs` の初期化関数を変更し、手動で最大サイズを77に設定しました）、
また、セーフティチェッカーの入力画像サイズに関する問題（Appleのコンパイル済みリポジトリCompVis/stable-diffusion-v1-4のセーフティチェッカーに置き換え、うまくいきました）が発生し、いくつかの問題に直面しました。
もしかしたら私の設定に問題があるのかもしれませんが、さらに調べて後日この記事を更新したいと思います。

### コンパイル (compile) 済み結果

モデルのコンパイルが成功すると、出力フォルダに以下のような構造が表示されるはずです。

![スクリーンショット 2022-12-19 15.44.44.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/c830020d-5c3a-4cd5-f83d-f3d3846528cc.png)

使用するファイルは `/compiled` フォルダ内にあります。

## Appleの変換済みモデルからダウンロード

AppleはすでにいくつかのモデルをCore MLのパッケージ形式に変換しています。

cloneコマンドでダウンロードすることができます。

```bash
git clone https://huggingface.co/apple/coreml-stable-diffusion-v1-5
```

huggingface.coアカウントのユーザー名とトークンを入力するよう要求されます。
`Hugging Face` のウェブサイトにアカウントを登録し、次のリンクを使ってアクセストークンを生成する必要があります: 
https://huggingface.co/settings/tokens

大きなファイルをダウンロードするため、多少時間がかかるかもしれません。

### 利用可能なリポジトリ

https://huggingface.co/apple/coreml-stable-diffusion-v1-4

```
git clone https://huggingface.co/apple/coreml-stable-diffusion-v1-4
```

https://huggingface.co/apple/coreml-stable-diffusion-v1-5

```
https://huggingface.co/apple/coreml-stable-diffusion-v1-5
```

https://huggingface.co/apple/coreml-stable-diffusion-2-base

```
https://huggingface.co/apple/coreml-stable-diffusion-2-base
```

:::note warn
上記機種は英語入力にのみ対応しています。
:::

Git LFS (大容量ファイルシステム) を使ってすべてのファイルをダウンロードします（サイズが大きいです）。

![スクリーンショット 2022-12-19 15.44.14.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/ade2df9f-0bb6-4d9a-9bd7-f3feca7ec31f.png)

git cloneした後、`split_einsum/compiled`フォルダに、使用するファイルが配置されます。

#### 各ファイルを個別にダウンロード

また、`GIT_LFS_SKIP_SMUDGE=1` というプレフィックスを使って、大きなファイルへのポインタだけをクローンし、各ファイルを個別にダウンロードすることもできます。

```bash
GIT_LFS_SKIP_SMUDGE=1 git clone https://huggingface.co/apple/coreml-stable-diffusion-v1-5
git lfs pull --include split_einsum/compiled/Unet.mlmodelc
git lfs pull --include split_einsum/compiled/VAEDecoder.mlmodelc
# ... 相対パスを指定して他のファイルをダウンロードする ...
```

## ファイル構成

### コンパイルファイル `compiled` と パッケージファイル `packages` の比較

パッケージファイルはPythonに適していますが、
Swiftのコードにはコンパイル版が必要です。

### オリジナル `original` と `split_einsum` の比較

`split_einsum` はAppleによって導入され、
すべてのコンピュートユニット（CPU、GPU、AppleのNeural Engine）と互換性があります。

`original` は、CPUとGPUにのみ対応しています。

とはいえ、デバイスによっては `split_einsum` よりも `original` の方が高速になることもあります。

## Pythonを使って画像を生成する

```bash
python -m python_coreml_stable_diffusion.pipeline --prompt "beautiful night sky, a lot of stars, beautiful, fantancy, vivid, colorful, meteor" -i <output-mlpackages-directory> -o </path/to/output/image> --compute-unit CPU_AND_NE --seed 93 --model-version CompVis/stable-diffusion-v1-4
```

<details><summary>上記コマンドを実行する際、正しい環境が表示されていることを確認してください `(coreml_stable_diffusion)`</summary><div>

**また、クローンしたgitディレクトリの中にいることを確認してください。**

```bash
(coreml_stable_diffusion) test@MacBook-Pro ~ % python -m python_coreml_stable_diffusion.pipeline --prompt "beautiful night sky, a lot of stars, beautiful, fantancy, vivid, colorful, meteor" -i <output-mlpackages-directory> -o </path/to/output/image> --compute-unit CPU_AND_NE --seed 93 --model-version CompVis/stable-diffusion-v1-4
```

</div></details>


`--prompt "beautiful night sky, a lot of stars, beautiful, fantancy, vivid, colorful, meteor"` は、アートのAIが描くための説明文としてのテキストです。

`-i <output-mlpackages-directory>` は `.mlpackage` ファイルを格納するディレクトリです。Appleからリポジトリをクローンした場合は、`/original/packages` フォルダになります。

`--seed 93`: これはランダムな整数値です。同じ乱数を使うと、AIは（同じモデルに対して）同じアートを生成する可能性が高いです。異なる画像を生成したい場合は、乱数を使用してください。

`--compute-unit` は、コンピュータに十分なメモリがある場合はALLにすることができます。そうでない場合は `CPU_AND_NE` に設定するとCPUとニューラルエンジンのみを使用することができます。

`--model-version CompVis/stable-diffusion-v1-4`は使用するモデルのリポジトリIDです。

## Swiftを使って画像を生成する

まず、空のSwift MacOSアプリケーションを作成します。

まずはMacOSでモデル生成処理を試してみてください。

### Swiftパッケージのインポート

Xcode内で、`File` メニューをクリックし、`Add Packages` をクリックします。以下のパッケージをインポートします。

```bash
https://github.com/apple/ml-stable-diffusion.git
```

Swiftのコード内で、`StableDiffusion` パイプライン フレームワーク（Swiftパッケージ内）と、
`CoreML` フレームワークをインポートします。

```swift
import CoreML
import StableDiffusion
```

### 計算装置の決定

計算装置は `MLComputeUnits` として定義されているので、それを設定します。

`.all`: すべての計算資源を使用します。

`.cpuOnly`: CPUのみを使用、これは最も遅いオプションです。

`.cpuAndGPU` はCPUとGPUを使用し、ハイエンドGPU構成のMacBookでは高速になります。

`.cpuAndNeuralEngine` は、CPUとAppleのNeural Engineチップを使用します。iOS（iPhoneやiPad）で使用する場合はこのオプションになります。

```swift
let config = MLModelConfiguration()
config.computeUnits = .cpuAndNeuralEngine
```

### リソースディレクトリ      

次に、リソースフォルダへのURLを含むパイプラインオブジェクトを作成します。リソースフォルダには、以下のものが含まれるはずです。

- merges.txt
- SafetyChecker.mlmodelc（オプション。出力画像にNSFWコンテンツをチェックさせたい場合は、このファイルを含めます)
- TextEncoder.mlmodelc（テキストエンコーダー）。
- Unet.mlmodelc
- VAEDecoder.mlmodelc
- vocab.json

```swift
let pipeline = try StableDiffusionPipeline(resourcesAt: resourcesFolderURL,
                                           configuration: config,
                                           disableSafety: true)
```

`disableSafety`は、出力が安全かどうかをチェックするかどうかを設定します。
この機能を無効にするには `true` に、
有効にするには`false` に設定します。
安全チェッカーを有効にする場合は、安全チェッカーのMLモデルファイル `SafetyChecker.mlmodelc` も提供する必要があります。

### 計算の開始

準備ができたら，テキストフレーズで画像生成関数を呼び出します

```swift
let resultingImages = try pipeline.generateImages(
    prompt: "beautiful night sky, a lot of stars, beautiful, fantancy, vivid, colorful, meteor",
    imageCount: 1,
    stepCount: 60,
    seed: 99
) { progress in
    print(progress.currentImages)
}
// 結果が利用可能
print(resultingImages.first?.imageData)
```

これは、ブロッキング `blocking` 関数呼び出しです。
コードの実行は、結果が利用可能になった時点で再開されます。

`prompt` は、生成する内容を記述する文章である。

`imageCount` は、生成する画像結果の数です。複数の画像を生成した場合、結果の配列 `resultingImages` には複数の出力が含まれます。

`stepCount` は、最終的な結果が生成されるまでにかかるステップ数です。

`seed` は、各世代で異なるアートを生成するための乱数です。
モデルと `seed` が同じであれば、画像も同じになる可能性があります。

`progress.currentImages` は、配列内の画像データのいずれかが `nil` であれば、その画像はセーフティチェックを通過していないことを意味します。


### 進捗状況の確認

プログレスハンドラ内では、進捗状況をモニターすることができます。
生成された画像の枚数を確認することができる。

`progress.step` は現在のステップを表します。

`progress.currentImages` は、現在生成されている `CGImage` を出力します。

`progress.stepCount` は画像生成にかかる総ステップ数

### 結果画像

上記の `generateImages` コマンドの実行が終了すると、
コマンドの実行結果を配列に格納する
配列で、要求された画像の数を含んでいます。
1枚の画像を要求した場合は、 `.first` を使用して結果の画像にアクセスすることができます。

```swift
guard let resultCGImageObject = resultingImages.first?.imageData else {
    return
}
```

## MacOSでの結果

https://twitter.com/MszPro/status/1604381610811346944

## iOSでの結果

iPhoneでは、画像生成の実行中にアプリがクラッシュすることがありました。これは、この処理が多くのメモリを消費するためで、システムがメモリを消費しすぎている場合、アプリを終了させます。

M1チップ搭載のiPad Proでは、ほとんどの場合、処理が成功しました。

また、特別なエンタイトルメントを追加することで、アプリがより多くのメモリ領域を使用できるようにすることもできます。

![スクリーンショット 2022-12-19 22.59.20.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/18efab70-bb2f-6bbc-ce18-a47365498baa.png)

## アートAIアプリ

上記のコンセプトを使って、テキスト入力で画像を生成する簡単なMacOSとiOSのアプリを作りました。
無料で、画像はローカルコンピュータ上で生成されます。

https://twitter.com/mszpro/status/1605351963624816641?s=61&t=edA34U89W5tNeeEXGuZJ8Q

https://apps.apple.com/jp/app/画像生成ai-ローカル-stable-diffusion/id1658459595


---

お読みいただきありがとうございました。

[🐘 マストドン @me@mszpro.com](https://sns.mszpro.com/@me)


[☺️ Twitter @MszPro](https://twitter.com/MszPro)


**☺️** サイト <https://MszPro.com>

<img width="150" src="https://cdn.mszmagic.com/static-web-content/AppClipImage_small.png">

![writing-quickly_emoji_400.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/635330/640938e9-c121-8152-b8c4-8ab63124afcc.png)

Written by MszPro\~