U1.4 19 分鐘閱讀 2026年9月

U1.4 反向:DDPM、DDIM 與 SDE/ODE

本篇重用M2.3導航每 30 秒更新一次:Euler 法與它的誤差·M3.0醉漢一小時後在哪:Random Walk 到 Brownian Motion·M3.1水流加亂流:SDE 是加了噪聲的 ODE·M3.3山谷裡隨機走的人群:Langevin Dynamics 與 Stationary Distribution·M2.2站內人數變化 = 進 − 出:Continuity Equation·M3.2一千片葉子在亂流裡:Fokker–Planck 方程式

照原本的步伐走一步,要付什麼代價?

U1.3 把缺的那一塊補上了:訓好的網路給的就是 score,也就是每個時刻、每個位置「人群往哪邊變密」。所以現在可以回頭問 U1.2 留下的那個問題了。

訓練時我們把路切成一千小步;
生成時,可以自己決定走幾步、每一步走多遠嗎?

先把帳算清楚再談少走幾步。倒著走一步那一行,U1.2 其實已經寫出來了:

xt1=μ~t(xt, x^θ(xt,t))+β~tz,zN(0,I).x_{t-1}=\tilde\mu_t\big(x_t,\ \hat x_\theta(x_t,t)\big)+\sqrt{\tilde\beta_t}\,z, \qquad z\sim\mathcal N(0,I).

問題是這一行只有在「q(xt1xt)q(x_{t-1}\mid x_t) 真的是那個 Gaussian」的時候才精確,而它其實不是。所以在問「能不能少走幾步」之前,得先知道照原本的步伐走一步,本身錯多少——因為那個誤差的大小,正好和步長綁在一起。

課堂提問Q1

U1.2 的積分寫著 q(xt1xt)=q(xt1xt,x0)p(x0xt)dx0q(x_{t-1}\mid x_t)=\int q(x_{t-1}\mid x_t,x_0)\,p(x_0\mid x_t)\,\mathrm dx_0——一堆 Gaussian 按後驗權重疊起來,那是一個混合 Gaussian,一般不是 Gaussian。但我們的取樣器只抽一個 N(μ~t(xt,x^0),β~tI)\mathcal N(\tilde\mu_t(x_t,\hat x_0),\tilde\beta_t I)

這時候很容易這樣想:x^0\hat x_0 已經是後驗平均了,代進去之後抽出來的 xt1x_{t-1} 平均也就會是對的,那還有什麼好擔心的?

這個推理對嗎?如果對,那錯的是什麼?

先想一想,再展開看整理後的答案

那個推理是對的——但它只顧到平均。 把混合的平均與變異數都算出來就看得到(變異數那一條用的是 law of total variance:總變異數=條件變異數的平均 + 條件平均的變異數)。因為 μ~t\tilde\mu_tx0x_0 是 affine 的,記它的 x0x_0 係數為 c0=αˉt1βt1αˉtc_0=\dfrac{\sqrt{\bar\alpha_{t-1}}\,\beta_t}{1-\bar\alpha_t},那麼

E[xt1xt]=μ~t(xt,E[x0xt]),Var[xt1xt]=β~tI+c02Var[x0xt].\mathbb E[x_{t-1}\mid x_t]=\tilde\mu_t\big(x_t,\mathbb E[x_0\mid x_t]\big), \qquad \operatorname{Var}[x_{t-1}\mid x_t]=\tilde\beta_t I+c_0^2\operatorname{Var}[x_0\mid x_t].

平均值是精確的;錯的只有變異數,而那個錯是 O(βt)O(\beta_t)

平均那一半精確,是 affine 的好處。錯的只有變異數:我們用了 β~t\tilde\beta_t,而真值多了一項 c02Var[x0xt]c_0^2\operatorname{Var}[x_0\mid x_t]——那是「x0x_0 到底是誰」的不確定性漏進來的部分。

大不大?c0c_0 正比於 βt\beta_t,而 β~t\tilde\beta_t 也正比於 βt\beta_t,所以丟掉的那一項相對於保留的那一項是 O(βt)O(\beta_t)——高一階,βt\beta_t 越小越可以忽略。拿 DDPM 的 linear schedule 實際算(β:1040.02\beta:10^{-4}\to0.02T=1000T=1000,資料的尺度取 1):

tt1050100300500700\ge700
丟掉的/保留的17%3.7%1.8%0.4%0.09%< 0.01%

這就是「把一件難事切成很多小步」真正的數學內容。 不是「每一步比較容易學」這種感覺——而是:每一步的 βt\beta_t 越小,用一個 Gaussian 代替那個混合分布的誤差就越小。步數換的是這個。反過來,如果只走幾步、每步的 β\beta 很大,這個近似就會壞掉——這也是為什麼 U6 想少步生成的時候,不能只是把同一個取樣器的步數調小。

tt 很小的時候比例看起來變大,但那裡 Var[x0xt]\operatorname{Var}[x_0\mid x_t] 本身已經趨近 0——xtx_t 幾乎就是 x0x_0,沒有什麼不確定性可漏。實作上最後一步通常直接取 β~1=0\tilde\beta_1=0,不加噪聲。)

DDPM:扣掉一點,再抖一下

x^0\hat x_0 代入那個 closed form 的 Gaussian,直接抽樣:

xt1=μ~t(xt,x^0)+β~tz,zN(0,I).x_{t-1}=\tilde\mu_t(x_t,\hat x_0)+\sqrt{\tilde\beta_t}\,z,\qquad z\sim\mathcal N(0,I).

再把 x^0=(xtσtϵθ)/αˉt\hat x_0=(x_t-\sigma_t\epsilon_\theta)/\sqrt{\bar\alpha_t} 代進去整理,就是 DDPM 原文 [1] 的形式:

xt1=1αt(xtβt1αˉtϵθ(xt,t))+β~tz.x_{t-1}=\frac{1}{\sqrt{\alpha_t}}\Big(x_t-\frac{\beta_t}{\sqrt{1-\bar\alpha_t}}\,\epsilon_\theta(x_t,t)\Big)+\sqrt{\tilde\beta_t}\,z .

每一步做兩件事:先用網路猜噪聲、扣掉一部分,然後再加回一點新的隨機噪聲。從 xTN(0,I)x_T\sim\mathcal N(0,I) 出發跑 TT 步,就得到一張圖——U1.2 最後那一段講的就是這件事,只是還沒給它名字:這種「照著每一步的條件分布一路往下抽」的取樣方式叫 ancestral sampling

第二件事常常讓人困惑:好不容易去噪,為什麼又要加噪回去?回到 U1.3 那個廣場就看得清楚。每個人都照「周遭的人平均往哪去」移動——但站在附近的人,看到的平均幾乎是同一個方向。照這樣走下去,同一團裡的人只會越靠越近,最後疊在同一個點上:人群還在,但它塌成了幾個點。加回噪聲,就是讓每個人在照平均走完之後再隨機挪一下,人群才維持該有的寬度——也就是當下的 pt1p_{t-1}

要注意這句話說的是**「朝平均走」會塌**,不是「確定性的取樣器」會塌——下一節的 DDIM 完全不加噪聲,卻不會塌,因為它補回去的是網路預測的噪聲方向 ϵθ\epsilon_\theta 而不是零。確定與隨機的差別留到那裡談。

DDIM:同一個網路,完全不加噪聲

換個角度看同一件事。DDPM 是從「反向的條件分布」推出來的,所以它一定得逐步走。但 U1.1 的 closed form 其實給了更直接的東西:每一個 xsx_s 都可以由 (x0,ϵ)(x_0,\epsilon) 這一對直接寫出來

xs=αˉsx0+σsϵ.x_s=\sqrt{\bar\alpha_s}\,x_0+\sigma_s\,\epsilon .

網路手上正好有這兩個的估計:x^0\hat x_0ϵθ(xt,t)\epsilon_\theta(x_t,t)。那就直接代進去

xs=αˉsx^0+σsϵθ(xt,t).x_{s}=\sqrt{\bar\alpha_{s}}\,\hat x_0+\sigma_{s}\,\epsilon_\theta(x_t,t).

這不是「相信」,而是一條構造:如果 x^0\hat x_0ϵθ\epsilon_\theta 正好等於真實的那一對 (x0,ϵ)(x_0,\epsilon),這一行就會精確落在真實的 xsx_s 上。這就是 DDIM [2](η=0\eta=0)。它有兩個很不一樣的性質:

  • 完全確定:給定 xTx_T,輸出唯一,沒有任何隨機。多樣性全部來自起點 xTx_T——路上不需要再補隨機,也不會因此塌成一團,因為每一步補回去的是 σsϵθ\sigma_s\epsilon_\theta 這個有方向的量。
  • 可以跳步:上面那條構造裡 ss 從頭到尾是自由的——它用的是 xsx_s(x0,ϵ)(x_0,\epsilon) 的關係,不是相鄰兩步的 Markov 結構。所以從 tt 直接跳到任意 s<ts \lt t 都行。

第二點就是開頭那個問題的答案:

走幾步、每一步走多遠,是取樣時才決定的事,和訓練無關。

DDPM 之所以非走一千步不可,是因為它的每一步都建在「相鄰兩步的條件分布」上,步長一大 Q1 那個 O(βt)O(\beta_t) 就撐不住。DDIM 換掉的是依據:它不問「下一步的條件分布長什麼樣」,只問「照現在估出來的 (x0,ϵ)(x_0,\epsilon),時刻 ss 應該在哪裡」——而那個問題對任何 ss 都問得出來。這就是 DDIM 能用 50 步、而 DDPM 要 1000 步的原因。

而且它用的是同一個訓好的 ϵθ\epsilon_\theta,沒有重訓。DDIM 的一般式還帶一個 η[0,1]\eta\in[0,1] 控制每步加回多少噪聲:η=0\eta=0 是確定版,η=1\eta=1 就退回 DDPM。

符號DDIM 的一般式(含 η)長什麼樣?

tt 跳到 s<ts \lt t

xs=αˉsx^0+1αˉsσ~2  ϵθ(xt,t)+σ~z,σ~=η1αˉs1αˉt1αˉtαˉs.x_s=\sqrt{\bar\alpha_s}\,\hat x_0+\sqrt{1-\bar\alpha_s-\tilde\sigma^2}\;\epsilon_\theta(x_t,t)+\tilde\sigma\,z, \qquad \tilde\sigma=\eta\sqrt{\frac{1-\bar\alpha_s}{1-\bar\alpha_t}}\sqrt{1-\frac{\bar\alpha_t}{\bar\alpha_s}} .

η=0\eta=0σ~=0\tilde\sigma=0,第三項消失、第二項補滿 1αˉs\sqrt{1-\bar\alpha_s},就是上面的 DDIM。所以這是一整族取樣器,η\eta 控制每一步補回多少隨機。

動手兩行就能驗:為什麼 η=1\eta=1 會退回 DDPM?

η=1\eta=1s=t1s=t-1,把 σ~\tilde\sigma 的平方寫開:

σ~2=1αˉt11αˉt(1αˉtαˉt1).\tilde\sigma^2=\frac{1-\bar\alpha_{t-1}}{1-\bar\alpha_t}\Big(1-\frac{\bar\alpha_t}{\bar\alpha_{t-1}}\Big).

括號裡那一團可以直接化簡——αˉt=αtαˉt1\bar\alpha_t=\alpha_t\bar\alpha_{t-1}U1.1 定義 αˉ\bar\alpha 時就有的,所以 αˉt/αˉt1=αt\bar\alpha_t/\bar\alpha_{t-1}=\alpha_t,而 1αt=βt1-\alpha_t=\beta_t。代回去:

σ~2=(1αˉt1)βt1αˉt=β~t.\tilde\sigma^2=\frac{(1-\bar\alpha_{t-1})\,\beta_t}{1-\bar\alpha_t}=\tilde\beta_t .

正是 U1.2 配出來的那個變異數。所以 η=1\eta=1 的那一端就是 DDPM,DDPM 與 DDIM 只是同一族的兩個端點

兩種走法,看得見

互動 demo:DDPM 與 DDIM 的軌跡。 兩邊用同一個 score(這裡直接用資料算出精確的 score,相當於一個訓到最佳的網路)、同一組起點,只有 η\eta 不同。把 η\eta 從 1 拉到 0,軌跡會從抖動變成光滑,但終點都落在資料上——這就是「邊際相同」看起來的樣子。把步數從 200 降到 50、25、10,終點離資料會越來越遠,而 η=0\eta=0 通常掉得慢一些。另外注意 η=0\eta=0 的軌跡明顯是彎的,這件事 U2 會再拿出來講。

(要提醒的是:這個 demo 的 score 是精確的,所以看不到「網路有誤差時,加回噪聲能把樣本拉回 ptp_t」那一面——那要真的訓練一個網路才看得到,留到 U1.5。)

如果步長縮到 0 呢?

到這裡取樣器已經可以跑了,所以接下來這一節不是在補救前面的任何東西——它是換一個視角,看同一件事在步長趨近 0 的時候長成什麼樣子。U1.3 最後問的正是這個:那個流動有沒有一個嚴謹的數學模型在描述它?有,而且答案會順便告訴我們「噪聲該加多少」其實是一個旋鈕,不是一個定數。

把步長寫成 Δt=1/T\Delta t=1/Tβtβ(t)Δt\beta_t\to\beta(t)\Delta tU1.1 那條 xt=1βtxt1+βtϵtx_t=\sqrt{1-\beta_t}\,x_{t-1}+\sqrt{\beta_t}\,\epsilon_t 的遞迴在連續時間的極限下就是一條 SDE:

dx=12β(t)xdt+β(t)dWt,t:01.dx=-\tfrac12\beta(t)\,x\,dt+\sqrt{\beta(t)}\,dW_t,\qquad t:0\to1 .

第一項把樣本往原點縮,第二項持續灌噪聲——正是 forward process 在做的事。

Anderson(1982)[3] 證明了一件很漂亮的事:把時間倒過來,它仍然是一條 SDE,而且 drift 裡多出一個 score 項:

dx=[12β(t)xβ(t)logpt(x)]dt+β(t)dWˉt,t:10.dx=\Big[-\tfrac12\beta(t)\,x-\beta(t)\,\nabla\log p_t(x)\Big]dt+\sqrt{\beta(t)}\,d\bar W_t,\qquad t:1\to0 .

Song et al.(2021)[4] 進一步指出:還存在一條完全沒有隨機項的 ODE,它推動的邊際分布與上面那條 SDE 在每個 tt 都相同

dxdt=12β(t)x12β(t)logpt(x)(probability-flow ODE).\frac{dx}{dt}=-\tfrac12\beta(t)\,x-\tfrac12\beta(t)\,\nabla\log p_t(x) \qquad\text{(probability-flow ODE)} .

注意 score 前面的係數:SDE 是 β\beta,ODE 只有 12β\tfrac12\beta

補充少掉的那一半 score 去哪了?

關鍵在 Fokker–Planck 方程(M3.2):噪聲項對分布造成的擴散 12βΔpt\tfrac12\beta\,\Delta p_t 可以改寫成一個散度的形式

12βΔpt=(12βptlogpt),\tfrac12\beta\,\Delta p_t=\nabla\cdot\Big(\tfrac12\beta\,p_t\,\nabla\log p_t\Big),

也就是「擴散」可以被吸進 drift 裡,變成一個沿著 logpt\nabla\log p_t 的移動。所以我們可以拿掉噪聲項,同時從 drift 扣掉那一半 score——分布的演化完全一樣,只是每條軌跡不再隨機。

把這個改寫代回 Fokker–Planck,drift 項與擴散項就併成一項:

tpt+(ptut)=0,ut(x)=12β(t)x12β(t)logpt(x).\partial_t p_t+\nabla\cdot\big(p_t\,u_t\big)=0,\qquad u_t(x)=-\tfrac12\beta(t)\,x-\tfrac12\beta(t)\,\nabla\log p_t(x) .

那個 utu_t 正是上面 PF-ODE 的速度場,而左邊這條方程式有名字:continuity equationM2.2)。它說的只是東西不會憑空出現或消失——ptutp_t u_t 是「流量」,某一點的密度會上升,只能是因為流進來的比流出去的多。

所以「SDE 與 ODE 的邊際相同」不是巧合:把擴散吸進 drift 之後,兩邊滿足的是同一條 continuity equation。U2.1 會把它反過來用——先指定想要的 ptp_t,再去找推動它的 utu_t

這件事之後會被推廣成一整族取樣器(U3):噪聲要注入多少,其實是一個可以調的旋鈕

三者的關係整理成一張表:

forward SDEreverse SDEPF-ODE
邊際 ptp_t相同相同相同
單條軌跡隨機隨機確定
離散版加噪DDPMDDIM

示意圖:時空圖,橫軸是時間(右邊 t=1、左邊 t=0),縱軸是一維資料空間,背景為 p_t(x) 的熱圖;上方是 reverse SDE 的抖動軌跡、下方是 PF-ODE 的光滑軌跡,兩組都從同一批起點出發並收在同樣的位置,左側附兩個看起來相同的終點分布。

圖:同一組邊際,兩種走法。 兩組軌跡從同一批起點出發,上面是 reverse SDE(抖動)、下面是 PF-ODE(光滑);左側兩個 t=0t=0 的邊際分布看起來一樣。差別不在最後停在哪裡,而在路上抖不抖。

DDPM 是 reverse SDE 的一階離散,DDIM 是 PF-ODE 的一階離散。

它們共用同一個 ϵθ\epsilon_\theta,因為兩者需要的都只是 score。

用廣場再說一次「邊際相同」是什麼意思:一千個人從同一批位置出發往資料走,一組人邊走邊隨機晃(SDE),一組人走得筆直(ODE)。每隔一段時間對整個廣場拍一張照,兩組人的分布會一模一樣——不一樣的只有每一個人走出來的那條路。所以「同一組邊際」講的是照片,不是路線。

注意這裡出現了第二套誤差帳。 Q1 算的是「在固定的一步上,用一個 Gaussian 代替混合分布錯多少」——那是模型族的誤差,O(βt)O(\beta_t)。這一節講的是「這一步是某條連續時間方程式的一階離散」——那是離散化的誤差,O(Δt)O(\Delta t)。兩者都正比於步長,但量的是不同的東西:前者就算你有精確的 score 也還在,後者就算模型族選得完美也還在。要少步生成,兩筆都得付。

一個留著的問題

課堂提問Q2

DDPM 與 DDIM 用同一個網路,一個隨機、一個確定,數學上都對——因為它們推動的邊際相同。

那它們的取樣結果會一樣嗎?步數少的時候,哪一個比較好?

先想一想,再展開看整理後的答案

「邊際相同」是連續時間、無限步的敘述。真正在跑的是有限步的離散化,而兩者的誤差來源不一樣:

  • ODE(DDIM)的誤差來自軌跡本身是彎的,而 Euler 用直線去逼近它——步數越少,割線與曲線的差距越大。
  • SDE(DDPM)除了同樣有 drift 的離散誤差,每一步還會注入噪聲;但反過來說,score 項會把偏離的樣本拉回當下的 ptp_t,等於自帶一點修正能力。

所以「哪一個好」沒有一個跟情況無關的答案,它取決於這兩種誤差誰佔上風:

模型誤差大的時候,SDE 的修正有東西可修;模型幾乎沒有誤差的時候,剩下的只有離散化,SDE 的噪聲就只是多餘的抖動。

這個判準是可以驗的,而且它會在課程裡出現兩次、結論方向相反——兩次都對:

  • U1.5U3 的 toy 上,速度場是精確算出來的(沒有網路誤差),於是確定性的那一端在幾乎所有步數都不輸。
  • 真實模型的文獻上,網路誤差不可忽略,於是在步數多到離散化誤差夠小之後,帶噪聲的取樣器往往品質更好——那個交叉點量的是前一種情況不存在的東西。

要把「拉回」與「彎曲」各自寫成算得出來的量,我們需要先有「路徑」與「速度場」的語言,那是 U2U3 的事。

這是一個方法,不是定律

我們並不是「隨便挑了一個 Gaussian Markov chain」,而是從想要的目標一路倒推並設計:一條每一步只改一點點、並且我們可以計算,而且最後會走向一個好抽的 noise distribution 的路。

但這也意味著,這個單元每一件事都是人挑的:加的是 Gaussian noise、縮放挑成 1βt\sqrt{1-\beta_t}、終點挑成 N(0,I)\mathcal N(0,I)、schedule 挑 linear 還是 cosine。這些選擇讓數學變得非常乾淨——從頭到尾都只有 Gaussian,所以每一個 q(xtx0)q(x_t\mid x_0) 都有 closed form。

而乾淨是有代價的,它把幾件事綁在一起了:

  • 起點分布只能是 Gaussian,因為 forward process 就是往那裡收斂的。
  • 路徑完全被 αˉt\bar\alpha_t 決定x0x_0xTx_T 之間的分布怎麼變,除了調 schedule 之外沒有別的自由度。

這個單元我們先接受了這些選擇,把整條路走完。U2.0 會回頭問:如果不想被綁住呢?

消化一下

想一想

DDPM 與 DDIM 取樣器共用同一個 ϵθ\epsilon_\theta,是因為:

想一想

PF-ODE 裡 score 項的係數是 reverse SDE 的一半。這一半去哪了?

想一想

下列哪個敘述正確?

想一想

DDPM 每一步「扣掉噪聲之後又加回一點新的噪聲」,這個加回來的噪聲是為了什麼?

參考文獻

  1. Ho, J., Jain, A., Abbeel, P. Denoising Diffusion Probabilistic Models. NeurIPS 2020. (ancestral sampling 的形式。)
  2. Song, J., Meng, C., Ermon, S. Denoising Diffusion Implicit Models. ICLR 2021. (DDIM 與含 η\eta 的一般式、跳步取樣。)
  3. Anderson, B. D. O. Reverse-time diffusion equation models. Stochastic Processes and their Applications, 1982. (反向 SDE 的來源。)
  4. Song, Y., Sohl-Dickstein, J., Kingma, D. P., Kumar, A., Ermon, S., Poole, B. Score-Based Generative Modeling through Stochastic Differential Equations. ICLR 2021. (probability-flow ODE 與「同一組邊際」的統一觀點。)