Stable Diffusion OpenVINOでIntel CPUでもAIに画像を生成してもらう

最近画像生成AIが流行りです.@shi3zさんの Memeplex.app で遊んだりしています.Memeplexはプロンプトのプリセットがあるし日本語を入力すると英語に翻訳してくれるので英語の出来ない自分でもとっつきやすいです.
ローカル環境でも試したいけどStable Diffusionはローカルで動かすにはGPUが必要.しかし手元にはないので出来ないな,クラウドを使ってみる?とか思っていたのですが,Intel CPU内蔵GPUで画像生成をしてくれる「stable_diffusion.openvino」を知ったので少し試してみました.

sd thumbnail

Stable Diffusion OpenVINO 動作要件確認

Stable Diffusion OpenVINOの要件は以下のようになっています.OpenVINOに対応したCPUだとOKのようです.

Requirements
Linux, Windows, MacOS
Python 3.8.+
CPU compatible with OpenVINO.

OpenVINOの要件は以下のページを見るとCore i 6世代目〜12世代目のようです.

CPU
Processors
6th to 12th generation Intel Core processors
1st to 3rd generation of Intel® Xeon® Scalable processors
Intel Atom® processor with Intel® Streaming SIMD Extensions 4.2 (Intel® SSE4.2)

手元の端末のCPUは以下のような感じで3世代目と6世代目.後者はぎりぎり対応していそうです.

$ lscpu | grep ^Model\ name:
Model name:                      Intel(R) Core(TM) i5-3320M CPU @ 2.60GHz
$ lscpu | grep ^Model\ name:
Model name:                      Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz

Stable Diffusion OpenVINO 導入

端末の内蔵diskは狭く空き容量が少ないので外付けHDDのvirtualenvに導入することにします.

$ mkdir /media/matoken/export/sd (1)
$ cd /media/matoken/export/sd
$ virtualenv . (2)
$ source bin/activate (3)
$ git clone https://github.com/bes-dev/stable_diffusion.openvino (4)
$ cd stable_diffusion.openvino
$ pip install -r requirements.txt (5)
  1. HDDに作業ディレクトリ作成
  2. virtualenv で環境作成
  3. virtualenv環境反映
  4. stable_diffusion.openvinoをclone
  5. Install

初回実行時にダウンロードされるmodelが4GBほどあるのですが,10回ほど試してもタイムアウトで中断してしまうのでVPSでダウンロードしてコピーしました.規定値のホームディレクトリ以下に導入しようとしてdisk fullになったのでhddにシンボリックリンクを貼ってHDDに導入しました.オリジナルの場所は ~/.cache/huggingface 以下です.

$ ls -Ss1 ~/.cache/huggingface/hub/models--bes-dev--stable-diffusion-v1-4-openvino/blobs/
合計 4169032
3357512 7655112cde3c5084c2709b2b89994834b24efc457f2c1b302bb3d7a056bfdb7a
 480740 b3f34c33d8c272f61c6780251a503911c7e7a448cdc10f8fb7d9bc59c3462951
 193328 456fd6d12ffab507af1ad6772b7b1922b35502272cd5be3708c8292252cd4c46
 133460 8732df1da0a3026da5ee6070df8899efbccf0d844821368214af8d95abeae467
   2952 a6514903a2875c318399e451c1f9ddaf4a3f7ba4
    460 dfb9780b4527132dfe9a19ccc7ce5c0d885cb2ae
    328 c0f568310ea3a649aea01772031087d324272780
    252 87adf22fe4160e26a799270b2f53c8c21c9d6cd0

プロンプトからの画像生成

ここまで来たら画像生成が出来ます.テキストの文字列でどんな画像を生成するか伝えます.この文字列をプロンプトといい基本的に英語,英語圏で通じる言葉で指示します.今回は「kawaii neko」としてみました.

$ python ./demo.py --prompt "kawaii neko"
Terminated

Terminatedと言われて処理が中断しました.どうもメモリが足りなそうです.実メモリは8GBです.disk swapでもう8GB追加して再度実行してみます.

メモリ不足なのでディスクスワップの追加

$ dd if=/dev/zero of=./swap.img bs=1M count=8096 (1)
$ sudo chown 0.0 ./swap.img
$ sudo chmod 600 ./swap.img
$ sudo mkswap ./swap.img (2)
$ sudo swapon `pwd`/swap.img (3)
$ python ./demo.py --prompt "kawaii neko" (4)
32it [13:14, 24.84s/it]
  1. 8GB程のディスクイメージの作成
  2. スワップとして初期化
  3. スワップを有効にする
  4. 再度画像生成

sd txt2img00

今度は15分程経って処理が終了し,output.png として画像が出来ました.何度か試すと10〜15分程で1枚出来ます.このときLoadAverageは10くらいまで上がって他の処理はあまりやりたくない感じに.寝ているときなどに処理する感じが良さそうです.

Note

他のCPUでの処理速度は以下にいくつか紹介されています.やはりGPUに比べると大分遅いですね.

Note

何度か動かすと数回に一回 Terminated が出ます.この環境に導入している nohung がkillしているようなので一時的に無効にすると安定して動作するようになりました.(一般的な環境には導入されていない)

$ sudo systemctl stop nohang-desktop.service
$ sudo systemctl stop nohang.service

次回以降起動時

shellを開いて以下のコマンドでStable Diffusionの環境を有効にします.

$ cd /media/matoken/export/sd/stable_diffusion.openvino (1)
$ source ../bin/activate (2)
$ sudo swapon `pwd`/swap.img (3)
  1. Stable Diffusion 作業ディレクトリに移動
  2. virtualenv環境反映
  3. disk swap反映

help

demo.py のhelpを見るとこんな感じ.色々できそうです.

$ python demo.py --help
usage: demo.py [-h] [--model MODEL] [--seed SEED] [--beta-start BETA_START] [--beta-end BETA_END] [--beta-schedule BETA_SCHEDULE]
               [--num-inference-steps NUM_INFERENCE_STEPS] [--guidance-scale GUIDANCE_SCALE] [--eta ETA] [--tokenizer TOKENIZER] [--prompt PROMPT]
               [--init-image INIT_IMAGE] [--strength STRENGTH] [--mask MASK] [--output OUTPUT]

optional arguments:
  -h, --help            show this help message and exit
  --model MODEL         model name
  --seed SEED           random seed for generating consistent images per prompt
  --beta-start BETA_START
                        LMSDiscreteScheduler::beta_start
  --beta-end BETA_END   LMSDiscreteScheduler::beta_end
  --beta-schedule BETA_SCHEDULE
                        LMSDiscreteScheduler::beta_schedule
  --num-inference-steps NUM_INFERENCE_STEPS
                        num inference steps
  --guidance-scale GUIDANCE_SCALE
                        guidance scale
  --eta ETA             eta
  --tokenizer TOKENIZER
                        tokenizer
  --prompt PROMPT       prompt
  --init-image INIT_IMAGE
                        path to initial image
  --strength STRENGTH   how strong the initial image should be noised [0.0, 1.0]
  --mask MASK           mask of the region to inpaint on the initial image
  --output OUTPUT       output image name

img2img

初期イメージを指定も試してみます. --init-image で適当な画像を指定してみました.ハンモックの画像にプロンプトで猫などを指定してみました.

$ python demo.py --seed ${seed} --prompt "sleep cat, campe site, hammock" --init-image=./hammock.jpg --output "${outfile}"

ハンモックに猫っぽいものが現れました.

元画像

sd original image

生成された画像

sd img2img01
sd img2img02

もう少し線画とかシンプルな画像のほうがいいかも?

同じSEEDとプロンプトで画像が固定されるのを確認

出来上がる画像は毎回同じプロンプトでも既定値ではSEEDがランダム生成されるので別の画像が生成されます.SEEDとプロンプトを固定して同じ画像が出力されるか見てみます.

Note
少し古いStable DiffusionだとSEEDを固定しても別の画像が出てくるようです.
$ python demo.py --seed 999999 --prompt "kawaii neko" --output "kawaii_neko-999999-01.png"
32it [09:47, 18.36s/it]
$ python demo.py --seed 999999 --prompt "kawaii neko" --output "kawaii_neko-999999-02.png"
32it [09:41, 18.18s/it]

見た目もチェックサムを比較しても同じ値になりました.

$ sha512sum ./kawaii_neko-999999-0?.png
3cd2fad521495571842d9f37f13113bd6a18195e120fd4cded40f7fcf59eb3807cdd9aa43ae4831dfd7e4b0228077bdcabd2a7a86947507e2863143a43d7cee9  ./kawaii_neko-999999-01.png
3cd2fad521495571842d9f37f13113bd6a18195e120fd4cded40f7fcf59eb3807cdd9aa43ae4831dfd7e4b0228077bdcabd2a7a86947507e2863143a43d7cee9  ./kawaii_neko-999999-02.png

sd kawaii neko seed same

ということは恐らく低解像度だと処理時間は短くなると思うので,低解像度でたくさん画像生成して気に入ったものを高解像度で作り直すといったことをすると効率が良さそう.でもまだ解像度指定は出来ないようです.

とりあえず解像度指定できるようになったときのために毎回SEEDを指定して,SEEDとプロンプトをexifに保存しておくことにしました.
SEEDの範囲は手元で試した感じでは2^32で 0〜4294967295 のようです.

seed=$( shuf -i 0-4294967295 -n 1 )
python demo.py --seed ${seed} --prompt "${prompt}" --init-image="${image}" --output "${outfile}"
exiftool -overwrite_original -comment="SEED:${seed}/PROMPT:${prompt}" "${outfile}"

SEEDで探索

MemeplexのDiscordでSEEDが近いと似た画像が生成されるというのを見たので試してみます.(そしてMemeplexにはSEED固定機能が追加された)

適当な画像のプロンプトは固定でSEEDを少しづつずらして画像生成を試してみます.

step 1

sd seed step1

step 10

sd seed step10

step 100

sd seed step100

step 1000

sd seed step1000

近いと似た傾向に画像になるような感じ?

strengthで探索

--strength オプションは0〜1で既定値は0.5のようです.これを変更してどうなるか見てみます.

まずはプロンプトとSEEDを固定して初期画像無しで—​strengthを0.1刻みで変更してみました.
見た目は変わらない?hashを比較すると別の画像になっています.

sd strength txt2img

次は猫画像を作成して,その画像を初期画像に指定してプロンプトに「dog」を指定,SEEDを固定しました.
段々と猫から犬になり,–strengthが1では顔の向きくらいしか残ってなさそうです.

sd strength img2img

初期画像に対するプロンプトの強さが変わる感じですね.

CPUを全部使うようにしてみる(速度は変わらない)

しばらく動かしてみていると4コア中2コアしか使っていないように見えます.以下のISSUEを参考に4コア使うようにしてみましたが,他の方と同じように特に速度は変わらなかったので元に戻し( $ git restore stable_diffusion_engine.py )ました.

$ git diff ./stable_diffusion_engine.py
diff --git a/stable_diffusion_engine.py b/stable_diffusion_engine.py
index f73541b..6c92198 100644
--- a/stable_diffusion_engine.py
+++ b/stable_diffusion_engine.py
@@ -27,6 +27,7 @@ class StableDiffusionEngine:
         self.scheduler = scheduler
         # models
         self.core = Core()
+        self.core.set_property("CPU", {"INFERENCE_NUM_THREADS": 4})
         # text features
         self._text_encoder = self.core.read_model(
             hf_hub_download(repo_id=model, filename="text_encoder.xml"),

プロンプト(呪文)の作り方

まずは他の方のプロンプトを真似させてもらうのがお手軽です.Memeplex.appだとギャラリーで気に入ったものをクリックするとプロンプトが表示されるのでそれをコピーしてカスタマイズするといいです.ちなみにMemeplexはプリセットが充実しているので便利です.SEEDや英語翻訳後のプロンプトも表示されるのでべつのStable Diffusionに指定することも出来ます.

The Ai Art も便利で,構図やフィルタなどの例がたくさん紹介されています.Cyberpunk styleを多用しがち…….

Twitterで「#StableDiffusion」などで検索するとたくさんの画像が出てきてプロンプトが記載されていることが多いです.

プロンプトの不明な画像は以下のsiteでプロンプトを推測してもらうことが出来ます.自分の生成した画像を入れてみましたが自分のプロンプトとはかけ離れたものが出てきました.あくまで推測ですね.

試した環境
$ git log -1
commit 294dd34234f0629f69d5af5b1190841560242969 (HEAD -> master, origin/master, origin/HEAD)
Author: Brian Foley <bpfoley@gmail.com>
Date:   Mon Sep 5 09:25:43 2022 -0400

    Update requirements.txt (#39)

    Add ftfy 6.1.1 to stop OpenAIGPTTokenizer's warning/fallback to  BERT BasicTokenizer.
$ dpkg-query -W python3
python3 3.9.2-3
$ lsb_release -dr
Description:    Debian GNU/Linux 11 (bullseye)
Release:        11
$ lscpu | grep ^Model\ name:
Model name:                      Intel(R) Core(TM) i5-6200U CPU @ 2.30GHz
$ cat /proc/meminfo | grep MemTotal:
MemTotal:        8019112 kB

コメントを残す

メールアドレスが公開されることはありません。 * が付いている欄は必須項目です