詳細はここ https://huggingface.co/docs/diffusers/using-diffusers/schedulers に書いてある。
先日の実験では DPMSolverMultistepScheduler を使うと真っ黒の画像になる、などと書いていたが、 今回あらためて試したところ、普通に作動した。
基本にするコード:
main.py
import torch
from diffusers import StableDiffusionPipeline, EulerDiscreteScheduler
model_id = "stabilityai/stable-diffusion-2-1"
device = "mps"
seed = 46
prompt = "A cup of coffee, simple background, art by Hokusai."
scheduler = EulerDiscreteScheduler.from_pretrained(model_id, subfolder="scheduler")
pipeline = StableDiffusionPipeline.from_pretrained(model_id, scheduler=scheduler)
pipeline = pipeline.to(device)
pipeline.enable_attention_slicing()
generator = torch.Generator(device).manual_seed(seed)
image = pipeline(prompt, guidance_scale=7.5, generator=generator).images[0]
image.save("a-cup-of-coffee.png")
実行すると次の絵ができました。
実際に出力されるのは 768x768 ですが、例によって 320x320 のサイズにリサイズして掲載しています。
スケジューラーを適用する部分のコードが現状はこれ:
scheduler = EulerDiscreteScheduler.from_pretrained(model_id, subfolder="scheduler")
pipeline = StableDiffusionPipeline.from_pretrained(model_id, scheduler=scheduler)
pipeline = pipeline.to(device)
この記述は、次のようにスッキリ記述できるとのこと。
pipeline = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
pipeline.scheduler = EulerDiscreteScheduler.from_config(pipeline.scheduler.config)
pipeline = pipeline.to(device)
DPMSolverMultistepScheduler に差し替えてみます。
main.py
import torch
from diffusers import StableDiffusionPipeline, DPMSolverMultistepScheduler
model_id = "stabilityai/stable-diffusion-2-1"
device = "mps"
seed = 46
prompt = "A cup of coffee, simple background, art by Hokusai."
pipeline = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
pipeline.scheduler = DPMSolverMultistepScheduler.from_config(pipeline.scheduler.config)
pipeline = pipeline.to(device)
pipeline.enable_attention_slicing()
generator = torch.Generator(device).manual_seed(seed)
image = pipeline(prompt, guidance_scale=7.5, generator=generator).images[0]
image.save("a-cup-of-coffee.png")
これを実行してできあがった画像はこちら:
実際に出力されるのは 768x768 ですが、例によって 320x320 のサイズにリサイズして掲載しています。
シードもプロンプトも同じなので完全に同じ絵になるかと思ったのですが、少しは異なります。
ちなみに torch_dtype=torch.float16 指定しているがこれを外したらどうなるのか? もっときれいな画像になるのであろうか?
#pipeline = StableDiffusionPipeline.from_pretrained(model_id, torch_dtype=torch.float16)
pipeline = StableDiffusionPipeline.from_pretrained(model_id)
実行結果の画像:
まあ、大差ない。
そもそも device が CUDA ではないから、このオプションがもともと有効ではなかった可能性あり。
StableDiffusionPipeline.from_pretrained で pipeline を組み立てた時点でセットされている scheduler は pipeline.scheduler すれば把握できる。
pipeline = StableDiffusionPipeline.from_pretrained(model_id)
print(pipeline.scheduler)
次のように出力された。 DDIMScheduler がセットされている。
DDIMScheduler {
"_class_name": "DDIMScheduler",
"_diffusers_version": "0.23.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": "v_prediction",
"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
}
pipeline.scheduler.compatibles すると、使えるスケジューラーの一覧が入手できるらしい。
pipeline = StableDiffusionPipeline.from_pretrained(model_id)
#print(pipeline.scheduler.compatibles)
for it in pipeline.scheduler.compatibles:
print(it)
<class 'diffusers.schedulers.scheduling_deis_multistep.DEISMultistepScheduler'>
<class 'diffusers.utils.dummy_torch_and_scipy_objects.LMSDiscreteScheduler'>
<class 'diffusers.schedulers.scheduling_euler_ancestral_discrete.EulerAncestralDiscreteScheduler'>
<class 'diffusers.schedulers.scheduling_ddpm.DDPMScheduler'>
<class 'diffusers.schedulers.scheduling_k_dpm_2_discrete.KDPM2DiscreteScheduler'>
<class 'diffusers.schedulers.scheduling_euler_discrete.EulerDiscreteScheduler'>
<class 'diffusers.schedulers.scheduling_k_dpm_2_ancestral_discrete.KDPM2AncestralDiscreteScheduler'>
<class 'diffusers.schedulers.scheduling_dpmsolver_multistep.DPMSolverMultistepScheduler'>
<class 'diffusers.schedulers.scheduling_ddim.DDIMScheduler'>
<class 'diffusers.schedulers.scheduling_pndm.PNDMScheduler'>
<class 'diffusers.schedulers.scheduling_heun_discrete.HeunDiscreteScheduler'>
<class 'diffusers.utils.dummy_torch_and_torchsde_objects.DPMSolverSDEScheduler'>
<class 'diffusers.schedulers.scheduling_dpmsolver_singlestep.DPMSolverSinglestepScheduler'>
<class 'diffusers.schedulers.scheduling_unipc_multistep.UniPCMultistepScheduler'>
試しに DPMSolverSinglestepScheduler を使ってみる。
DPMSolverSinglestepScheduler の説明: https://huggingface.co/docs/diffusers/v0.23.1/en/api/schedulers/singlestep_dpm_solver
だいたい 10ステップで高品質な絵ができるという話なのでやってみる。
import torch
from diffusers import StableDiffusionPipeline, DPMSolverSinglestepScheduler
model_id = "stabilityai/stable-diffusion-2-1"
seed = 46
device = "mps"
prompt = "A cup of coffee, simple background, art by Hokusai."
pipeline = StableDiffusionPipeline.from_pretrained(model_id)
pipeline.scheduler = DPMSolverSinglestepScheduler.from_config(pipeline.scheduler.config)
pipeline = pipeline.to(device)
pipeline.enable_attention_slicing()
generator = torch.Generator(device).manual_seed(seed)
image = pipeline(
prompt,
guidance_scale=7.5,
num_inference_steps=10,
generator=generator).images[0]
image.save("a-cup-of-coffee.png")
num_inference_steps=10 を pipeline に指定することでステップ数を指定できる。 デフォルトの 50 ステップが 10ステップで絵ができるので、生成時間は 1/3 程度(本来は 1/5 になるべき?)です。
生成された絵はこれ:
これが少ないステップ数で高品質になったのかわからないので、 デフォルトのスケジューラー( DDIMScheduler )で 10ステップ にした画像を生成してみます。
これ:
あぁ確かに。これは「まだ早すぎたんだ」感がすごい。
では DPMSolverSinglestepScheduler を使って 25ステップ を試します。
確かに品質が高くなっています。100ステップにしたらどうなるんだろう?
すくなくとも スケジューラーとして DPMSolverSinglestepScheduler を使った場合については、 カップの取っ手の部分の描画がよくなってきてはいるものの、 ステップ数を増やしたからといって劇的によくなった感じはしない。 ある程度(50ステップ)以上は それほど変わりがないのかもしれない。
10,25,100ステップと並べてみると違いがわかる。