ジャコ Lab

プログラミング関連のメモ帳的ブログです

Schedulers とは?

Civitai 等のモデルページを見ていると、 Sampler が指定されています。
diffusers では、 Scheduler がそれに相当するようです。

この記事では Scheduler について調べてみます。

huggingface.co

Scheduler とは

schedulers define the whole denoising process.

Scheduler はノイズ除去プロセス全体を定義してくれるとのことです。

Scheduler の確認方法

So it can be accessed via the "scheduler" property.

scheduler プロパティでアクセスできるとのことですね。

# パイプラインのスケジューラを確認する
print(pipe.scheduler)

---

PNDMScheduler {
  "_class_name": "PNDMScheduler",
  "_diffusers_version": "0.25.1",
  "beta_end": 0.012,
  "beta_schedule": "scaled_linear",
  "beta_start": 0.00085,
  "clip_sample": false,
  "num_train_timesteps": 1000,
  "prediction_type": "epsilon",
  "set_alpha_to_one": false,
  "skip_prk_steps": true,
  "steps_offset": 1,
  "timestep_spacing": "leading",
  "trained_betas": null
}

ロードしているパイプラインのデフォルトに設定されているものになるんですかね?

scheduler の変更方法

Every scheduler has a property compatibles which defines all compatible schedulers.

スケジューラには compatibles というプロパティがあって、互換性のあるスケジューラが定義されているようです

print(pipe.scheduler.compatibles)

---

[
    <class 'diffusers.schedulers.scheduling_pndm.PNDMScheduler'>,
    <class 'diffusers.schedulers.scheduling_k_dpm_2_discrete.KDPM2DiscreteScheduler'>,
    <class 'diffusers.schedulers.scheduling_unipc_multistep.UniPCMultistepScheduler'>,
    <class 'diffusers.schedulers.scheduling_euler_discrete.EulerDiscreteScheduler'>,
    <class 'diffusers.schedulers.scheduling_ddpm.DDPMScheduler'>,
    <class 'diffusers.schedulers.scheduling_euler_ancestral_discrete.EulerAncestralDiscreteScheduler'>,
    <class 'diffusers.utils.dummy_torch_and_torchsde_objects.DPMSolverSDEScheduler'>,
    <class 'diffusers.schedulers.scheduling_deis_multistep.DEISMultistepScheduler'>,
    <class 'diffusers.schedulers.scheduling_heun_discrete.HeunDiscreteScheduler'>,
    <class 'diffusers.schedulers.scheduling_dpmsolver_multistep.DPMSolverMultistepScheduler'>,
    <class 'diffusers.schedulers.scheduling_dpmsolver_singlestep.DPMSolverSinglestepScheduler'>,
    <class 'diffusers.schedulers.scheduling_k_dpm_2_ancestral_discrete.KDPM2AncestralDiscreteScheduler'>,
    <class 'diffusers.schedulers.scheduling_ddim.DDIMScheduler'>,
    <class 'diffusers.schedulers.scheduling_lms_discrete.LMSDiscreteScheduler'>
]

たくさんありました。

To change the scheduler of the pipeline you can make use of the convenient config property in combination with the from_config() function.

スケジューラは config というプロパティも持っていて、
from_config() メソッドと組み合わせて使うらしいです。

from diffusers import DDIMScheduler

ddim_scheduler = DDIMScheduler.from_config(pipe.scheduler.config)
pipe.scheduler = ddim_scheduler

print(pipe.scheduler)

---

DDIMScheduler {
  "_class_name": "DDIMScheduler",
  "_diffusers_version": "0.25.1",
  "beta_end": 0.012,
  "beta_schedule": "scaled_linear",
  "beta_start": 0.00085,
  "clip_sample": false,
  "clip_sample_range": 1.0,
  "dynamic_thresholding_ratio": 0.995,
  "num_train_timesteps": 1000,
  "prediction_type": "epsilon",
  "rescale_betas_zero_snr": false,
  "sample_max_value": 1.0,
  "set_alpha_to_one": false,
  "skip_prk_steps": true,
  "steps_offset": 1,
  "thresholding": false,
  "timestep_spacing": "leading",
  "trained_betas": null
}

変わりましたね。

実際に実行してみる

ドキュメントにある通り、以下の条件で実行してみようと思います。

  • モデル: runwayml/stable-diffusion-v1-5
  • プロンプト: "A photograph of an astronaut riding a horse on Mars, high resolution, high definition."
  • seed: 8
  • ステップ数: スケジューラによって変える

デフォルト (PNDMScheduler)

PNDMScheduler

おお、ドキュメントと全く同じものが出ました!

DDIMScheduler

DDIMScheduler

おお!これも全く同じものが出ました!
今までモデルページのプロンプトに合わせて実行してても全く同じものは出なかったので嬉しいぃ!

LMSDiscreteScheduler

LMSDiscreteScheduler usually leads to better results:

通常、こっちのほうが良い結果が得られる!?

LMSDiscreteScheduler

良い結果かどうかはちょっとわからないですが、
これもドキュメントと同じものが出ました!

EulerDiscreteScheduler, EulerAncestralDiscreteScheduler

EulerDiscreteScheduler and EulerAncestralDiscreteScheduler can generate high quality results with as little as 30 steps.

これらは、30ステップで良い結果が得られるとな!?
ということは、、、前回の記事(以下の記事)で、
30ステップで品質が悪くなったように見えるのは Scheduler のせいである可能性が高いですね!

zako-lab929.hatenablog.com

とりあえず EulerDiscreteSchedulerEulerAncestralDiscreteScheduler を 30 ステップで実行してみましょう

EulerDiscreteScheduler | EulerAncestralDiscreteScheduler

全く同じのが出るって気持ちいい!

DPMSolverMultistepScheduler

DPMSolverMultistepScheduler gives a reasonable speed/quality trade-off and can be run with as little as 20 steps.

こちらはスピードとクオリティのトレードオフにより20ステップで出来るって書いてあるっぽいですね?

DPMSolverMultistepScheduler

確かに早いですね。
2秒くらいで出来ました。

まとめ

スケジューラによってプロセスが異なるということで、
品質やステップ数などに影響が出るため、スケジューラーの指定は重要そうな気がしました!

huggingface.co

そして上記には、 Web UI と Diffusers の Scheduler 比較表がありました。

A1111-k-diffusion diffusers Usage
DPM++ 2M DPMSolverMultistepScheduler
DPM++ 2M Karras DPMSolverMultistepScheduler init with use_karras_sigmas=True
DPM++ 2M SDE DPMSolverMultistepScheduler init with algorithm_type="sde-dpmsolver++"
DPM++ 2M SDE Karras DPMSolverMultistepScheduler init with use_karras_sigmas=True and algorithm_type="sde-dpmsolver++"
DPM++ 2S a N/A very similar to DPMSolverSinglestepScheduler
DPM++ 2S a Karras N/A very similar to DPMSolverSinglestepScheduler(use_karras_sigmas=True, ...)
DPM++ SDE DPMSolverSinglestepScheduler
DPM++ SDE Karras DPMSolverSinglestepScheduler init with use_karras_sigmas=True
DPM2 KDPM2DiscreteScheduler
DPM2 Karras KDPM2DiscreteScheduler init with use_karras_sigmas=True
DPM2 a KDPM2AncestralDiscreteScheduler
DPM2 a Karras KDPM2AncestralDiscreteScheduler init with use_karras_sigmas=True
DPM adaptive N/A
DPM fast N/A
Euler EulerDiscreteScheduler
Euler a EulerAncestralDiscreteScheduler
Heun HeunDiscreteScheduler
LMS LMSDiscreteScheduler
LMS Karras LMSDiscreteScheduler init with use_karras_sigmas=True
N/A DEISMultistepScheduler
N/A UniPCMultistepScheduler

これで勝つるかもしれません!