当前位置: 首页 > news >正文

DDPM原理解析

1. DDPM原理

  • 论文:DDPM: Denoising Diffusion Probabilistic Models

1.1 概述

DDPM包括两个过程:前向过程(forward process)反向过程(reverse process),其中前向过程又称为扩散过程(diffusion process),如下图所示。无论是前向过程还是反向过程都是一个参数化的马尔可夫链(Markov chain),其中反向过程可以用来生成图片。下图中,由高斯随机噪声XTX_TXT生成原始图片X0X_0X0为反向过程,反之为前向过程。

在这里插入图片描述

1.2 Forward(扩散过程)

一句话概括,前向过程就是对原始图片X0X_0X0不断加高斯噪声最后生成随机噪声XTX_TXT的过程,如下图所示。

在这里插入图片描述

Xt−1X_{t-1}Xt1XtX_tXt表示为:
xt=αtxt−1+1−αtϵt−1(1)\mathbf{x}_{t}=\sqrt{\alpha_{t}}\mathbf{x}_{t-1}+\sqrt{1-\alpha_{t}}{ \epsilon}_{t-1} \tag{1} xt=αtxt1+1αtϵt1(1)

# 生成[b, 1, 1, 1]的tensor, 完成“信号衰减 + 噪声注入”
def extract(a, t, x_shape):b, *_ = t.shapeout = a.gather(-1, t)return out.reshape(b, *((1,) * (len(x_shape) - 1)))def perturb_x(self, x, t, noise):# DDPM 前向加噪的公式# self.sqrt_alphas_cumprod = np.sqrt(alphas_cumprod)# self.sqrt_one_minus_alphas_cumprod = np.sqrt(1 - alphas_cumprod)return (extract(self.sqrt_alphas_cumprod, t,  x.shape) * x +extract(self.sqrt_one_minus_alphas_cumprod, t, x.shape) * noise)

其中αt\alpha_{t}αt是一个很小值的超参数, ϵt−1∼N(0,1)\boldsymbol{\epsilon_{t-1}\sim N\left(0,1\right)}ϵt1N(0,1)是高斯噪声。由公式(1)推导,最终可以得到X0X_0X0XtX_tXt​的公式,表示如下:
xt=αˉtx0+1−αˉtϵ(2)\mathbf{x}_{t}=\sqrt{\bar{\alpha}_{t}}\mathbf{x}_{0}+\sqrt{1-\bar{\alpha}_{t}} \boldsymbol{\epsilon} \tag2 xt=αˉtx0+1αˉtϵ(2)
其中αˉt=∏i=1tαi,ϵ∼N(0,1)\begin{array}{l}\boldsymbol{\bar{\alpha}_{t}=\prod_{i=1}^{t}\alpha_{i}\text{ },\text{ }\epsilon\sim N\left(0,1\right)}\end{array}αˉt=i=1tαi , ϵN(0,1)也是一个高斯噪声。有了公式(2),便可以由输入图片直接生成随机噪声XtX_tXt

1.3 Backward(去噪过程)

前向过程是将原始图片变成随机噪声,而反向过程就是通过预测噪声ϵ\epsilonϵ,将随机噪声XTX_TXT逐步还原为原始图片X0X_0X0​,如下图所示。

在这里插入图片描述

反向过程公式表示如下:
xt–1=1αt(xt−1−αt1−αˉtϵθ(xt,t))+σtz(3)\mathbf{x}_{t\text{--}1}=\frac{1}{\sqrt{\alpha_{t}}}\bigg(\mathbf{x}_{t}- \frac{1-\alpha_{t}}{\sqrt{1-\bar{\alpha}_{t}}}\boldsymbol{\epsilon}_{\theta} \left(\mathbf{x}_{t},t\right) \bigg)+\sigma_{t}\mathbf{z} \tag3 xt1=αt1(xt1αˉt1αtϵθ(xt,t))+σtz(3)
其中ϵθ{\epsilon}_{\theta}ϵθ是噪声估计函数,用于估计真实噪声ϵ\epsilonϵθ\thetaθ是模型训练的参数,z∼N(0,1)\mathbf{z}\sim N\left(0,1\right)zN(0,1)σtz\sigma_{t}\mathbf{z}σtz表示的是预测噪声和真实噪声的误差。DDPM的关键就是训练噪声估计模型ϵθ(xt,t)\boldsymbol{\epsilon}_{\theta} \left(\mathbf{x}_{t},t\right)ϵθ(xt,t)用于估计真实的噪声ϵ\epsilonϵ​。

estimated_noise = self.model(perturbed_x, t, y)
def remove_noise(self, x, t, y, use_ema=True):# self.remove_noise_coeff = betas / np.sqrt(1 - alphas_cumprod))if use_ema:return ((x - extract(self.remove_noise_coeff, t, x.shape) * self.ema_model(x, t, y)) *extract(self.reciprocal_sqrt_alphas, t, x.shape))else:return ((x - extract(self.remove_noise_coeff, t, x.shape) * self.model(x, t, y)) *extract(self.reciprocal_sqrt_alphas, t, x.shape))
# 去噪
def sample(self, batch_size, device, y=None, use_ema=True):if y is not None and batch_size != len(y):raise ValueError("sample batch size different from length of given y")# 生成一个随机的噪声图像 shape为(batch_size, img_channels, img_size[0], img_size[1])x = torch.randn(batch_size, self.img_channels, *self.img_size, device=device)for t in range(self.num_timesteps - 1, -1, -1):# 生成一个形状为(batch_size,)的tensor, 每个元素都是tt_batch = torch.tensor([t], device=device).repeat(batch_size)x = self.remove_noise(x, t_batch, y, use_ema)if t > 0:x += extract(self.sigma, t_batch, x.shape) * torch.randn_like(x) # 预测噪声和真实噪声的误差return x.cpu().detach()

1.4 Training

Diffusion模型的训练可以分为两个部分:

  1. 前向扩散过程(Forward Diffusion Process)→ 图片中添加噪声
  2. 反向扩散过程(Reverse Diffusion Process) → 去除图片中的噪声

在这里插入图片描述

前面提到DDPM的关键是训练噪声估计模型ϵθ(xt,t)\boldsymbol{\epsilon}_{\theta} \left(\mathbf{x}_{t},t\right)ϵθ(xt,t),用于估计ϵ\epsilonϵ​,那么损失函数可以使用MSE误差,表示如下:
Loss=∥ϵ−ϵθ(xt,t)∥2=∥ϵ−ϵθ(αˉtxt−1+1−αˉtϵ,t)∥2(4)Loss=\left\|{\epsilon}-{\epsilon}_{\theta}\left(\mathbf{x}_{t},t\right) \right\|^{2}=\left\|{\epsilon}-{\epsilon}_{\theta}\left(\sqrt{\bar{ \alpha}}_{t}\mathbf{x}_{t-1}+\sqrt{1-\bar{\alpha}_{t}}{\epsilon},t\right) \right\|^{2} \tag 4 Loss=ϵϵθ(xt,t)2=ϵϵθ(αˉtxt1+1αˉtϵ,t)2(4)
整个训练过程可以表示如下:

在这里插入图片描述

在每一轮的训练过程中,包含以下内容:

  1. 每一个训练样本选择一个随机时间步长t
  2. 将time step t对应的高斯噪声应用到图片中
  3. 将time step转化为对应embedding

在这里插入图片描述

下面是每一轮详细的训练过程:

在这里插入图片描述

# 对时间轴输入的全连接层
self.time_mlp = nn.Sequential(PositionalEmbedding(base_channels, time_emb_scale),nn.Linear(base_channels, time_emb_dim),SiLU(),nn.Linear(time_emb_dim, time_emb_dim),
) if time_emb_dim is not None else None
# 对时间time_emb做一个全连接,施加在通道上
if self.time_bias is not None:if time_emb is None:raise ValueError("time conditioning was specified but time_emb is not passed")out += self.time_bias(self.activation(time_emb))[:, :, None, None]

1.5 Generation

在得到预估噪声ϵθ(xt,t)\boldsymbol{\epsilon}_{\theta} \left(\mathbf{x}_{t},t\right)ϵθ(xt,t)后,就可以按公式(3)逐步得到最终的图片X0X_0X0​,整个过程表示如下:

在这里插入图片描述

下图的Sample a Gaussian表示生成随机高斯噪声,Iteratively denoise the image表示反向扩散过程,如何一步步从高斯噪声变成输出图片。可以看到最终生成的Denoised image非常清晰。

在这里插入图片描述

1.6 Problems

  • UNet引入时间tt是增长的还是随机的?

    • 引入时间步长t是为了模拟一个随时间逐渐增强的扰动过程。每个时间步长t代表一个扰动过程,从初始状态开始,通过多次应用噪声来逐渐改变图像的分布。因此,较小的t代表较弱的噪声扰动,而较大的t代表更强的噪声扰动。
    • DDPM 中的 UNet 都是共享参数的,那如何根据不同的输入生成不同的输出,最后从一个完全的一个随机噪声变成一个有意义的图片,这还是一个非常难的问题。我们希望这个 UNet 模型在刚开始的反向过程之中,它可以先生成一些物体的大体轮廓,随着扩散模型一点一点往前走,然后到最后快生成逼真图像的时候,这时候希望它学习到高频的一些特征信息。由于 UNet 都是共享参数,这时候就需要 time embedding 去提醒这个模型,我们现在走到哪一步了,现在输出是想要粗糙一点的,还是细致一点的。
    • t在训练过程是随机的每次训练中会从T∈[0, 1000]中均匀采样,在生成的时候在从1000逐渐降低到0,来模拟去噪过程。
  • 时间t是如何编码的?

    #------------------------------------------#
    #   计算时间步长的位置嵌入。
    #   一半为sin,一半为cos。
    #------------------------------------------#
    class PositionalEmbedding(nn.Module):def __init__(self, dim, scale=1.0):super().__init__()assert dim % 2 == 0self.dim = dimself.scale = scaledef forward(self, x):device      = x.devicehalf_dim    = self.dim // 2emb = math.log(10000) / half_dimemb = torch.exp(torch.arange(half_dim, device=device) * -emb)# x * self.scale和emb外积emb = torch.outer(x * self.scale, emb)emb = torch.cat((emb.sin(), emb.cos()), dim=-1)return emb
    

1.7 Reference

  • AIGC爆火的背后——扩散模型DDPM浅析
  • 十分钟读懂Diffusion:图解Diffusion扩散模型
  • 代码
http://www.dtcms.com/a/414761.html

相关文章:

  • 白盒密码:守护不可信环境中的密钥安全
  • 创建一个网站买卖WordPress外链方法
  • 使用 Go SDK 玩转 Docker:从容器到多架构构建
  • 原生微信小程序开发基础知识总结架构逻辑
  • 树莓派实现的自动垃圾(纸团)回收机器人
  • 【ROS2学习笔记】节点篇:节点概述
  • Java面试宝典:网络协议与Netty二
  • 自然语言处理(01)
  • 如何利用模板 + 继承的方式,形成动态多态的效果呢?
  • UE_ContrlRig
  • 江苏省城乡住房建设厅网站网站建设及维护流程图
  • ubuntu18.04安装五笔字型的方法
  • 上市公司网站建设要求成都丁香人才网官网专区
  • AI 原生应用:内容创作从 “手工作坊” 到 “智能工厂” 的革命
  • AIGC实战——交互式生成对抗网络(iGAN)
  • Scikit-learn Python机器学习 - 聚类分析算法 - DBSCAN(基于密度的噪声应用空间聚类)
  • PyTorch 实战:CIFAR-10 图像分类与网络优化
  • STM32H743-ARM例程10-WWDG
  • STM32H743-ARM例程9-IWDG看门狗
  • 什么是 mmdet3d
  • 建设银行嘉兴分行网站首页胶州网站建设dch100
  • Metal - 9. 深入剖析 3D 场景
  • 3DVG的当前面临的挑战和问题
  • 无代码企业网站开发网站建设管理和维护
  • 【C++】string类的常见接口的使用
  • 网站建设制作设计营销公司杭州亚马逊雨林探险作文
  • 东莞圆心科技网站开发哪里有做网站系统
  • 网站定位要点 有哪些方面大航母网站建设费用
  • iServer 启动端口冲突
  • 大连网站建设佳熙科技湖南专业seo优化公司