创建或修改目录:/www/wwwroot/104.219.215.234/data 失败!
【BS-008】のどちんこ責め M女りな</a>2015-02-27RASH&$ビザールスタイル82分钟 使用Pytorch中重新已毕去噪扩散概率模子(DDPM)(附代码) - 好看的欧美情色电影

好看的欧美情色电影

【BS-008】のどちんこ責め M女りな</a>2015-02-27RASH&$ビザールスタイル82分钟 使用Pytorch中重新已毕去噪扩散概率模子(DDPM)(附代码)

发布日期:2024-08-16 20:11    点击次数:176

【BS-008】のどちんこ責め M女りな</a>2015-02-27RASH&$ビザールスタイル82分钟 使用Pytorch中重新已毕去噪扩散概率模子(DDPM)(附代码)

【BS-008】のどちんこ責め M女りな2015-02-27RASH&$ビザールスタイル82分钟

本文约6500字,提议阅读13分钟

本文将构建基础的无条款扩散模子,即去噪扩散概率模子(DDPM)。

扩散模子常常是一种生成式深度学习模子,它通过学习去噪经由来创建数据。扩散模子有许多变体,其中最流行的是条款文本模子,大概凭据辅导生成特定的图像。某些扩散模子(如Control-Net)甚而能将图像与某些艺术格调交融。

在本文中,咱们将构建基础的无条款扩散模子,即去噪扩散概率模子(DDPM)。从探究算法的直不雅职责旨趣出手,然后在PyTorch中重新构建它。本文主要关心算法背后的想想和具体已毕细节。

咱们先展示一下本文的落幕,使用扩散模子生成给MNIST的数字。

扩散模子旨趣

扩散经由包括正向经由和反向经由。正向经由是基于噪声规画的预定马尔可夫链。噪声规画是一组方差B1, B2, … BT,这些方差松手构成马尔可夫链的条款正态分散。

正向经由的数学抒发式代表了正向经由,但直不雅上咱们不错将其相识为一个序列,逐步将数据示例X映射到纯噪声。在中间时候才能t,咱们得到X的带噪声版块,在最终时候才能T,咱们达到由轨范正态分散大要松手的纯噪声。在构建扩散模子时,需要承袭咱们的噪声规画。举例,在DDPM中,噪声规画特征是从1e-4到0.02线性加多方差的1000个时候步。相通庞大的是要老成正向经由是静态的,这意味着是咱们承袭噪声规画手脚扩散模子的一个超参数,况且这个正向经由是无用考研的,因为它还是明确界说。

对于正向经由的临了一个要道细节是,因为这些分散是正态的,不错数学上推导出一个称为“扩散核”的分散,这是给定出手数据点,正向经由中任何中间值的分散。这么就不错绕过正向经由中冉冉加多t-1级噪声的悉数中间才能,径直得回带有t噪声的图像,这在后期考研模子时会止境浮浅。这在数学上示意为:

这里的时候t的alpha界说为从出手时候步到面前时候步的积累(1-B)。

反向经由是扩散模子的要道。实践上是通过逐步移除噪声从纯噪声图像生成新图像的经由。从纯噪声数据出手,对于每个时候才能t,减去表面上由正向经由在该时候才能添加的噪声量。通过不时移除噪声,最终得到近似于原始数据分散的东西。是以咱们的主要职责是考研一个模子来近似正向经由,算计一个不错生成新样本的反向经由。

为了考研这么一个模子来算计反向扩散经由,咱们不错死守底下界说的算法:

从考研数据集结立时抽取一个数据点。

在噪声(方差)规画中承袭一个立不时候步。

添加该时候步的噪声到数据中,通过“扩散核”模拟正向扩散经由。

将扩散图像传入模子,瞻望添加的噪声。

计较瞻望噪声和实践噪声之间的均方差错,并通过该方针函数优化模子的参数。

重叠以上才能!

通过这种设施,模子冉冉学习怎样有用地去除噪声,最终大概从险些鼓胀的噪声中复原出与原始数据相似的图像。这种考研方针不仅匡助模子学会准确地瞻望噪声,而且还优化了它在各个时候才能去噪的才能,从而使反向经由愈加准确和高效。

在算法中,要是不看完竣的推导经由的话数学公式领先看起来可能有些奇怪,但从直观上讲,它是基于噪声规画的alpha值对扩散核进行的从新参数化,简易来说,它等于瞻望噪声与添加到图像中的实践噪声之间的闲居差。

要是咱们的模子大概奏效地基于正向经由的特定时候步瞻望噪声量,那么就不错从时候步T的噪声出手,冉冉移除每个时候步的噪声,直到复原出与原始数据分散相似的生成样本。

网曝黑料

采样算法不错回想如下:【BS-008】のどちんこ責め M女りな2015-02-27RASH&$ビザールスタイル82分钟

1、从轨范正态分散生树立时噪声。

对于从临了一个时候步出手向后移动的每个时候步:

2、通过算计反向经由分散来更新Z,该分散的均值由前一步的Z参数化,方差由该时候步模子算计的噪声参数化。

3、为了褂讪性,添加小数噪声回到图像中(底下会解析原因)。

4、重叠上述才能,直到达到时候步0,这么就得到了复原的图像!

这个经由的要道在于,每一步都精准休养噪声的移除,模拟反向扩散,从而冉冉接近原始数据的分散。添加小数噪声的倡导是为了留神在去噪经由中可能出现的数值不褂讪性,这么不错匡助模子更平滑地逆向映射至原始数据。

生成图像的算法天然在数学上看起来复杂,但从直观上讲,它归结为一个迭代经由,咱们从纯噪声出手,算计表面上在时候步t添加的噪声,并将其减去。咱们一直这么作念,直到得到咱们的生成样本。需要老成的一个小细节是,在咱们减去算计的噪声后,咱们会加回一小部分噪声,以保捏经由的褂讪性。举例,一出手就一次性算计并减去沿路噪声会导致止境不连贯的样本,因此在实行中,加回一丝噪声并通过每个时候步迭代,还是被实证露馅能生成更好的样本。

在这个经由中,中枢想想是通过冉冉去除每个时候步预估的噪声,然后适应地从新引入一部分噪声,这么不错幸免经由中的潜在不褂讪性。迭代不仅匡助复原更精准的图像,还能确保生成经由中图像质料的连贯性和实用性。每一步的噪声从新引入天然看似反直观,但在实践中,这种计谋对于保捏悉数这个词经由的褂讪性至关庞大,亦然已毕高质料图像生成的要道才能。

Unet

在DDPM(去噪扩散概率模子)的辩论中,作家使用了领先为医学图像分割盘算推算的UNET架构来构建模子,瞻望扩散反向经由中的噪声。本文中咱们将使用32x32像素的图像,MNIST等于这么的数据集,但这个模子也不错彭胀以处理更高分离率的数据。UNET有许多变种,但咱们将构建的模子架构概览如下图所示。

UNET是一个深度学习鸠集,它具有对称的编码器-解码器结构。编码器冉冉裁减图像的空间维度,而加多通谈数,捕捉图像中的深层特征。解码器则作念相背的职责,冉冉复原图像的空间维度和减少通谈数,最终输出与输入图像相通大小的落幕。在这个经由中,编码器妥协码器之间有卓越王人集,不错匡助解码器更好地复原图像细节。

这种架构止境稳妥用于图像的生成任务,因为它不错有用地处理和重建图像中的细节。在扩散模子中,UNET的任务是瞻望每一步中添加到图像中的噪声,这对于模子逆向去噪经由的奏效至关庞大。通过这种神志,UNET不错冉冉减少噪声,最终复原出明晰的图像。

DDPM UNET与经典UNET的主要区别在于DDPM UNET在16x16维度层中加入了老成力机制,况且在每个残差块中加入了正弦变换器镶嵌。正弦镶嵌的兴味在于告诉模子咱们正在尝试瞻望哪个时候步的噪声。通过在噪声规画中注入位置信息,不错匡助模子瞻望每个时候步的噪声。举例,要是咱们的噪声规画在某些时候步中有好多噪声,模子对其必须瞻望的时候步的相识不错匡助模子对相适时候步的噪声进行瞻望。

正弦镶嵌是不同的正弦和余弦频率,不错径直添加到输入中,给模子异常的位置/序列相识。从底下的图像中不错看出,每个正弦波都是唯一无二的,这将使模子阻滞到其在咱们噪声规画中的位置。

模子代码已毕

在咱们的模子已毕中,将从界说咱们的导入出手并编码正弦时候步镶嵌。

# Imports import torch import torch.nn as nn import torch.nn.functional as F from einops import rearrange #pip install einops from typing import List import random import math from torchvision import datasets, transforms from torch.utils.data import DataLoader from timm.utils import ModelEmaV3 #pip install timm from tqdm import tqdm #pip install tqdm import matplotlib.pyplot as plt #pip install matplotlib import torch.optim as optim import numpy as np class SinusoidalEmbeddings(nn.Module): def __init__(self, time_steps:int, embed_dim: int): super.__init__ position = torch.arange(time_steps).unsqueeze(1).float div = torch.exp(torch.arange(0, embed_dim, 2).float * -(math.log(10000.0) / embed_dim)) embeddings = torch.zeros(time_steps, embed_dim, requires_grad=False) embeddings[:, 0::2] = torch.sin(position * div) embeddings[:, 1::2] = torch.cos(position * div) self.embeddings = embeddings def forward(self, x, t): embeds = self.embeddings[t].to(x.device) return embeds[:, :, None, None]

UNET每一层中的残差块将与原始DDPM论文中使用的块使用疏导的参数。每个残差块将包括以下一系列组件:

组归一化(Group Norm):这种归一化技能是批归一化的一种变体,用于松手里面协变量偏移,止境适用于小批量大小的情况。

ReLU激活函数:这是一种非线性激活函数,它允许模子拿获输入数据中的复杂款式和非线性策划。

3x3“same”卷积:这种卷积操作保捏输出特征图的空间尺寸与输入疏导,这是通过适应的填充来已毕的。

Dropout:这是一种正则化技能,通过在考研经由中立时丢弃(即开荒为零)一些汇鸠合的激活单位,来留神模子过拟合。

卓越王人集(Skip Connection):这种王人集径直将前边某层的输出传递到背面的层,这有助于处分深度汇鸠合的梯度消除问题,并允许模子在深层中保留低级特征的信息。

# Residual Blocks class ResBlock(nn.Module): def __init__(self, C: int, num_groups: int, dropout_prob: float): super.__init__ self.relu = nn.ReLU(inplace=True) self.gnorm1 = nn.GroupNorm(num_groups=num_groups, num_channels=C) self.gnorm2 = nn.GroupNorm(num_groups=num_groups, num_channels=C) self.conv1 = nn.Conv2d(C, C, kernel_size=3, padding=1) self.conv2 = nn.Conv2d(C, C, kernel_size=3, padding=1) self.dropout = nn.Dropout(p=dropout_prob, inplace=True) def forward(self, x, embeddings): x = x + embeddings[:, :x.shape[1], :, :] r = self.conv1(self.relu(self.gnorm1(x))) r = self.dropout(r) r = self.conv2(self.relu(self.gnorm2(r))) return r + x

在DDPM中,作家在UNET的每个层(分离率轨范)使用了两个残差块,况且在16x16维度层之间的两个残差块中加入了经典的老成力机制。底下咱们将已毕这种老成力机制为UNET:

class Attention(nn.Module): def __init__(self, C: int, num_heads:int , dropout_prob: float): super.__init__ self.proj1 = nn.Linear(C, C*3) self.proj2 = nn.Linear(C, C) self.num_heads = num_heads self.dropout_prob = dropout_prob def forward(self, x): h, w = x.shape[2:] x = rearrange(x, 'b c h w -> b (h w) c') x = self.proj1(x) x = rearrange(x, 'b L (C H K) -> K b H L C', K=3, H=self.num_heads) q,k,v = x[0], x[1], x[2] x = F.scaled_dot_product_attention(q,k,v, is_causal=False, dropout_p=self.dropout_prob) x = rearrange(x, 'b H (h w) C -> b h w (C H)', h=h, w=w) x = self.proj2(x) return rearrange(x, 'b h w C -> b C h w')

在已毕老成力机制时,数据的处理相对径直。咱们将数据重塑,使得高度(h)和宽度(w)的维度统一成“序列”维度,近似于传统Transformer模子的输入,而通谈维度则造成镶嵌特征维度。使用torch.nn.functional.scaled_dot_product_attention,因为这个已毕包含了flash attention,这是一种优化版的老成力机制,从数学上与经典老成力等价。界说UNET的一个完竣层:

class UnetLayer(nn.Module): def __init__(self, upscale: bool, attention: bool, num_groups: int, dropout_prob: float, num_heads: int, C: int): super.__init__ self.ResBlock1 = ResBlock(C=C, num_groups=num_groups, dropout_prob=dropout_prob) self.ResBlock2 = ResBlock(C=C, num_groups=num_groups, dropout_prob=dropout_prob) if upscale: self.conv = nn.ConvTranspose2d(C, C//2, kernel_size=4, stride=2, padding=1) else: self.conv = nn.Conv2d(C, C*2, kernel_size=3, stride=2, padding=1) if attention: self.attention_layer = Attention(C, num_heads=num_heads, dropout_prob=dropout_prob) def forward(self, x, embeddings): x = self.ResBlock1(x, embeddings) if hasattr(self, 'attention_layer'): x = self.attention_layer(x) x = self.ResBlock2(x, embeddings) return self.conv(x), x

在DDPM中,每一层如包含两个残差块,况且可能包含一个老成力机制,此外还将镶嵌传递到每个残差块中。复返的下采样或上采样的值以及之前的值,将被存储并用于残差串联的卓越王人集。

完成UNET类如下:

class UNET(nn.Module): def __init__(self, Channels: List = [64, 128, 256, 512, 512, 384], Attentions: List = [False, True, False, False, False, True], Upscales: List = [False, False, False, True, True, True], num_groups: int = 32, dropout_prob: float = 0.1, num_heads: int = 8, input_channels: int = 1, output_channels: int = 1, time_steps: int = 1000): super.__init__ self.num_layers = len(Channels) self.shallow_conv = nn.Conv2d(input_channels, Channels[0], kernel_size=3, padding=1) out_channels = (Channels[-1]//2)+Channels[0] self.late_conv = nn.Conv2d(out_channels, out_channels//2, kernel_size=3, padding=1) self.output_conv = nn.Conv2d(out_channels//2, output_channels, kernel_size=1) self.relu = nn.ReLU(inplace=True) self.embeddings = SinusoidalEmbeddings(time_steps=time_steps, embed_dim=max(Channels)) for i in range(self.num_layers): layer = UnetLayer( upscale=Upscales[i], attention=Attentions[i], num_groups=num_groups, dropout_prob=dropout_prob, C=Channels[i], num_heads=num_heads ) setattr(self, f'Layer{i+1}', layer) def forward(self, x, t): x = self.shallow_conv(x) residuals = [] for i in range(self.num_layers//2): layer = getattr(self, f'Layer{i+1}') embeddings = self.embeddings(x, t) x, r = layer(x, embeddings) residuals.append(r) for i in range(self.num_layers//2, self.num_layers): layer = getattr(self, f'Layer{i+1}') x = torch.concat((layer(x, embeddings)[0], residuals[self.num_layers-i-1]), dim=1) return self.output_conv(self.relu(self.late_conv(x)))

这个已毕中与原文的唯一的区别是上游通谈比UNET的典型通谈稍稍大一些。因为这种架构在16GB VRAM的单个GPU上考研效能更高。

补救器

为DDPM编写噪声/方差补救轨范也止境简易。在DDPM中,咱们的补救器将在1e-4出手,在0.02收尾,并线性加多。

class DDPM_Scheduler(nn.Module): def __init__(self, num_time_steps: int=1000): super.__init__ self.beta = torch.linspace(1e-4, 0.02, num_time_steps, requires_grad=False) alpha = 1 - self.beta self.alpha = torch.cumprod(alpha, dim=0).requires_grad_(False) def forward(self, t): return self.beta[t], self.alpha[t]

同期复返beta(方差)值和alpha值,因为考研和抽样公式都是基于它们的数学推导而使用的。

临了这个函数界说了一个立时种子。要是想要重现一个特定的考研实例,每次使用疏导的种子时,立时权重和优化器出手化都是疏导的。

def set_seed(seed: int = 42): torch.manual_seed(seed) torch.cuda.manual_seed_all(seed) torch.backends.cudnn.deterministic = True torch.backends.cudnn.benchmark = False np.random.seed(seed) random.seed(seed)

考研代码

对于咱们的已毕,咱们将创建一个模子来生成MNIST数据(手写数字)。由于这些图像在PyTorch中默许是28x28的,咱们将图像填充到32x32,以适应原始论文中考研的32x32图像的轨范。

使用Adam优化器,出手学习率开荒为2e-5。咱们还使用EMA(指数移动平均)来匡助普及生成质料。EMA是模子参数的加权平均,在推理时不错创建更平滑、噪声更小的样本。在这个已毕中,使用了timm库的EMA V3的已毕,权重开荒为0.9999,与DDPM论文中所使用疏导。

def train(batch_size: int=64, num_time_steps: int=1000, num_epochs: int=15, seed: int=-1, ema_decay: float=0.9999, lr=2e-5, checkpoint_path: str=None): set_seed(random.randint(0, 2**32-1)) if seed == -1 else set_seed(seed) train_dataset = datasets.MNIST(root='./data', train=True, download=False,transform=transforms.ToTensor) train_loader = DataLoader(train_dataset, batch_size=batch_size, shuffle=True, drop_last=True, num_workers=4) scheduler = DDPM_Scheduler(num_time_steps=num_time_steps) model = UNET.cuda optimizer = optim.Adam(model.parameters, lr=lr) ema = ModelEmaV3(model, decay=ema_decay) if checkpoint_path is not None: checkpoint = torch.load(checkpoint_path) model.load_state_dict(checkpoint['weights']) ema.load_state_dict(checkpoint['ema']) optimizer.load_state_dict(checkpoint['optimizer']) criterion = nn.MSELoss(reduction='mean') for i in range(num_epochs): total_loss = 0 for bidx, (x,_) in enumerate(tqdm(train_loader, desc=f"Epoch {i+1}/{num_epochs}")): x = x.cuda x = F.pad(x, (2,2,2,2)) t = torch.randint(0,num_time_steps,(batch_size,)) e = torch.randn_like(x, requires_grad=False) a = scheduler.alpha[t].view(batch_size,1,1,1).cuda x = (torch.sqrt(a)*x) + (torch.sqrt(1-a)*e) output = model(x, t) optimizer.zero_grad loss = criterion(output, e) total_loss += loss.item loss.backward optimizer.step ema.update(model) print(f'Epoch {i+1} | Loss {total_loss / (60000/batch_size):.5f}') checkpoint = { 'weights': model.state_dict, 'optimizer': optimizer.state_dict, 'ema': ema.state_dict } torch.save(checkpoint, 'checkpoints/ddpm_checkpoint')

推理

在推理阶段,仅仅在逆转前向经由。从纯噪声出手,当今已考研的模子不错在每个时候步瞻望算计的噪声,然后不错迭代生周全新的样本。从每个不同的噪声起初,不错生成一个与原始数据分散相似但特有的样本。

def display_reverse(images: List): fig, axes = plt.subplots(1, 10, figsize=(10,1)) for i, ax in enumerate(axes.flat): x = images[i].squeeze(0) x = rearrange(x, 'c h w -> h w c') x = x.numpy ax.imshow(x) ax.axis('off') plt.show def inference(checkpoint_path: str=None, num_time_steps: int=1000, ema_decay: float=0.9999, ): checkpoint = torch.load(checkpoint_path) model = UNET.cuda model.load_state_dict(checkpoint['weights']) ema = ModelEmaV3(model, decay=ema_decay) ema.load_state_dict(checkpoint['ema']) scheduler = DDPM_Scheduler(num_time_steps=num_time_steps) times = [0,15,50,100,200,300,400,550,700,999] images = [] with torch.no_grad: model = ema.module.eval for i in range(10): z = torch.randn(1, 1, 32, 32) for t in reversed(range(1, num_time_steps)): t = [t] temp = (scheduler.beta[t]/( (torch.sqrt(1-scheduler.alpha[t]))*(torch.sqrt(1-scheduler.beta[t])) )) z = (1/(torch.sqrt(1-scheduler.beta[t])))*z - (temp*model(z.cuda,t).cpu) if t[0] in times: images.append(z) e = torch.randn(1, 1, 32, 32) z = z + (e*torch.sqrt(scheduler.beta[t])) temp = scheduler.beta[0]/( (torch.sqrt(1-scheduler.alpha[0]))*(torch.sqrt(1-scheduler.beta[0])) ) x = (1/(torch.sqrt(1-scheduler.beta[0])))*z - (temp*model(z.cuda,[0]).cpu) images.append(x) x = rearrange(x.squeeze(0), 'c h w -> h w c').detach x = x.numpy plt.imshow(x) plt.show display_reverse(images) images = []

临了要是你需要一个main函数串联考研和推理的话,就用底下这个:

def main: train(checkpoint_path='checkpoints/ddpm_checkpoint', lr=2e-5, num_epochs=75) inference('checkpoints/ddpm_checkpoint') if __name__ == '__main__': main

凭据上述代码进行75次考研后,得到了如下落幕:

回想

以上等于咱们先容的扩散概率模子(DDPM)的已毕经由。咱们起初辩论了怎样为生成MNIST数据创建模子,包括将图像从默许的28x28尺寸填充到32x32,以适应原论文的轨范。在优化方面,咱们承袭了Adam优化器,并勾搭指数移动平均(EMA)来普及生成质料。

在模子考研部分,咱们死守了一系列明确的才能,包括数据的噪声化、应用UNET进行瞻望及差错优化。咱们还引入了基本的查验点机制,以便在不同的考研周期中暂停和复原考研。推理阶段则是逆上前向经由,从纯噪声出手,通过模子冉冉瞻望和排斥噪声,最终身成与原始数据分散相似但特有的图像。

此外,咱们还包括了一个扶持函数,以可视化神志展示扩散图像,匡助用户直不雅相识模子学习逆向经由的恶果。通过这一系列的已毕和优化【BS-008】のどちんこ責め M女りな2015-02-27RASH&$ビザールスタイル82分钟,DDPM展现了其在图像生成和去噪方面的刚劲才能。






Powered by 好看的欧美情色电影 @2013-2022 RSS地图 HTML地图

Copyright Powered by站群系统 © 2013-2024

创建或修改目录:/www/wwwroot/104.219.215.234/data 失败!
JzEngine Create File False