勾配降下党青年局

万国のグラーディエントよ、降下せよ!

さんぷらーについて

 各サンプラーの意味とかがなんとなく分かりたくて書いたものです。SDEやODEの導出に関する話はでてきません(分からんし)。

拡散過程の定義

サンプラーによって使われている文字の意味が違うので、ここでは文字をあわせていいきたいと思います。そのため論文の式そのままにできないので間違っている可能性があります。
拡散過程は分散保存型と分散発散型の二種類に分かれています。

分散保存型

元の画像を弱めながらノイズを加えていく方法です。
 x_{t} = \sqrt{\alpha_t}x_{t-1} + \sqrt{1-\alpha_t}\epsilon

二つの係数の二乗和をとると1になります。つまり分散がどの時刻でも固定されます。

この拡散過程は以下のようにx_tを単独でサンプリングすることができます。
 x_{t} = \sqrt{\bar{\alpha}_t}x_{0} + \sqrt{1-\bar{\alpha}_t}\epsilon
ここで、\bar{\alpha}_t = \displaystyle{\prod_{s=1}^{t}\alpha_s}です。

この説明には\betaも使うことが多いです。ば~の有無にかかわらず、\alpha = 1-\betaです。\betaを使った方がシンプルになるときは\betaを使います。

分散発散型

元の画像をそのままにして、ノイズを加えていく方法です。
x_t = x_{0} + \sigma_t \epsilon

Stable Diffusionは学習時に分散保存型を採用していますが、分散発散型であると仮定して生成することも可能です。
\sigma_t = \frac{\sqrt{1-\bar{\alpha}_t}}{\sqrt{\bar{\alpha}_t}}とすれば、\sqrt{\bar{\alpha}_t}x_t = \sqrt{\bar{\alpha}_t}x_{0}+ \sqrt{1-\bar{\alpha}_t}\epsilonとスケーリングすることで分散保存型の式になるので、それをUNetに入力すればよいです。出力は係数が掛けられていない元のノイズなので、スケーリングは必要ありません。

離れたタイムステップ間のサンプリング

離れた時刻t-hから tへのサンプリングもできます。
x_{t} = \sqrt{\frac{\bar{\alpha}_{t}}{\bar{\alpha}_{t-h}}}x_{t-h} + \sqrt{1-\frac{\bar{\alpha}_{t}}{\bar{\alpha}_{t-h}}}\epsilon

\bar{\alpha}は累積積なので、h = 1だったら、\alpha_tがそのままでてきますね。
1ステップ分の式を離れた時刻に対応する式に置き換えたい場合、\alpha_t\frac{\bar{\alpha}_{t}}{\bar{\alpha}_{t-h}}に置き換えればよいだけです。またh自然数ではなく実数にすることができます(時刻を離散時間から連続時間にする)。UNetの時刻埋め込みはうまいこと連続になるよう設定されているので、離散的な時刻しか学習していなくても問題ないらしい。

逆拡散過程

逆拡散過程では、加えられたノイズをモデルに予測させ、その結果を使って次のステップの画像を推定します。その推定の仕方はサンプラーによって異なります。

ノイズの予測を\epsilon(x_t, t)とすると、ノイズのない画像の予測\hat{x_0}は、
\hat{x}_0 = \frac{1}{\sqrt{\bar{\alpha}_t}}(x_t - \sqrt{1-\bar{\alpha}_t}\epsilon(x_t, t))
となります。

モデルの予測結果から導出する変数は、\hat{x}_0, \hat{\epsilon}など帽子をつけてあげます。

画像生成の流れ

Stable Diffusionの画像生成はdiffusersでは以下のようなコードになっています。

# timestepの設定
self.scheduler.set_timesteps(num_inference_steps)
timesteps = self.scheduler.timesteps

# 初期ノイズの作成
latents = torch.randn(batch_size, 4, height // 8, width // 8)

# 分散発散型の場合simga_1000をかける
latents = latents * self.scheduler.init_noise_sigma

# ノイズ除去ループ
for i, t in enumerate(timesteps):
    #分散発散型の場合に入力を分散保存型に置き換える
    latent_model_input = self.scheduler.scale_model_input(latents, t)

    #ノイズ予測
    noise_pred = self.unet(latent_model_input , t)

    # 次のステップの潜在変数を推定
    latents = self.scheduler.step(noise_pred, t, latents).prev_sample

今回の話の主題ではない条件付き生成に関わる部分などは省略しています。時刻t \in [1, 2, \cdots, 1000]を設定したステップ数n分取り出して、\tau_1 , \cdots, \tau_nとして、x_{\tau_n}\to x_{\tau_{n-1}} \to \cdots \to x_{\tau_{1}}と処理を繰り返します。このとき現在の画像から与えられたノイズを予測する役割を持つのがUNetで、次の時刻の状態を予測する役割を持つのがサンプラーになります。

微分方程式サンプラー

DDPM、DDIMといった微分方程式を使わないサンプラーは、以下のように平均と分散を推定することで次の画像を予測します。
x_{t-1} = \mu_\theta(x_t,t) + \beta \epsilon
ただし分散は学習せず固定します。

DDPM

DDPMSamplerは最初にできたサンプラーです。

DDPM1
\hat{x}_{t-1} = \frac{1}{\sqrt{\alpha_{t}}}(\hat{x}_{t} - \frac{1-\alpha_{t}}{\sqrt{1-\bar{\alpha}_{t}}}\hat{\epsilon}) + \sqrt{1-\bar{\alpha}_{t}}\epsilon

またバリエーションとして、DDPMの導出中にでてくるq(x_{t-1}|x_t,x_0)からでてくる平均と分散を使ってx_{t-1}を予測する式もあります。

DDPM2
2. \hat{x}_{t-1} = \frac{\sqrt{\bar{\alpha}_{t-1}}\beta_t}{\bar{\beta}_t}\hat{x_0}+\frac{\sqrt{\alpha_t}\bar{\beta}_{t-1}}{\bar{\beta}_t}x_t + \sqrt{\frac{\bar{\beta}_{t-1}}{\bar{\beta}_{t}}\beta_t}\epsilon

よくわかりませんが、diffusersではこっちを使っているようです。後述のDDIMの特殊ケースになります。

DDIM

拡散過程は今まで加えられてきたノイズと、次に加えるノイズが全くの無関係でした。つまりx_tが依存するのはx_{t-1}のみでした。逆に加えるノイズを全時刻で固定することを考えると、x_tx_0のみに依存するようになります。DDIMではその間をとるような拡散過程を考えます。するとDDPMとDDIMはうまいこと最適解が一致するため、DDPMで学習したモデルに対してDDIMを根拠にした生成を行えます。DDIMSamplerは1000ステップ必要だったDDPMSamplerに比べて数十ステップくらいで生成できるようになりますた。

サンプリングは、

DDIM
1. はいぱら\etaに対して、s_t = \eta\sqrt{\frac{\bar{\beta}_{t-1}}{\bar{\beta}_t}\beta_t}とする
2. \hat{x}_{t-1} = \sqrt{\bar{\alpha}_{t-1}}\hat{x}_{0} + \sqrt{\bar{\beta}_{t-1}-{s_t}^2}\hat{\epsilon} + s_t\epsilon

(1)\eta=1のとき、DDPMの二つ目の式と同じになります。
計算
第二項は

\begin{eqnarray}
\sqrt{\bar{\beta}_{t-1}-\frac{\bar{\beta}_{t-1}}{\bar{\beta}_t}\beta_t}\hat{\epsilon} & = & \sqrt{\frac{(\bar{\beta}_{t}-\beta_t)\bar{\beta}_{t-1}}{\bar{\beta}_t}}\hat{\epsilon} \\
& = & \sqrt{\frac{(\bar{\beta}_{t}-\beta_t)\bar{\beta}_{t-1}}{\bar{\beta}_t}}\frac{x_t-\sqrt{\bar{\alpha_t}}\hat{x}_0}{\sqrt{\hat\beta_{t}}} \\
& = & \frac{\sqrt{(\bar{\beta}_{t}-\beta_t)\bar{\beta}_{t-1}}}{\bar{\beta}_t}(x_t-\sqrt{\bar{\alpha_t}}\hat{x}_0) \\
& = & \frac{\sqrt{(1-\bar{\alpha}_{t}- (1- \alpha_t))\bar{\beta}_{t-1}}}{\bar{\beta}_t}(x_t-\sqrt{\bar{\alpha_t}}\hat{x}_0) \\
& = & \frac{\sqrt{\alpha_t(1-\bar{\alpha}_{t-1})\bar{\beta}_{t-1}}}{\bar{\beta}_t}(x_t-\sqrt{\bar{\alpha_t}}\hat{x}_0) \\
& = & \frac{\sqrt{\alpha_t\bar{\beta}_{t-1}\bar{\beta}_{t-1}}}{\bar{\beta}_t}(x_t-\sqrt{\bar{\alpha_t}}\hat{x}_0) \\
& = & \sqrt{\alpha_t}\frac{\bar{\beta}_{t-1}}{\bar{\beta_{t}}}x_t - -\sqrt{\alpha_t\bar{\alpha_t}}\frac{\bar{\beta}_{t-1}}{\bar{\beta_{t}}}\hat{x_0}\\
\end{eqnarray}

x_tの係数に着目すると、\sqrt{\alpha_t}\frac{\bar{\beta}_{t-1}}{\bar{\beta_{t}}}となりDDPMの二番目の式と一致しました^^

\hat{x_0}の係数に着目すると、-\sqrt{\alpha_t\bar{\alpha_t}}\frac{\bar{\beta}_{t-1}}{\bar{\beta_{t}}}となり
第一項の\hat{x_0}の係数と足すと、
\sqrt{\bar{\alpha}_{t-1}}-\sqrt{\alpha_t\bar{\alpha_t}}\frac{\bar{\beta}_{t-1}}{\bar{\beta_{t}}}=\sqrt{\bar{\alpha}_{t-1}}\frac{\bar{\beta}_{t}-\alpha_t\bar{\beta}_{t-1}}{\bar{\beta}_{t}}=\sqrt{\bar{\alpha}_{t-1}}\frac{1-\bar{\alpha}_{t}-\alpha_t + \alpha_t\bar{\alpha}_{t-1}}{\bar{\beta}_{t}}
=\sqrt{\bar{\alpha}_{t-1}}\frac{\beta_{t}}{\bar{\beta}_{t}}
DDPMの二番目の式の係数と一致しました^^
ノイズの係数は計算せずとも一致していることが分かります^^

(2)\eta=0のとき、生成過程でランダムノイズ部分がなくなり、初期ノイズから決定的に生成するようになります。つまり全時刻で同じノイズを与えたと考えた時の生成法となります。
\hat{x}_{t-1} = \sqrt{\bar{\alpha}_{t-1}}\hat{x}_{0} + \sqrt{\bar{\beta}_{t-1}}\hat{\epsilon}
ニューラルネットワークによるノイズ予測が完全に正しければ、各ステップにおけるノイズ予測は定数になりステップをいくつスキップするかに関わらず同じ結果が得られます。現実的にはそんなネットワークは作れませんが(作れたとしても面白くない)、ある程度予測精度が高ければ、1ステップはさすがに無理だけど、数十ステップくらいで生成できるようになる、というイメージっぽいです(あってるか分からん)。
ここまで長々と説明してなんですが、どの実装でもデフォルトだと\eta=0になります。他のパターンなんて知っててもどうしようもないですね。

PNDM(PLMS)

PNDMはDDIMの更新式をODE化して初期値問題を解く方法です。非微分方程式じゃないんですが、DDIMの拡張みたいなんでここに入れました。式を厳密に入れるととんでもないことになるので省略しますが、最初の3ステップはるんげくったを使って計算し、その後は過去3ステップ分の予測結果を利用した多段法を使います。
更新式の計算は以下の通りです。DDIMの\eta=0の式からはじまります。

\begin{eqnarray}
\hat{x}_{t-h} &=& \sqrt{\bar{\alpha}_{t-h}}\hat{x}_{0} + \sqrt{\bar{\beta}_{t-h}}\hat{\epsilon} \\
 &=& \sqrt{\bar{\alpha}_{t-h}}\frac{1}{\sqrt{\bar{\alpha}_t}}(x_t - \sqrt{1-\bar{\alpha}_t}\hat{\epsilon}) + \sqrt{\bar{\beta}_{t-h}}\hat{\epsilon} \\
 &=&  \frac{\sqrt{\bar{\alpha}_{t-h}}}{\sqrt{\bar{\alpha}_t}}x_t -  \frac{\sqrt{\bar{\alpha}_{t-h}(1-\bar{\alpha}_t)}- \sqrt{\bar{\alpha}_t(1-\bar{\alpha}_{t-h})}}{\sqrt{\bar{\alpha}_t}}\\
 &=&  \frac{\sqrt{\bar{\alpha}_{t-h}}}{\sqrt{\bar{\alpha}_t}}x_t -  \frac{\bar{\alpha}_{t-h}(1-\bar{\alpha}_t)- \bar{\alpha}_t(1-\bar{\alpha}_{t-h})}{\sqrt{\bar{\alpha}_t}(\sqrt{\bar{\alpha}_{t-h}(1-\bar{\alpha}_t)}+ \sqrt{\bar{\alpha}_t(1-\bar{\alpha}_{t-h})})}\\
 &=&  \frac{\sqrt{\bar{\alpha}_{t-h}}}{\sqrt{\bar{\alpha}_t}}x_t -  \frac{\bar{\alpha}_{t-h}-\bar{\alpha}_t}{\sqrt{\bar{\alpha}_t}(\sqrt{\bar{\alpha}_{t-h}(1-\bar{\alpha}_t)}+ \sqrt{\bar{\alpha}_t(1-\bar{\alpha}_{t-h})})}\\
\end{eqnarray}
最後の2行は分子の有理化?っぽい計算であまり意味はないんですが、微分方程式としてちゃんと導出する場合は最後の行が出てくるんだと思います。

微分方程式サンプラー(dpm-solver以外)

拡散モデルの逆拡散過程は微分方程式としても表現できます。確率微分方程式(SDE)のまま計算する方法と、常微分方程式(ODE)として変形したものを計算する方法があるみたいですがよく分かりません。

ODEは分散発散型にすると式が簡単になります。そのためこのカテゴリのサンプラーは分散発散型を前提にしています。
肝心の微分方程式は以下の通りです。
dx = \epsilon_\theta(x_t,t)\frac{d\sigma}{dt}dt=\hat{\epsilon}d\sigma
画像の微小変化量=ノイズ予測に\sigmaの微小変化をかけたもの、というめちゃくちゃシンプルな式ですね。

Euler

Euler
1. x_{t-h}=x_{t}-dx=x_{t}-\epsilon_\theta(x_t,t)(\sigma_{t}-\sigma_{t-h})
Euler法は1階微分により傾きを求めてその傾き通り更新ということをちびちびとするだけです。勾配降下法に似ていますね。
1階の近似なので早いけど精度はあんまりという感じですね。

diffusersでは少しノイズを加えてx_{t+g}=x_t + \epsilon\sqrt{{\sigma_{t+g}}^2-{\sigma_{t}}^2}としたあとに、x_{t-h}=x_{t+g}-\hat{\epsilon}(\sigma_{t+g}-\sigma_{t-h})とするような実装になっていますが、どの実装でもデフォルトではg=0なんであまり気にしなくてよさそうです。DDIMの\etaと似たような意味なんじゃないかな。

Heun

Heun
1. {x'}_{t-h}=x_{t}-\epsilon_\theta(x_{t},t)(\sigma_{t}-\sigma_{t-h})
2. x_{t-h}=x_{t}-\frac{\epsilon_\theta({x'}_{t-h},t-h)+\epsilon_\theta(x_{t},t)}{2}(\sigma_{t}-\sigma_{t-h})

一階微分だけで二階近似ができる方法です。一度Euler法で目標地点を推定した後、その場所でのノイズ予測との平均をとって更新します。Euler法に比べて計算時間が2倍になります。

DPM-Solver系サンプラー

dpm-solverは拡散モデル専用のソルバーで、時刻tではなく\lambda_t=\log \sqrt{\mathrm{SNR}(t)}を変数としてODE化したものです。SNRは信号対雑音比とよばれ、ノイズがどれほど弱いか(小さくなると強い)を表す指標です。\mathrm{SNR}(t)=\frac{\bar{\alpha}_t}{1-\bar{\alpha}_t}=-\frac{1}{\sigma_t^2}になります。ちなみに\lambda_t = - \log \sigma_tです。

全然分からんが厳密に求められる部分と近似が必要な部分を分離して、近似が必要な部分だけ近似することで精度をあげているらしい。

DPM-Solver

DPM-Solver-1
x_{t-1}=\frac{1}{\sqrt{\alpha_{t}}}x_{t}-\sqrt{\bar{\beta}_{t-1}}(e^{\lambda_{t-1}-\lambda_{t}}-1)\epsilon_\theta(x_t,t)
※離れたタイムステップに関しては、\alpha_t\frac{\bar{\alpha}_{t}}{\bar{\alpha}_{t-h}}に置き換えればよいだけです。

この更新式はDDIMの\eta=0の場合と全く同じになります。

第一項について、

\begin{eqnarray}
\frac{1}{\sqrt{\alpha_{t}}}x_{t} &=& \frac{1}{\sqrt{\alpha_{t}}}(\sqrt{\bar{\alpha}_t}\hat{x_0}+\sqrt{\bar{\beta}_{t}}\hat{\epsilon}) \\
&=& \sqrt{\bar{\alpha}_{t-1}}\hat{x_0}+\frac{\sqrt{\bar{\beta}_{t}}}{\sqrt{\alpha_{t}}}\hat{\epsilon} \\
 
\end{eqnarray}
第二項について、
\begin{eqnarray}-\sqrt{\bar{\beta}_{t-1}}(e^{\lambda_{t-1}-\lambda_{t}}-1)\hat{\epsilon} &=& -\sqrt{\bar{\beta}_{t-1}}(\frac{e^{\log \sigma_{t}}}{e^{\log \sigma_{t-1}}}-1)\hat{\epsilon}  \\
&=& -\sqrt{\bar{\beta}_{t-1}}(\frac{\sigma_{t}}{\sigma_{t-1}}-1)\hat{\epsilon} \\
&=& -\sqrt{\bar{\beta}_{t-1}}(\frac{\sqrt{1-\bar{\alpha}_{t}}}{\sqrt{\bar{\alpha}_{t}}}\frac{\sqrt{\bar{\alpha}_{t-1}}}{\sqrt{1-\bar{\alpha}_{t-1}}}-1)\hat{\epsilon} \\
&=& -\sqrt{\bar{\beta}_{t-1}}(\frac{\sqrt{\bar{\beta}_{t}}}{\sqrt{\alpha_{t}}\sqrt{\bar{\beta}_{t-1}}}-1)\hat{\epsilon} \\
&=& - \frac{\sqrt{\bar{\beta}_{t}}}{\sqrt{\alpha_t}}\hat{\epsilon} +\sqrt{\bar{\beta}_{t-1}}\hat{\epsilon}  \\
\end{eqnarray}

第一項と第二項を足すと、DDIMの更新式

\hat{x}_{t-1} = \sqrt{\bar{\alpha}_{t-1}}\hat{x}_{0} + \sqrt{\bar{\beta}_{t-1}}\hat{\epsilon}

になりました。

というわけで1階ではDDIMと同じなので通常使われません。使われるのは2階や3階です。

DPM-Solver-2
1.s=t(\frac{\lambda_{t-1}+\lambda_{t}}{2})
2.x_{s}=\frac{\sqrt{\bar{\alpha}_{s}}}{\sqrt{\bar{\alpha}_{t}}}x_{t}-\sqrt{\bar{\beta}_{s}}(e^{\frac{\lambda_{t-1}-\lambda_{t}}{2}}-1)\epsilon_\theta(x_{t},t)
3.x_{t-1}=\frac{\sqrt{\bar{\alpha}_{t-1}}}{\sqrt{\bar{\alpha}_{t}}}x_{t}-\sqrt{\bar{\beta}_{t-1}}(e^{\lambda_{t-1}-\lambda_{t}}-1)\epsilon_\theta(x_{s},s)
2階は中点法を使います。まず次のステップまでの中点(対数平方根SNR基準)を1階のDPM-solverで推定し、その地点でのノイズ予測結果を利用して次のステップの画像を1階のDPM-solverで推定します。

3階はよ―わからんけど同じようなことを3回にするんでしょう。

モデルの計算回数や時刻に応じて何階にするかを自動で決定する方式(ComfyUIのdpm-fast)やステップサイズを適応的に変更する方法(dpm-adaptive)も提案されています。
また後述しますがノイズの強さを調整することも考えられています。

DPM-Solver++

dom-solverはCFGを使うと、精度が下がるという弱点があるらしく、それを改善するために予測ノイズではなく予測した元画像を利用する方式がDPM-Solver++です。

DPM-Solver++-1
x_{t-1}=\sqrt{\frac{\bar{\beta}_{t-1}}{\bar{\beta}_{t}}}x_{t}-\sqrt{\bar{\alpha}_{t-1}}(e^{\lambda_{t}-\lambda_{t-1}}-1)\hat{x}

最適解自体はdpm-solverと同じですが、どの部分を近似するかというところが違うらしい。CFGを使う場合、ノイズ予測が学習時と生成時で一致しないので、ノイズ予測結果ではなく元の画像の予測結果を使ってるみたいな感じなんかね。

これも2階や3階があります。2階は論文にはより一般化された記述がなされていましたが、ComfyUIの実装をみると中点法を使ってるっぽいのでdpm-solverと同様ということで省略します。ただしこちらは過去のステップの情報を使うことで、1回分の計算で2階近似できるようになるMulti Steps(M)バージョンがあります。

DPM-Solver++-2M
1. h_{t-1} = \lambda_{t-1}-\lambda_{t}
2.r_{t-1} = \frac{h_{t}}{h_{t-1}}
3.D_{t-1} = (1+\frac{1}{2r_{t-1}})x_\theta(x_{t-1},t-1)-\frac{1}{2r_{t-1}}x_\theta(x_{t},t)
4.x_{t-1}=\sqrt{\frac{\bar{\beta}_{t-1}}{\bar{\beta}_{t}}}x_{t}-\sqrt{\bar{\alpha}_{t-1}}(e^{-h_{t-1}}-1)D_{t-1}
Adams-Bashforth法というやつらしいよ。式中にモデルの予測が2つでてきますが、1つは過去の情報を記憶しておけばよいので1回の計算で済みます。これに対して中点法など過去のステップの情報を使わない方法はSingle stepと呼ばれます。2SとかのSのことです。

DPM-solver-SDE

SDE版のソルバーも提案されています。まあ全然わかりませんけど。

DPM-Solver-1-SDE
x_{t-1}=\frac{1}{\sqrt{\alpha_{t}}}x_{t}-2\sqrt{\bar{\beta}_{t-1}}(e^{\lambda_{t-1}-\lambda_{t}}-1)\hat{\epsilon}+\sqrt{\bar{\beta}_{t-1}}\sqrt{(e^{2(\lambda_{t-1}-\lambda_{t})}-1)}\epsilon

DPM-Solver++-1-SDE
x_{t-1}=\frac{1}{\sqrt{\beta_{t}}}e^{\lambda_{t}-\lambda_{t-1}}x_{t}+\sqrt{\bar{\alpha}_{t-1}}(1-e^{\lambda_{t}-\lambda_{t-1}})\hat{x}+\sqrt{\bar{\beta}_{t-1}}\sqrt{1-e^{2(\lambda_{t}-\lambda_{t-1})}}\epsilon

各ステップでノイズが加えられるので、決定的な生成になりません。DDIMの\etaをいじるのと似ているのかな。

ancestral sampling

eulerやdpm-solver等で適用できるやつです。1ステップごとに普通より多めにノイズ除去をして、少しノイズを加えるということをします。これもDDIMの\etaを調整するのと似ているのかな。x_tx_0だけでなくx_{t-1}にも依存するようにします(だから先祖サンプリング?)。これによって安定するけど収束しづらくなると意味不明な説明がされています(収束しづらいのに安定するってなんだよ)。

ancestral sampling
1. \sigma_{to} = \sigma_{t-h},\ \  \sigma_{from} = \sigma_t
2. \sigma_{up} = \sqrt{\frac{\sigma_{to}^2}{\sigma_{from}^2}(\sigma_{from}^2-\sigma_{to}^2)}
3. \sigma_{down} = \sqrt{\sigma_{to}^2-\sigma_{up}^2}
4. x_{t(\sigma_{down})}=\mathrm{sampler}(x_{t(\sigma_{from})}, t(\sigma_{from})\to t(\sigma_{down}))
5. x_{t(\sigma_{to})} = x_{t(\sigma_{down})} + \sigma_{up} \epsilon

ノイズスケジュール

ステップをスキップするとき、時刻をどう分けるかという工夫の余地があります。細かい方法を除けば3つの方法があります。
以下の記事が詳しいです。
KSampler ノード - ComfyUI 解説 (wiki ではない)

normal

時刻を普通に等分します。おわり。

karras

Karrasさんが考えたスケジューラーです。\sigmaの7乗根を等分します。normalに比べて中間のステップを飛ばす代わりに最初と最後らへんの精度をあげているようです。webuiでは最後にKarrasがつくサンプラーがこれを採用しています。

exponential

ComfyUIにあります。対数平方根SNRを等分します。dpm-solverで提案されたやつです。ノイズの大きい部分を飛ばしてノイズの小さい部分をより細かくします。