DDPM原理与代码剖析

这篇具有很好参考价值的文章主要介绍了DDPM原理与代码剖析。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

前言

鸽了好久没更了,主要是刚入学学业压力还蛮大,挺忙的,没时间总结啥东西。

接下来就要好好搞科研啦。先来学习一篇diffusion的经典之作Denoising Diffusion Probabilistic Models(DDPM)。(看完这篇可看它的改进版 IDDPM原理和代码剖析)

DDPM原理与代码剖析 先不断前向加高斯噪声,这一步骤称为前向过程。然后就是利用模型不断预测加噪前的图片,从而还原出原图像。

同时在学习时,deep_thoughts这个up的视频帮了我不少忙, 由衷感谢 54、Probabilistic Diffusion Model概率扩散模型理论与完整PyTorch代码详细解读, 推荐大家去观看他的视频。

没事多学点数学: 生成扩散模型漫谈:构建ODE的一般步骤(上)



DDPM重要公式

由于有些公式推导过程可能较长,我会把它放到【推导】部分,至于【提纲】部分则会列出简洁的重要的公式。

提纲

(1) 前向加噪
q ( X t ∣ X t − 1 ) = N ( X t ; 1 − β t X t − 1 , β t I ) q(X_t|X_{t-1}) = N(X_t;\sqrt{1-\beta_t}X_{t-1}, \beta_t I) q(XtXt1)=N(Xt;1βt Xt1,βtI)

β t \beta_t βt 在 DDPM中是0到1的小数,并且满足 β 1 < β 2 < . . . < β T \beta_1 \lt \beta_2 \lt ... \lt \beta_T β1<β2<...<βT


(2)
q ( X t ∣ X 0 ) = N ( X t ; α ‾ t X 0 , ( 1 − α ‾ t ) I ) q(X_t|X_0) = N(X_t; \sqrt{\overline{\alpha}_t}X_0, (1-\overline{\alpha}_t)I) q(XtX0)=N(Xt;αt X0,(1αt)I)
或者写为
X t = α ‾ t X 0 + 1 − α ‾ t   ϵ X_t = \sqrt{\overline{\alpha}_t}X_0+\sqrt{1-\overline{\alpha}_t}~\epsilon Xt=αt X0+1αt  ϵ
其中, α t \alpha_t αt 定义为 1 − β t 1-\beta_t 1βt, 不要问 α t + β t \alpha_t + \beta_t αt+βt 为何为1, 因为我们就是定义来的,定义 α \alpha α 只是为了让后续公式书写更加简洁。


(3) 后验的均值和方差
q ( X t − 1 ∣ X t , X 0 ) q(X_{t-1}|X_t, X_0) q(Xt1Xt,X0) 的均值 μ ~ ( X t , X 0 ) \widetilde{\mu}(X_t, X_0) μ (Xt,X0) 以及方差 β ~ t \widetilde{\beta}_t β t 分别为
μ ~ ( X t , X 0 ) = α ‾ t − 1 1 − α ‾ t X 0 + α t ( 1 − α ‾ t − 1 ) 1 − α ‾ t X t \widetilde{\mu}(X_t, X_0) = \frac{\sqrt{\overline{\alpha}_{t-1}}}{1-\overline{\alpha}_t} X_0 + \frac{\sqrt{\alpha_t}(1-\overline{\alpha}_{t-1})}{1-\overline{\alpha}_{t}}X_t μ (Xt,X0)=1αtαt1 X0+1αtαt (1αt1)Xt
β ~ t = 1 − α ‾ t − 1 1 − α ‾ t β t \widetilde{\beta}_t = \frac{1-\overline{\alpha}_{t-1}}{1-\overline{\alpha}_t} \beta_t β t=1αt1αt1βt

另外根据公式 (2) , 利用 X 0 X_0 X0 X t X_t Xt的关系,有 X 0 = 1 α ‾ t ( X t − 1 − α ‾ t    ϵ t ) X_0=\frac{1}{\sqrt{\overline{\alpha}_t}}(X_t-\sqrt{1-\overline{\alpha}_t}~~\epsilon_t) X0=αt 1(Xt1αt   ϵt), 带入到上式中,得到
μ ~ ( X t , X 0 ) = 1 α ‾ t ( X t − β t 1 − α ‾ t ϵ t ) \widetilde{\mu}(X_t, X_0) = \frac{1}{\sqrt{\overline{\alpha}_t}}(X_t-\frac{\beta_t}{\sqrt{1-\overline{\alpha}_t}}\epsilon_t) μ (Xt,X0)=αt 1(Xt1αt βtϵt)



推导

主要参考 deep thoughts-关于第54期视频去噪概率扩散模型DDPM的更新版notebook分享

DDPM原理与代码剖析DDPM原理与代码剖析
DDPM原理与代码剖析
DDPM原理与代码剖析
DDPM原理与代码剖析

由于
DDPM原理与代码剖析

DDPM原理与代码剖析
DDPM原理与代码剖析
DDPM原理与代码剖析



DDPM 训练和采样

原论文总结得很好,直接抄下hh

DDPM原理与代码剖析
DDPM原理与代码剖析



DDPM S_curve数据集小demo

声明: 暂时找不到原始出处,这是根据一个开源项目来的。
如果有小伙伴知道原始出处在哪,请麻烦留言,我后续会补上。
同时声明该案例只用于学习!!

数据集加载

import matplotlib.pyplot as plt
import numpy as np
from sklearn.datasets import make_s_curve
import torch

s_curve,_ = make_s_curve(10**4,noise=0.1)
s_curve = s_curve[:,[0,2]]/10.0

print("shape of s:",np.shape(s_curve))

data = s_curve.T

fig,ax = plt.subplots()
ax.scatter(*data,color='blue',edgecolor='white');

ax.axis('off')

device = 'cuda' if torch.cuda.is_available() else 'cpu'

dataset = torch.Tensor(s_curve).float().to(device)

shape of s: (10000, 2)
DDPM原理与代码剖析

确定超参数的值(important)

接下来主要是算出一些有用的量。

num_steps = 100

#制定每一步的beta
betas = torch.linspace(-6,6,num_steps).to(device)
betas = torch.sigmoid(betas)*(0.5e-2 - 1e-5)+1e-5

#计算alpha、alpha_prod、alpha_prod_previous、alpha_bar_sqrt等变量的值
alphas = 1-betas
alphas_prod = torch.cumprod(alphas,0)
alphas_prod_p = torch.cat([torch.tensor([1]).float().to(device),alphas_prod[:-1]],0)
alphas_bar_sqrt = torch.sqrt(alphas_prod)
one_minus_alphas_bar_log = torch.log(1 - alphas_prod)
one_minus_alphas_bar_sqrt = torch.sqrt(1 - alphas_prod)

assert alphas.shape==alphas_prod.shape==alphas_prod_p.shape==\
alphas_bar_sqrt.shape==one_minus_alphas_bar_log.shape\
==one_minus_alphas_bar_sqrt.shape
print("all the same shape",betas.shape)

噪声方案

#制定每一步的beta
betas = torch.linspace(-6,6,num_steps).to(device)
betas = torch.sigmoid(betas)*(0.5e-2 - 1e-5)+1e-5

注意一下很多变量都是列表。
α t = 1 − β t \alpha_t = 1-\beta_t αt=1βt

alphas = 1-betas

α ‾ t = ∏ i = 0 n α i \overline{\alpha}_t = \prod_{i=0}^n \alpha_i αt=i=0nαi

alphas_prod = torch.cumprod(alphas, dim=0)

α t − 1 \alpha_{t-1} αt1 在代码中为 alphas_prod_p

alphas_prod_p = torch.cat([torch.tensor([1]).float().to(device),alphas_prod[:-1]],0)

α ‾ t \sqrt{\overline{\alpha}_t} αt 在代码中为 alphas_bar_sqrt

alphas_bar_sqrt = torch.sqrt(alphas_prod)

l o g ( 1 − α ‾ t ) log(1-\overline{\alpha}_t) log(1αt)

one_minus_alphas_bar_log = torch.log(1 - alphas_prod)

one_minus_alphas_bar_sqrt对应 1 − α ‾ t \sqrt{1-\overline{\alpha}_t} 1αt

one_minus_alphas_bar_sqrt = torch.sqrt(1 - alphas_prod)



前向过程采样(important)

X t = α ‾ t X 0 + 1 − α ‾ t   ϵ X_t = \sqrt{\overline{\alpha}_t}X_0+\sqrt{1-\overline{\alpha}_t}~\epsilon Xt=αt X0+1αt  ϵ

#计算任意时刻的x采样值,基于x_0和重参数化
def q_x(x_0,t):
    """可以基于x[0]得到任意时刻t的x[t]"""
    noise = torch.randn_like(x_0).to(device)
    alphas_t = alphas_bar_sqrt[t]
    alphas_1_m_t = one_minus_alphas_bar_sqrt[t]
    return (alphas_t * x_0 + alphas_1_m_t * noise)#在x[0]的基础上添加噪声

演示数据前向100步的结果

num_shows = 20
fig,axs = plt.subplots(2,10,figsize=(28,3))
plt.rc('text',color='black')

#共有10000个点,每个点包含两个坐标
#生成100步以内每隔5步加噪声后的图像
for i in range(num_shows):
    j = i//10
    k = i%10
    q_i = q_x(dataset, torch.tensor([i*num_steps//num_shows]).to(device))#生成t时刻的采样数据
    q_i = q_i.to('cpu')
    axs[j,k].scatter(q_i[:,0],q_i[:,1],color='red',edgecolor='white')
    axs[j,k].set_axis_off()
    axs[j,k].set_title('$q(\mathbf{x}_{'+str(i*num_steps//num_shows)+'})$')
DDPM原理与代码剖析

模型

import torch
import torch.nn as nn

class MLPDiffusion(nn.Module):
    def __init__(self,n_steps,num_units=128):
        super(MLPDiffusion,self).__init__()
        
        self.linears = nn.ModuleList(
            [
                nn.Linear(2,num_units),
                nn.ReLU(),
                nn.Linear(num_units,num_units),
                nn.ReLU(),
                nn.Linear(num_units,num_units),
                nn.ReLU(),
                nn.Linear(num_units,2),
            ]
        )
        self.step_embeddings = nn.ModuleList(
            [
                nn.Embedding(n_steps,num_units),
                nn.Embedding(n_steps,num_units),
                nn.Embedding(n_steps,num_units),
            ]
        )
    def forward(self,x,t):
#         x = x_0
        for idx,embedding_layer in enumerate(self.step_embeddings):
            t_embedding = embedding_layer(t)
            x = self.linears[2*idx](x)
            x += t_embedding
            x = self.linears[2*idx+1](x)
            
        x = self.linears[-1](x)
        
        return x



损失函数(important)

由于DDPM中方差被设置为定值,因此这里只需要比较均值的loss, 又因为DDPM是预测噪声,因为只要比较后验的噪声和模型预测的噪声的MSE loss就可以指导模型进行训练了。

def diffusion_loss_fn(model,x_0,alphas_bar_sqrt,one_minus_alphas_bar_sqrt,n_steps):
    """对任意时刻t进行采样计算loss"""
    batch_size = x_0.shape[0]
    
    #对一个batchsize样本生成随机的时刻t
    t = torch.randint(0,n_steps,size=(batch_size//2,)).to(device)
    t = torch.cat([t,n_steps-1-t],dim=0)
    t = t.unsqueeze(-1)
    
    #x0的系数
    a = alphas_bar_sqrt[t]
    
    #eps的系数
    aml = one_minus_alphas_bar_sqrt[t]
    
    #生成随机噪音eps
    e = torch.randn_like(x_0).to(device)
    
    #构造模型的输入
    x = x_0 * a + e * aml
    
    #送入模型,得到t时刻的随机噪声预测值
    output = model(x,t.squeeze(-1))
    
    #与真实噪声一起计算误差,求平均值
    return (e - output).square().mean()

其中 X t = α ‾ t X 0 + 1 − α ‾ t   ϵ X_t = \sqrt{\overline{\alpha}_t}X_0+\sqrt{1-\overline{\alpha}_t}~\epsilon Xt=αt X0+1αt  ϵ, 即为代码中的

 x = x_0 * a + e * aml



逆过程采样(important)

p_sample_loop负责迭代式的调用p_sample, 是不断恢复图像的过程。

def p_sample_loop(model,shape,n_steps,betas,one_minus_alphas_bar_sqrt):
    """从x[T]恢复x[T-1]、x[T-2]|...x[0]"""
    cur_x = torch.randn(shape).to(device)
    x_seq = [cur_x]
    for i in reversed(range(n_steps)):
        cur_x = p_sample(model,cur_x,i,betas,one_minus_alphas_bar_sqrt)
        x_seq.append(cur_x)
    return x_seq

def p_sample(model,x,t,betas,one_minus_alphas_bar_sqrt):
    """从x[T]采样t时刻的重构值"""
    t = torch.tensor([t]).to(device)
    coeff = betas[t] / one_minus_alphas_bar_sqrt[t]
    eps_theta = model(x,t)
    mean = (1/(1-betas[t]).sqrt())*(x-(coeff*eps_theta))
    z = torch.randn_like(x).to(device)
    sigma_t = betas[t].sqrt()
    sample = mean + sigma_t * z
    return (sample)

这里 X t − 1 = μ ~ + β t z X_{t-1} = \widetilde{\mu} + \sqrt{\beta_t} z Xt1=μ +βt z (DDPM不学习方差,方差直接设置为 β \beta β, 所以标准差就是 β t \sqrt{\beta_t} βt , 其中 z是随机生成的噪声)
μ ~ ( X t , X 0 ) = 1 α ‾ t ( X t − β t 1 − α ‾ t ϵ t ) \widetilde{\mu}(X_t, X_0) = \frac{1}{\sqrt{\overline{\alpha}_t}}(X_t-\frac{\beta_t}{\sqrt{1-\overline{\alpha}_t}}\epsilon_t) μ (Xt,X0)=αt 1(Xt1αt βtϵt) 对应下面的代码

coeff = betas[t] / one_minus_alphas_bar_sqrt[t]
eps_theta = model(x,t)
mean = (1/(1-betas[t]).sqrt())*(x-(coeff*eps_theta))

one_minus_alphas_bar_sqrt对应 1 − α ‾ t \sqrt{1-\overline{\alpha}_t} 1αt



模型训练

seed = 1234
    
print('Training model...')
batch_size = 128
dataloader = torch.utils.data.DataLoader(dataset,batch_size=batch_size,shuffle=True)
num_epoch = 4000
plt.rc('text',color='blue')

model = MLPDiffusion(num_steps)#输出维度是2,输入是x和step
model = model.cuda()
optimizer = torch.optim.Adam(model.parameters(),lr=1e-3)

for t in range(num_epoch):
    for idx,batch_x in enumerate(dataloader):
        loss = diffusion_loss_fn(model,batch_x,alphas_bar_sqrt,one_minus_alphas_bar_sqrt,num_steps)
        optimizer.zero_grad()
        loss.backward()
        torch.nn.utils.clip_grad_norm_(model.parameters(),1.)
        optimizer.step()
        
    if(t%100==0):
        print(loss)
        x_seq = p_sample_loop(model,dataset.shape,num_steps,betas,one_minus_alphas_bar_sqrt)
        
        x_seq = [item.to('cpu') for item in x_seq]
        fig,axs = plt.subplots(1,10,figsize=(28,3))
        for i in range(1,11):
            cur_x = x_seq[i*10].detach()
            axs[i-1].scatter(cur_x[:,0],cur_x[:,1],color='red',edgecolor='white');
            axs[i-1].set_axis_off();
            axs[i-1].set_title('$q(\mathbf{x}_{'+str(i*10)+'})$')

Training model…
tensor(0.5281, device=‘cuda:0’, grad_fn=)
tensor(0.6795, device=‘cuda:0’, grad_fn=)
tensor(0.3125, device=‘cuda:0’, grad_fn=)
tensor(0.3071, device=‘cuda:0’, grad_fn=)
tensor(0.2241, device=‘cuda:0’, grad_fn=)
tensor(0.3483, device=‘cuda:0’, grad_fn=)
tensor(0.4395, device=‘cuda:0’, grad_fn=)
tensor(0.3733, device=‘cuda:0’, grad_fn=)
tensor(0.6234, device=‘cuda:0’, grad_fn=)
tensor(0.2991, device=‘cuda:0’, grad_fn=)
tensor(0.3027, device=‘cuda:0’, grad_fn=)
tensor(0.3399, device=‘cuda:0’, grad_fn=)
tensor(0.2055, device=‘cuda:0’, grad_fn=)
tensor(0.4996, device=‘cuda:0’, grad_fn=)
tensor(0.4738, device=‘cuda:0’, grad_fn=)
tensor(0.1580, device=‘cuda:0’, grad_fn=)

好多个epoch之后be like:
DDPM原理与代码剖析


动画演示

import io
from PIL import Image

imgs = []
for i in range(100):
    plt.clf()
    q_i = q_x(dataset,torch.tensor([i]))
    plt.scatter(q_i[:,0],q_i[:,1],color='red',edgecolor='white',s=5);
    plt.axis('off');
    
    img_buf = io.BytesIO()
    plt.savefig(img_buf,format='png')
    img = Image.open(img_buf)
    imgs.append(img)
reverse = []
for i in range(100):
    plt.clf()
    cur_x = x_seq[i].detach()
    plt.scatter(cur_x[:,0],cur_x[:,1],color='red',edgecolor='white',s=5);
    plt.axis('off')
    
    img_buf = io.BytesIO()
    plt.savefig(img_buf,format='png')
    img = Image.open(img_buf)
    reverse.append(img)

保存为gif文章来源地址https://www.toymoban.com/news/detail-443220.html

imgs = imgs + reverse
imgs[0].save("diffusion.gif",format='GIF',append_images=imgs,save_all=True,duration=100,loop=0)

到了这里,关于DDPM原理与代码剖析的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 通俗理解DDPM到Stable Diffusion原理

    🤗关注公众号 funNLPer 畅度阅读🤗 代码1:stabel diffusion 代码库 代码2:diffusers 代码库 论文:High-Resolution Image Synthesis with Latent Diffusion Models 模型权重:runwayml/stable-diffusion-v1-5

    2024年02月11日
    浏览(40)
  • AIGC系列之:DDPM原理解读(简单易懂版)

    目录 DDPM基本原理 DDPM中的Unet模块 Unet模块介绍 Unet流程示意图 DownBlock和UpBlock MiddleBlock 文生图模型的一般公式 总结         本文部分内容参考文章:https://juejin.cn/post/7251391372394053691,https://zhuanlan.zhihu.com/p/563661713,感谢博主的辛苦工作,本文尽量去繁就简去理解DDPM的原理

    2024年04月17日
    浏览(32)
  • 生成式 AI - Diffusion 模型 (DDPM)原理解析(1)

    来自 论文《 Denoising Diffusion Probabilistic Model》(DDPM) 论文链接:https://arxiv.org/abs/2006.11239 Hung-yi Lee 课件整理 简单地介绍diffusion model 的基本概念,diffusion model有很多不同的变形,现在比较成功的使用diffusion model实现的图像生成的系统,比如阿里、Google的系统基本上都是用差不

    2024年03月13日
    浏览(62)
  • AI绘画Stable Diffusion原理之扩散模型DDPM

    传送门: stable diffusion:Git|论文 stable-diffusion-webui:Git Google Colab Notebook部署stable-diffusion-webui:Git kaggle Notebook部署stable-diffusion-webui:Git AI绘画,输入一段文本就能生成相关的图像,stable diffusion便是其中一个重要分支。自己对其中的原理比较感兴趣,因此开启这个系列的文章

    2024年02月03日
    浏览(50)
  • Webpack5入门到原理1:前言

    开发时,我们会使用框架(React、Vue),ES6 模块化语法,Less/Sass 等 css 预处理器等语法进行开发。 这样的代码要想在浏览器运行必须经过编译成浏览器能识别的 JS、Css 等语法,才能运行。 所以我们需要打包工具帮我们做完这些事。 除此之外,打包工具还能压缩代码、做兼容

    2024年01月20日
    浏览(51)
  • Stable Diffusion 原理介绍与源码分析(二、DDPM、DDIM、PLMS算法分析)

    Stable Diffusion 原理介绍与源码分析(一、总览) 发现标题越起越奇怪了… 本文继续介绍 Stable Diffusion 框架的实现。在之前的文章 Stable Diffusion 原理介绍与源码分析(一、总览) 中,我介绍了 Stable Diffusion 文生图框架的整体结构,如下图,并简要描述了其各个重要组成模块:

    2023年04月09日
    浏览(37)
  • 掌握 GitHub Copilot:6个代码自动补全的必备技巧前言

    GitHub Copilot 是一款由人工智能驱动的编码助手,它能够根据上下文提供代码建议,极大地加快了开发过程。在之前介绍如何激活 Copilot 的文章之后,本文将深入探讨六个关键技巧,以高效利用 GitHub Copilot。 通过以下快捷键,可以更高效地使用 GitHub Copilot: **Tab:**接受建议。

    2024年04月16日
    浏览(82)
  • Visual Studio Code 珍藏好久的插件推荐

    目录 1、Prettier - Code formatter ​2、ESLINT 3、Chinese (Simplified) (简体中文) Language Pack for Visual Studio Code 4、GitLens — Git supercharged 5、vscode-icons​编辑 6、Remote - SSH 7、Auto Rename Tag 8、Vetur 9、Path Intellisense 10、Auto Close Tag 11、ES7+ React/Redux/React-Native snippets 12、Code Spell Checker 13、npm Intelli

    2024年02月09日
    浏览(185)
  • icloud照片要是关闭有什么影响?

    关闭iCloud照片将对您的设备和照片库产生以下影响: 1. 照片同步停止:关闭iCloud照片后,您的设备将不再自动同步照片到iCloud。这意味着您拍摄的新照片和录制的新视频将不会自动上传到iCloud照片库。                                     2. 存储空间释放:关闭iCloud照片

    2024年01月17日
    浏览(44)
  • Flutter原理篇:GestureDetector原理深度剖析及手势原理(上)

    今天我们来讲讲GestureDetector的深度剖析,只有了解原理了,才能知道手势冲突如何解决以及如何更灵活的运用手势。 我们先来看看GestureDetector的内部结构 1. GestureDetector 只是一个包装类,最终还是由 Listener 的 RenderPointListener 执行事件的操作 2.点击事件开始时会首先执行 RawG

    2024年04月27日
    浏览(37)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包