さんぷらーについて
各サンプラーの意味とかがなんとなく分かりたくて書いたものです。SDEやODEの導出に関する話はでてきません(分からんし)。
拡散過程の定義
サンプラーによって使われている文字の意味が違うので、ここでは文字をあわせていいきたいと思います。そのため論文の式そのままにできないので間違っている可能性があります。
拡散過程は分散保存型と分散発散型の二種類に分かれています。
分散保存型
元の画像を弱めながらノイズを加えていく方法です。
二つの係数の二乗和をとると1になります。つまり分散がどの時刻でも固定されます。
この拡散過程は以下のようにを単独でサンプリングすることができます。
ここで、です。
この説明にはも使うことが多いです。ば~の有無にかかわらず、です。を使った方がシンプルになるときはを使います。
分散発散型
元の画像をそのままにして、ノイズを加えていく方法です。
Stable Diffusionは学習時に分散保存型を採用していますが、分散発散型であると仮定して生成することも可能です。
とすれば、とスケーリングすることで分散保存型の式になるので、それをUNetに入力すればよいです。出力は係数が掛けられていない元のノイズなので、スケーリングは必要ありません。
離れたタイムステップ間のサンプリング
離れた時刻からへのサンプリングもできます。
は累積積なので、だったら、がそのままでてきますね。
1ステップ分の式を離れた時刻に対応する式に置き換えたい場合、をに置き換えればよいだけです。または自然数ではなく実数にすることができます(時刻を離散時間から連続時間にする)。UNetの時刻埋め込みはうまいこと連続になるよう設定されているので、離散的な時刻しか学習していなくても問題ないらしい。
逆拡散過程
逆拡散過程では、加えられたノイズをモデルに予測させ、その結果を使って次のステップの画像を推定します。その推定の仕方はサンプラーによって異なります。
ノイズの予測をとすると、ノイズのない画像の予測は、
となります。
モデルの予測結果から導出する変数は、など帽子をつけてあげます。
画像生成の流れ
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
今回の話の主題ではない条件付き生成に関わる部分などは省略しています。時刻]を設定したステップ数分取り出して、として、と処理を繰り返します。このとき現在の画像から与えられたノイズを予測する役割を持つのがUNetで、次の時刻の状態を予測する役割を持つのがサンプラーになります。
非微分方程式系サンプラー
DDPM、DDIMといった微分方程式を使わないサンプラーは、以下のように平均と分散を推定することで次の画像を予測します。
ただし分散は学習せず固定します。
DDPM
DDPMSamplerは最初にできたサンプラーです。
またバリエーションとして、DDPMの導出中にでてくるからでてくる平均と分散を使ってを予測する式もあります。
よくわかりませんが、diffusersではこっちを使っているようです。後述のDDIMの特殊ケースになります。
DDIM
拡散過程は今まで加えられてきたノイズと、次に加えるノイズが全くの無関係でした。つまりが依存するのはのみでした。逆に加えるノイズを全時刻で固定することを考えると、はのみに依存するようになります。DDIMではその間をとるような拡散過程を考えます。するとDDPMとDDIMはうまいこと最適解が一致するため、DDPMで学習したモデルに対してDDIMを根拠にした生成を行えます。DDIMSamplerは1000ステップ必要だったDDPMSamplerに比べて数十ステップくらいで生成できるようになりますた。
サンプリングは、
2.
(1)のとき、DDPMの二つ目の式と同じになります。
計算
第二項は
の係数に着目すると、となりDDPMの二番目の式と一致しました^^
の係数に着目すると、となり
第一項のの係数と足すと、
DDPMの二番目の式の係数と一致しました^^
ノイズの係数は計算せずとも一致していることが分かります^^
(2)のとき、生成過程でランダムノイズ部分がなくなり、初期ノイズから決定的に生成するようになります。つまり全時刻で同じノイズを与えたと考えた時の生成法となります。
ニューラルネットワークによるノイズ予測が完全に正しければ、各ステップにおけるノイズ予測は定数になりステップをいくつスキップするかに関わらず同じ結果が得られます。現実的にはそんなネットワークは作れませんが(作れたとしても面白くない)、ある程度予測精度が高ければ、1ステップはさすがに無理だけど、数十ステップくらいで生成できるようになる、というイメージっぽいです(あってるか分からん)。
ここまで長々と説明してなんですが、どの実装でもデフォルトだとになります。他のパターンなんて知っててもどうしようもないですね。
微分方程式系サンプラー(dpm-solver以外)
拡散モデルの逆拡散過程は微分方程式としても表現できます。確率微分方程式(SDE)のまま計算する方法と、常微分方程式(ODE)として変形したものを計算する方法があるみたいですがよく分かりません。
ODEは分散発散型にすると式が簡単になります。そのためこのカテゴリのサンプラーは分散発散型を前提にしています。
肝心の微分方程式は以下の通りです。
画像の微小変化量=ノイズ予測にの微小変化をかけたもの、というめちゃくちゃシンプルな式ですね。
Euler
1階の近似なので早いけど精度はあんまりという感じですね。
diffusersでは少しノイズを加えてとしたあとに、とするような実装になっていますが、どの実装でもデフォルトではなんであまり気にしなくてよさそうです。DDIMのと似たような意味なんじゃないかな。
Heun
2.
一階微分だけで二階近似ができる方法です。一度Euler法で目標地点を推定した後、その場所でのノイズ予測との平均をとって更新します。Euler法に比べて計算時間が2倍になります。
DPM-Solver系サンプラー
dpm-solverは拡散モデル専用のソルバーで、時刻ではなくを変数としてODE化したものです。SNRは信号対雑音比とよばれ、ノイズがどれほど弱いか(小さくなると強い)を表す指標です。になります。ちなみにです。
全然分からんが厳密に求められる部分と近似が必要な部分を分離して、近似が必要な部分だけ近似することで精度をあげているらしい。
DPM-Solver
この更新式はDDIMのの場合と全く同じになります。
第一項について、
第二項について、
第一項と第二項を足すと、DDIMの更新式
になりました。
というわけで1階ではDDIMと同じなので通常使われません。使われるのは2階や3階です。
2.
3.
3階はよ―わからんけど同じようなことを3回にするんでしょう。
モデルの計算回数や時刻に応じて何階にするかを自動で決定する方式(ComfyUIのdpm-fast)やステップサイズを適応的に変更する方法(dpm-adaptive)も提案されています。
また後述しますがノイズの強さを調整することも考えられています。
DPM-Solver++
dom-solverはCFGを使うと、精度が下がるという弱点があるらしく、それを改善するために予測ノイズではなく予測した元画像を利用する方式がDPM-Solver++です。
最適解自体はdpm-solverと同じですが、どの部分を近似するかというところが違うらしい。CFGを使う場合、ノイズ予測が学習時と生成時で一致しないので、ノイズ予測結果ではなく元の画像の予測結果を使ってるみたいな感じなんかね。
これも2階や3階があります。2階は論文にはより一般化された記述がなされていましたが、ComfyUIの実装をみると中点法を使ってるっぽいのでdpm-solverと同様ということで省略します。ただしこちらは過去のステップの情報を使うことで、1回分の計算で2階近似できるようになるMulti Steps(M)バージョンがあります。
2.
3.
4.
DPM-solver-SDE
SDE版のソルバーも提案されています。まあ全然わかりませんけど。
各ステップでノイズが加えられるので、決定的な生成になりません。DDIMのをいじるのと似ているのかな。
ancestral sampling
eulerやdpm-solver等で適用できるやつです。1ステップごとに普通より多めにノイズ除去をして、少しノイズを加えるということをします。これもDDIMのを調整するのと似ているのかな。がだけでなくにも依存するようにします(だから先祖サンプリング?)。これによって安定するけど収束しづらくなると意味不明な説明がされています(収束しづらいのに安定するってなんだよ)。
2.
3.
4.
5.
ノイズスケジュール
ステップをスキップするとき、時刻をどう分けるかという工夫の余地があります。細かい方法を除けば3つの方法があります。
以下の記事が詳しいです。
KSampler ノード - ComfyUI 解説 (wiki ではない)
normal
時刻を普通に等分します。おわり。
karras
Karrasさんが考えたスケジューラーです。の7乗根を等分します。normalに比べて中間のステップを飛ばす代わりに最初と最後らへんの精度をあげているようです。webuiでは最後にKarrasがつくサンプラーがこれを採用しています。
元論文
[2006.11239] Denoising Diffusion Probabilistic Models
[2010.02502] Denoising Diffusion Implicit Models
[2202.09778] Pseudo Numerical Methods for Diffusion Models on Manifolds
[2206.00927] DPM-Solver: A Fast ODE Solver for Diffusion Probabilistic Model Sampling in Around 10 Steps
[2211.01095] DPM-Solver++: Fast Solver for Guided Sampling of Diffusion Probabilistic Models
[2206.00364] Elucidating the Design Space of Diffusion-Based Generative Models
参考
思いつくものをいい加減に貼っていく。
拡散モデル - 岩波書店https://hillbig.github.io/diffusion-models/
コンピュータビジョン最前線 Summer 2023 - 共立出版
改訂版 Stable Diffusionで使われているアルゴリズムの解説 - 過学習ショップ - BOOTH
もし生物情報科学専攻の大学院生が "StableDiffusion" を理解しようとしたら 9 ~Stable Diffusion②~ - 何だって、したしむ
DDPMの関連技術 | henatips
DiffusionによるText2Imageの系譜と生成画像が動き出すまで - Speaker Deck
【論文解説】Diffusion Modelを理解する | 楽しみながら理解するAI・機械学習入門