1
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

MacBook(M2)にインストールしたStable DiffusionのAPIをPythonで呼び出して画像を生成してみた

Last updated at Posted at 2023-07-26

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つ追記してコメントアウトを解除します。

  • --apiweb UIAPIと共に起動されます。--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)を使いますが、リファレンスでは下記のように記載されています。

image01.png

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画像が生成されました。

image02.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株式会社 採用サイトよりご確認ください。

1
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
5

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?