【Stable Diffusion】DPM-Solverによる画像生成の高速化

【Stable Diffusion】DPM-Solverによる画像生成の高速化 機械学習

「Stable Diffusionで画像をもっと速く生成したい」
「Stable Diffusionで当たり画像を効率良く作りたい」

このような場合には、SamplerにDPM-Solverを使うことをオススメします。
この記事では、SamplerをDPM-Solverに変更する方法を解説しています。

本記事の内容

  • Stable DiffusionにおけるSamplerとは?
  • DPM-Solverとは?
  • Stable DiffusionでDPM-Solverを動作させる方法
  • PNDMとDPM-Solverの比較

それでは、上記に沿って解説していきます。

Stable DiffusionにおけるSamplerとは?

Sampler(サンプラー)とは、学習済みモデルをもとに実際に画像を生成するアルゴリズムのことです。
ノイズ処理に関するアルゴリズムだと覚えておけばよいでしょう。

Samplerを説明する際に、次のような画像が用いられます。

縦軸には、Samplerが表示されています。
そして、横軸はStepsとなります。

基本的には、Samplerによって生成される画像の内容は変わりません。
ただ、画像生成のSteps(速度)で違いが生まれます。

また、Stable DiffusionにおいてはPNDMがデフォルトのSamplerとなります。

[2202.09778] Pseudo Numerical Methods for Diffusion Models on Manifolds
https://arxiv.org/abs/2202.09778

次の設定ファイルに、PNDMが記載されていることを確認できます。

以上、Stable DiffusionにおけるSamplerについて説明しました。
次は、DPM-Solverについて説明します。

DPM-Solverとは?

DPM-Solverは、高速に処理できるSamplerです。
公式(GitHub)ページでは、次の画像でDPM-Solverの効果を説明しています。

先ほど見た画像と同じ軸ですね。
縦軸はSamplerであり、横軸はStepsとなります。

ただ、この画像はちょっとやり過ぎです。
最後のStepsが999は、極端過ぎます。
とにかく、DPM-Solverが速いことを言いたいのでしょう。

実際のところは、次のような結果になるようです。
と言っても、DPM-Solverの開発者の主張に過ぎませんけど。

SamplerSteps
PNDM50
DPM-Solver10~25

これは、高品質のサンプルを生成する場合のStepsの比較になります。
モノによっては、5倍の速度もあり得るようです。

最低でも2倍の処理速度が出るなら、十分に利用する価値はあるでしょう。
img2imgにおいては、よりその効果を発揮するはずです。

以上、DPM-Solverについて説明しました。
最後に、Stable DiffusionでDPM-Solverを動作させる方法を説明します。

Stable DiffusionでDPM-Solverを動作させる方法

Stable Diffusionでは、正確にはDPM-Solver++が動作可能です。
DPM-Solver++は、DPM-Solverの改良版になります。

そのDPM-Solver++をStable Diffusionを動かす方法を説明していきます。
まずは、動作確認用のコードから。

from diffusers import StableDiffusionPipeline, DPMSolverMultistepScheduler
import torch

MODEL_ID = "runwayml/stable-diffusion-v1-5"
DEVICE = "cuda"
YOUR_TOKEN = "コピーしたアクセストークン"

scheduler = DPMSolverMultistepScheduler(
    beta_start=0.00085,
    beta_end=0.012,
    beta_schedule="scaled_linear",
    num_train_timesteps=1000,
    trained_betas=None,
    predict_epsilon=True,
    thresholding=False,
    algorithm_type="dpmsolver++",
    solver_type="midpoint",
    lower_order_final=True,
)

pipe = StableDiffusionPipeline.from_pretrained(
    MODEL_ID,
    torch_dtype=torch.float16,
    use_auth_token=YOUR_TOKEN,
    scheduler=scheduler
)

pipe = pipe.to(DEVICE)

prompt = "a photo of an astronaut riding a horse on mars"
image = pipe(
    prompt,
    num_inference_steps=25,
    guidance_scale=7.5,
).images[0]

image.save("astronaut_rides_horse.png")

このコードを動かすには、Stable Diffusionが大前提となります。
そして、上記コードではStable Diffusion 1.5vを学習済みモデルに指定しています。

そのため、まずはStable Diffusion 1.5vが動くまでの状態を用意しましょう。
さらに、そこから以下のパッケージをインストールします。

requirements.txt

git+https://github.com/huggingface/diffusers.git 
scipy 
ftfy 
accelerate

Diffusersについては、Githubから開発中のモノをインストール(再インストール)します。
2022年11月中旬時点では、Diffusersは次のバージョンが最新となります。

まだ0.7系では、上記コードは動きません。
具体的には、「DPMSolverMultistepScheduler」がimportできないのです。
つまり、存在しないということになります。

0.8系から「DPMSolverMultistepScheduler」を利用できるようになります。
だからこそ、現時点ではGithubからインストールする必要があるのです。

0.8系が正式に公開されたら、そんなことをする必要はなくなるでしょう。
準備が整ったら、コードを実行します。

私の環境では、2秒で次のような画像が生成されました。

時間については、マシンスペックによって違いが出るでしょう。
ただ、たった2秒でこの質の画像が生成されるのは驚きです。

通常、Stepsは「70」ぐらいが推奨されています。
しかし、上記コードでは「25」に設定しています。

num_inference_steps=25,

ちなみに、Stepsに「70」を設定した場合は5秒かかっています。

以上、Stable DiffusionでDPM-Solverを動作させる方法を説明しました。
最後に、PNDMとDPM-Solverの比較を説明します。

PNDMとDPM-Solverの比較

Stepsは10~100(10カウントアップ)で画像を生成しています。
モデルは、Stable Diffusion 1.5vの他にMidjourney v4 Diffusionを利用しています。

各Steps毎の画像は次の配置で結合しています。

1020304050
60708090100

結果その1

PNDM

DPM-Solver

モデルには、Stable Diffusion 1.5vを利用しています。
次のStepsで同じレベルの画像が生成されていることを確認できます。

PNDM100
DPM-Solver30

PNDMの試行錯誤の過程がよくわかります。
ただ、推奨とされているSteps 70でも未完成という状況です。

PNDMを使ってきた今までは、経験則的にSteps 100を設定してきました。
やはり、それはそれで正しかったのでしょう。

でも、DPM-Solverを使えばSteps 30で済みます。
処理時間で言えば、3分の1以下となります。

結果その2

PNDM

DPM-Solver

モデルには、Midjourney v4 Diffusionを利用しています。
次のStepsで同じレベルの画像が生成されていることを確認できます。

PNDM100
DPM-Solver30 or 40

PNDMのStreps60から80の心変わりは何なんでしょうね?
Steps50である程度の方向性が決まっているのに、ブレるのが不思議です。

それに対して、DPM-SolverはもうSteps10の段階で方向性は決まっています。
あとは、精度を上げていくという感じです。

結果その3

PNDM

DPM-Solver

モデルには、Midjourney v4 Diffusionを利用しています。
次のStepsで同じレベルの画像が生成されていることを確認できます。

PNDM100
DPM-Solver40

PNDMの変化は、ある意味アートですね。
しかし、これはStepsによって結果が全く異なる可能性があり得ることを示しています。

こんなにPNDMが不安定だとは、知りませんでした・・・
それに対して、DPM-Solverは安定しています。

まとめ

比較した結果より、DPM-Solverが速いことはわかりました。
Steps40の時点で完成と言えます。

そして、PNDMの利用は危険だということもわかりました。
これだけStepsで画像の構造が変わるのは、利用する上では怖い部分です。
デフォルトの「50」を使っておけば、そこまで不安定ではありませんけどね。

その意味でも、PNDMからDPM-Solverに置き換えるのは全然ありでしょう。
DPM-SolverがデフォルトSamplerに採用される日も近いかもしれません。

また、当たり画像を探る点において、DPM-Solverは効果的です。
Steps20の時点である程度の方向性(構造)は、大体わかります。

Steps20で大量に画像を生成して、その中から良いものをピックアップします。
ピックアップしたモノ(正確にはSEED)を、さらに良い条件で生成すればよいでしょう。

以上、PNDMとDPM-Solverの比較を説明しました。

タイトルとURLをコピーしました