剖析擴散模型(Denoising Diffusion Probabilistic Models)

文章目錄

  • 1. 前言
  • 2. 前向擴散過程(Forward Diffusion)
  • 3. 反向生成過程(Reverse Process)
  • 4. 訓練和推理過程中的偽代碼
  • 5. 訓練過程代碼實現(Training)
    • 5.1 時間嵌入模塊——TimeEmbedding
    • 5.2 前向擴散過程——GaussianDiffusionTrainer
  • 6. 推理過程代碼實現(Sampling)

1. 前言

??擴散模型參考的論文:Denoising Diffusion Probabilistic Models。擴散模型(Denoising Diffusion Probabilistic Models, DDPM)是一種生成模型,它通過學習逆轉一個逐步向數據中添加噪聲的過程來生成新數據。這種方法受到了非平衡熱力學的啟發,其中系統從有序狀態逐漸過渡到無序狀態(即增加了噪聲)。DDPM的目標是學習如何逆轉這個過程,從而從完全隨機的狀態恢復出有意義的數據。擴散模型的基本思想是:通過添加噪聲將原始數據逐步擾亂成高斯分布(前向擴散過程),然后學習如何逐步去噪恢復原始數據(反向生成過程)

補充知識(重參數采樣(參數重整化))

  1. 如果隨機變量 X \mathbf{X} X 服從均值為 μ \mu μ,方差為 σ 2 \sigma^2 σ2 的高斯分布(正態分布),即 X ~ N ( μ , σ 2 ) \mathbf{X} \sim \mathcal{N}(\mu, \sigma^2) XN(μ,σ2)。對隨機變量 X \mathbf{X} X 進行標準化的步驟為: X ? μ σ = Z ~ N ( 0 , 1 ) \frac{\mathbf{X} - \mu}{\sigma} = \mathbf{Z} \sim \mathcal{N}(0, 1) σX?μ?=ZN(0,1),這里的 Z \mathbf{Z} Z 是一個新的隨機變量,隨機變量 Z \mathbf{Z} Z 服從均值為0,方差為1的標準正態分布。 X ? μ \mathbf{X} - \mu X?μ 表示將原分布中心平移到原點(去中心化),除以 σ \sigma σ 表示將尺度標準化為單位標準差。

  2. 我們先從標準正態分布 Z ~ N ( 0 , 1 ) \mathbf{Z} \sim \mathcal{N}(0, 1) ZN(0,1) 進行采樣,經過線性變換 X = μ + σ ? Z \mathbf{X}=\mu+\sigma\cdot \mathbf{Z} X=μ+σ?Z 得到的數據分布,等價于直接從均值為 μ \mu μ,方差為 σ 2 \sigma^2 σ2 的正態分布 X ~ N ( μ , σ 2 ) \mathbf{X} \sim \mathcal{N}(\mu, \sigma^2) XN(μ,σ2) 中進行采樣。下面給出具體推導和驗證:
    (1)標準正態分布的性質: Z ~ N ( 0 , 1 ) \mathbf{Z} \sim \mathcal{N}(0, 1) ZN(0,1),即均值為 0,方差為 1。
    (2)線性變換的均值和方差:對 Z \mathbf{Z} Z 進行線性變換 X = μ + σ ? Z \mathbf{X}=\mu+\sigma\cdot \mathbf{Z} X=μ+σ?Z,均值為: E [ X ] = E [ μ + σ ? Z ] = σ ? E [ Z ] + μ = σ ? 0 + μ = μ \mathbb{E}[\mathbf{X}] =\mathbb{E}[\mathbf{\mu+\sigma\cdot \mathbf{Z}}]= \sigma \cdot \mathbb{E}[\mathbf{Z}] + \mu = \sigma \cdot 0 + \mu = \mu E[X]=E[μ+σ?Z]=σ?E[Z]+μ=σ?0+μ=μ;方差為: D [ X ] = D [ μ + σ ? Z ] = σ 2 ? D [ Z ] = σ 2 ? 1 = σ 2 \mathbb{D}[\mathbf{X}] =\mathbb{D}[\mathbf{\mu+\sigma\cdot \mathbf{Z}}] = \sigma^2 \cdot \mathbb{D}[\mathbf{Z}] =\sigma^2 \cdot 1= \sigma^2 D[X]=D[μ+σ?Z]=σ2?D[Z]=σ2?1=σ2
    (3)正態分布的封閉性:線性變換不改變正態性,因此對 Z \mathbf{Z} Z 進行線性變換 X = μ + σ ? Z \mathbf{X}=\mu+\sigma\cdot \mathbf{Z} X=μ+σ?Z 仍服從正態分布,即 X ~ N ( μ , σ 2 ) \mathbf{X} \sim \mathcal{N}(\mu, \sigma^2) XN(μ,σ2)

2. 前向擴散過程(Forward Diffusion)

??前向加噪過程是一個固定的馬爾可夫鏈,對干凈的原始圖像數據 x 0 \mathbf{x}_0 x0? 逐步添加噪聲依次得到 x 1 , x 2 , … , x T \mathbf{x}_1, \mathbf{x}_2, \ldots,\mathbf{x}_T x1?,x2?,,xT?,直到第 T T T 步時圖像數據 x T \mathbf{x}_T xT? 接近高斯噪聲(純噪聲,完全看不出內容)。下面給出前向擴散過程中的核心數學公式
??(1)基于前一時刻( t ? 1 t-1 t?1)的圖像數據 x t ? 1 \mathbf{x}_{t-1} xt?1? 和當前時刻( t t t)加入的標準高斯噪聲 ε t ~ N ( 0 , 1 ) \pmb{\varepsilon}_{t}\sim \mathcal{N}(0, 1) εt?N(0,1),我們可獲取 t t t 時刻噪聲圖像 x t \mathbf{x}_t xt? 對應的數學表達式:
x t = 1 ? β t x t ? 1 + β t ε t ( 1 ) \mathbf{x}_t = \sqrt{1 - \beta_t} \, \mathbf{x}_{t-1} + \sqrt{\beta_t} \, \pmb{\varepsilon}_{t} \qquad \qquad (1) xt?=1?βt? ?xt?1?+βt? ?εt?(1)

??其中 β t \beta_t βt? 是在 ( 0 , 1 ) (0,1) (0,1) 之間逐步增長的噪聲強度( β t \beta_t βt? 可看作加入的高斯噪聲權重),一般來說隨著 t t t 的增大, β t \beta_t βt? 的取值就越大。圖像數據從 x t ? 1 \mathbf{x}_{t-1} xt?1? x t \mathbf{x}_{t} xt? 的加噪過程服從正態分布,如下所示:
q ( x t ∣ x t ? 1 ) = N ( x t ; 1 ? β t x t ? 1 , β t I ) ( 2 ) q(\mathbf{x}_t | \mathbf{x}_{t-1}) = \mathcal{N}(\mathbf{x}_t; \sqrt{1 - \beta_t}\mathbf{x}_{t-1}, \beta_t \mathbf{I}) \qquad \qquad (2) q(xt?xt?1?)=N(xt?;1?βt? ?xt?1?,βt?I)(2)
??其中, x t \mathbf{x}_t xt? 是以均值為 1 ? β t x t ? 1 \sqrt{1 - \beta_t}\mathbf{x}_{t-1} 1?βt? ?xt?1?,方差為 β t \beta_t βt? 的高斯分布, I \mathbf{I} I 表示單位矩陣。

??(2)任意時刻的噪聲圖像 x t \mathbf{x}_t xt? 可直接由 x 0 \mathbf{x}_0 x0? 計算(無需迭代),我們定義 α t = 1 ? β t \alpha_t=1 - \beta_t αt?=1?βt?,計算公式如下:
x t = α  ̄ t x 0 + 1 ? α  ̄ t ε t ( 3 ) \mathbf{x}_t= \sqrt{\overline{\alpha}_t} \, \mathbf{x}_0 + \sqrt{1 - \overline{\alpha}_t} \, \pmb{\varepsilon}_t \qquad \qquad (3) xt?=αt? ?x0?+1?αt? ?εt?(3)

??其中, α ˉ t = ∏ s = 1 t ( 1 ? β s ) = ( 1 ? β 1 ) ? ( 1 ? β 2 ) … ( 1 ? β t ) = α 1 ? α 2 … α t \bar{\alpha}_t = \prod_{s=1}^{t}(1 - \beta_s)=(1 - \beta_1)\cdot(1 - \beta_2)\ldots(1 - \beta_t)=\alpha_1 \cdot \alpha_2 \ldots \alpha_t αˉt?=s=1t?(1?βs?)=(1?β1?)?(1?β2?)(1?βt?)=α1??α2?αt?。圖像數據從 x 0 \mathbf{x}_{0} x0? x t \mathbf{x}_{t} xt? 的加噪過程服從正態分布,如下所示:
q ( x t ∣ x 0 ) = N ( x t ; α ˉ t x 0 , ( 1 ? α ˉ t ) I ) ( 4 ) q(\mathbf{x}_t \mid \mathbf{x}_0) = \mathcal{N}(\mathbf{x}_t; \sqrt{\bar{\alpha}_t}\mathbf{x}_0, (1 - \bar{\alpha}_t)\mathbf{I}) \qquad \qquad (4) q(xt?x0?)=N(xt?;αˉt? ?x0?,(1?αˉt?)I)(4)

??其中, x t \mathbf{x}_t xt? 是以均值為 α ˉ t x 0 \sqrt{\bar{\alpha}_t}\mathbf{x}_0 αˉt? ?x0?,方差為 ( 1 ? α ˉ t ) (1 - \bar{\alpha}_t) (1?αˉt?) 的高斯分布, I \mathbf{I} I 表示單位矩陣。

3. 反向生成過程(Reverse Process)

??這個過程是一個可學習的馬爾可夫鏈,目標是從純高斯噪聲 x T \mathbf{x}_T xT? 開始一步步去噪直到生成清晰的圖像。反向去噪的核心數學公式定義為:
x t ? 1 = 1 α t ( x t ? 1 ? α t 1 ? α  ̄ t ε θ ( x t , t ) ) + σ t z ( 5 ) \mathbf{x}_{t-1} = \frac{1}{\sqrt{\alpha_t}} \left( \mathbf{x}_t - \frac{1 - \alpha_t}{\sqrt{1 - \overline{\alpha}_t}} \, \pmb{\varepsilon}_\theta(\mathbf{x}_t, t) \right) + \sigma_t \mathbf{z} \qquad \qquad (5) xt?1?=αt? ?1?(xt??1?αt? ?1?αt??εθ?(xt?,t))+σt?z(5)

??其中, ε θ ( x t , t ) \pmb{\varepsilon}_\theta(\mathbf{x}_t, t) εθ?(xt?,t) 是 UNet網絡輸出的預測噪聲; σ t = β t ? 1 ? α ˉ t ? 1 1 ? α ˉ t \sigma_t=\sqrt{\beta_t \cdot \frac{1 - \bar{\alpha}_{t-1}}{1 - \bar{\alpha}_t}} σt?=βt??1?αˉt?1?αˉt?1?? ? z \mathbf{z} z 是標準高斯噪聲 z ~ N ( 0 , 1 ) \mathbf{z}\sim \mathcal{N}(0, 1) zN(0,1)。高斯噪聲數據從 x t \mathbf{x}_{t} xt? x t ? 1 \mathbf{x}_{t-1} xt?1? 的去噪過程服從正態分布,如下所示:
p θ ( x t ? 1 ∣ x t , x 0 ) = N ( x t ? 1 ; 1 α t ( x t ? 1 ? α t 1 ? α  ̄ t ε θ ( x t , t ) ) , β t ? 1 ? α ˉ t ? 1 1 ? α ˉ t I ) ( 6 ) p_{\theta}(\mathbf{x}_{t-1} \mid \mathbf{x}_t, \mathbf{x}_0) = \mathcal{N}(\mathbf{x}_{t-1};\frac{1}{\sqrt{\alpha_t}} \left(\mathbf{x}_t - \frac{1 - \alpha_t}{\sqrt{1 - \overline{\alpha}_t}} \, \pmb{\varepsilon}_\theta(\mathbf{x}_t, t) \right), \beta_t \cdot \frac{1 - \bar{\alpha}_{t-1}}{1 - \bar{\alpha}_t}\mathbf{I}) \qquad \qquad (6) pθ?(xt?1?xt?,x0?)=N(xt?1?;αt? ?1?(xt??1?αt? ?1?αt??εθ?(xt?,t)),βt??1?αˉt?1?αˉt?1??I)(6)

??其中, x t ? 1 \mathbf{x}_{t-1} xt?1? 是以均值為 1 α t ( x t ? 1 ? α t 1 ? α  ̄ t ε θ ( x t , t ) ) \frac{1}{\sqrt{\alpha_t}} \left( \mathbf{x}_t - \frac{1 - \alpha_t}{\sqrt{1 - \overline{\alpha}_t}} \, \pmb{\varepsilon}_\theta(\mathbf{x}_t, t) \right) αt? ?1?(xt??1?αt? ?1?αt??εθ?(xt?,t)),方差為 β t ? 1 ? α ˉ t ? 1 1 ? α ˉ t \beta_t \cdot \frac{1 - \bar{\alpha}_{t-1}}{1 - \bar{\alpha}_t} βt??1?αˉt?1?αˉt?1?? 的高斯分布, I \mathbf{I} I 表示單位矩陣。

4. 訓練和推理過程中的偽代碼

在這里插入圖片描述

1. 訓練流程(Training)
??從上面公式 (3) 可知: x t = α  ̄ t x 0 + 1 ? α  ̄ t ε t \mathbf{x}_t= \sqrt{\overline{\alpha}_t} \, \mathbf{x}_0 + \sqrt{1 - \overline{\alpha}_t} \, \pmb{\varepsilon}_t xt?=αt? ?x0?+1?αt? ?εt?,因此 ε θ ( α  ̄ t x 0 + 1 ? α  ̄ t ε , t ) = ε θ ( x t , t ) \pmb{\varepsilon}_{\theta}(\sqrt{\overline{\alpha}_t} \, \mathbf{x}_0 + \sqrt{1 - \overline{\alpha}_t} \, \pmb{\varepsilon},t)=\pmb{\varepsilon}_\theta(\mathbf{x}_t, t) εθ?(αt? ?x0?+1?αt? ?ε,t)=εθ?(xt?,t) 表示UNet網絡在 t t t 時刻輸出的預測噪聲。

(1)第一步:隨機采樣時間步數(時間 t t t 不固定),并對時間步數 t t t 進行位置編碼。例如 t = 100 t=100 t=100(從1到T=1000中隨機選),隨后編碼—>Time step embedding(t),這里的Time step embedding 使用標準的位置編碼方式。
(2)第二步:隨機采樣標準高斯噪聲 ε ~ N ( 0 , 1 ) \pmb{\varepsilon} \sim \mathcal{N}(0, 1) εN(0,1),利用公式 (3) x t = α  ̄ t x 0 + 1 ? α  ̄ t ε \mathbf{x}_t= \sqrt{\overline{\alpha}_t} \, \mathbf{x}_0 + \sqrt{1 - \overline{\alpha}_t} \, \pmb{\varepsilon} xt?=αt? ?x0?+1?αt? ?ε 對原始圖像數據 x 0 \mathbf{x}_0 x0? 進行加噪,得到噪聲圖像 x 100 \mathbf{x}_{100} x100?
(3)第三步:將得到的噪聲圖像 x 100 \mathbf{x}_{100} x100? 和編碼后的時間步 Time step embedding(t) 共同送到類似于UNet神經網絡模型中,Unet網絡模型會輸出一個預測噪聲 ε θ \pmb{\varepsilon}_{\theta} εθ?
(4)第四步:計算預測噪聲 ε θ \pmb{\varepsilon}_{\theta} εθ? 與 真實噪聲 ε \pmb{\varepsilon} ε 之間的誤差(MSE Loss,使用均方誤差損失函數),優化網絡參數,使得模型越來越擅長預測噪聲。

2. 推理過程(Sampling / Generation)
??推理就是生成新樣本的過程,也叫采樣,采樣過程的核心思想是:逐步(迭代)去噪聲。
(1)第一步:假設 T = 1000 \mathbf{T}=1000 T=1000,從標準正態分布中隨機生成一張全是高斯噪聲的圖像 x 1000 \mathbf{x}_{1000} x1000?
(2)第二步:把 x 1000 \mathbf{x}_{1000} x1000? t = 1000 \mathbf{t}=1000 t=1000 輸入到 UNet 網絡中來獲取預測噪聲 ε θ \pmb{\varepsilon}_{\theta} εθ?
(3)第三步:將預測的噪聲 ε θ \pmb{\varepsilon}_{\theta} εθ? ε θ ( x t , t ) \pmb{\varepsilon}_\theta(\mathbf{x}_t, t) εθ?(xt?,t)) 代入公式 (5) x t ? 1 = 1 α t ( x t ? 1 ? α t 1 ? α  ̄ t ε θ ( x t , t ) ) + σ t z \mathbf{x}_{t-1} = \frac{1}{\sqrt{\alpha_t}} \left( \mathbf{x}_t - \frac{1 - \alpha_t}{\sqrt{1 - \overline{\alpha}_t}} \, \pmb{\varepsilon}_\theta(\mathbf{x}_t, t) \right) + \sigma_t \mathbf{z} xt?1?=αt? ?1?(xt??1?αt? ?1?αt??εθ?(xt?,t))+σt?z 中,獲取前一時刻 x 999 \mathbf{x}_{999} x999? 的圖像數據;
(4)第四步:逐步迭代,將 x T = x 999 , x 998 , … , x 2 \mathbf{x}_{T}=\mathbf{x}_{999},\mathbf{x}_{998}, \ldots,\mathbf{x}_{2} xT?=x999?,x998?,,x2? t = 999 , 998 , … , 2 \mathbf{t}=999,998,\ldots,2 t=999,998,,2 依次輸入到 UNet 網絡模型中來獲取預測噪聲,直到獲得 x 1 \mathbf{x}_{1} x1? 時的圖像數據。
(5)第五步:將 x 1 \mathbf{x}_{1} x1? t = 1 \mathbf{t}=1 t=1 輸入到 UNet 網絡中來預測噪聲 ε θ \pmb{\varepsilon}_{\theta} εθ?,接著將預測的噪聲 ε θ \pmb{\varepsilon}_{\theta} εθ? ε θ ( x t , t ) \pmb{\varepsilon}_\theta(\mathbf{x}_t, t) εθ?(xt?,t)) 代入 x t ? 1 = 1 α t ( x t ? 1 ? α t 1 ? α  ̄ t ε θ ( x t , t ) ) \mathbf{x}_{t-1} = \frac{1}{\sqrt{\alpha_t}} \left( \mathbf{x}_t - \frac{1 - \alpha_t}{\sqrt{1 - \overline{\alpha}_t}} \, \pmb{\varepsilon}_\theta(\mathbf{x}_t, t) \right) xt?1?=αt? ?1?(xt??1?αt? ?1?αt??εθ?(xt?,t)) 中,獲取圖像數據 x 0 \mathbf{x}_{0} x0?

5. 訓練過程代碼實現(Training)

參考來源:【代碼精讀】Diffusion Model 擴散模型

5.1 時間嵌入模塊——TimeEmbedding

class TimeEmbedding(nn.Module):"""定義``時間嵌入``模塊"""def __init__(self, T, d_model, dim):"""初始的time-embedding是由一系列不同頻率的正弦、余弦函數采樣值表示,即:[[sin(w_0*x), cos(w_0*x)],[sin(w_1*x), cos(w_1*x)],...,[sin(w_T)*x, cos(w_T*x)]], 維度為 T * d_model在本實例中,頻率范圍是[0:T], x在1e-4~1范圍,共d_model // 2個離散點;將sin, cos并在一起組成d_model個離散點Args:T: int, 總迭代步數,本實例中T=1000d_model: 輸入維度(通道數/初始embedding長度)dim: 輸出維度(通道數)"""assert d_model % 2 == 0super().__init__()# 前兩行計算x向量,共64個點emb = torch.arange(0, d_model, step=2) / d_model * math.log(10000)emb = torch.exp(-emb)# T個時間位置組成頻率部分pos = torch.arange(T).float()# 兩兩相乘構成T*(d_model//2)的矩陣,并assert形狀emb = pos[:, None] * emb[None, :]assert list(emb.shape) == [T, d_model // 2]# 計算不同頻率sin, cos值,判斷形狀,并reshape到T*d_modelemb = torch.stack([torch.sin(emb), torch.cos(emb)], dim=-1)assert list(emb.shape) == [T, d_model // 2, 2]emb = emb.view(T, d_model)# MLP層,通過初始編碼計算提取特征后的embedding# 包含兩個線性層,第一個用swish激活函數,第二個不使用激活函數self.timembedding = nn.Sequential(nn.Embedding.from_pretrained(emb),nn.Linear(d_model, dim),Swish(),nn.Linear(dim, dim),)self.initialize()def initialize(self):for module in self.modules():if isinstance(module, nn.Linear):init.xavier_uniform_(module.weight)init.zeros_(module.bias)def forward(self, t):emb = self.timembedding(t)return emb

??TimeEmbedding 類是擴散模型中用于生成時間步嵌入的核心組件,其作用是將離散的時間步轉換為富含時序信息的連續向量表示。擴散模型通過多步迭代逐步去噪,模型需感知當前所處的時間步以調整去噪行為。TimeEmbedding 將時間步編碼為高維向量,使模型能捕獲不同時間步的動態特征。其設計借鑒了Transformer的位置編碼思想,但針對擴散模型的時間特性進行了調整。

5.2 前向擴散過程——GaussianDiffusionTrainer

# ``extract``函數的作用是從v這一序列中按照索引t取出需要的數,然后reshape到輸入數據x的維度
def extract(v, t, x_shape):"""Extract some coefficients at specified timesteps, then reshape to[batch_size, 1, 1, 1, 1, ...] for broadcasting purposes."""device = t.device# ``torch.gather``的用法建議看https://zhuanlan.zhihu.com/p/352877584的第一條評論# 在此處的所有調用實例中,v都是一維,可以看作是索引取值,即等價v[t], t大小為[batch_size, 1]out = torch.gather(v, index=t, dim=0).float().to(device)# 再把索引到的值reshape到[batch_size, 1, 1, ...], 維度和x_shape相同return out.view([t.shape[0]] + [1] * (len(x_shape) - 1))# ``GaussianDiffusionTrainer``包含了Diffusion Model的前向過程(加噪) & 訓練過程
class GaussianDiffusionTrainer(nn.Module):def __init__(self, model, beta_1, beta_T, T):"""初始化前向模型Args:model: 骨干模型,主流為U-Net+Attentionbeta_1: beta的起始值,本實例中取1e-4beta_T: bata在t=T時的值,本實例中取0.2T: 時間步數, 本實例中取1000"""super().__init__()# 參數賦值self.model = modelself.T = T# 等間隔得到beta_1到beta_T之間共T個step對應的beta值,組成序列存為類成員(后邊可以用``self.betas``訪問)self.register_buffer('betas', torch.linspace(beta_1, beta_T, T).double())# 根據公式,令alphas = 1 - betasalphas = 1. - self.betas# 根據公式,計算alpha連乘結果,存為alphas_bar# ``torch.cumprod``用于計算一個序列每個數與其前面所有數連乘的結果,得到一個序列,長度等于原序列長度# 例如:# a = torch.tensor([2,3,1,4])# b = torch.cumprod(a, dim=0)其實就等于torch.tensor([2, 2*3, 2*3*1, 2*3*1*4]) = torch.tensor([2, 6, 6, 24])alphas_bar = torch.cumprod(alphas, dim=0)# calculations for diffusion q(x_t | x_{t-1}) and others# 根據公式計算sqrt(alphas_bar)以及sqrt(1-alphas_bar)分別作為正向擴散的均值和標準差,存入類成員# 可用``self.sqrt_alphas_bar``和``sqrt_one_minus_alphas_bar``來訪問self.register_buffer('sqrt_alphas_bar', torch.sqrt(alphas_bar))self.register_buffer('sqrt_one_minus_alphas_bar', torch.sqrt(1. - alphas_bar))def forward(self, x_0):"""Algorithm 1."""# 從0~T中隨機選batch_size個時間點t = torch.randint(self.T, size=(x_0.shape[0], ), device=x_0.device)# 參數重整化技巧,先生成均值為0方差為1的高斯分布,再通過乘標準差加均值的方式用于間接采樣noise = torch.randn_like(x_0)x_t = (extract(self.sqrt_alphas_bar, t, x_0.shape) * x_0 +extract(self.sqrt_one_minus_alphas_bar, t, x_0.shape) * noise)# 做一步反向擴散,希望模型可以預測出加入的噪聲,也就是公式中的z_tloss = F.mse_loss(self.model(x_t, t), noise, reduction='none')return loss

??GaussianDiffusionTrainer 類用于實現擴散模型的 前向過程(加噪) 和 訓練目標(噪聲預測)。核心思想是逐步向輸入數據 x 0 x_0 x0? 添加高斯噪聲,并訓練模型預測噪聲。extract 函數用于從序列 v 中按索引 t 提取值,并將其形狀調整為與輸入數據 x 的維度匹配,以便廣播計算。

  1. 計算 α t \alpha_t αt? β t \beta_t βt?
    ??假設 beta_1=0.0001beta_T=0.02,通過代碼 self.register_buffer('betas', torch.linspace(beta_1, beta_T, T).double()) 可得到 β t \beta_t βt? = self.betas,那么 α t \alpha_t αt? = 1. - self.betas β t \beta_t βt? α t \alpha_t αt? 的形狀大小均為 (1000, )

  2. 計算 α ˉ t \bar{\alpha}_t αˉt?
    ??通過代碼 torch.cumprod(alphas, dim=0) 來獲取 α ˉ t \bar{\alpha}_t αˉt? = alphas_bar

  3. 計算 α ˉ t \sqrt{\bar{\alpha}_t} αˉt? ? 1 ? α ˉ t \sqrt{1-\bar{\alpha}_t} 1?αˉt? ?
    ?? α ˉ t \sqrt{\bar{\alpha}_t} αˉt? ? = self.sqrt_alphas_bar 1 ? α ˉ t \sqrt{1-\bar{\alpha}_t} 1?αˉt? ? = self.sqrt_one_minus_alphas_bar

  4. 隨機采樣時間步數
    ??t = torch.randint(self.T, size=(x_0.shape[0], ), device=x_0.device),假設 self.T = 1000、batch_size = 8,那么時間 t 的取值范圍是 [0, 1000),例如 t = tensor([902, 605, 411, 926, 894, 297, 147, 79], device=‘cuda:0’)

  5. 利用公式(3)計算 x t \mathbf{x}_t xt?

x_t = (extract(self.sqrt_alphas_bar, t, x_0.shape) * x_0 +extract(self.sqrt_one_minus_alphas_bar, t, x_0.shape) * noise)
  1. UNet 網絡預測噪聲
    ??通過代碼 self.model(x_t, t) 可得到預測噪聲 ε θ \pmb{\varepsilon}_{\theta} εθ? ε θ \pmb{\varepsilon}_{\theta} εθ? 的shape為 [8, 3, 32, 32]。隨后利用均方誤差損失函數計算損失——loss = F.mse_loss(self.model(x_t, t), noise, reduction='none')

6. 推理過程代碼實現(Sampling)

class GaussianDiffusionSampler(nn.Module):def __init__(self, model, beta_1, beta_T, T):"""所有參數含義和``GaussianDiffusionTrainer``(前向過程)一樣"""super().__init__()self.model = modelself.T = T# 這里獲取betas, alphas以及alphas_bar和前向過程一模一樣self.register_buffer('betas', torch.linspace(beta_1, beta_T, T).double())alphas = 1. - self.betasalphas_bar = torch.cumprod(alphas, dim=0)# 這一步是方便后面運算,相當于構建alphas_bar{t-1}alphas_bar_prev = F.pad(alphas_bar, [1, 0], value=1)[:T]  # 把alpha_bar的第一個數字換成1,按序后移# 根據公式,后向過程中的計算均值需要用到的系數用coeff1和coeff2表示self.register_buffer('coeff1', torch.sqrt(1. / alphas))self.register_buffer('coeff2', self.coeff1 * (1. - alphas) / torch.sqrt(1. - alphas_bar))# 根據公式,計算后向過程的方差self.register_buffer('posterior_var', self.betas * (1. - alphas_bar_prev) / (1. - alphas_bar))def predict_xt_prev_mean_from_eps(self, x_t, t, eps):"""該函數用于反向過程中,條件概率分布q(x_{t-1}|x_t)的均值Args:x_t: 迭代至當前步驟的圖像t: 當前步數eps: 模型預測的噪聲,也就是z_tReturns:x_{t-1}的均值,mean = coeff1 * x_t - coeff2 * eps"""assert x_t.shape == eps.shapereturn (extract(self.coeff1, t, x_t.shape) * x_t -extract(self.coeff2, t, x_t.shape) * eps)def p_mean_variance(self, x_t, t):"""該函數用于反向過程中,計算條件概率分布q(x_{t-1}|x_t)的均值和方差Args:x_t: 迭代至當前步驟的圖像t: 當前步數Returns:xt_prev_mean: 均值var: 方差"""# below: only log_variance is used in the KL computations# 這一步我略有不解,為什么要把算好的反向過程的方差大部分替換成betas。# 我猜測,后向過程方差``posterior_var``的計算過程僅僅是betas乘上一個(1 - alpha_bar_{t-1}) / (1 - alpha_bar_{t}),# 由于1 - alpha_bar_{t}這個數值非常趨近于0,分母為0會導致nan,# 而整體(1 - alpha_bar_{t-1}) / (1 - alpha_bar_{t})非常趨近于1,所以直接用betas近似后向過程的方差,# 但是t = 1 的時候(1 - alpha_bar_{0}) / (1 - alpha_bar_{1})還不是非常趨近于1,所以這個數值要保留,# 因此就有拼接``torch.cat([self.posterior_var[1:2], self.betas[1:]])``這一步var = torch.cat([self.posterior_var[1:2], self.betas[1:]])var = extract(var, t, x_t.shape)# 模型前向預測得到eps(也就是z_t)eps = self.model(x_t, t)# 計算均值xt_prev_mean = self.predict_xt_prev_mean_from_eps(x_t, t, eps=eps)return xt_prev_mean, vardef forward(self, x_T):"""Algorithm 2."""# 反向擴散過程,從x_t迭代至x_0x_t = x_Tfor time_step in reversed(range(self.T)):print(time_step)# t = [1, 1, ....] * time_step, 長度為batch_sizet = x_t.new_ones([x_T.shape[0], ], dtype=torch.long) * time_step# 計算條件概率分布q(x_{t-1}|x_t)的均值和方差mean, var= self.p_mean_variance(x_t=x_t, t=t)# no noise when t == 0# 最后一步的高斯噪聲設為0(我認為不設為0問題也不大,就本實例而言,t=0時的方差已經很小了)if time_step > 0:noise = torch.randn_like(x_t)else:noise = 0x_t = mean + torch.sqrt(var) * noiseassert torch.isnan(x_t).int().sum() == 0, "nan in tensor."x_0 = x_t# ``torch.clip(x_0, -1, 1)``,把x_0的值限制在-1到1之間,超出部分截斷return torch.clip(x_0, -1, 1)
  1. 獲取 α t \alpha_t αt? β t \beta_t βt? α ˉ t \bar{\alpha}_t αˉt? α ˉ t ? 1 \bar{\alpha}_{t-1} αˉt?1?
    ?? β t \beta_t βt? = self.betas α t \alpha_t αt? = 1. - self.betas α ˉ t \bar{\alpha}_t αˉt? = alphas_bar α ˉ t ? 1 \bar{\alpha}_{t-1} αˉt?1? = alphas_bar_prev

  2. 獲取系數
    ??self.coeff1 = 1 α t \frac{1}{\sqrt{\alpha_t}} αt? ?1?self.coeff2 = 1 α t ( 1 ? α t 1 ? α  ̄ t ) \frac{1}{\sqrt{\alpha_t}} \left( \frac{1 - \alpha_t}{\sqrt{1 - \overline{\alpha}_t}}\right) αt? ?1?(1?αt? ?1?αt??)self.posterior_var = β t ? 1 ? α ˉ t ? 1 1 ? α ˉ t \beta_t \cdot \frac{1 - \bar{\alpha}_{t-1}}{1 - \bar{\alpha}_t} βt??1?αˉt?1?αˉt?1??

  3. 獲取前一時刻高斯噪聲 x t ? 1 \mathbf{x}_{t-1} xt?1? 的方差和均值
    ?? 通過代碼 var = torch.cat([self.posterior_var[1:2], self.betas[1:]]) 來獲取方差 β t ? 1 ? α ˉ t ? 1 1 ? α ˉ t \beta_t \cdot \frac{1 - \bar{\alpha}_{t-1}}{1 - \bar{\alpha}_t} βt??1?αˉt?1?αˉt?1??
    ?? 通過代碼 eps = self.model(x_t, t) 來獲取網絡的預測噪聲 ε θ ( x t , t ) \pmb{\varepsilon}_\theta(\mathbf{x}_t, t) εθ?(xt?,t)
    ?? 通過代碼 xt_prev_mean = self.predict_xt_prev_mean_from_eps(x_t, t, eps=eps) 來獲取預測的均值 1 α t ( x t ? 1 ? α t 1 ? α  ̄ t ε θ ( x t , t ) ) \frac{1}{\sqrt{\alpha_t}} \left( \mathbf{x}_t - \frac{1 - \alpha_t}{\sqrt{1 - \overline{\alpha}_t}} \, \pmb{\varepsilon}_\theta(\mathbf{x}_t, t) \right) αt? ?1?(xt??1?αt? ?1?αt??εθ?(xt?,t))

  4. 計算前一時刻的高斯噪聲 x t ? 1 \mathbf{x}_{t-1} xt?1?
    ??通過代碼 x_t = mean + torch.sqrt(var) * noise 來計算前一時刻的高斯噪聲 x t ? 1 \mathbf{x}_{t-1} xt?1? ,該代碼對應于公式(5)。

參考博客:
DDPM解讀(一)| 數學基礎,擴散與逆擴散過程和訓練推理方法
超詳細的擴散模型(Diffusion Models)原理+代碼
擴散模型 (Diffusion Model) 簡要介紹與源碼分析

參考視頻:
2025版最新的Diffusion Model | 擴散模型原理及代碼實現,3小時快速上手!(附帶源碼)
大白話AI | 圖像生成模型DDPM | 擴散模型 | 生成模型 | 概率擴散去噪生成模型
添【大白話01】一文理清 Diffusion Model 擴散模型 | 原理圖解+公式推導
【較真系列】講人話-Diffusion Model全解(原理+代碼+公式)

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/904054.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/904054.shtml
英文地址,請注明出處:http://en.pswp.cn/news/904054.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

基于 Spring Boot 瑞吉外賣系統開發(九)

基于 Spring Boot 瑞吉外賣系統開發(九) 保存菜品 菜品管理頁面提供了一個“新增菜品”按鈕,單擊該按鈕時,會打開新增菜品頁面。 請求路徑/dish,請求方法POST,參數使用DishDto類接收。 DishDto 添加f…

w317汽車維修預約服務系統設計與實現

🙊作者簡介:多年一線開發工作經驗,原創團隊,分享技術代碼幫助學生學習,獨立完成自己的網站項目。 代碼可以查看文章末尾??聯系方式獲取,記得注明來意哦~🌹贈送計算機畢業設計600個選題excel文…

【Agent搭建】利用coze平臺搭建一個AI銷售?

目錄 一、關于coze 核心功能 二、搭建屬于你自己智能體 備注:(以下說明比較需要調整的板塊) 1、從Prompt工程開始 2、搭建工作流 3、添加知識 三、總結 一、關于coze Coze是字節跳動推出的AI應用開發平臺,專注于幫助用戶快速…

Sharding-JDBC分庫分表中的熱點數據分布不均勻問題及解決方案

引言 在現代分布式應用中,使用Sharding-JDBC進行數據庫的分庫分表是提高系統性能和擴展性的常見策略。然而,在實際應用中,某些特定的數據(如最新訂單、熱門商品等)可能會成為“熱點”,導致這些部分的數據處…

DSP48E2 的 MAC模式功能仿真

DSP48E2 仿真代碼: 測試的功能為 P i ( A D ) ? B P i ? 1 P_{i} (AD) * B P_{i-1} Pi?(AD)?BPi?1? timescale 1ns / 1nsmodule dsp_tb;// 輸入reg CLK;reg CE;reg SCLR;reg signed [26:0] A, D;reg signed [17:0] B;// 輸出wire signed [47:0] P;par…

抽象工廠模式(Abstract Factory Pattern)

很好!你現在已經開始接觸設計模式了,而**抽象工廠模式(Abstract Factory Pattern)是一種常用于“創建一系列相關產品”**的經典設計模式。 我會一步步幫你理解: 🧠 一句話解釋 抽象工廠模式:提…

Thymeleaf模板引擎從入門到實戰:Spring Boot整合與核心用法詳解

在 Java Web 開發的世界里,模板引擎是連接后端數據與前端展示的重要橋梁。Thymeleaf 憑借其強大的功能和簡潔的語法,逐漸成為眾多開發者的首選。如果你正在尋找一款能夠讓你的 Web 應用開發更加高效、代碼更加優雅的模板引擎,那么 Thymeleaf …

【HarmonyOS】作業三 UI

目錄 一. 單選題(共10題,10分) 1. (單選題, 1分)關于Tabs組件頁簽的位置設置,下面描述錯誤的是 2. (單選題, 1分)下面哪個組件不能包含子組件? 3. (單選題, 1分)ArkTS語言的實現計數器功能的組件名稱是以下哪個? 4. (單選題…

《算法筆記》10.6小節——圖算法專題->拓撲排序 問題 C: Legal or Not

題目描述 ACM-DIY is a large QQ group where many excellent acmers get together. It is so harmonious that just like a big family. Every day,many "holy cows" like HH, hh, AC, ZT, lcc, BF, Qinz and so on chat on-line to exchange their ideas. When so…

博客信息管理/博客管理

🛠 博客管理模塊:設計建議 你應該以To B 的后臺系統思路來設計,但保持簡單、輕量級、自己易維護是關鍵。下面是針對你這個場景的建議。 🧱 前端頁面結構(React/Vue 可用) 頁面 說明 博客列表頁 展示所有博…

全平臺開源即時通訊IM框架MobileIMSDK:7端+TCP/UDP/WebSocket協議,鴻蒙NEXT端已發布,5.7K Stars

一、基本介紹 MobileIMSDK是一套全平臺原創開源IM通信層框架: 超輕量級、高度提煉,lib包50KB以內;精心封裝,一套API同時支持UDP、TCP、WebSocket三種協議(可能是全網唯一開源的);客戶端支持iOS…

SpringBoot商城平臺系統設計與開發

概述 SpringBoot商城平臺系統實現了商品展示、購物車、訂單管理等商城核心功能,適合作為計算機專業設計項目或商城項目開發參考,實現商城平臺的核心功能,學習商品管理、訂單處理、支付集成等關鍵技術實現。 主要內容 1. 前臺用戶功能模塊 …

【網絡原理】深入理解HTTPS協議

本篇博客給大家帶來的是網絡原理的知識點, 由于時間有限, 分三天來寫, 本篇為線程第三篇,也是最后一篇. 🐎文章專欄: JavaEE初階 🚀若有問題 評論區見 ? 歡迎大家點贊 評論 收藏 分享 如果你不知道分享給誰,那就分享給薯條. 你們的支持是我不斷創作的動…

【C語言練習】018. 定義和初始化結構體

018. 定義和初始化結構體 018. 定義和初始化結構體1. 定義結構體示例1:定義一個簡單的結構體輸出結果2. 初始化結構體示例2:在聲明時初始化結構體輸出結果示例3:使用指定初始化器初始化結構體(C99及以上標準支持)輸出結果3. 結構體數組示例4:定義和初始化結構體數組輸出結…

3D版同步幀游戲

以下是實現一個3D版同步幀游戲的詳細步驟與完整代碼示例。我們將以第一人稱射擊游戲(FPS)為原型,重點講解3D空間中的同步機制優化。 項目升級:3D版核心改動 1. 3D坐標系與消息結構 // common/messages.go type Vector3 struct {X float32 `json:"x"`Y float32 `…

卷積神經網絡進化史:從LeNet-5到現代架構的完整發展脈絡

摘要 本文系統梳理卷積神經網絡(CNN)從誕生到繁榮的發展歷程。從1998年Yann LeCun開創性的LeNet-5出發,重點解析2012年引爆深度學習革命的AlexNet,并詳細拆解后續演進的五大技術方向:網絡深度化(VGG)、卷積功能強化(ResNet)、檢測任務遷移(F…

在 Windows 中安裝 Pynini 的記錄

#工作記錄 概述 Pynini 是一個用于加權有限狀態文法編譯的 Python 庫,廣泛應用于自然語言處理(NLP)領域。以下記錄旨在用于回顧和幫助大家在 Windows 系統中安裝 Pynini。 安裝思路: 優先用conda虛擬環境 或 在python3.12的vir…

深挖Java之:運算符與輸入器

今天我要介紹的是在Java中對于運算符與輸入器的一些基礎語法運算符與輸入器的代碼示例以及應用場景,他們在應用上的優勢與劣勢作說明介紹: 介紹:運算符與輸入器是兩個基礎且關鍵的概念,它們共同構成了程序與用戶、程序與數據之間…

動態規劃之多狀態問題1

題目解析: 也就是給一個預約數組,選擇一些數字,讓其總和最大,但不能選擇相鄰的兩個數字 算法原理: 依舊可以根據經驗題目 以dp[i]位置結尾時,巴拉巴拉 根據題目要求補充完整,dp[i]&#xff…

計網_可靠傳輸ARQ機制

2024.09.04:網工老姜&beokayy網工學習筆記 第5節 可靠傳輸機制 5.1 可靠傳輸5.2 ARQ機制、ARQ協議5.3 ARQ簡介(可靠傳輸)5.3.1 停止等待協議(1)無差錯情況(2)有差錯情況確認丟失確認遲到 5.…