U1.2 37 分鐘閱讀 2026年9月

U1.2 Denoising:倒著走一步,要怎麼學?

本篇重用L0.1差一度與差十度:損失函數是一種宣告·L0.0房仲怎麼估價:從例子學規則·M1.2天氣預報該報幾度:MSE 的最小值是 Conditional Expectation·M1.3快篩陽性:Bayes 與 Posterior·M1.0兩台體重計:Gaussian 的線性組合·M5.1用錯的機率表下注一年會多輸多少:KL Divergence 與 Cross-Entropy

倒著走一步,如何從 q(xt1xt)q(x_{t-1}\mid x_t) 抽樣?

上一篇我們已經把前進的路 forward process 給設計好了:知道怎麼從 xt1x_{t-1}xtx_t,而且任意時刻的 xtx_t 都能用一行公式從 x0x_0 獲得。現在我們想做的是反過來——手上已有一個 xtx_t,要怎麼退到 xt1x_{t-1},也就是說,要怎麼從 q(xt1xt)q(x_{t-1}\mid x_t) 抽樣。

複習為什麼是「從 q(xt1xt)q(x_{t-1}\mid x_t) 抽樣」,而不是算出一個答案?

先複習 q(xt1xt)q(x_{t-1}\mid x_t) 在描述什麼:給定現在的 xtx_t,退到前一步、落在差不多 xt1x_{t-1} 這個位置的機率密度。

用上一篇那條從台大到屏東的路線來說:給定現在人在屏東,前一站是高雄(走西部)還是台東(繞東部)?機率會告訴我們每一種可能性有多大,我們就照著它抽一個——抽到高雄或台東都是合理的答案。

為什麼要寫成「分布」而不是「一個答案」?因為加噪那一步真的把資訊丟掉了:很多不同的 xt1x_{t-1} 都可能變成手上這個 xtx_t,而只有分布記得住是哪些、各自多可能。至於拿到這個分布之後要怎麼用——每一步真的抽一個,還是每一步都走一個確定的方向——那是另一個問題,U1.4 會看到兩種做法都成立。

首先我們知道,xtx_t 是由 xt1x_{t-1} 加了一撮隨機的 Gaussian noise 得到的。所以 xtx_t 一旦固定,往回看 xt1x_{t-1},會因為那撮 noise 的隨機性而有一整個範圍的可能。我們要的就是那個範圍上的機率密度。

課堂提問Q1

最直覺的想法是把加噪那一步直接反解。既然

xt=αtxt1+βtϵt,x_t=\sqrt{\alpha_t}\,x_{t-1}+\sqrt{\beta_t}\,\epsilon_t ,

那我就抽一個 ϵtN(0,I)\epsilon_t\sim\mathcal N(0,I),代進去解出

xt1=(xtβtϵt)/αtx_{t-1}=\big(x_t-\sqrt{\beta_t}\,\epsilon_t\big)\big/\sqrt{\alpha_t}

不就好了嗎?反正 noise 本來就是隨機抽的。

這樣為什麼不行?

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

問題出在「ϵt\epsilon_t 本來就是隨機抽的」這句話——它在加噪的時候成立,在取樣的時候不成立。

加噪時,我們先有 xt1x_{t-1},再抽一個「與它無關」的 ϵt\epsilon_t——這兩個變數確實互相獨立。但在 reverse process 要做 denoise 時,我們手上先有 xtx_t,想要利用 ϵt\epsilon_t 決定 xt1x_{t-1};而 xtx_t 是用當初那個特定的 ϵt\epsilon_t 算出來的(現在看不到),因此 ϵt\epsilon_txtx_t 不是獨立的:看到 xtx_t,等於看到「它因為 ϵt\epsilon_t 而落在哪裡」——這件事本身就帶著關於 ϵt\epsilon_t 的資訊。

我們可以透過計算兩者之間的共變數(covariance)來證明不獨立這件事。因為 ϵt\epsilon_txt1x_{t-1} 是獨立的,

Cov(ϵt,xt)=Cov(ϵt, αtxt1+βtϵt)=βtI    0.\operatorname{Cov}(\epsilon_t,\,x_t) =\operatorname{Cov}\big(\epsilon_t,\ \sqrt{\alpha_t}\,x_{t-1}+\sqrt{\beta_t}\,\epsilon_t\big) =\sqrt{\beta_t}\,I\;\ne\;0 .

covariance 不是零,就代表有相關;有相關,就不能另外抽一個與 xtx_t 獨立的 noise 去替代 ϵt\epsilon_t

那「不獨立」到底改變了什麼?ϵt\epsilon_tmarginal distribution 仍然是 N(0,I)\mathcal N(0,I),但給定 xtx_t 之後,ϵt\epsilon_t 的分布就變了。所以從 N(0,I)\mathcal N(0,I) 抽一個與 xtx_t 獨立的 ϵt\epsilon_t 代進去,就變成錯的。

回到上一篇的洗牌。你把一副排好的牌洗了一次,然後只看到洗完的樣子——沒看到洗之前。洗牌當然是隨機的,但你看到的那個結果,本身就透露了那一次是怎麼洗的:如果洗完之後有幾張還連在一起,那一次顯然沒把那一段拆開。

所以你不能說「反正洗牌是隨機的」,就自己隨便洗一次、再宣稱這樣就把它倒回去了——那樣只會回到一個錯的順序。ϵt\epsilon_t 就是那一次洗牌:一旦看到 xtx_t,它就不再是一個可以隨便重抽的東西。

所以反解這條路是行不通的。那如果我們老老實實去算 q(xt1xt)q(x_{t-1}\mid x_t) 呢?

因為我們是知道 q(xtxt1)q(x_t\mid x_{t-1}) 的,這時候就會想要用 Bayes 定理來算 q(xt1xt)q(x_{t-1}\mid x_t)M1.3):

q(xt1xt)=q(xtxt1)pt1(xt1)pt(xt).q(x_{t-1}\mid x_t)=\frac{q(x_t\mid x_{t-1})\,p_{t-1}(x_{t-1})}{p_t(x_t)} .

分子的 q(xtxt1)q(x_t\mid x_{t-1}) 我們確實會算——那是上一篇自己設計的那一步(U1.1)。但右邊還有 pt1(xt1)p_{t-1}(x_{t-1})pt(xt)p_t(x_t):它們是資料經過加噪之後的 marginal distribution,也就是「所有真實圖片加噪 tt 步之後,長成 xtx_t 的可能性有多大」,我們記成 ptp_t。要知道它,就得把每一張真實圖片的貢獻都加總起來——也就是得先知道整個 pdatap_{\text{data}}(但很明顯我們不知道)。這種「式子寫得出來、但實際上算不出來」的東西,以下都叫 不可算(intractable)

如果算不出來,那可不可以用「學」的?那要怎麼學?

我們先換一個角度想。其實我們本來就沒有打算把所有東西都直接算出來——如果每一個 quantity 都可以直接算,那我們根本就不需要 learning。

所以現在既然真正的 q(xt1xt)q(x_{t-1}\mid x_t) 不好算,我們可不可以乾脆學一個東西來逼近它?例如,用一個 neural network 來參數化一個 conditional distribution pθ(xt1xt)p_\theta(x_{t-1}\mid x_t),接下來的目標就很自然了:想辦法調整 θ\theta,讓 pθ(xt1xt)p_\theta(x_{t-1}\mid x_t) 盡可能接近真正的 q(xt1xt)q(x_{t-1}\mid x_t)

如果這件事做得到,那我們是不是就不需要真的把 q(xt1xt)q(x_{t-1}\mid x_t) 算出來了?

問題就從:

「這個 distribution 要怎麼算?」

變成:

「我要怎麼設計一個 learning problem,讓 neural network 把它學出來?」

那就來設計這個 learning problem。第一件事是把「接近」說清楚——也就是寫下一個 loss function。兩個分布之間最常用的那個 loss function 是 Kullback–Leibler divergenceM5.1),以下都簡稱 KL;而 xtx_t 本身也是隨機的,所以要對所有可能的 xtx_t 取平均:

J(θ)=Ept(xt)[DKL(q(xt1xt)pθ(xt1xt))].\mathcal J(\theta)=\mathbb E_{p_t(x_t)}\Big[D_{\mathrm{KL}}\big(q(x_{t-1}\mid x_t)\,\big\|\,p_\theta(x_{t-1}\mid x_t)\big)\Big].

這一行就是最直覺、我們真正想要最小化的東西。好消息是 learning objective 有了,壞消息是裡面那個 q(xt1xt)q(x_{t-1}\mid x_t) 還是不可算,所以這個 loss 我們似乎還是算不出來,也不知道怎麼求 gradient。

課堂提問Q2

我們常常在想一個方法的時候、遇到問題就會忘記靜下心來看看我們有什麼?能做什麼?這時不如回頭看一下我們一開始到底有什麼資訊是可以用的——forward process 給了我們什麼?

我們在 forward process 建立的是一筆要拿來訓練的資料,我們做的是:抽一張資料集裡的真實圖片 x0x_0、抽一個時間 tt、抽一個 ϵ\epsilon,然後一行算出 xtx_t。所以我們其實不是只有 xtx_t,還有創造它的 (x0,ϵ,t)(x_0,\epsilon,t)

那這其中有誰可以幫助我們算出 q(xt1xt)q(x_{t-1}\mid x_t)?或是可以有一樣效果的 loss function 呢?

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

x0x_0

q(xt1xt)q(x_{t-1}\mid x_t) 的時候,我們假裝手上只有 xtx_t,但我們其實還知道它是來自哪一張圖 x0x_0。而那正是卡住的原因:pt1(xt1)p_{t-1}(x_{t-1})pt(xt)p_t(x_t) 之所以難算,就是因為它們把所有可能的 x0x_0 都考慮進去了

既然算不動的原因是「要考慮所有的 x0x_0」,那就先別考慮全部:x0x_0 也放進條件裡看看。

訓練的時候,我們其實多知道一件事

先不要急著看公式。想一下 xtx_t 是哪裡來的。

訓練的時候,我們先從 dataset 拿一張真正的資料 x0x_0,再自己一步一步加 noise 產生 xtx_t。所以每一個訓練時看到的 xtx_t,我們都知道它原本是哪一張 x0x_0 變出來的。這件事在我們真的要生成新資料的時候沒有——那時候只有當下的 xtx_t;但在 training 的時候,x0x_0 一直都藏在我們手上。

那問題來了:如果 q(xt1xt)q(x_{t-1}\mid x_t) 不可算,多告訴我們原本的 x0x_0,事情會不會變簡單?也就是不要先問

q(xt1xt),而是問q(xt1xt,x0).q(x_{t-1}\mid x_t),\qquad\text{而是問}\qquad q(x_{t-1}\mid x_t,x_0).

答案是:會,而且它可以直接算出來。那我們可不可以拿這個「算得出來的東西」來教模型?於是把 training objective 改寫成

J~(θ)=Epdata(x0) Eq(xtx0)[DKL(q(xt1xt,x0)pθ(xt1xt))].\widetilde{\mathcal J}(\theta)=\mathbb E_{p_{\text{data}}(x_0)}\ \mathbb E_{q(x_t\mid x_0)} \Big[D_{\mathrm{KL}}\big(q(x_{t-1}\mid x_t,x_0)\,\big\|\,p_\theta(x_{t-1}\mid x_t)\big)\Big].

這裡有一個看起來很奇怪的地方:左邊那個拿來當 target 的 q(xt1xt,x0)q(x_{t-1}\mid x_t,x_0) 看得到 x0x_0,但右邊我們真正要學的 pθ(xt1xt)p_\theta(x_{t-1}\mid x_t) 看不到

為什麼?因為 generation 的時候我們根本沒有 x0x_0,模型最後一定只能靠 xtx_t 往回走。所以 training 時我們可以用 x0x_0 造一個「比較容易算的 target」,但模型最後仍然只能看到 xtx_t

這看起來有點像作弊,甚至更嚴重:兩邊條件的東西根本不一樣。我們真的還是在學原本那個 q(xt1xt)q(x_{t-1}\mid x_t) 嗎?

是。而且這裡不是 approximation。

在看證明之前,先想一下為什麼它會成立。固定一個 xtx_t,在整個訓練過程中,它有可能會被很多張不同的 x0x_0 給造出來。而每一筆訓練資料都拿出一個不一樣的 x0x_0 要模型去對齊,但模型只看得到 xtx_t,分不出手上這一筆是哪一張 x0x_0 來的,所以它只能給一個答案去應付全部——就是把所有 x0x_0 各自給出的那個分布,按它們出現的「頻率」平均起來,而那個平均就會是 q(xt1xt)q(x_{t-1}\mid x_t)

也就是這個意思:

Ep(x0xt)[q(xt1xt,x0)]=q(xt1xt).\mathbb E_{p(x_0\mid x_t)}\big[q(x_{t-1}\mid x_t,x_0)\big]=q(x_{t-1}\mid x_t).

所以兩個 objective 分別是:直接對齊那個算不出來的 q(xt1xt)q(x_{t-1}\mid x_t),和透過對齊一堆算得出來的 q(xt1xt,x0)q(x_{t-1}\mid x_t,x_0)、再讓模型自己去取平均 Ep(x0xt)[]\mathbb E_{p(x_0\mid x_t)}[\,\cdot\,],也是去對齊 q(xt1xt)q(x_{t-1}\mid x_t)

這裡用的雖然是 KL,但和 L2 那種把差距平方起來的距離有類似的性質;以 L2 舉一個 toy example,寫 aˉ=a1+a2+a33\bar a=\frac{a_1+a_2+a_3}{3},minimizing 13[(xa1)2+(xa2)2+(xa3)2]\frac13\big[(x-a_1)^2+(x-a_2)^2+(x-a_3)^2\big] 和 minimizing (xaˉ)2(x-\bar a)^2 會得到一樣的最佳解 xx,因為兩者之差是一個常數——配方出來就看得到:

13[(xa1)2+(xa2)2+(xa3)2]=(xaˉ)2+(a1aˉ)2+(a2aˉ)2+(a3aˉ)23不含 x.\frac13\big[(x-a_1)^2+(x-a_2)^2+(x-a_3)^2\big] =(x-\bar a)^2 +\underbrace{\frac{(a_1-\bar a)^2+(a_2-\bar a)^2+(a_3-\bar a)^2}{3}}_{\text{不含 }x} .

根據這樣的性質,我們預測會有:

J~(θ)=J(θ)+Cargminθ J~(θ)=argminθ J(θ),\widetilde{\mathcal J}(\theta)=\mathcal J(\theta)+C \quad\Longrightarrow\quad \arg\min_\theta\ \widetilde{\mathcal J}(\theta)=\arg\min_\theta\ \mathcal J(\theta),

其中 CC 完全不依賴 θ\theta;而最佳的那個 pθp_\theta——寫成 p(xt1xt)p^\star(x_{t-1}\mid x_t)——正是上面那個平均 Ep(x0xt)[q(xt1xt,x0)]\mathbb E_{p(x_0\mid x_t)}\big[q(x_{t-1}\mid x_t,x_0)\big],也就是 q(xt1xt)q(x_{t-1}\mid x_t)

所以我們只是把一個算不出來的 learning objective,換成一個算得出來、但最佳解完全相同的 objective。模型從來沒有直接拿那個算不出來的 q(xt1xt)q(x_{t-1}\mid x_t) 作為目標,卻可以透過很多個「知道 x0x_0 的 training examples」把它學起來。

動手自己實際推一次:為什麼 J~(θ)=J(θ)+C\widetilde{\mathcal J}(\theta)=\mathcal J(\theta)+C 是對的?

我們想證明的是:雖然 training 時改用 q(xt1xt,x0)q(x_{t-1}\mid x_t,x_0) 當 target,但最後學到的東西,和原本拿 q(xt1xt)q(x_{t-1}\mid x_t) 當 target 是一樣的。

先固定一個 xtx_t,看這個 KL:

DKL(q(xt1xt,x0)pθ(xt1xt)).D_{\mathrm{KL}}\big(q(x_{t-1}\mid x_t,x_0)\,\big\|\,p_\theta(x_{t-1}\mid x_t)\big).

把 KL 的定義展開:

DKL(q(xt1xt,x0)pθ(xt1xt))=q(xt1xt,x0)logq(xt1xt,x0)dxt1q(xt1xt,x0)logpθ(xt1xt)dxt1.\begin{aligned} &D_{\mathrm{KL}}\big(q(x_{t-1}\mid x_t,x_0)\,\big\|\,p_\theta(x_{t-1}\mid x_t)\big)\\[4pt] &=\int q(x_{t-1}\mid x_t,x_0)\log q(x_{t-1}\mid x_t,x_0)\,\mathrm dx_{t-1}\\[2pt] &\quad-\int q(x_{t-1}\mid x_t,x_0)\log p_\theta(x_{t-1}\mid x_t)\,\mathrm dx_{t-1}. \end{aligned}

先看第一項:

q(xt1xt,x0)logq(xt1xt,x0)dxt1.\int q(x_{t-1}\mid x_t,x_0)\log q(x_{t-1}\mid x_t,x_0)\,\mathrm dx_{t-1}.

這裡完全沒有 θ\theta。所以不管之後再對 x0x_0xtx_t 取多少次期望,對我們「調整 θ\theta」這件事來說,它都只是一個常數。

因此真正會影響 learning 的,是第二項:

q(xt1xt,x0)logpθ(xt1xt)dxt1.-\int q(x_{t-1}\mid x_t,x_0)\log p_\theta(x_{t-1}\mid x_t)\,\mathrm dx_{t-1}.

現在對「有可能造出這個 xtx_t」的 x0x_0 取平均:

Ep(x0xt)[q(xt1xt,x0)logpθ(xt1xt)dxt1].-\,\mathbb E_{p(x_0\mid x_t)}\Big[\int q(x_{t-1}\mid x_t,x_0)\log p_\theta(x_{t-1}\mid x_t)\,\mathrm dx_{t-1}\Big].

注意 logpθ(xt1xt)\log p_\theta(x_{t-1}\mid x_t) 只看 xtx_txt1x_{t-1},不依賴 x0x_0。所以我們可以先把所有可能的 x0x_0 平均掉:

[q(xt1xt,x0)p(x0xt)dx0]logpθ(xt1xt)dxt1.-\int\Big[\int q(x_{t-1}\mid x_t,x_0)\,p(x_0\mid x_t)\,\mathrm dx_0\Big]\log p_\theta(x_{t-1}\mid x_t)\,\mathrm dx_{t-1}.

那中括號裡是什麼?

q(xt1xt,x0)p(x0xt)dx0.\int q(x_{t-1}\mid x_t,x_0)\,p(x_0\mid x_t)\,\mathrm dx_0 .

它的意思就是:已知現在的 xtx_t,把所有可能的原圖 x0x_0 都按照 p(x0xt)p(x_0\mid x_t) 的機率加權平均。根據 marginalization,這正好就是

q(xt1xt).q(x_{t-1}\mid x_t).

因此第二項變成

q(xt1xt)logpθ(xt1xt)dxt1,-\int q(x_{t-1}\mid x_t)\log p_\theta(x_{t-1}\mid x_t)\,\mathrm dx_{t-1},

也就是 q(xt1xt)q(x_{t-1}\mid x_t)pθp_\theta 的 cross entropy。

而原本的 DKL(q(xt1xt)pθ(xt1xt))D_{\mathrm{KL}}\big(q(x_{t-1}\mid x_t)\,\big\|\,p_\theta(x_{t-1}\mid x_t)\big) 展開之後,也只有這個 cross entropy 和 θ\theta 有關;剩下那個 q(xt1xt)q(x_{t-1}\mid x_t) 的 entropy 一樣不含 θ\theta

因此兩個 objective 最後只差一個與 θ\theta 無關的常數,也就有完全相同的最佳解:

J~(θ)=J(θ)+Cargminθ J~(θ)=argminθ J(θ).\widetilde{\mathcal J}(\theta)=\mathcal J(\theta)+C \quad\Longrightarrow\quad \arg\min_\theta\ \widetilde{\mathcal J}(\theta)=\arg\min_\theta\ \mathcal J(\theta).

而當模型夠有表達能力的時候,最佳的情況就是

pθ(xt1xt)=q(xt1xt).p_\theta(x_{t-1}\mid x_t)=q(x_{t-1}\mid x_t).

所以 training 時雖然用了額外知道的 x0x_0,模型最後學到的仍然是我們真正想要的那個 reverse distribution。

這個「取平均」的、將不可算變成可以算的技巧,這門課中會反覆看到,以下都叫它 conditional trick。它每一次出現的形狀都一樣:不可算的目標是一個邊際量,而把某個東西放進條件裡之後就算得出來,剩下的平均交給 loss 自己做。 這一篇用的是 KL 版本;U1.3 會用到 MSE 版本,而 U2 的 conditional flow matching 是速度版本。

q(xt1xt,x0)q(x_{t-1}\mid x_t,x_0) 算出來

知道了 learning objective 是可行的之後,我們回過頭來算 q(xt1xt,x0)q(x_{t-1}\mid x_t,x_0)。一樣先用 Bayes:

q(xt1xt,x0)=q(xtxt1,x0)q(xt1x0)q(xtx0)=q(xtxt1)q(xt1x0)q(xtx0).q(x_{t-1}\mid x_t,x_0) =\frac{q(x_t\mid x_{t-1},x_0)\,q(x_{t-1}\mid x_0)}{q(x_t\mid x_0)} =\frac{q(x_t\mid x_{t-1})\,q(x_{t-1}\mid x_0)}{q(x_t\mid x_0)} .

第二個等號用的是 Markov propertyq(xtxt1,x0)=q(xtxt1)q(x_t\mid x_{t-1},x_0)=q(x_t\mid x_{t-1})——往前走一步只讀現在這個狀態,x0x_0 知不知道都一樣。至於 q(xt1x0)q(x_{t-1}\mid x_0)q(xtx0)q(x_t\mid x_0) 這兩項,可以注意到它們都多了一個 x0x_0 的條件,而這三項全部都是 forward process 裡設計出來的 Gaussian

q(xtxt1)q(x_t\mid x_{t-1}) 是 forward process 每往前一步的設計,q(xt1x0)q(x_{t-1}\mid x_0)q(xtx0)q(x_t\mid x_0) 則是我們在 U1.1 最後得到的 closed form(把 tt 換成 t1t-1 就有中間那一條):

q(xtxt1)=N(αtxt1, βtI),每一步的設計q(xt1x0)=N(αˉt1x0, (1αˉt1)I),closed formq(xtx0)=N(αˉtx0, (1αˉt)I).closed form\begin{aligned} q(x_t\mid x_{t-1})&=\mathcal N\big(\sqrt{\alpha_t}\,x_{t-1},\ \beta_t I\big), &&\text{每一步的設計}\\[2pt] q(x_{t-1}\mid x_0)&=\mathcal N\big(\sqrt{\bar\alpha_{t-1}}\,x_0,\ (1-\bar\alpha_{t-1})I\big), &&\text{closed form}\\[2pt] q(x_t\mid x_0)&=\mathcal N\big(\sqrt{\bar\alpha_t}\,x_0,\ (1-\bar\alpha_t)I\big). &&\text{closed form} \end{aligned}

Bayes 右邊在乘除的是三個機率密度,不是三個隨機變數。而 Gaussian 的密度是「exp\exp(一個 xx 的二次式)」,把它們乘起來、再除掉一個,只是在指數上把幾個二次式加加減減——加減完還是二次式,所以配方之後出來的仍然是一個 Gaussian。

動手算一下:配出來的這個 Gaussian q(xt1xt,x0)=N(μ~t, β~tI)q(x_{t-1}\mid x_t,x_0)=\mathcal N(\tilde\mu_t,\ \tilde\beta_t I),它的變異數會跟 x0x_0 有關嗎?

動手自己配一次方:μ~t\tilde\mu_tβ~t\tilde\beta_t 是怎麼跑出來的?

首先 q(xt1xt,x0)q(x_{t-1}\mid x_t,x_0) 之中,只有 xt1x_{t-1} 是變數,其他兩個是給定的(視為常數),因此我們只要管 q(xt1x0)q(x_{t-1}\mid x_0)q(xtxt1)q(x_t\mid x_{t-1}) 的乘積,不用理 q(xtx0)q(x_t\mid x_0)

q(xt1xt,x0)  q(xt1x0)q(xtxt1)  exp[xtαtxt122βtxt1αˉt1x022(1αˉt1)].q(x_{t-1}\mid x_t,x_0)\ \propto\ q(x_{t-1}\mid x_0)\,q(x_t\mid x_{t-1}) \ \propto\ \exp\Big[-\frac{\|x_t-\sqrt{\alpha_t}\,x_{t-1}\|^2}{2\beta_t} -\frac{\|x_{t-1}-\sqrt{\bar\alpha_{t-1}}\,x_0\|^2}{2(1-\bar\alpha_{t-1})}\Big].

方括號裡是 xt1x_{t-1} 的一個二次式。把它按次數收好:平方項的係數是

A=αtβt+11αˉt1,A=\frac{\alpha_t}{\beta_t}+\frac{1}{1-\bar\alpha_{t-1}},

一次項寫成 2bxt1-2\,b^\top x_{t-1} 的話,

b=αtβtxt+αˉt11αˉt1x0.b=\frac{\sqrt{\alpha_t}}{\beta_t}\,x_t+\frac{\sqrt{\bar\alpha_{t-1}}}{1-\bar\alpha_{t-1}}\,x_0 .

於是整個指數是 A2xt1b/A2-\tfrac{A}{2}\big\|x_{t-1}-b/A\big\|^2 再加一個不含 xt1x_{t-1} 的常數,常數可再次無視。對照 Gaussian 的密度公式,直接可以得到 β~t=1/A\tilde\beta_t=1/Aμ~t=b/A\tilde\mu_t=b/A

剩下的只是化簡。AA 通分之後分子是 αt(1αˉt1)+βt\alpha_t(1-\bar\alpha_{t-1})+\beta_t,而這裡只需要 U1.1 定義 αt\alpha_tαˉt\bar\alpha_t 時就留下的兩個恆等式——αt+βt=1\alpha_t+\beta_t=1αtαˉt1=αˉt\alpha_t\bar\alpha_{t-1}=\bar\alpha_t

αtαtαˉt1+βt=(αt+βt)αˉt=1αˉt,\alpha_t-\alpha_t\bar\alpha_{t-1}+\beta_t=(\alpha_t+\beta_t)-\bar\alpha_t=1-\bar\alpha_t ,

所以 β~t=(1αˉt1)βt1αˉt\tilde\beta_t=\dfrac{(1-\bar\alpha_{t-1})\,\beta_t}{1-\bar\alpha_t}。把它乘進 bb,兩個分母各自消掉,就是下面那兩個係數。

代進去,我們可以推出

q(xt1xt,x0)=N(μ~t(xt,x0), β~tI),q(x_{t-1}\mid x_t,x_0)=\mathcal N\big(\tilde\mu_t(x_t,x_0),\ \tilde\beta_t I\big),

μ~t=αˉt1βt1αˉtx0+αt(1αˉt1)1αˉtxt,β~t=1αˉt11αˉtβt.\tilde\mu_t=\frac{\sqrt{\bar\alpha_{t-1}}\,\beta_t}{1-\bar\alpha_t}\,x_0 +\frac{\sqrt{\alpha_t}\,(1-\bar\alpha_{t-1})}{1-\bar\alpha_t}\,x_t, \qquad \tilde\beta_t=\frac{1-\bar\alpha_{t-1}}{1-\bar\alpha_t}\,\beta_t .

這個分布的平均 μ~t\tilde\mu_tx0x_0xtx_t 的一個加權平均——一邊拉向起點、一邊留在原地,權重只由 forward process 設計的 schedule 決定。變異數 β~t\tilde\beta_t完全不含 x0x_0xtx_t,只是 schedule 的一個數字。

DDPM 的訓練

現在 learning objective 中的 target q(xt1xt,x0)q(x_{t-1}\mid x_t,x_0) 算得出來了,下一步就是具體的訓練方法了。首先我們注意到

q(xt1xt,x0)=N(μ~t(xt,x0), β~tI)q(x_{t-1}\mid x_t,x_0)=\mathcal N\big(\tilde\mu_t(x_t,x_0),\ \tilde\beta_t I\big)

之中只有 μ~t(xt,x0)\tilde\mu_t(x_t,x_0)xtx_tx0x_0 有關,β~t\tilde\beta_t 是常數。而 μ~t(xt,x0)\tilde\mu_t(x_t,x_0) 裡面,模型唯一沒有的就是 x0x_0。因此最直觀的選擇就是:變異數照抄,平均也照抄同一個形狀,只把缺的那一塊換成網路的輸出 x^θ(xt,t)\hat x_\theta(x_t,t)

pθ(xt1xt)=N(μ~t(xt, x^θ(xt,t)), β~tI).p_\theta(x_{t-1}\mid x_t)=\mathcal N\Big(\tilde\mu_t\big(x_t,\ \hat x_\theta(x_t,t)\big),\ \tilde\beta_t I\Big).

可以特別留意到這個神經網路的 input 是合理的:當下的狀態 xtx_t,跟在第幾步 tt。(在 U1.4 我們會討論這樣的假設帶來什麼代價,我們可不可以接受?)

這個選擇讓 learning objective 中的 KL 變成只剩兩個平均之間的距離:

DKL(q(xt1xt,x0)pθ(xt1xt))=12β~tμ~t(xt,x0)μ~t(xt,x^θ(xt,t))2.\begin{aligned} D_{\mathrm{KL}}\big(q(x_{t-1}\mid x_t,x_0)\,\big\|\,p_\theta(x_{t-1}\mid x_t)\big) &=\frac{1}{2\tilde\beta_t}\Big\|\tilde\mu_t(x_t,x_0)-\tilde\mu_t\big(x_t,\hat x_\theta(x_t,t)\big)\Big\|^2 . \end{aligned}

最後得到 L2L_2。兩個 Gaussian 的變異數相同,normalizing constant 就一樣、取對數相減會消掉;展開之後 xt1x_{t-1} 的二次項也消掉,剩下的正是兩個平均之間的距離。

μ~t\tilde\mu_tx0x_0 是 affine 的,x0x_0 的係數就是上面那個 αˉt1βt1αˉt\frac{\sqrt{\bar\alpha_{t-1}}\,\beta_t}{1-\bar\alpha_t},所以這個距離立刻化成兩張圖之間的距離:

μ~t(xt,x0)μ~t(xt,x^θ)2=(αˉt1βt1αˉt)2x0x^θ2.\Big\|\tilde\mu_t(x_t,x_0)-\tilde\mu_t\big(x_t,\hat x_\theta\big)\Big\|^2=\Big(\frac{\sqrt{\bar\alpha_{t-1}}\,\beta_t}{1-\bar\alpha_t}\Big)^{2}\big\|x_0-\hat x_\theta\big\|^2 .

把它代回去,整個訓練目標就是一個加權的平方誤差

J~(θ)=Et,x0,ϵ[w(t)x^θ(xt,t)x02],w(t)=αˉt1βt2(1αˉt)(1αˉt1),\widetilde{\mathcal J}(\theta)=\mathbb E_{t,\,x_0,\,\epsilon}\Big[w(t)\,\big\|\hat x_\theta(x_t,t)-x_0\big\|^2\Big], \qquad w(t)=\frac{\bar\alpha_{t-1}\,\beta_t}{2(1-\bar\alpha_t)(1-\bar\alpha_{t-1})},

其中 xt=αˉtx0+σtϵx_t=\sqrt{\bar\alpha_t}\,x_0+\sigma_t\epsilon 是一行算出來的。沒有對抗、沒有 normalizing constant,就是一個平方誤差——U1.0 說「路徑自己定,每一步就變成回歸」,指的就是這一行。

在討論 w(t)w(t) 之前,應該要有人舉手問:

L2L_2 不是才剛被我們否決過嗎?
為什麼這一次它就可以了?

課堂提問Q3

U1.0 我們算過:拿 L2L_2 去比對資料 x0x_0 與生成結果 Gθ(z)G_\theta(z),最佳解是一張所有訓練圖片的平均,模型會直接往它學習。現在這個 loss 也是 L2L_2、也是拿模型輸出 x^θ(xt,t)\hat x_\theta(x_t,t) 去比對真實的 x0x_0

為什麼這一次不會出問題?

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

差別只有一個字:配對

上一次 zzx0x_0 是各自獨立抽的,模型拿到 zz,但對於它可能跟哪一個 x0x_0 有關完全沒有線索,所以最佳解是取平均 Epdata[x0]\mathbb E_{p_{\text{data}}}[x_0],一個與模型輸入無關的常數。但這一次的 xtx_t 是從某一張特定的 x0x_0 加噪來的,兩者被 forward process 綁在一起。L2L_2 的最佳解因此變成一個條件期望M1.2):

x^(xt,t)=E[x0xt].\hat x^{\star}(x_t,t)=\mathbb E\big[x_0\mid x_t\big].

它是一個xtx_t 改變的函數,不是常數。tt 很小的時候,xtx_t 幾乎就是 x0x_0,這個條件期望幾乎等於原圖;tt 很大的時候,同一個 xtx_t 可能來自很多張不同的圖,條件期望就是那些圖的加權平均——這時候預測本來就該是模糊的。(這件事看下面那張圖會更清楚。)

雖然同樣是做 L2L_2 norm minimization,上一次的最佳解是一個常數,而這一次是一個取決於當下 state xtx_t 的函數。

其中的差別就來自於模型的輸入和目標 x0x_0 有沒有被以某種方式配對在一起。可以想像成看視力檢查表上的那個 E,猜它的開口朝上下左右哪一邊:畫面很清楚時,你就直接讀出來;畫面糊到只剩輪廓時,你能給的答案就是以 1/41/4 的機率盲猜,猜了幾次後就跟給出「所有可能的平均」沒什麼兩樣。

(注意 w(t)w(t) 只是每個 tt 的權重、不隨 x^θ\hat x_\theta 改變,所以它不影響每一個 tt 上的最佳解是什麼。)

把這個最佳解代回 pθp_\theta,整條鏈就閉合了:模型族裡最好的那個平均——寫成 μ\mu^\star——是

μ(xt,t)=μ~t(xt, E[x0xt]),\mu^\star(x_t,t)=\tilde\mu_t\big(x_t,\ \mathbb E[x_0\mid x_t]\big),

也就是真正那個邊際 q(xt1xt)q(x_{t-1}\mid x_t) 的平均。所以「倒著走一步需要知道什麼」有了完整的答案:散布是 schedule 給的,中心由 E[x0xt]\mathbb E[x_0\mid x_t] 決定,而那一個量就是我們要學的東西。

(要說清楚的是:「L2L_2 的最佳解是條件期望」這件事,我們在這裡只是提到,並沒有證明——上面是靠和前一個情境對照得到的。這個結論的證明與它真正的份量,U1.3 會好好討論。)

示意圖:上排 t 小,三張候選原圖中只有一張亮著,加噪後的 x_t 仍看得出是貓,模型輸出幾乎與原圖相同;下排 t 大,五張不同的照片(貓、鳥、兔、盆栽)都連到同一張看不出內容的 x_t,權重以線的粗細表示,模型輸出是一張模糊的加權平均。

圖:同一個 xtx_t 可以來自很多張圖。 上排 tt 小,能對上的原圖只有一張,輸出就幾乎是原圖;下排 tt 大,很多張圖都可能變成同一個 xtx_tL2L_2 的最佳解就是它們的加權平均。所以這裡的模糊是正確答案,不是訓練失敗。

看一個點怎麼被去噪

互動 demo:去噪一個點。 在平面上點一個位置當成 xtx_t,再拖 tt。每個資料點的大小是它的後驗權重 p(x0xt)exp(xtαˉtx02/2σt2)p(x_0\mid x_t)\propto\exp\big(-\|x_t-\sqrt{\bar\alpha_t}x_0\|^2/2\sigma_t^2\big),箭頭指向 E[x0xt]\mathbb E[x_0\mid x_t]tt 小的時候只有一兩個點亮著,箭頭幾乎指在原地;tt 大的時候整批點都亮,箭頭就指向一個平均的位置。

學完之後,怎麼真的走回去?

前面我們已經把模型訓練好了。現在假設手上有一個 xtx_t,下一步就是要產生 xt1x_{t-1}

我們前面把 reverse distribution 寫成

pθ(xt1xt),p_\theta(x_{t-1}\mid x_t),

而且選擇用 Gaussian 來 parametrize 它。網路負責預測 x^θ(xt,t)\hat x_\theta(x_t,t),再把它代回前面推導出的 posterior mean:

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).

這樣就完成一次 xtxt1x_t\to x_{t-1}

接下來沒有新的東西:從

xTN(0,I)x_T\sim\mathcal N(0,I)

開始,重複同樣的步驟,

xTxT1x1x0,x_T\to x_{T-1}\to\cdots\to x_1\to x_0,

最後就得到一個 sample。

到這裡,我們已經知道 DDPM 怎麼訓練,也知道訓練完之後怎麼拿來生成

這樣的 regression,憑什麼保證生成出來的東西是好的?

前面一路做下來,我們最後得到的只是一個 regression loss。但我們真正關心的是:把這個 loss 壓低,真的會讓模型生成的 data distribution 更接近資料實際的分布嗎?

根據其實是有的,我們可以沿著三個步驟去解釋、證明。

第一步:從 likelihood 出發。 我們希望模型對真實資料給高 likelihood,也就是讓 logpθ(x0)-\log p_\theta(x_0) 越小越好。但 pθ(x0)p_\theta(x_0) 需要把整條 latent path 積掉,不好直接算。利用 forward process q(x1:Tx0)q(x_{1:T}\mid x_0) 和 Jensen inequality,可以得到

logpθ(x0)  Eq(x1:Tx0) ⁣[logpθ(x0:T)q(x1:Tx0)].-\log p_\theta(x_0)\ \le\ \mathbb E_{q(x_{1:T}\mid x_0)}\!\left[-\log\frac{p_\theta(x_{0:T})}{q(x_{1:T}\mid x_0)}\right].

也就是說,我們可以改去最小化 negative log-likelihood 的一個上界,也就是 ELBO(evidence lower bound,見 當那個要加總的量算不出來,可以退到哪裡?)對應的 loss。

第二步:把整條 path 看成兩個 distribution。 再對 x0pdatax_0\sim p_{\text{data}} 取平均,上面的 quantity 可以寫成

DKL(q(x0:T)pθ(x0:T))+constant.D_{\mathrm{KL}}\big(q(x_{0:T})\,\big\|\,p_\theta(x_{0:T})\big)+\text{constant}.

所以問題變成:讓模型的整條 reverse path,接近資料經過 forward process 產生的那條 path。

第三步:Markov structure 讓這個 path-level KL 可以逐步拆開。 最後跟 θ\theta 有關的部分,就是每個 timestep 的 reverse transition mismatch:

tEpt(xt)[DKL(q(xt1xt)pθ(xt1xt))].\sum_t\mathbb E_{p_t(x_t)}\Big[D_{\mathrm{KL}}\big(q(x_{t-1}\mid x_t)\,\big\|\,p_\theta(x_{t-1}\mid x_t)\big)\Big].

而這正是我們前面一路改寫、最後變成 regression loss 的東西。

所以整條關係是

 regression loss  reverse-step KL  path KL  logpθ(x0) 的上界 \boxed{\ \text{regression loss}\ \longrightarrow\ \text{reverse-step KL}\ \longrightarrow\ \text{path KL}\ \longrightarrow\ -\log p_\theta(x_0)\ \text{的上界}\ }

也就是說,前面的 regression 並不是憑空設計的:它一路可以接回我們真正關心的 generative likelihood。

不過這並不代表每一步都能完全學準。我們把 pθ(xt1xt)p_\theta(x_{t-1}\mid x_t) 限制在特定的 Gaussian family 裡,因此一般不保證它能精確等於真正的 reverse conditional。

這也留下幾個後面的問題:這個 approximation 到底有多好?noise 一定要加嗎?如果 timestep 切得越來越細,又會發生什麼?

這些等到 U1.4 再討論!

同一個 reverse step,不一定要學 x0x_0

xt=αˉtx0+σtϵx_t=\sqrt{\bar\alpha_t}x_0+\sigma_t\epsilon 可以看到:在 xtx_t 已知的情況下,只要知道 x0x_0ϵ\epsilon 其中一個,另一個就可以直接算出來:

x0=xtσtϵαˉtϵ=xtαˉtx0σt.x_0=\frac{x_t-\sigma_t\epsilon}{\sqrt{\bar\alpha_t}} \qquad\Longleftrightarrow\qquad \epsilon=\frac{x_t-\sqrt{\bar\alpha_t}x_0}{\sigma_t}.

所以,網路不一定非得直接預測 x0x_0。我們也可以讓它預測 ϵ\epsilon,再用上面的式子換回 x0x_0。同一個 denoising 問題,可以選擇讓網路預測不同、但彼此可以換算的 quantity。這個「網路輸出要用哪一種表示方式」的選擇,就叫做 parametrization

在我們目前這個 formulation 裡,實務上常見的選擇有三種:x0x_0-prediction、ϵ\epsilon-prediction,以及 vv-prediction。

x0x_0-prediction:直接輸出 x^0\hat x_0,也就是〈DDPM 的訓練〉推出來的那個 loss。

ϵ\epsilon-prediction(DDPM 原文 [1]):讓網路去猜那個總噪聲。

Lϵ=E[ϵθ(xt,t)ϵ2],x^0=xtσtϵθαˉt.\mathcal L_\epsilon=\mathbb E\big[\|\epsilon_\theta(x_t,t)-\epsilon\|^2\big], \qquad \hat x_0=\frac{x_t-\sigma_t\epsilon_\theta}{\sqrt{\bar\alpha_t}} .

vv-prediction [3]:把 (αˉt,σt)(\sqrt{\bar\alpha_t},\sigma_t) 看成 (cosϕt,sinϕt)(\cos\phi_t,\sin\phi_t),定義

v=αˉtϵσtx0.v=\sqrt{\bar\alpha_t}\,\epsilon-\sigma_t\,x_0 .

vv(x0,ϵ)(x_0,\epsilon) 平面上與 xtx_t 垂直的那個方向。它在 t0t\to0 時像 ϵ\epsilon、在 tTt\to T 時像 x0-x_0,兩端都不會退化。這個「兩端都不退化」現在看起來只是好看,要到 U6.1 把步數減到很少的時候才真正派上用場——vv-prediction 最早就是在那裡被提出來的。

符號為什麼 v 可以看成「垂直方向」?

因為 αˉt+σt2=1\bar\alpha_t+\sigma_t^2=1,我們可以寫 αˉt=cosϕt\sqrt{\bar\alpha_t}=\cos\phi_tσt=sinϕt\sigma_t=\sin\phi_t。於是

xt=cosϕtx0+sinϕtϵ,v=cosϕtϵsinϕtx0.x_t=\cos\phi_t\,x_0+\sin\phi_t\,\epsilon,\qquad v=\cos\phi_t\,\epsilon-\sin\phi_t\,x_0 .

在以 x0x_0ϵ\epsilon 為兩軸的平面上,xtx_tvv 剛好是互相垂直的一組座標——vv 就是「沿著 ϕt\phi_t 增加的方向」,也就是 xtx_tϕt\phi_t 的導數。這也是它兩端都不退化的原因:不管 ϕt\phi_t 靠近 0 還是 π/2\pi/2,垂直方向永遠存在。

三者之間可以透過 affine transformation 互相轉換,而且轉換係數只和 tt 有關。所以,在表示上,只要知道其中一個,就可以直接算出另外兩個——給定其中一個訓好的網路,另外兩個不用重訓,代數換算就有了。實作那篇會要你親手驗證一次。

但用這三種 parametrization 去訓練,最後會得到完全一樣的結果嗎?

表示上等價,但訓練上不相同

假設我們都使用看起來一樣的 MSE loss——就是前面一路在用的那個平方誤差:

E[predictiontarget2],\mathbb E\big[\|\text{prediction}-\text{target}\|^2\big],

把 target 從 x0x_0 換成 ϵ\epsilonvv 之後,對應回同一個 quantity 時,不同 noise level 的誤差會被乘上不同的權重。

x^0\hat x_0ϵθ\epsilon_\theta 的關係代進去就看得到:

x^0x02=σt2αˉtϵθϵ2=1SNR(t)ϵθϵ2,SNR(t)=αˉt1αˉt.\|\hat x_0-x_0\|^2=\frac{\sigma_t^2}{\bar\alpha_t}\,\|\epsilon_\theta-\epsilon\|^2 =\frac{1}{\mathrm{SNR}(t)}\,\|\epsilon_\theta-\epsilon\|^2, \qquad \mathrm{SNR}(t)=\frac{\bar\alpha_t}{1-\bar\alpha_t}.

所以前面推出來的那個加權平方誤差,換到 ϵ\epsilon 座標之後也只是換一組權重:

J~(θ)=Et[w(t)SNR(t)(該 t 的 ϵ-loss)],w(t)SNR(t)=βt2αt(1αˉt1).\widetilde{\mathcal J}(\theta)=\mathbb E_t\Big[\tfrac{w(t)}{\mathrm{SNR}(t)}\cdot\big(\text{該 } t \text{ 的 }\epsilon\text{-loss}\big)\Big], \qquad \frac{w(t)}{\mathrm{SNR}(t)}=\frac{\beta_t}{2\,\alpha_t\,(1-\bar\alpha_{t-1})}.

所以三種 parametrization 雖然可以互相換算,但它們定義的 training objective 並不完全相同。

要小心「不完全相同」指的是什麼:不同寫法的最小值點是同一個(都被同一個條件期望達成);不一樣的是在有限容量、有限訓練時間下,它們對不同 tt 的重視程度。也就是說:

representation equivalent    optimization equivalent\boxed{\text{representation equivalent} \;\neq\; \text{optimization equivalent}}

差別主要就在於:不同的 parametrization,會讓模型更重視不同 noise level 的誤差。

這裡我們順便講一下 DDPM 原文實際採用的做法。

在實作上,它直接把這個 weighting w(t)w(t) 拿掉,改成均勻(uniform)加權的 ϵ\epsilon-MSE:

Lsimple(θ)=Et,x0,ϵ[ϵθ(xt,t)ϵ2].\mathcal L_{\text{simple}}(\theta)=\mathbb E_{t,\,x_0,\,\epsilon}\big[\|\epsilon_\theta(x_t,t)-\epsilon\|^2\big].

關於這樣的操作,我們可以理解成:

forward process 決定我們怎麼製造不同 noise level 的資料;
weighting 決定 training 時多重視哪些 noise level。

兩件事其實可以分開設計。因此,即使 forward process 不變,我們仍然可以改變不同 tt 在 loss 裡的 weighting。代價是前面那個 ELBO 的不等式跟著失效:加權一換,被界住的就不再是原來那個 logpθ(x0)-\log p_\theta(x_0)。理想情況下這不改變每個 tt 對應的最佳 predictor,但會改變實際訓練時模型把 capacity 和 optimization effort 放在哪些地方。U2 比較 diffusion 與 flow matching 時,這個 distinction 還會再出現。

DDPM 的訓練核心其實就這五行

repeat
  x0 ← 一個 batch 的資料
  t  ← Uniform{1,…,T}
  ε  ← N(0, I)
  xt ← √ᾱ_t · x0 + √(1-ᾱ_t) · ε
  loss ← ‖ε_θ(xt, t) − ε‖²
  梯度下降

這裡我們先寫成 pseudo code。真的要實作,還需要決定 batch size、TT、noise schedule、ϵθ\epsilon_\theta 的網路架構和 optimizer,但核心 training loop 就是上面這幾步。

U1.5,我們會把它真的寫成可以跑的程式。到時候你也會看到一個有趣的現象:loss 不會一路掉到 0,而會停在一個非零值附近。這不是程式寫錯;在 U1.3,我們會先了解為什麼這件事本來就應該發生。

消化一下

想一想

把目標從「q(xt1xt)q(x_{t-1}\mid x_t)pθp_\theta 的 KL」換成「q(xt1xt,x0)q(x_{t-1}\mid x_t,x_0)pθp_\theta 的 KL、再對 x0x_0 取平均」,這個換法是什麼?

想一想

這一篇從頭到尾,哪一步才是真正的取捨(也就是可能讓我們拿不到真正最佳解的那一步)?

想一想

訓好一個 ϵ\epsilon-prediction 網路之後,想拿到 x^0\hat x_0,需要做什麼?

想一想

DDPM 原文用的 Lsimple\mathcal L_{\text{simple}} 和這一篇推導出來的目標,關係是什麼?

想一想

tt 固定在很大的值(噪聲很重)訓練,然後看模型對單一個 xtx_t 的輸出 x^0\hat x_0,會看到什麼?

參考文獻

  1. Ho, J., Jain, A., Abbeel, P. Denoising Diffusion Probabilistic Models. NeurIPS 2020. (變分推導、ϵ\epsilon-prediction 與「丟掉加權」的簡化 loss。)
  2. Lai, C.-H., Song, Y., Kim, D., Mitsufuji, Y., Ermon, S. The Principles of Diffusion Models. 2025, Section 2.2. (本篇的骨架:先用等價定理證明條件化合法,再挑模型族。)
  3. Salimans, T., Ho, J. Progressive Distillation for Fast Sampling of Diffusion Models. ICLR 2022. (vv-prediction 的出處。)
  4. Kingma, D. P., Gao, R. Understanding Diffusion Objectives as the ELBO with Simple Data Augmentation. NeurIPS 2023. (把「加權」與 ELBO 的關係講清楚。)