跳轉到

06.2 擴散模型與隨機微分方程#

本章導讀#

生成模型要回答:「資料是從什麼分布來的?」 2020 年的擴散模型(DDPM)給出了一個反直覺的答案:先學會破壞(加噪聲),再學會逆轉(去噪)。 其數學基礎是物理裡的老朋友——擴散過程——配上伊藤清的隨機微積分。

準備說明#

想像一滴墨水滴進清水:

  • 前向:墨水慢慢擴散,最後整杯水均勻渾濁——有序變無序,純高斯噪聲。
  • 反向:我們問——能不能從渾濁的水「倒放」回一滴墨水?

物理上倒放幾乎不可能(熵增)。但機器學習的招數是:把每個小步的倒放學出來。 每一步只加一點噪聲,逆轉每一步只需要一小段去噪——學幾千個小步,就能從純噪聲一路「倒回」一張圖。

正規理論#

前向過程:離散版#

給定資料 \(\mathbf{x}_0 \sim q(\mathbf{x}_0)\) ,前向逐步加噪:

\[ q(\mathbf{x}_t \mid \mathbf{x}_{t-1}) = \mathcal{N}\!\left(\mathbf{x}_t;\ \sqrt{1-\beta_t}\,\mathbf{x}_{t-1},\ \beta_t \mathbf{I}\right) \]

\(\beta_t\) 是噪聲計畫。任意時刻可一步到位(令 \(\alpha_t = \prod_{s\le t}(1-\beta_s)\) ):

\[ q(\mathbf{x}_t \mid \mathbf{x}_0) = \mathcal{N}\!\left(\mathbf{x}_t;\ \sqrt{\alpha_t}\,\mathbf{x}_0,\ (1-\alpha_t)\mathbf{I}\right) \]

\(t \to \infty\) 時 \(\alpha_t \to 0\) , \(\mathbf{x}_t\) 趨於標準高斯——有序變無序。

連續版:隨機微分方程與伊藤清微積分#

令 \(t \in [0, T]\) 連續,前向過程是一支隨機微分方程(SDE):

\[ d\mathbf{x} = -\frac{1}{2}\beta(t)\,\mathbf{x}\, dt + \sqrt{\beta(t)}\, d\mathbf{w} \]

\(d\mathbf{w}\) 是布朗運動的增量( \(\mathbb{E}[d\mathbf{w}] = 0\) , \(\mathrm{Var}(d\mathbf{w}) = dt\) )。 伊藤清微積分處理含隨機項的微分:隨機項的「二階效應」不可忽略( \((d\mathbf{w})^2 = dt\) )。

Fokker–Planck 方程給出機率密度 \(p(\mathbf{x}, t)\) 的演化:

\[ \frac{\partial p}{\partial t} = -\nabla\cdot\big(f(\mathbf{x},t)\,p\big) + \frac{1}{2}\nabla^2\!\big(g^2(t)\,p\big) \]

前向 SDE 把 \(p\) 逐步推向高斯。

反向過程:時間倒流的 SDE#

安德森(Anderson, 1982)證明:前向 SDE 的時間反演也是一支 SDE:

\[ d\mathbf{x} = \left[-\frac{1}{2}\beta(t)\,\mathbf{x} - \beta(t)\, \nabla_{\mathbf{x}} \log p_t(\mathbf{x})\right] dt + \sqrt{\beta(t)}\, d\bar{\mathbf{w}} \]

關鍵項是分數函數(score function) \(\nabla_{\mathbf{x}}\log p_t(\mathbf{x})\) ——它指向機率密度上升最快的方向。

學習:去噪即學分數#

分數函數未知,但可用神經網路 \(\mathbf{s}_\theta\) 近似,訓練目標出奇地簡單:

\[ \mathcal{L}(\theta) = \mathbb{E}_{t, \mathbf{x}_0, \boldsymbol{\epsilon}}\Big[\big\| \mathbf{s}_\theta(\mathbf{x}_t, t) - \nabla_{\mathbf{x}_t}\log p(\mathbf{x}_t \mid \mathbf{x}_0) \big\|^2\Big] \]

而對高斯前向, \(\nabla\log p(\mathbf{x}_t \mid \mathbf{x}_0) = -\boldsymbol{\epsilon}/\sqrt{1-\alpha_t}\) ,其中 \(\boldsymbol{\epsilon}\) 就是那個已知的噪聲——

\[ \boxed{\; \mathcal{L}(\theta) = \mathbb{E}\Big[\big\| \mathbf{s}_\theta(\sqrt{\alpha_t}\,\mathbf{x}_0 + \sqrt{1-\alpha_t}\,\boldsymbol{\epsilon},\ t) + \boldsymbol{\epsilon}/\sqrt{1-\alpha_t} \big\|^2\Big) \approx \mathbb{E}\big[\|\boldsymbol{\epsilon}_\theta(\mathbf{x}_t, t) - \boldsymbol{\epsilon}\|^2\big] \;} \]

去噪 = 預測加進去的噪聲。生成時:從純高斯 \(\mathbf{x}_T \sim \mathcal{N}(\mathbf{0}, \mathbf{I})\) 出發,用學到的 \(\mathbf{s}_\theta\) 積分反向 SDE,一路走到 \(\mathbf{x}_0\) ——純噪聲「倒放」成一張圖。

與變分推斷的等價#

DDPM 的證明有兩條路:(1) 變分推斷的證據下界(ELBO,04.3 節的 KL 散度逐層相加); (2) 分數匹配(score matching)。兩者給出同一個訓練目標——機率論的殊途同歸。

簡易範例:一維擴散與去噪#

一維資料 \(x_0 = 2\) , \(\beta = 0.1\) (常數),前向三步:

\[ x_1 = \sqrt{0.9}\times 2 + \sqrt{0.1}\,\epsilon_1,\quad x_2 = \sqrt{0.9}\,x_1 + \sqrt{0.1}\,\epsilon_2,\ \dots \]

(取 \(\epsilon_i = 0\) 看均值軌跡: \(2 \to 1.897 \to 1.800 \to 1.708\) ——均值向 0 衰減,方差向 1 增長。)

反向一步的去噪目標:給定 \(x_1\) ,預測噪聲 \(\epsilon_1\) 。若模型預測 \(\hat\epsilon = 0.3\) 而真值 \(0.5\) , 損失 \(= (0.3 - 0.5)^2 = 0.04\) 。訓練幾千步後,模型「知道」每一步該減掉多少噪聲—— 反覆應用,就能從噪聲重建 \(x_0 \approx 2\) 。

歷史典故#

習題#

  1. 對常數 \(\beta\) 的一維前向,求 \(x_t\) 的均值與方差(封閉式),驗證 \(t\to\infty\) 時趨於 \(\mathcal{N}(0,1)\) 。
  2. 證明:高斯前向下 \(\nabla_{\mathbf{x}_t}\log p(\mathbf{x}_t\mid\mathbf{x}_0) = -\boldsymbol{\epsilon}/\sqrt{1-\alpha_t}\) (提示:對高斯密度取對數再求導)。
  3. 解釋為什麼反向 SDE 中的分數函數是「必需」的,以及為什麼可以直接用噪聲預測替代它。

補充#

1. 數學推導證明#

證明(習題 2):高斯前向的分數函數。

\(q(\mathbf{x}_t\mid\mathbf{x}_0) = \mathcal{N}(\sqrt{\alpha_t}\,\mathbf{x}_0, (1-\alpha_t)\mathbf{I})\) 的對數密度(略去常數):

\[ \log p = -\frac{\|\mathbf{x}_t - \sqrt{\alpha_t}\,\mathbf{x}_0\|^2}{2(1-\alpha_t)} \]

對 \(\mathbf{x}_t\) 求導: \(\nabla_{\mathbf{x}_t}\log p = -\dfrac{\mathbf{x}_t - \sqrt{\alpha_t}\,\mathbf{x}_0}{1-\alpha_t}\) 。而重參數化 \(\mathbf{x}_t = \sqrt{\alpha_t}\,\mathbf{x}_0 + \sqrt{1-\alpha_t}\,\boldsymbol{\epsilon}\) 給出分子 \(= \sqrt{1-\alpha_t}\,\boldsymbol{\epsilon}\) ,故

\[ \nabla_{\mathbf{x}_t}\log p(\mathbf{x}_t\mid\mathbf{x}_0) = -\frac{\boldsymbol{\epsilon}}{\sqrt{1-\alpha_t}} \]

分數函數與噪聲只差一個已知常數——學分數 \(\Leftrightarrow\) 學噪聲,後者可直接監督(噪聲是自己加進去的,已知答案)。 \(\blacksquare\)

證明(習題 1):常數 \(\beta\) 前向的均值與方差。

遞迴 \(x_t = \sqrt{1-\beta}\,x_{t-1} + \sqrt{\beta}\,\epsilon_t\) ( \(\epsilon_t\) 獨立標準常態)。取期望: \(\mu_t = \sqrt{1-\beta}\,\mu_{t-1}\) ,故 \(\mu_t = (1-\beta)^{t/2}x_0 = \sqrt{\alpha_t}\,x_0 \to 0\) 。方差: \(\sigma_t^2 = (1-\beta)\sigma_{t-1}^2 + \beta\) ( \(\sigma_0^2 = 0\) ),解得 \(\sigma_t^2 = 1 - (1-\beta)^t = 1 - \alpha_t \to 1\) 。故 \(x_t \Rightarrow \mathcal{N}(0,1)\) ——有序變無序的精確陳述。 \(\blacksquare\)

說明(習題 3):分數為何必需。 前向 SDE 的漂移 \(f\) 把密度推向高斯;時間倒流時 Fokker–Planck 方程多出一項 \(-\nabla\cdot(g^2 p)\) ,把它併回漂移即得反向 SDE 的修正項 \(-g^2\nabla\log p_t\) 。沒有它,倒放只會繼續擴散(錯方向);有了它,每一步都被拉回高密度區。因為分數 \(\propto -\boldsymbol{\epsilon}\) ,訓練時用已知噪聲當標籤即可——物理要求分數,數學允許用噪聲代替。

2. 簡易範例#

範例一:均值軌跡手算。 \(x_0 = 2\) 、 \(\beta = 0.1\) ( \(\sqrt{0.9} \approx 0.9487\) ): \(\epsilon_i = 0\) 時 \(2 \to 1.897 \to 1.800 \to 1.708\) ——均值向 0 衰減(程式 _code/06.2-ddpm-forward-denoise.py 的「理論均值」欄逐項印出 \(1.8974, 1.8000, 1.7076, \dots\) ,與手算一致)。

範例二:封閉式的蒙地卡羅驗證。 程式在 \(t = 10\) 做 20 萬次抽樣:實測均值 \(1.1811\) vs 理論 \(\sqrt{\alpha_{10}}\cdot 2 = 1.1810\) ;實測方差 \(0.6529\) vs 理論 \(1 - \alpha_{10} = 0.6513\) ——三位小數吻合。程式末段另由 \(x_{10} = 1.3154\) 反推噪聲 \(\epsilon \approx 0.1665\) 、分數 \(\approx -0.2063\) ——去噪標籤的具體長相。