Supershipの名畑です。今期アニメのAIの遺電子が原作連載開始されたのは8年近く前なわけですが、現代においては、さらに迫って感じられます。
はじめに
前回の記事Stable Diffusion web UIをMacBook(M2)にインストールして画像の生成をしてみた記録ではweb UI(ブラウザ)を経由してStable Diffusionの画像生成を行いました。
今回はweb UIを経由せずに、PythonからローカルのAPIを叩いて画像の生成を行ってみます。
環境設定
前回の記事で行った環境構築が完了していることが前提です。
Pythonの呼び出しではrequestsメソッドを用いますが、標準ライブラリであるurllibを使う形に置き換えていただいてももちろん大丈夫です。公式のサンプルコードがrequestsを用いていたのでそれに従っただけです。
COMMANDLINE_ARGSの設定
コマンドライン引数を設定します。
stable-diffusion-webuiの配下にあるwebui-user.shを開きます。
#!/bin/bash
#########################################################
# Uncomment and change the variables below to your need:#
#########################################################
# Install directory without trailing slash
#install_dir="/home/$(whoami)"
# Name of the subdirectory
#clone_dir="stable-diffusion-webui"
# Commandline arguments for webui.py, for example: export COMMANDLINE_ARGS="--medvram --opt-split-attention"
#export COMMANDLINE_ARGS=""
# python3 executable
#python_cmd="python3"
以下略
このファイルのCOMMANDLINE_ARGSの行に起動時の引数を3つ追記してコメントアウトを解除します。
- --api:web UIがAPIと共に起動されます。--nowebuiを指定するとAPIのみを起動することも可能です。その場合はポート番号が7860ではなく7861になるのでご注意ください。
- --skip-torch-cuda-test:現在のmacOSはCUDAに対応していないため、該当のテストをスキップさせます。
- --no-half:前回も書きましたが、デフォルト設定だと「ビデオカードがhalf typeをサポートしていない」という旨のエラーが出るためこの指定をします。
適用すると下記になります。
export COMMANDLINE_ARGS="--api --skip-torch-cuda-test --no-half"
コマンドライン引数について詳しくは公式のCommand Line Arguments and Settingsをご覧ください。
web UIの起動
これも前回同様です。
stable-diffusion-webuiに移動します。
$ cd /path/to/stable-diffusion-webui
webui.shを叩きます。
$ ./webui.sh
略
Running on local URL: http://127.0.0.1:7860
To create a public link, set `share=True` in `launch()`.
Startup time: 3.1s (import torch: 0.8s, import gradio: 0.4s, import ldm: 0.3s, other imports: 0.7s, load scripts: 0.4s, create ui: 0.3s, gradio launch: 0.1s).
DiffusionWrapper has 859.52 M params.
Applying attention optimization: InvokeAI... done.
Textual inversion embeddings loaded(0):
Model loaded in 5.2s (load weights from disk: 0.4s, create model: 0.5s, apply weights to model: 2.5s, move model to device: 1.5s, calculate empty prompt: 0.2s).
APIリファレンス
web UIが起動した状態であれば http://127.0.0.1:7860/docs でAPIリファレンスを開くことができます。
今回はText2ImgapiのAPI(/sdapi/v1/txt2img)を使いますが、リファレンスでは下記のように記載されています。
Pythonのコード
例のごとく、プロンプトとして「28-year-old Japanese pretty woman with black bobbed hair」を、ネガティブプロンプトとして「text, letter, belongings」を指定してみることとします。ここはもちろんご自由に書き換えてください。
import requests
import base64
import time # ファイル名にtimestampを入れるためのみに使用
url = "http://127.0.0.1:7860"
payload = {
"prompt":"28-year-old Japanese pretty woman with black bobbed hair",
"negative_prompt": "text, letter, belongings"
}
response = requests.post(url=f'{url}/sdapi/v1/txt2img', json=payload)
# print(response.json()["parameters"]) # レスポンスパラメータを表示したいならコメントアウト解除
with open(f"./{int(time.time())}.png", "wb") as f:
f.write(base64.b64decode(response.json()["images"][0]))
結果
無事にpng画像が生成されました。
{'enable_hr': False, 'denoising_strength': 0, 'firstphase_width': 0, 'firstphase_height': 0, 'hr_scale': 2.0, 'hr_upscaler': None, 'hr_second_pass_steps': 0, 'hr_resize_x': 0, 'hr_resize_y': 0, 'hr_sampler_name': None, 'hr_prompt': '', 'hr_negative_prompt': '', 'prompt': '28-year-old Japanese pretty woman with black bobbed hair', 'styles': None, 'seed': -1, 'subseed': -1, 'subseed_strength': 0, 'seed_resize_from_h': -1, 'seed_resize_from_w': -1, 'sampler_name': None, 'batch_size': 1, 'n_iter': 1, 'steps': 50, 'cfg_scale': 7.0, 'width': 512, 'height': 512, 'restore_faces': False, 'tiling': False, 'do_not_save_samples': False, 'do_not_save_grid': False, 'negative_prompt': 'text, letter, belongings', 'eta': None, 's_min_uncond': 0.0, 's_churn': 0.0, 's_tmax': None, 's_tmin': 0.0, 's_noise': 1.0, 'override_settings': None, 'override_settings_restore_afterwards': True, 'script_args': [], 'sampler_index': 'Euler', 'script_name': None, 'send_images': True, 'save_images': False, 'alwayson_scripts': {}}
web UIだと15秒以内だったのが、API経由だと35秒程度かかりましたが、デフォルトのステップ数が50だからですね、きっと(web UIの場合のデフォルトは20)。
設定の上書き
ここまで見てきて気づいてきた方もいるかもしれませんが、前回の記事においてweb UI上で最後に設定したモデルであるDreamShaper(厳密にはdreamshaper_7.safetensors [ed989d673d])が適用されています。
設定を変更したいときは、ConfigのAPI(/sdapi/v1/options)を呼び出します。
たとえばsd_model_checkpointだけを変更するコードは下記です。
option_payload = {
"sd_model_checkpoint": "v2-1_768-ema-pruned.ckpt [ad2a33c361]"
}
response = requests.post(url=f'{url}/sdapi/v1/options', json=option_payload)
参考までに、modelの一覧はSd ModelsのAPI(/sdapi/v1/sd-models)で取得できます。
response = requests.get(url=f'{url}/sdapi/v1/sd-models')
responseをjsonメソッドで書き出して整形して表示してみます。
print(json.dumps(response.json(), indent=4))
[
{
"title": "v2-1_768-ema-pruned.ckpt [ad2a33c361]",
"model_name": "v2-1_768-ema-pruned",
"hash": "ad2a33c361",
"sha256": "ad2a33c361c1f593c4a1fb32ea81afce2b5bb7d1983c6b94793a26a3b54b08a0",
"filename": "/path/to/stable-diffusion-webui/models/Stable-diffusion/v2-1_768-ema-pruned.ckpt",
"config": null
},
{
"title": "dreamshaper_7.safetensors [ed989d673d]",
"model_name": "dreamshaper_7",
"hash": "ed989d673d",
"sha256": "ed989d673dbf0153d1cd16994c1bfa27a0f13de1e60665aabcb99334ca5b78e9",
"filename": "/path/to/stable-diffusion-webui/models/Stable-diffusion/dreamshaper_7.safetensors",
"config": null
}
]
最後に
コードで呼び出せるとやれることの幅も広がりますね。
遊び方をもっと考えたい気持ちになる。
宣伝
SupershipのQiita Organizationを合わせてご覧いただけますと嬉しいです。他のメンバーの記事も多数あります。
Supershipではプロダクト開発やサービス開発に関わる方を絶賛募集しております。
興味がある方はSupership株式会社 採用サイトよりご確認ください。