Diffusion添加噪声noise的方式有哪些?怎么向图像中添加噪声?

添加噪声的方式大致分为两种,一种是每张图像在任意timestep都加入一样的均匀噪声,另一种是按照timestep添加不同程度的噪声

一、在任意timestep都加入一样的noise

batch_size = 32

x_start = torch.rand(batch_size,3,256,256)
noise = torch.randn_like(x_start)
x_noisy = x_start + noise

print(x_noisy)

二、按照timestep添加不同程度的noise

插入的方式有很多:(linear、cosine、sqrt_linear、sqrt),不论哪种方式插入noise,都是按照以下的公式进行的噪声插入,只不过是β在每个timestep的值不一样,从而造成不同timestep有不同程度的噪声

这里的x0可以是不同的东西,加入噪声可以有多种应用,例如最常见的输入图像(bz, 3, 256, 256)【经典的diffusion论文】、输入图像经过pretrain encoder后的表征(bz, 512, 1, 1)【RCG论文】...

1、最简单的写法(linear)

通过线性的方式(torch.linspace)插入noise

import torch


## ----------------------------- 确定超参数的值 ----------------------------- ##
num_steps = 100

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

# 定义调整noise的常量
alphas_bar_sqrt = torch.sqrt(alphas_prod)
one_minus_alphas_bar_sqrt = torch.sqrt(1 - alphas_prod)


## ----------------------------- 确定扩散前向过程任意时刻的采样值 x[t]: x[0] + t --> x[t] ----------------------------- ##
def q_x(x_0, t):
    """
    x[0] + t --> x[t]
    :param x_0:初始数据
    :param t:任意时刻
    """
    noise = torch.randn_like(x_0)
    # 取出在某个时刻t所对应的alphas_t、alphas_1_m_t的值
    alphas_t = alphas_bar_sqrt[t]
    alphas_1_m_t = one_minus_alphas_bar_sqrt[t]
    x_t = alphas_t * x_0 + alphas_1_m_t * noise
    return x_t



batch_size = 32
x_start = torch.rand(batch_size,3,256,256)
# 给x_start加上在timestep 65 的时候噪声
x_noisy = q_x(x_start, 65)

一文弄懂 Diffusion Model(DDPM)+ 代码实现-CSDN博客

 

2、可选不同的β策略

不同的β策略

import torch
from inspect import isfunction
from functools import partial
import numpy as np


to_torch = partial(torch.tensor, dtype=torch.float32)
def make_beta_schedule(schedule, n_timestep, linear_start=1e-4, linear_end=2e-2, cosine_s=8e-3):
    """
    设置β的调度值
    """
    if schedule == "linear":
        betas = (torch.linspace(linear_start ** 0.5, linear_end ** 0.5, n_timestep, dtype=torch.float64) ** 2)
    elif schedule == "cosine":
        timesteps = (torch.arange(n_timestep + 1, dtype=torch.float64) / n_timestep + cosine_s)
        alphas = timesteps / (1 + cosine_s) * np.pi / 2
        alphas = torch.cos(alphas).pow(2)
        alphas = alphas / alphas[0]
        betas = 1 - alphas[1:] / alphas[:-1]
        betas = np.clip(betas, a_min=0, a_max=0.999)
    elif schedule == "sqrt_linear":
        betas = torch.linspace(linear_start, linear_end, n_timestep, dtype=torch.float64)
    elif schedule == "sqrt":
        betas = torch.linspace(linear_start, linear_end, n_timestep, dtype=torch.float64) ** 0.5
    else:
        raise ValueError(f"schedule '{schedule}' unknown.")
    return betas.numpy()

定义超参数 

betas = make_beta_schedule(schedule="linear", n_timestep=1000, linear_start=0.0015, linear_end=0.0195, cosine_s=0.008)

alphas = 1. - betas
alphas_cumprod = np.cumprod(alphas, axis=0)
alphas_cumprod = to_torch(alphas_cumprod)
sqrt_alphas_cumprod = to_torch(np.sqrt(alphas_cumprod))
sqrt_one_minus_alphas_cumprod = to_torch(np.sqrt(1. - alphas_cumprod))


batch_size = 32
# x_start = torch.rand(batch_size,512,1,1)
x_start = torch.rand(batch_size,3,256,256)
noise = torch.randn_like(x_start)
t = torch.randint(0, 1000, (batch_size,)).long()


def exists(x):
    return x is not None


def default(val, d):
    if exists(val):
        return val
    return d() if isfunction(d) else d


def extract_into_tensor(a, t, x_shape):
    b, *_ = t.shape
    out = a.gather(-1, t)
    return out.reshape(b, *((1,) * (len(x_shape) - 1)))


def q_sample(x_start, t, noise=None):
    noise = default(noise, lambda: torch.randn_like(x_start))
    return (extract_into_tensor(sqrt_alphas_cumprod, t, x_start.shape) * x_start +
            extract_into_tensor(sqrt_one_minus_alphas_cumprod, t, x_start.shape) * noise)


x_noisy = q_sample(x_start=x_start, t=t, noise=noise)

### 扩散模型中添加高斯噪声的作用 在扩散模型中,添加高斯噪声是一个核心操作。这一过程有助于逐步破坏输入数据的信息结构,从而使得模型能够学习如何逆向恢复这些被破坏的数据[^1]。 具体来说,通过逐渐增加的高斯噪声扰动,可以使原本复杂的分布变得简单化,最终接近于标准正态分布。这种机制允许模型在一个可控的方式下探索数据的空间变化特性,并学会从纯随机噪声重建出有意义的数据样本。此过程中引入的不同层次的噪声模拟了多种可能存在的不确定性因素,增强了模型对于各类干扰条件下的鲁棒性和泛化能力[^2]。 ### 实现方法 为了实现上述目标,在实践中通常采用如下方式来加入高斯噪声: #### 前向扩散过程 定义一系列的时间步$t$,其中$t=0, ..., T$;随着$t$的增长,所加上的噪声强度也随之增大。每一步骤的具体做法是在当前状态$x_t$的基础上叠加一个服从$\mathcal{N}(0,\beta_t)$分布的小幅度增量$\epsilon_t$作为新的状态$x_{t+1}$: $$ x_{t+1} = \sqrt{(1-\beta_t)}x_t+\sqrt{\beta_t}\cdot\epsilon_t $$ 这里$\beta_t$代表的是方差系数,它决定了每一时刻应该施加多大程度的扰动效果。随着时间推移,累积起来的效果就是让初始信号慢慢退化直至完全淹没在背景噪音之中[^3]。 ```python import numpy as np def add_gaussian_noise(x_0, beta_schedule): """ 向给定的数据点序列添加渐增式的高斯白噪声 参数: x_0 (np.ndarray): 初始干净数据 beta_schedule (list or array-like): 方差调度表 返回: list of np.ndarrays: 不同时间戳对应的含噪版本 """ noisy_samples = [] current_sample = x_0.copy() for t, beta in enumerate(beta_schedule): noise = np.random.normal(loc=0., scale=np.sqrt(beta), size=current_sample.shape) next_sample = np.sqrt(1-beta)*current_sample + noise noisy_samples.append(next_sample) # 更新用于下一阶段传播的状态变量 current_sample = next_sample return noisy_samples ``` 在这个例子中,`add_gaussian_noise` 函数接收一组原始数据 `x_0` 和预设好的 $\beta$ 调度列表,返回经过逐次污染后的各期观测值集合。注意这里的 $\beta$ 序列应当精心设计以确保平稳过渡而不至于过早丧失细节信息。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Pengsen Ma

太谢谢了

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值