天呐!原来我们每天都在用的AI生图,背后竟是如此“粗暴”的原理?!(附源码运行显示)

🤯 天呐!原来我们每天都在用的AI生图,背后竟是如此“粗暴”的原理?! 🤯

你有没有想过,那些让设计师集体失业、让普通人秒变艺术家的AI绘画工具,它们到底是怎么“画”出那些以假乱真的图像的?🤔

今天,就让我们一起揭开AI绘画的神秘面纱,看看它背后究竟隐藏着怎样的“魔法”!🧙‍

1.  AI绘画?不,其实是“噪声”的艺术!🎨

想象一下,你有一张干净的白纸,想要在上面画出一只可爱的猫咪。🐱 你会怎么做? 一笔一笔地勾勒线条,一点一点地填充颜色,对吧?

 

但AI可不是这么干的! 它的“绘画”过程,更像是“从噪声中捞图”。

啥是噪声? 你可以把它想象成电视机没有信号时出现的雪花点,或者收音机调台时发出的“沙沙”声。 它们看起来杂乱无章,毫无意义,对吧?



AI绘画的第一步,就是往一张干净的图片上,一点一点地“加噪声”。就像你往一杯清水里,慢慢地滴入墨水,直到它完全变成一团漆黑。⚫

2.  “加噪”容易,“去噪”难? AI的“逆向思维”!🧠

你可能会问:把图片变成噪声,这有什么用? 别急,好戏还在后头!

AI绘画的第二步,就是“去噪”。它会学习如何从这些充满噪声的图片中,一点一点地还原出原始的图像。就像你把一杯墨水,慢慢地过滤、净化,直到它重新变回清澈透明。💧

这个过程,可比“加噪”难多了! 但这正是AI的厉害之处。它通过大量的学习和训练,掌握了从噪声中识别图像特征的能力。 即使图片被噪声“污染”得面目全非,AI也能从中“嗅”出蛛丝马迹,还原出图像的本来面貌。

3.  DDPM:AI绘画的“秘密武器”!⚔️

看到这里,你是不是对AI绘画的原理有了一点点感觉了? 其实,上面讲的这个过程,就是目前最火的AI绘画模型之一——DDPM(Denoising Diffusion Probabilistic Models,去噪扩散概率模型)的核心思想。

DDPM就像一位神奇的魔术师,它先用“噪声”把图像“变没”,再用“去噪”的魔法把图像“变回来”。🎩✨

4.  亲手体验“噪声”的魔力!🖐️

说了这么多,不如亲自上手体验一下! 下面这段代码,可以让你直观地看到图片是如何一步步变成噪声的:
 

import torch
import torch.nn as nn
class NoiseScheduler(nn.Module):
    def __init__(self, beta_start=0.0001, beta_end=0.02, num_steps=1000):
        """初始化噪声调度器
        Args:
            beta_start: β1,初始噪声水平
            beta_end: βT,最终噪声水平 
            num_steps: T,扩散步数
            device: 运行设备
        """
        super().__init__()
        self.beta_start = beta_start
        self.beta_end = beta_end
        self.num_steps = num_steps

        # β_t: 线性噪声调度
        self.register_buffer('betas', torch.linspace(beta_start, beta_end, num_steps))
        # α_t = 1 - β_t
        self.register_buffer('alphas', 1.0 - self.betas)
        # α_bar_t = ∏(1-β_i) from i=1 to t
        self.register_buffer('alpha_bar', torch.cumprod(self.alphas, dim=0))
        # α_bar_(t-1)
        self.register_buffer('alpha_bar_prev', torch.cat([torch.tensor([1.0]), self.alpha_bar[:-1]], dim=0))
        # sqrt(α_bar_t)
        self.register_buffer('sqrt_alpha_bar', torch.sqrt(self.alpha_bar))
        # 1/sqrt(α_t)
        self.register_buffer('sqrt_recip_alphas', torch.sqrt(1.0 / self.alphas))
        # sqrt(1-α_bar_t)
        self.register_buffer('sqrt_one_minus_alpha_bar', torch.sqrt(1.0 - self.alpha_bar))

        # 1/sqrt(α_bar_t)
        self.register_buffer('sqrt_recip_alphas_bar', torch.sqrt(1.0 / self.alpha_bar))
        # sqrt(1/α_bar_t - 1)
        self.register_buffer('sqrt_recipm1_alphas_bar', torch.sqrt(1.0 / self.alpha_bar - 1))
        # 后验分布方差 σ_t^2
        self.register_buffer('posterior_var', self.betas * (1.0 - self.alpha_bar_prev) / (1.0 - self.alpha_bar))
        # 后验分布均值系数1: β_t * sqrt(α_bar_(t-1))/(1-α_bar_t)
        self.register_buffer('posterior_mean_coef1', self.betas * torch.sqrt(self.alpha_bar_prev) / (1.0 - self.alpha_bar))
        # 后验分布均值系数2: (1-α_bar_(t-1)) * sqrt(α_t)/(1-α_bar_t)
        self.register_buffer('posterior_mean_coef2', (1.0 - self.alpha_bar_prev) * torch.sqrt(self.alphas) / (1.0 - self.alpha_bar))
   
    def get(self, var, t, x_shape):
        """获取指定时间步的变量值并调整形状
        Args:
            var: 要查询的变量
            t: 时间步
            x_shape: 目标形状
        Returns:
            调整后的变量值
        """
        # 从变量张量中收集指定时间步的值
        out = var[t]
        # 调整形状为[batch_size, 1, 1, 1],以便进行广播
        return out.view([t.shape[0]] + [1] * (len(x_shape) - 1))

    def add_noise(self, x, t):
        """向输入添加噪声
        实现公式: x_t = sqrt(α_bar_t) * x_0 + sqrt(1-α_bar_t) * ε, ε ~ N(0,I)
        Args:
            x: 输入图像 x_0
            t: 时间步
        Returns:
            (noisy_x, noise): 加噪后的图像和使用的噪声
        """
        # 获取时间步t对应的sqrt(α_bar_t)
        sqrt_alpha_bar = self.get(self.sqrt_alpha_bar, t, x.shape)
        # 获取时间步t对应的sqrt(1-α_bar_t)
        sqrt_one_minus_alpha_bar = self.get(self.sqrt_one_minus_alpha_bar, t, x.shape)
        # 从标准正态分布采样噪声 ε ~ N(0,I)
        noise = torch.randn_like(x)
        # 实现前向扩散过程: x_t = sqrt(α_bar_t) * x_0 + sqrt(1-α_bar_t) * ε
        return sqrt_alpha_bar * x + sqrt_one_minus_alpha_bar * noise, noise


def plot_diffusion_steps(image, noise_scheduler, step_size=100):
    """绘制图像逐步加噪的过程
    Args:
        image: 原始图像
        noise_scheduler: 噪声调度器
        step_size: 每隔多少步绘制一次
    Returns:
        fig: 绘制的图像
    """
    num_images = noise_scheduler.num_steps // step_size
    fig = plt.figure(figsize=(15, 3))
   
    # 绘制原始图像
    plt.subplot(1, num_images + 1, 1)
    plt.imshow(show_tensor_image(image))
    plt.axis('off')
    plt.title('Original')
   
    # 绘制不同时间步的噪声图像
    for idx in range(num_images):
        t = torch.tensor([idx * step_size])
        noisy_image, _ = noise_scheduler.add_noise(image, t)
        plt.subplot(1, num_images + 1, idx + 2)
        plt.imshow(show_tensor_image(noisy_image))
        plt.axis('off')
        plt.title(f't={t.item()}')
   
    plt.tight_layout()
    return fig


if __name__ == "__main__":
    import matplotlib.pyplot as plt
    from dataloader import load_transformed_dataset, show_tensor_image

    train_loader, test_loader = load_transformed_dataset()
    image, _ = next(iter(train_loader))
    noise_scheduler = NoiseScheduler()
    noisy_image, noise = noise_scheduler.add_noise(image, torch.randint(0, noise_scheduler.num_steps, (image.shape[0],)))
    plt.imshow(show_tensor_image(noisy_image))

    # 绘制加噪过程
    fig = plot_diffusion_steps(image[0:1], noise_scheduler)
    plt.show()



只需运行 `python ddpm/diffusion.py`,你就能亲眼见证一张图片是如何逐渐被噪声吞噬的。🤯

5.  AI绘画,未来可期!🚀

看完这篇文章,你是不是对AI绘画有了全新的认识? 它不再是高深莫测的“黑科技”,而是一个充满趣味和挑战的领域。

未来,随着技术的不断发展,AI绘画将会给我们带来更多的惊喜和可能性。 也许有一天,我们每个人都能成为AI绘画大师,用想象力和创造力,创造出属于自己的艺术作品!🎨🖼️

#AI绘画 #DDPM #噪声 #去噪 #原理揭秘 #科技 #未来看完这篇文章,你有什么想法? 快来评论区分享你的观点吧!👇

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值