CS236 補充課 C · 密度的流動
CS236 補充課 C · 前置數學

連續方程:粒子在流動時,密度怎麼變

Diffusion 和 flow 都在做同一件事:推動一大群粒子,讓它們的分佈慢慢改變。這一頁從「密度是什麼」開始,一步一步推導粒子的速度如何決定密度的變化,再用它算 likelihood。最後一節完整拆解 CS236 最神奇的一件事:為什麼隨機的雜訊,可以用一個確定的速度場取代。

先修:補充課 A(Taylor、score、Jacobian、散度)、B(ODE、分離變數) 服務:第 7–8、14、16、17 講 預計閱讀 2–3 小時,可以分次讀

讀完這頁你應該能夠

  1. 說明機率密度和機率的差別,以及為什麼密度可以大於 1。
  2. 區分 \(\partial_tp\)(站著看)和 \(\frac{d}{dt}p\)(跟著粒子看),並用連鎖律連起來。
  3. 用「一段區間的機率不變」推導變數變換公式 \(p_Y(y) = p_X(x)/|T'(x)|\)。
  4. 用「流進減流出」一步一步推導連續方程 \(\partial_tp = -\nabla\cdot(p\,\mathbf v)\)。
  5. 推導 \(\frac{d}{dt}\log p_t(\mathbf x_t) = -\nabla\cdot\mathbf v\),並說明它如何用來算 likelihood。
  6. 從粒子左右跳推導熱方程,並一行一行改寫成速度場 \(v = -\tfrac12\sigma^2\partial_x\log p_t\)。
  7. 解釋為什麼隨機抖動和確定性流動的路徑完全不同,每個時刻的分佈卻一模一樣。

00這一頁要回答什麼

同一件事有兩種描述方式:

  • 粒子的描述:每一顆粒子怎麼走。這是 補充課 B 的 ODE \(\frac{dx}{dt} = v(x, t)\)。
  • 分佈的描述:整群粒子的密度 \(p_t(x)\) 怎麼變。

生成模型真正在乎的是分佈:要把雜訊的分佈變成資料的分佈。但模型學的是速度場,也就是粒子的規則。所以我們需要一座橋:給定粒子的速度,密度怎麼變?答案就是連續方程。第 1–2 節準備工具,第 3–6 節推導,第 7–8 節是它在 CS236 的兩個重要應用。

01密度是什麼:機率是面積,不是高度

連續的隨機變數 \(X\) 落在某一個精確的值的機率是 0,只有落在一段區間才有意義。密度 \(p(x)\) 的定義是:

$$P(a\le X\le b) = \int_a^bp(x)\,dx$$
0.5 到 1.5面積 = 機率p(x)
機率是曲線下的面積,曲線的高度本身不是機率。

對很小的區間,面積約等於「高 × 寬」:

$$P(x\le X\le x + dx)\approx p(x)\,dx$$

所以密度的單位是「每單位長度的機率」。就像人口密度是每平方公里的人數,它不是人數本身。這也解釋了為什麼密度可以大於 1:\([0, 0.5]\) 上的均勻分佈,高度必須是 2,面積 \(2\times0.5 = 1\) 才對。

本頁最常用的畫面是粒子:丟很多顆粒子,每顆都按 \(p\) 抽樣,它們的直方圖就接近 \(p\)。粒子密的地方密度高,稀疏的地方密度低,所有粒子的總數(總機率)固定是 1。

一句話帶走:密度 × 寬度 = 機率;粒子擠在一起,密度就高。

02兩種時間導數:站著看,還是跟著走

密度現在會隨時間改變,寫成 \(p(x, t)\) 或 \(p_t(x)\),它有兩個輸入。如果問「密度變化多快」,要先說清楚你站在哪裡:

站著看 \(\partial_tp\)跟著粒子看 \(\frac{d}{dt}p(x(t), t)\)
意思固定位置 \(x\),看那裡的密度隨時間的變化坐在一顆粒子上,看腳下的密度隨時間的變化
比喻站在河邊固定一點量水溫坐在船上順流而下量水溫
算法偏導:把 \(x\) 當常數連鎖律(下面的式子)

坐在船上時,水溫改變有兩個原因:河水本身隨時間變冷,以及船漂到了水溫不同的地方。這正是多變數的連鎖律:

全導數 $$\frac{d}{dt}p(x(t), t) = \underbrace{\frac{\partial p}{\partial t}}_{\text{當地變}} + \underbrace{\frac{\partial p}{\partial x}\frac{dx}{dt}}_{\text{移動}}$$
手算

\(f(x, t) = xt\),粒子走 \(x(t) = t^2\)。直接代入:\(f = t^3\),導數 \(3t^2\)。

用公式:\(\partial_tf = x = t^2\);\(\partial_xf\cdot\frac{dx}{dt} = t\cdot2t = 2t^2\)。相加 \(3t^2\),相同。

一句話帶走:\(\partial_t\) 是站著看,\(\frac{d}{dt}\) 是跟著走;兩者差一項「移動造成的變化」。

03變數變換:同一批樣本,機率不變

從最簡單的例子開始

\(X\) 是 \([0, 1]\) 上的均勻分佈,高度 1。令 \(Y = T(X) = 2X\),\(Y\) 就落在 \([0, 2]\)。區間變成兩倍長,但總機率還是 1,所以高度必須變成 \(\tfrac12\)。

再看一小段。\(X\) 落在 \([0, 0.5]\) 的機率,等於 \(Y\) 落在 \([0, 1]\) 的機率,因為那是同一批樣本,只是被搬到新的位置。

面積 0.5高 0.5 × 寬 1面積還是 0.5高 0.25 × 寬 2T(x) = 2xxy
寬度變 2 倍,高度就變 1/2,面積(機率)不變。

一般的推導

\(T\) 是遞增函數,\(y = T(x)\)。

  1. 小區間 \([x, x + dx]\) 被送到 \([T(x), T(x + dx)]\)。由一階 Taylor,新的長度是 \(T'(x)\,dx\)。
  2. 這兩個區間的機率相同(同一批樣本): $$p_Y(y)\cdot T'(x)\,dx = p_X(x)\,dx$$
  3. 消去 \(dx\),除以 \(T'(x)\)。如果 \(T\) 遞減,長度要取絕對值,所以一般寫成:
變數變換 $$p_Y(y) = \frac{p_X(x)}{|T'(x)|},\qquad y = T(x)$$

\(|T'| > 1\) 是拉長,密度變低;\(|T'| \lt 1\) 是壓縮,密度變高。

手算

\(X\sim\mathcal N(0, 1)\),\(Y = 2X + 1\)。在 \(y = 1\)(對應 \(x = 0\)):\(T' = 2\),所以 \(p_Y(1) = p_X(0)/2\)\(\ = 0.1995\)。對照 \(\mathcal N(1, 4)\) 的峰高 \(\frac{1}{2\sqrt{2\pi}} = 0.1995\),相同。

多維時,把長度的倍數換成面積(體積)的倍數,也就是 補充課 A 第 5 節的 \(|\det J|\):

$$p_Y(T(\mathbf x)) = \frac{p_X(\mathbf x)}{|\det J_T(\mathbf x)|}$$

取 log 後除法變減法:\(\log p_Y = \log p_X - \log|\det J_T|\)。連續做很多層變換,就是一層一層減,這正是第 7–8 講 normalizing flow 的 \(\sum\log|\det J|\)。

Demo C1 · 每一條色帶的面積都是 10%

怎麼看:左圖把 \(p_X\) 切成 10 塊機率各 10% 的色帶,右圖看每一塊被 \(T\) 送到哪裡。寬度變了,高度就反過來變,面積不變。把 \(a\) 拉大,\(T'\) 小的地方被壓縮得很厲害,那裡的密度衝得很高。
p_X:標準常態,切成 10 等份
p_Y:Y = T(X) = X + a·sin(2X)
一句話帶走:變換只是搬動樣本,每一段的機率不變,所以寬度放大幾倍,密度就縮小幾倍。
小練習:\(X\) 是 \([0, 1]\) 上的均勻分佈,\(Y = X/4\)。\(Y\) 的密度是多少?
\(T' = 1/4\),所以 \(p_Y = 1/(1/4) = 4\),在 \([0, 1/4]\) 上。面積 \(4\times\frac14 = 1\) ✓。密度大於 1 沒有問題。
在 CS236 哪裡用到:第 7 講的一維、多維變數變換;第 8 講的 coupling flow。

04粒子在流,密度跟著變

現在把「一次變換」換成「連續地流動」。每顆粒子照 ODE \(\frac{dx}{dt} = v(x, t)\) 走(補充課 B)。從 \(x_0\) 出發、走到時間 \(t\) 的位置記作 \(\Phi_t(x_0)\)。\(\Phi_t\) 本身就是一個變換,所以變數變換公式照樣適用:

$$p_t(y) = p_0(x_0)\,\Big|\frac{\partial\Phi_t}{\partial x_0}\Big|^{-1}$$

其中 \(y = \Phi_t(x_0)\)。

手算

\(v(x) = -x\),粒子往 0 收縮。由 B 第 3 節,\(\Phi_t(x_0) = x_0e^{-t}\),所以 \(\frac{\partial\Phi_t}{\partial x_0} = e^{-t}\)。代入:

$$p_t(y) = p_0(ye^{t})\,e^{t}$$

如果 \(p_0 = \mathcal N(0, 1)\),所有粒子都乘上 \(e^{-t}\),所以 \(p_t = \mathcal N(0, e^{-2t})\):標準差照 \(e^{-t}\) 變窄,峰照 \(e^{t}\) 變高。

這裡已經可以算出任何時刻的密度,但要先解出整段 \(\Phi_t\),而且公式沒有直接告訴我們「當下」的變化。下一節換一個角度,直接寫出密度的變化率。

Demo C2 · 6,000 顆粒子的直方圖 vs. 用變數變換算出的精確密度

怎麼看:藍色長條是真的模擬 6,000 顆粒子,橙色曲線是變數變換公式。兩者重合。按播放,切換速度場:
  • 收縮:上面手算的例子,分佈保持高斯、持續變窄。
  • 分岔:\(x = 0\) 處速度為 0,但左右兩邊把粒子推離 0、推向 \(\pm1\)(下圖綠線在 0 附近是正斜率)。單峰被撕成兩峰,0 附近幾乎被清空。
不論怎麼流,讀數裡的總機率都是 1.000:粒子不會憑空出現或消失。
粒子直方圖精確密度 p_t(變數變換)p₀下圖:速度 v(x)
一句話帶走:流動到時間 \(t\) 也是一次變換,所以密度由變數變換決定。

05連續方程:一個盒子的帳本

通量:每單位時間穿過一點的量

先想高速公路。某路段的車輛密度是每公里 20 輛,車速每小時 60 公里。一小時內穿過某個收費站的車,就是收費站後方 60 公里內的那些車,共 \(20\times60 = 1200\) 輛。這個「每單位時間穿過的量」叫通量(flux):

通量 $$J(x) = p(x)\,v(x)$$

也就是密度 × 速度。

粒子的機率也一樣。\(J > 0\) 是往右流,\(J \lt 0\) 是往左流。

盒子的帳本

站在固定的位置,取一段 \([a, b]\) 當作盒子。粒子不會憑空出現或消失,所以盒子裡的質量只會因為邊界的進出而改變:

J(a)J(b)盒子裡的質量∫ p dxab
從左邊流進來 \(J(a)\),從右邊流出去 \(J(b)\)。
$$\frac{d}{dt}\int_a^bp\,dx = J(a) - J(b)$$
手算

一段 2 公里的路,入口每小時進來 1200 輛,出口每小時離開 1500 輛。路段裡每小時少 300 輛,平均密度每小時下降 \(300/2 = 150\) 輛/公里。

注意:重要的是通量的差,不是通量本身。如果進出都是 1500,車再多、開再快,密度也不變。

讓盒子縮成一點

  1. 盒子很小時,左邊的積分約是「高 × 寬」,所以把 \(b - a\) 記成 \(\Delta x\): $$\frac{\partial p}{\partial t}\,\Delta x\approx J(a) - J(a + \Delta x)$$
  2. 兩邊除以 \(\Delta x\): $$\frac{\partial p}{\partial t}\approx-\frac{J(a + \Delta x) - J(a)}{\Delta x}$$
  3. 右邊正是導數的定義。\(\Delta x\to0\),再代入 \(J = pv\):
連續方程 $$\frac{\partial p}{\partial t} = -\frac{\partial}{\partial x}\big(p\,v\big)$$

多維:\(\dfrac{\partial p}{\partial t} = -\nabla\cdot\big(p\,\mathbf v\big)\)

負號的意思:通量往右遞增的地方(流出比流入多),密度下降。多維時把盒子換成小方塊,每個方向都做一次,就是 補充課 A 第 6 節的散度,只是流動的東西從「面積」換成了「\(p\mathbf v\)」。這種含偏導數的方程叫 PDE,未知函數是整片密度 \(p(x, t)\)。

兩個驗算

手算一:整體平移

\(v = c\) 是常數,分佈整體往右平移:\(p_t(x) = p_0(x - ct)\)。左邊:\(\partial_tp = -c\,p_0'\)。右邊:\(-\partial_x(cp) = -c\,p_0'\)。相等 ✓。雖然速度不是 0,但處處相同,所以形狀不變。

手算二:第 4 節的收縮流

\(v = -x\),\(p_t(x) = e^{t}\varphi(xe^{t})\),\(\varphi\) 是標準常態密度。

左邊(乘積法則+連鎖律):\(\partial_tp = e^{t}\varphi + e^{2t}x\,\varphi'\)。

右邊:\(-\partial_x(-xp) = p + x\,\partial_xp\),代入後也是 \(e^{t}\varphi + e^{2t}x\,\varphi'\)。相等 ✓。

Demo C3 · 盒子的進出帳(分岔流 v = x − x³)

怎麼看:拖動盒子的位置和時間。讀數比較兩個數字:用邊界通量算出的 \(J(a) - J(b)\),和把盒子裡的質量在 \(t\pm0.005\) 各算一次再相減得到的變化率。兩者一致(差距在千分之幾以內,來自數值計算),就是連續方程。
密度 p_t通量 J = p·v(虛線)盒子與邊界上的流量箭頭
另一種推導:從變數變換公式取極限

把 ODE 用 Euler 走一小步:\(\mathbf x_{t+\Delta t} = \mathbf x_t + \Delta t\,\mathbf v(\mathbf x_t)\)。這是一個變換,它的 Jacobian 是 \(I + \Delta t\,\partial\mathbf v/\partial\mathbf x\),行列式是 \(1 + \Delta t\,\nabla\cdot\mathbf v + O(\Delta t^2)\)(補充課 A §6)。代入變數變換公式、取 log:

$$\begin{aligned}&\log p_{t+\Delta t}(\mathbf x_{t+\Delta t})\\={}&\log p_t(\mathbf x_t) - \Delta t\,\nabla\cdot\mathbf v(\mathbf x_t) + O(\Delta t^2)\end{aligned}$$

這就是第 6 節的「沿著軌跡」公式。再把左邊用 Taylor 展開,整理後就得到連續方程。

出處:Lai et al. (2026) 附錄 B.1.2「Continuous-Time Limit: Continuity Equation」(就是這個推導),附錄 B.2 從守恆律推導(本節的盒子帳本);Holderrieth & Erives (2026) 第 3 章 Theorem「Continuity Equation」。

一句話帶走:盒子裡的質量只因進出而變,所以密度的變化率等於通量的負導數:\(\partial_tp = -\partial_x(pv)\)。
小練習:\(p = 0.5\)(常數)、\(v(x) = x\)。此刻 \(\partial_tp\) 是多少?為什麼密度會下降?
\(\partial_tp = -\partial_x(0.5x) = -0.5\)。越往右速度越快,右邊流出的比左邊流入的多,粒子被拉開,密度處處下降。

06跟著粒子看:密度沿著軌跡怎麼變

連續方程是站著看。現在用第 2 節的工具,換成坐在粒子上看。這個公式是下一節算 likelihood 的基礎。

  1. 用乘積法則展開連續方程的右邊: $$\frac{\partial p}{\partial t} = -\frac{\partial(pv)}{\partial x} = -v\frac{\partial p}{\partial x} - p\frac{\partial v}{\partial x}$$
  2. 把 \(v\,\partial_xp\) 移到左邊: $$\frac{\partial p}{\partial t} + v\frac{\partial p}{\partial x} = -p\frac{\partial v}{\partial x}$$
  3. 粒子的速度就是 \(\frac{dx}{dt} = v\),所以左邊正是第 2 節的全導數 \(\frac{d}{dt}p(x(t), t)\): $$\frac{d}{dt}p_t(x_t) = -p_t(x_t)\,\frac{\partial v}{\partial x}$$
  4. 兩邊除以 \(p\)。由連鎖律 \(\frac{1}{p}\frac{dp}{dt} = \frac{d}{dt}\log p\):
沿著軌跡的 log 密度 $$\frac{d}{dt}\log p_t(\mathbf x_t) = -\nabla\cdot\mathbf v(\mathbf x_t, t)$$

白話:粒子腳下的 log 密度,以「當地散度」的速率下降。周圍被撐開(散度 > 0)時,同樣的機率分散到更大的區域,密度變低;被擠壓時密度變高。

這和補充課 A 第 6 節的結論是同一件事:跟著流動的小區域,面積的 log 以 \(\nabla\cdot\mathbf v\) 的速率增加。而面積 × 密度 = 機率不變,所以兩者的 log 變化率剛好相反。

手算

\(v = -x\):散度是 \(-1\),所以 \(\log p\) 每單位時間增加 1。對照第 4 節:粒子從 \(x_0\) 走到 \(x_0e^{-t}\),腳下的密度是 \(p_t(x_0e^{-t}) = e^{t}\varphi(x_0)\),取 log 得 \(t + \log\varphi(x_0)\),確實以速率 1 增加。

Demo C4 · 五個小方塊在非線性流裡被拉扯

怎麼看:背景顏色是散度(橙色撐開、藍色擠壓),方塊跟著流動變形。讀數比較兩個數字:方塊面積的 log 變化(直接量多邊形面積),和沿著中心軌跡積分的散度 \(\int_0^T\nabla\cdot\mathbf v\,dt\)。方塊越小,兩者越一致。速度場是 \(\mathbf v = (0.9\sin1.3x - 0.4y,\ 0.4x + 0.9\sin1.3y)\),散度 \(1.17(\cos1.3x + \cos1.3y)\) 隨位置改變。
背景:散度 > 0(撐開)散度 < 0(擠壓)方塊與中心的軌跡
一句話帶走:沿著軌跡,\(\log p\) 的變化率就是負的散度。
小練習:\(v(x) = 2x\),粒子腳下的 \(\log p\) 變化率是多少?經過時間 1,密度變成幾倍?
\(-\partial_xv = -2\)。\(\log p\) 減少 2,所以密度乘上 \(e^{-2}\approx0.135\)。

07用 ODE 算 likelihood:CNF 與 probability flow ODE

為什麼需要它

生成模型想知道:這筆資料在模型下的機率密度是多少?如果模型是一個 ODE,把雜訊推成資料,上一節的公式就能算出來。

做法

把上一節的公式從 \(0\) 積到 \(T\)。左邊變成 \(\log p_T(\mathbf x_T) - \log p_0(\mathbf x_0)\),移項:

精確的 log-likelihood $$\begin{aligned}\log p_0(\mathbf x_0) ={}&\log p_T(\mathbf x_T)\\&+ \int_0^T\nabla\cdot\mathbf v(\mathbf x_t, t)\,dt\end{aligned}$$
  1. 從資料點 \(\mathbf x_0\) 出發,用數值方法把 ODE 解到 \(T\)。
  2. 一路把散度加起來,得到積分。
  3. 終點 \(\mathbf x_T\) 的分佈是簡單的高斯,\(\log p_T(\mathbf x_T)\) 可以直接算。
  4. 兩者相加。

這叫 continuous normalizing flow(CNF)。它和第 7–8 講的離散 flow 是同一個想法:

離散 flow連續 flow(CNF)
變換一層一層的 \(T_k\)解一個 ODE
密度的改變\(\sum\log|\det J_k|\)\(\int\nabla\cdot\mathbf v\,dt\)
要算什麼行列式trace
計算量一般 \(O(d^3)\),所以要設計三角 Jacobian\(O(d^2)\);Hutchinson 估計只要一次反向傳播,\(O(d)\)

行列式變成 trace 的原因見補充課 A 第 6 節。Hutchinson 估計是 \(\nabla\cdot\mathbf v\approx\boldsymbol\epsilon^\top\frac{\partial\mathbf v}{\partial\mathbf x}\boldsymbol\epsilon\)(第 12 講;推導在補充課 A 第 7 節的補充框)。

第 14、17 講用 diffusion model 算 likelihood(CIFAR-10 上 2.83 bits/dim)就是這樣做的:probability flow ODE 的速度場是 \(\mathbf v = \mathbf f - \tfrac12g^2\nabla\log p_t\),用學到的 score 代入。這個速度場從哪裡來,就是下一節的主題。

Demo C5 · 一維 probability flow ODE:累積散度得到精確的 log p

怎麼看:資料是兩個高斯的混合,\(t = 0\) 時幾乎沒有雜訊,\(t = 1\) 時加了標準差 3 的雜訊。這裡用的是完美的 score,讀數的誤差只來自 ODE 的數值解。拖動 \(x_0\):
  • 軌跡合併成一個寬的高斯,而且彼此不交叉(補充課 B §6)。
  • 選在峰頂(例如 \(x_0 = 0.9\)):峰被抹平時,附近的粒子被撐開,\(\int\nabla\cdot\mathbf v\,dt\approx+1.64\),所以 \(\log p_0\) 比 \(\log p_1\) 高:資料在那裡很密。
  • 選在兩峰之間(例如 \(x_0 = -0.6\)):低谷正在被填平,粒子被擠在一起,積分約 \(-1.98\),\(\log p_0\) 比 \(\log p_1\) 低:資料在那裡很稀少。
p_t(x)(越深越高)從資料分位數出發的軌跡你選的 x₀ 的軌跡下圖:散度與累積積分
一句話帶走:解 ODE,一路把散度加起來,再加上終點的 \(\log p_T\),就是資料點的精確 log-likelihood。

08加上雜訊:擴散也可以寫成一個速度場

這一節是本頁最重要、也最不直覺的部分。到目前為止粒子都是確定地流動。但 diffusion 是在加隨機雜訊,每顆粒子都亂抖。我們要證明一件神奇的事:

本節的結論

隨機抖動對整體分佈造成的效果,和一個確定的速度場 \(v = -\tfrac12\sigma^2\partial_x\log p_t\) 完全相同。

這就是 probability flow ODE 的由來,也是 diffusion model 能變成 flow 的原因。我們分八步走,每一步都可以驗證。

第一步:粒子左右跳,尖峰被抹平

把雜訊簡化到最單純的情況:位置是等間隔的格點,每過一小段時間,每顆粒子都有一半機率往左跳一格、一半機率往右跳一格。從 1000 顆粒子都在中間開始:

開始10001 步5005002 步2505002503 步125375375125
每一格的粒子,下一步平分給左右鄰居。沒有任何粒子知道該往哪裡走,但整體一定會散開。

某一格下一步的粒子數,來自左右兩格各一半:

$$N_i^{\text{新}} = \tfrac12N_{i-1} + \tfrac12N_{i+1}$$

也就是說,每一格的新值是左右鄰居的平均。尖峰的鄰居比較低,所以尖峰會下降;低谷的鄰居比較高,所以低谷會上升。這就是雜訊抹平分佈的機制。

谷底 p″ > 0兩邊比中間高中間變高峰頂 p″ < 0兩邊比中間低中間變低直線 p″ = 0中間等於兩邊平均不變
中間比兩邊低時,下一步會變高;比兩邊高時,下一步會變低。如果三點成一直線,中間剛好是兩邊的平均,所以不變。這個差距正是二階導數。

Demo C6 · 粒子左右跳

怎麼看:長條是精確的粒子比例(每步都用上面的公式更新),黑線是第三步要驗算的高斯(只在單峰時畫)。拖動步數,看讀數裡的變異數是不是剛好等於步數。切到雙峰:兩個峰慢慢併成一個,中間的低谷被填平。
粒子比例高斯 N(0, n)

第二步:從跳動推出方程(熱方程)

把格點間距記成 \(\Delta\),時間步記成 \(\Delta t\),粒子數換成密度。上面的規則就是:

$$\begin{aligned}&p(x, t + \Delta t)\\={}&\tfrac12p(x - \Delta, t) + \tfrac12p(x + \Delta, t)\end{aligned}$$

右邊用二階 Taylor 展開:

$$\begin{aligned}&p(x\pm\Delta)\\={}&p\pm\Delta\,\partial_xp + \tfrac12\Delta^2\,\partial_x^2p + \cdots\end{aligned}$$

正負兩式取平均,一階項互相抵銷,只剩:

$$\begin{aligned}&\tfrac12p(x - \Delta) + \tfrac12p(x + \Delta)\\={}&p + \tfrac12\Delta^2\,\partial_x^2p\end{aligned}$$

左邊展開成 \(p + \Delta t\,\partial_tp\),兩邊消去 \(p\),再除以 \(\Delta t\):

$$\frac{\partial p}{\partial t} = \frac{\Delta^2}{2\Delta t}\,\frac{\partial^2p}{\partial x^2}$$

要讓它在 \(\Delta t\to0\) 時有意義,\(\Delta^2/\Delta t\) 必須維持固定,記成 \(\sigma^2\)。也就是每步跳 \(\Delta = \sigma\sqrt{\Delta t}\)。這就是補充課 A 第 8 節的 \(\sqrt{\Delta t}\),也就是布朗運動(補充課 E),寫成 \(dx = \sigma\,dW\)。於是得到:

熱方程(擴散方程) $$\frac{\partial p}{\partial t} = \frac{\sigma^2}{2}\,\frac{\partial^2p}{\partial x^2}$$

第三步:驗算一個解

取 \(\sigma = 1\)。從原點出發走了時間 \(t\),獨立的抖動相加,變異數是 \(t\),所以應該是 \(p = \mathcal N(0, t)\):

$$p(x, t) = \frac{1}{\sqrt{2\pi t}}\,e^{-x^2/(2t)}$$

代入熱方程驗算。對 \(t\) 微分(乘積法則,兩個部分都有 \(t\)):

$$\frac{\partial p}{\partial t} = p\cdot\Big(-\frac{1}{2t} + \frac{x^2}{2t^2}\Big)$$

對 \(x\) 微分兩次:\(\partial_xp = -\frac xt\,p\),再微分一次:

$$\frac{\partial^2p}{\partial x^2} = p\cdot\Big(-\frac1t + \frac{x^2}{t^2}\Big)$$

乘上 \(\tfrac12\),正好等於 \(\partial_tp\) ✓。

第四步:回憶 score

接下來的關鍵只是一個恆等式。score 是 \(\partial_x\log p\),由連鎖律 \(\partial_x\log p = \frac{\partial_xp}{p}\),移項:

關鍵恆等式 $$\partial_xp = p\cdot\partial_x\log p$$

它只是把導數換個寫法,沒有任何近似。例如上面的高斯:score 是 \(-x/t\),而 \(\partial_xp = -\frac xt\,p\),確實相同。

第五步:一行一行改寫

目標是把熱方程改寫成連續方程 \(\partial_tp = -\partial_x(pv)\) 的樣子。我們從右邊開始。

  1. 二階導數就是「導數的導數」,常數放進去: $$\frac{\sigma^2}{2}\partial_x^2p = \partial_x\Big(\frac{\sigma^2}{2}\,\partial_xp\Big)$$
  2. 用第四步的恆等式,把括號裡的 \(\partial_xp\) 換掉: $$= \partial_x\Big(\frac{\sigma^2}{2}\,p\,\partial_x\log p\Big)$$
  3. 提出一個負號,並把 \(p\) 單獨放在前面: $$= -\partial_x\Big(p\cdot\Big[-\frac{\sigma^2}{2}\,\partial_x\log p\Big]\Big)$$
  4. 方括號裡的東西取名叫 \(v\),就完全是連續方程的形式:
雜訊的等效速度場 $$\begin{aligned}\frac{\partial p}{\partial t} &= -\partial_x(p\,v)\\v(x, t) &= -\frac{\sigma^2}{2}\,\partial_x\log p_t(x)\end{aligned}$$

現在邏輯很清楚了:

  • 隨機抖動的粒子,密度滿足熱方程。
  • 照速度 \(v\) 確定流動的粒子,密度滿足連續方程(第 5 節)。
  • 上面剛證明這是同一條方程。方程相同、起始的 \(p_0\) 相同,答案就相同。

方向也很合理。score 指向高密度,前面的負號讓 \(v\) 從高密度指向低密度,正好模仿「擴散把尖峰抹平」。而且 score 是相對的變化(\(p'/p\)),所以密度很低的地方,只要坡度是相對陡的,粒子也跑得很快。

橙色箭頭:v = −½·score,從高密度往低密度推
雙峰分佈上的速度場。每個峰的兩側都被往外推,峰頂的速度接近 0。兩峰正中間的速度也是 0,但左右的粒子都往那裡推,所以低谷被填平。

Demo C7 · 這個速度場真的滿足方程嗎

怎麼看:上圖是一個雙峰分佈被擴散抹平的 \(p_t\),下圖是 score 和速度 \(v = -\tfrac12\text{score}\)。拖動位置 \(x\),讀數比較兩個獨立算出的數字:\(\partial_tp\)(直接對時間微分)和 \(-\partial_x(pv)\)(用速度場算)。它們永遠相等。也請注意:峰頂的速度幾乎是 0,但密度一直在下降,因為決定密度變化的是通量的斜率,不是速度本身。
p_t(x)scorev = −½·score

第六步:高斯的例子,完全解出來

回到 \(\sigma = 1\) 的 \(p_t = \mathcal N(0, t)\)。score 是 \(-x/t\),所以

$$v(x, t) = -\tfrac12\cdot\Big(-\frac xt\Big) = \frac{x}{2t}$$

粒子照 \(\frac{dx}{dt} = \frac{x}{2t}\) 走。這個 ODE 可以分離變數(補充課 B 第 3 節):

$$\begin{aligned}\frac1x\frac{dx}{dt} &= \frac{1}{2t}\\\ln x &= \tfrac12\ln t + C\\x(t) &= x(t_0)\sqrt{\frac{t}{t_0}}\end{aligned}$$

每顆粒子的位置都乘上同一個倍數 \(\sqrt{t/t_0}\)。例如 \(t_0 = 1\),在 \(x = 1\) 的粒子,到 \(t = 4\) 走到 \(x = 2\)。

驗證分佈:\(t_0\) 時粒子是 \(\mathcal N(0, t_0)\),全部乘上 \(\sqrt{t/t_0}\),變異數變成 \(t_0\cdot\frac{t}{t_0} = t\),也就是 \(\mathcal N(0, t)\)。和真正隨機抖動得到的分佈完全相同 ✓。

第七步:為什麼路徑不同,直方圖卻一樣

綠:x = x₀√t橙:隨機抖動t = 1t = 4
綠色是上面解出的確定性路徑,平滑地散開,永遠不交叉。橙色是隨機抖動的路徑,彎彎曲曲,互相交叉。

想像一條街上的人群,有兩種散開的方式。一種是每個人都亂走,人群自然散開。另一種是每個人都照規定平順地往外走,靠外的走快一點。如果規定設計得剛好,從空中拍下任何一個時刻的照片,兩者的人群分佈都一模一樣,雖然每個人走過的路線完全不同。

隨機抖動probability flow ODE
每個時刻的分佈 \(p_t\)完全相同
單一粒子的路徑彎曲、會交叉平滑、不交叉
從同一點出發每次走到不同地方永遠走到同一個地方
可以用來取樣(DDPM)取樣(DDIM)、算 likelihood

相同的只有「每個時刻單獨的分佈」。像「\(x_0\) 和 \(x_t\) 的關係」這種跨時間的性質並不相同:ODE 裡 \(x_t\) 完全由 \(x_0\) 決定,抖動就不是。

Demo C8 · 隨機抖動 vs. 確定性的 probability flow:同樣的直方圖、不同的路徑

怎麼看:左圖是兩種粒子各 3,000 顆的直方圖,黑線是精確的 \(p_t\)。三者重合,讀數裡的平均和標準差也非常接近(樣本有限,所以不會完全相等)。右圖是 12 條路徑:橙色亂抖,綠色平滑。
時間 t 的直方圖(各 3,000 顆)
12 條路徑:x(縱軸)對 t(橫軸)
隨機抖動 dx = dW確定性流動 dx/dt = −½ ∂ₓlog p_t精確的 p_t

第八步:一般情況,就是 probability flow ODE

如果粒子本身還有一個速度 \(f\),再加上強度 \(g\) 的雜訊(這叫 SDE,補充課 E),密度的方程就是兩項相加(補充課 F 會完整推導):

$$\partial_tp = -\partial_x(fp) + \frac{g^2}{2}\partial_x^2p$$

第二項用第五步的方法改寫,兩項就能合併成一個連續方程:

probability flow ODE $$\frac{d\mathbf x}{dt} = \mathbf f - \frac12g^2\nabla\log p_t(\mathbf x)$$

這就是第 14 講的公式,係數 \(\tfrac12\) 來自熱方程的 \(\frac{\sigma^2}{2}\)。Diffusion model 學的 score,代入這裡就得到一個可以解的 ODE,第 7 節的 likelihood 計算也就成立了。

一句話帶走:雜訊讓密度滿足熱方程,而用 \(\partial_xp = p\,\partial_x\log p\) 可以把熱方程改寫成連續方程,所以抖動的效果等同於速度場 \(-\tfrac12\sigma^2\nabla\log p_t\)。
小練習:\(\sigma = 1\),\(p_t = \mathcal N(0, t)\)。在 \(t = 2\)、\(x = 3\) 的粒子,速度是多少?方向是往外還是往內?
\(v = \frac{x}{2t} = \frac{3}{4} = 0.75\),正的,往外(遠離峰)。
在 CS236 哪裡用到:第 14 講「為什麼 ODE 的係數是 ½」;第 16 講 §8;第 17 講「ODE 和 SDE 的邊際相同」;DDIM 就是在解這個 ODE。

09在 CS236 哪裡用到

本頁的概念出現的地方
變數變換 = 質量守恆第 7 講的一維、多維變數變換;第 8 講的 coupling flow
\(\sum\log|\det J|\to\int\nabla\cdot\mathbf v\,dt\)第 7–8 講的離散 flow 與 CNF 的對應;第 14 講「likelihood 要積分 Jacobian 的 trace,而不是 determinant」
沿軌跡的 log p第 14 講 Demo C、第 17 講 §2:用 probability flow ODE 算精確 likelihood
Hutchinson trace 估計第 12 講 Demo B;高維時估計 \(\nabla\cdot\mathbf v\)
擴散 = 速度場 \(-\tfrac12g^2\nabla\log p\)第 14 講「為什麼 ODE 的係數是 ½」、第 16 講 §8、第 17 講「ODE 和 SDE 的邊際相同」;補充課 F

常見誤解

誤解:「粒子跑得快的地方密度就低」。決定密度變化的不是速度本身,而是通量的變化。整群粒子一起等速平移,密度形狀完全不變。
誤解:「速度為 0 的點,密度不會變」。Demo C2 的分岔流在 \(x = 0\) 速度為 0,但散度是正的(左右兩邊往外推),那裡的密度一直下降。Demo C7 的峰頂也是如此。
誤解:「probability flow ODE 的路徑就是 SDE 粒子的平均路徑」。兩者只是每個時刻的分佈相同,個別的路徑完全不同(Demo C8)。ODE 的粒子不會交叉,SDE 的粒子會。
誤解:「密度不能大於 1」。不能大於 1 的是機率。密度乘上寬度才是機率,高度可以任意大。
誤解:「CNF 要算行列式」。連續時間只需要 trace(散度),這正是 CNF 比離散 flow 自由的地方:速度場可以是任意的神經網路,不必設計成三角 Jacobian。

自我測驗

1. \(Y = 2X\),\(X\sim\mathcal N(0,1)\)。\(p_Y(0)\) 是 \(p_X(0)\) 的幾倍?用「區間的質量不變」解釋。
\(1/2\) 倍。\([0, dx]\) 被拉成 \([0, 2dx]\),同樣的機率分到兩倍長的區間,密度減半。
2. 寫出一維連續方程。通量是什麼?
\(\partial_tp = -\partial_x(pv)\);通量 \(J = pv\),單位時間通過某一點的機率。
3. 用 ODE 算 \(\log p_0(\mathbf x_0)\),需要知道哪兩樣東西?
終點的 \(\log p_T(\mathbf x_T)\)(通常是標準高斯,容易算),以及沿軌跡的 \(\int_0^T\nabla\cdot\mathbf v\,dt\)。
4. 粒子每步以各半機率跳 \(\pm\Delta\),時間步 \(\Delta t\)。為什麼 \(\Delta\) 要正比於 \(\sqrt{\Delta t}\)?
第二步的推導中,擴散係數是 \(\Delta^2/(2\Delta t)\)。要在 \(\Delta t\to0\) 時維持固定,\(\Delta^2\) 必須正比於 \(\Delta t\)。
5. 熱方程 \(\partial_tp = \tfrac12\partial_x^2p\) 等價於哪一個速度場的連續方程?它把粒子往哪裡推?
\(v = -\tfrac12\partial_x\log p_t\):沿 score 的反方向,從高密度往低密度推,模仿擴散把尖峰抹平。
6. 既然 ODE 和抖動的分佈相同,為什麼用 ODE 走的粒子不會交叉,抖動的粒子會?
ODE 的解唯一,同一時刻不會有兩顆粒子在同一位置(補充課 B 第 6 節)。兩者相同的只有每個時刻的分佈,個別路徑沒有任何要求。

延伸閱讀

  • Lai et al. (2026) 附錄 B:從變數變換到連續方程(B.1.1–B.1.2)、Fokker–Planck(B.1.3)、連續方程的物理直覺與守恆律推導(B.2)。
  • Holderrieth & Erives (2026) 第 3 章:Continuity Equation 定理與它在 flow matching 的用途;附錄有 Fokker–Planck 的完整證明。
  • Grathwohl et al. (2019), FFJORD:CNF 加上 Hutchinson trace 估計。
  • Song et al. (2021) 附錄 D:probability flow ODE 的推導與 likelihood 計算。