🎃

diffusersでschedulerを変える方法

2022/12/05に公開

どうもこんにちは。Kaibaです。
diffusersでガチャをブン回しているんですがいい加減WebUIでDAAM使ってプロンプト研究しなきゃなと思い続けています。一体いつ導入するのか。

初めに

この記事ではdiffuserでSchedulerを変える方法について説明します。 Twitterで魔術師の方々を覗いていると度々eulerが~ddimが~みたいな話を見かけるんですが、サンプラーって何??どうやって変えればいいの?? っていうのがよく分からなかったのでメモとして残しておきます。ckptをdiffusers用に変換とかの情報はあったりしたんですがSchedulerを変える方法は日本語ではあんまり見つからなかったんですよね。diffusersでSchedulerを変えようとする人はみんな公式ドキュメントくらいすぐ読めるしいらないってことなんでしょうか。
とにかく、この記事は機械学習なんて全然わかんないよ〜!けど画像生成AIは面白いし色々試したいよ〜!という人向けです。 というか僕向けです。いや、なんも分からんなら大人しくWebUI使ってろって話なんですけどね。
うちの大学にも機械学習の講義生えないかなぁ…

Schedulerとは

まずSchedulerとはなんぞや?という話をします。難しい話は僕も分からないので避けて説明します。ふんわりと理解してもらえれば。
stable diffusionなどの潜在拡散モデルでは、潜在空間と呼ばれるピクセルよりも小さな次元でいくつかのステップに分けてノイズを除去していき、画像を生成します。 Schedulerはこの除去するノイズの量、除去する際のステップ数の決定を担っています。 早い話、Schedulerを変えると生成時の出力結果が変わります。魔術師達の呟きを見るに画像の画風が変わったりもするみたいです。また、画像の推論(生成)を行うことをサンプリングというため、モデルによってはSchedulerをSamplerとも呼ぶようです。ややこしいですね

diffusersでSchedulerを変える

それでは本題のSchedulerを変える方法です。とはいってもdiffusersが有能なおかげで死ぬほど簡単です。Schedulerを作成してpipelineを作るときにSchedulerを渡してやるだけです。公式に載ってるコードまんまです。

試しに今回はEulerDiscreteSchedulerを指定してみます。

import torch
from diffusers import StableDiffusionPipeline, EulerDiscreteScheduler

rep_name="モデルのリポジトリ名(ex. hakurei/waifu-diffusion)"

c_scheduler = EulerDiscreteScheduler.from_config(rep_name, subfolder="scheduler")
pipe = StableDiffusionPipeline.from_pretrained(
    rep_name,
    torch_dtype=torch.float16, scheduler=c_scheduler
).to("cuda")

また、diffusers v0.8.0以降では以下のコードで既に生成されたpipelineのSchedulerを変更することができます。

pipeline.scheduler = EulerDiscreteScheduler.from_config(pipeline.scheduler.config)

diffusers v0.9.0時点で実装されているSchedulerのうち、txt2imgで使えるSchedulerは以下の通りです。

  • DDIMScheduler
  • DPMSolverMultistepScheduler (別名 DPM-Solver++ diffusers v0.8.0~)
  • LMSDiscreteScheduler
  • PNDMScheduler
  • EulerDiscreteScheduler (diffusers v0.7.0~)
  • EulerAncestralDiscreteScheduler (略称 Euler a, diffusers v0.7.0~)

    デフォルトではPNDMSchedulerになっているそうです。また、0.7.0で追加されたEuler系Schedulerは計算速度が高速で、20~30ステップでも良い結果を出力してくれるそうです。

比較

prompt, negative prompt, CFG_scale, step, seedはそれぞれ以下の通り。
モデルはAnything_v3を使用しました。

prompt="masterpiece, highres, 1girl, upper body, brown eyes, teenage, smile, black medium hair, medium breast, school uniform"
negative_prompt=""
CFG_scale = 15
step_num = 36
seed = 8648493847483974335

DDIMScheduler


time=00:17

DPMSolverMultistepScheduler


time=00:20

LMSDiscreteScheduler


step_num =50 time=00:24
step数36で実行した際は目の部分がノイズのままだったためstep50での結果です。まだ少しノイズの跡がありますね。

PNDMScheduler


time=00:18

EulerDiscreteScheduler


time=00:17

EulerAncestralDiscreteScheduler


time=00:17

おわりに

Schedulerによって微妙に描き込みや必要step数が変わってきますね。計算速度などを考えてもEuler系がよさげな気がします。正直Schedulerが何をしているのか僕もさっぱりですが、EulerDiscreteSchedulerに変更してからというもの、生成速度も上がって生成画像のクオリティも良さげになって大満足です!これでプロンプト研究が捗りますね!

最後に記事を書く上で参考になったサイトをのせておきます。それでは!
https://zenn.dev/tomo_makes/books/4ed97f06d02a38
https://zenn.dev/mimitako/articles/stable_diffusion_sampler

Discussion