博客主页 🏗️
文章

Count:

计 48 篇
61
Diffusion Model
无标签
Diffusion Model
分类: Code
简介:Diffusion model更新一下很早之前的工作吧,后面会有更有趣的东西,但是更新时间不一定咯。DDPM:Diffusion model:扩散模型,本质上是一个生成模型。我理解的是对输入图像X进入多层Encoder,每一层形成马克可夫链,施加随机噪声(一般是高斯噪声)。最后通过同样层数的Decoder消除噪声获得X’。其实就是学习恢复数据的过程。下面对比这几个比较相似的生成模型。、其实Diffusion model跟GAN和VAE等模型的最大区别就是不是通过一个模型来生成的,而是基于马尔科夫链,通过学习噪声来生成数据。Diffusion包括前向扩散过程和反向生成过程。其中前向扩散过程指的是:像观测数据中加入噪声,直到观测数据变为高斯分布。反向生成过程指的是:从一个高斯分布中采样,随着时间T逐步的消除噪声,最终还原到清晰数据。从x0 >xt是一个逐步加噪的过程,其中噪声是已知的,最终目的是生成一张标准高斯分布图像;xt >x0是一个消噪的过程,这个噪声是需要去学习的,最终目的是还原一张图片。前向过程前向过程是增加噪声、有序到无序、熵增的过程,其满足马尔科夫过程,当前图像xt只与上一时刻xt 1有关。2024 09 14T04:40:33.png当然在前向过程中,如果我们想求得x_t,我们是否就需要一步一步的求得x_1,x_2...,x_t 1呢?这样子就跟RNN一样是一个串行的过程,计算量大且效率不高。因此经过公式推导可以知道,我们是可以从x_0直接推导到x_t的。推导过程如下:逆向过程逆向过程就是消除噪声的过程,从无序到有序,熵减的过程。也就是我们要从x_t推到x_0,但是一般反向进行推导是很困难的,所以我们先从x_t推导到x_t 1再一步一步的到x_0。根据上述最后一个公式,我们的未知量就只有z_t,即t步对应的噪声,这是需要我们进行预测的。最终就是这样一个过程。训练过程和采样过程如图所示,这里需要注意的是虽然T是固定的(200or其他),但是我们在训练的时候给定的t是随机的在0 T之间,并且t需要做位置编码,根据t从x_0求出x_t,最后将x_t和t送入模型训练,预测出噪声和真实噪声比较,计算损失,最后传播梯度。demoimport matplotlib.pyplot as plt import numpy as np from sklearn.datasets import make_s_curve import torch # TODO 实验数据 s_curve , _ = make_s_curve(10**4 , noise = 0.1) s_curve = s_curve[:,[0,2] ]/10.0 print("shape of moons :",np.shape(s_curve)) data = s_curve.T fig,ax = plt.subplots() ax.scatter(*data ,color='red',edgecolor='white') ax.axis('off') plt.show() dataset = torch.Tensor(s_curve).float() # shape of moons : (10000, 2) # TODO 确定超参数的值 num_steps = 100 # 可以由beta alpha 分布 均值 标准差 进行估算 # 学习的超参数 动态的在(0,1)之间逐渐增大 betas = torch.linspace( 6,6,num_steps) 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 ,dim=0 ) # 累积连乘 https://pytorch.org/docs/stable/generated/torch.cumprod.html alphas_prod_p = torch.cat([torch.tensor([1]).float() ,alphas_prod[: 1]],0) # p means previous 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_prod.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) # # TODO 确定扩散过程中任意时刻的采样值 def q_x(x_0 ,t): noise = torch.randn_like(x_0) # noise 是从正太分布中生成的随机噪声 alphas_t = alphas_bar_sqrt[t] ## 均值 \sqrt{\bar \alpha_t} alphas_l_m_t = one_minus_alphas_bar_sqrt[t] ## 标准差 \sqrt{ 1 \bar \alpha_t} # alphas_t = extract(alphas_bar_sqrt , t, x_0) # 得到sqrt(alphas_bar[t]) ,x_0的作用是传入shape # alphas_l_m_t = extract(one_minus_alphas_bar_sqrt , t, x_0) # 得到sqrt(1 alphas_bart[t]) return (alphas_t * x_0 + alphas_l_m_t * noise) # TODO 演示原始数据分布加噪100步后的效果 num_shows = 20 fig , axs = plt.subplots(2,10,figsize=(28,3)) plt.rc('text',color='blue') # 共有10000个点,每个点包含两个坐标 # 生成100步以内每隔5步加噪声后的图像 for i in range(num_shows): j = i // 10 k = i % 10 t = i*num_steps//num_shows # t=i*5 q_i = q_x(dataset ,torch.tensor( [t] )) # 使用刚才定义的扩散函数,生成t时刻的采样数据 x_0为dataset 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 _{'+str(i*num_steps//num_shows)+'})$') plt.show() # TODO 编写拟合逆扩散过程 高斯分布 的模型 # \varepsilon_\theta(x_0,t) 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): 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 # TODO loss 使用最简单的 loss def diffusion_loss_fn(model,x_0,alphas_bar_sqrt,one_minus_alphas_bar_sqrt,n_steps):# n_steps 用于随机生成t '''对任意时刻t进行采样计算loss''' batch_size = x_0.shape[0] # 随机采样一个时刻t,为了体检训练效率,需确保t不重复 # weights = torch.ones(n_steps).expand(batch_size, 1) # t = torch.multinomial(weights,num_samples=1,replacement=False) # [barch_size, 1] t = torch.randint(0,n_steps,size=(batch_size//2,)) # 先生成一半 t = torch.cat([t,n_steps 1 t],dim=0) # 【batchsize,1】 t = t.unsqueeze( 1)# batchsieze # print(t.shape) # x0的系数 a = alphas_bar_sqrt[t] # 生成的随机噪音eps e = torch.randn_like(x_0) # eps的系数 aml = one_minus_alphas_bar_sqrt[t] # 构造模型的输入 x = x_0* a + e *aml # 送入模型,得到t时刻的随机噪声预测值 output = model(x,t.squeeze( 1)) # 与真实噪声一起计算误差,求平均值 return (e output).square().mean() # TODO 编写逆扩散采样函数(inference过程) 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) 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) coeff = betas[t] / one_minus_alphas_bar_sqrt[t] eps_theta = model(x,t) mean = (1/(1 betas[t]).sqrt())*(x (coeff*eps_theta)) # 之前写错了:mean = (1/(1 betas[t].sqrt()) * (x (coeff * eps_theta))) z = torch.randn_like(x) sigma_t = betas[t].sqrt() sample = mean + sigma_t * z return (sample) # TODO 模型的训练 seed = 1234 class EMA(): '''构建一个参数平滑器''' def __init__(self,mu = 0.01): self.mu =mu self.shadow = def register(self,name,val): self.shadow[name] = val.clone() def __call__(self, name, x): # call函数? assert name in self.shadow new_average = self.mu * x +(1.0 self.mu) * self.shadow[name] self.shadow[name] = new_average.clone() return new_average 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 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() # for name ,param in model.named_parameters(): # if params.requires_grad: # param.data = ems(name,param.data) # print loss if (t% 100 == 0): print(loss) x_seq = p_sample_loop(model,dataset.shape,num_steps,betas,one_minus_alphas_bar_sqrt)# 共有100个元素 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 _{'+str(i*10)+'})$') 结果数据集使用sklearn.datasets中的make_s_curve生成三维S曲线数据集,10k个三维点,我直接截取了第0维和第3维数据投影到二维平面呈S型。训练时使用这个二维投影点组成的分布图形进行训练,batch_size=128,epoch=4000,每一轮将点集打乱。也就是每一个iteration从10k点中抽取128直至抽完算一个epoch,也就是学习这些点集的分布。原始分布:加噪过程:训练过程:
147
小南山公园 小南山公园 小南山公园 小南山公园
无标签
小南山公园
125
西湾红树林-(漏拍孤独的树版) 西湾红树林-(漏拍孤独的树版) 西湾红树林-(漏拍孤独的树版) 西湾红树林-(漏拍孤独的树版)
无标签
西湾红树林-(漏拍孤独的树版)
295
机器视觉与深度学习基础知识补漏Week1
无标签
机器视觉与深度学习基础知识补漏Week1
分类: 默认分类
简介:机器视觉与深度学习基础知识补漏Week1线性分类器分类器设计总体流程下图是分类器设计总体流程图像表示二值化图像;(0or1)灰度图像;(0 255 单通道)彩色图像;(三通道RGB)分类模型线性分类器:f(x,w)计算分类得分,选取其中最高的分类得分作为分类输出。其中w其实是作为权重矩阵,w表示对图像中特殊部分进行突出显示,b为偏置项。(模板)线性分类器其实就是寻找分类的决策边界。通过决策边界来判断样本的分类情况。### 损失函数损失值:真实值和预测值的差值。一般数据集的损失函数定义:多累支撑向量机损失:其中存在一个+1操作,是为了防止两类误差分类预测值相近,虽然预测正确,但是分类器仍需优化的情况。引入正则损失(对参数的损失,参数平衡)。其中包含一个超参数用来调整数据损失和正则损失的权重关系。优化算法目标旨在:寻找使得损失函数达到最小时的那一组W参数。直接方法:使得损失函数对W求导得0。梯度下降算法:梯度下降的方向以及步长(lr)。具体流程:计算梯度 >更新梯度梯度计算方法:1.按照导数公式求导,(f(x+n) f(x))/n这一套。2.使用解析法,现有的求导公式。随机梯度下降法:相较于梯度下降法,其是随机使用一个样本进行计算梯度,减少了计算量,在大量的数据下其正向优化效果能掩盖噪声带来的负面影响。小批量梯度下降法:每次随机选取m个样本计算梯度。m=1时就是随机梯度下降法。iteration;batch_size;epoch;数据集划分:这里搞清楚了验证集和训练集的区别:训练集只能用俩评估最终模型的性能;验证集是用来判定不同朝参属下的模型的性能,本质上用于选择超参数;训练集用来训练模型里面的参数;K折交叉验证:数据量小的时候使用,分为shuffled和not..数据预处理(去范围,去量纲):全连接神经网络网络结构激活函数常用的激活函数:损失函数SOFTMAX:将输出分数压缩到0 1内,即一个概率分布。相较于之前的输出分数,这里我们输出的是一个概率。因此对应的损失函数也应该改变。交叉熵损失:对于SOFTMAX预测概率和真实one hot编码的真实值进行损失值计算的方法。这里介绍了三个概念:熵、交叉熵和相对熵;其关系是交叉熵=熵+相对熵。由于在我们的分类任务中,确定分类结果的熵为0,所以我们可以使用交叉熵来代替相对熵来度量两个分布的不相似性。我们再将之前了解的多类支持向量机损失和交叉熵损失进行比较:其计算过程也不同。前者将每一类预测得分 真实值求和;而后者则使用真实的类别预测概率做负对数求损失。举个例子:计算图计算图是一种有向图,它用来表达输入、输出及中间变量的计算关系,图中的每一个节点对应着一种数学运算。计算图可以更好的帮我们表示计算机中表达式运算的过程,尤其是在反向传播中进行求梯度的链式求导的过程。小知识点:计算图的颗粒度。使用计算颗粒度大的门,也就是这个门不仅仅是一个符号,而是一个公式,会大大减小我们的计算量,提高计算效率,但是这种门/公式得需要自己设计。动量法对于SGD,其可能存在山谷问题,导致出现震荡。引入动量法,实际上就是引入了历史梯度信息协同更新梯度。这里引入了动量系数,用以表示历史梯度信息所占的权重(可以理解为摩擦系数)。动量法的另一个优势:通过一个历史梯度能将我们推出鞍点这个范围。另一种方法:自适应梯度法自适应梯度法:本质就是在震荡的方向减小其步长,在平缓的方向增大其步长。而对于如何分辨震荡和平缓,其依据是梯度幅度的平方大小,大的为震荡方向,小的为平缓方向。缺陷就是:随着步数的累计,历史梯度值越来越大,导致整体步长被压制,步长越来越小。为了解决这个缺陷同样引入了一个权值(类似动量),用以控制历史梯度值的影响范围。动量法和自适应梯度法结合:Adam。这里有一个细节:由于在累计梯度和累计平方梯度时,导致一开始的用来更新权值的梯度被缩小(冷启动),模型很难收敛,因此提出了一个修正偏差。其保证了初试的修正动量和修正自适应梯度能保持原有的梯度,在经过一段时间的更新后,缩小当前梯度的影响,放大两者结合的优点(累计梯度和累计平方梯度)。权值初始化首先要避免全0初始化,这样导致输出全为0,并且方向传播时的梯度也一样,最后更新后的权值也全部一样,也就是所有神经元学习到的东西全部一样,等价为1一个神经元,导致无法训练。其次权值随机初始化,保证权值服从N(0,0.01)的高斯分布。但是我们发现在第三个及之后的隐层的输出全为0,也就是前向传播的信息全部丢失了。并且因此在反向传播时局部梯度也为0,反向传播也消失。我们的神经元全部处于饱和阶段,正向传播信息传递过去了,但是在反向传播时局部梯度全部为0(梯度消失)。可以看出我们希望得到一个在正向传播过程和反向传播过程中信息不丢失的初始化方法。Xavier初始化:使得输入与输出分布相同(都为正态分布)通过分析可以知道,我们W的分布要为(0,1/N)时,输入和输出的分布才相同。批归一化解决前向过程中信号消失的问题(输出不至于小到0)。在反向传播中让较小的值回归到0均值1方差左右。下面是归一化的过程最后增加了4.平移缩放,因为0均值1方差不一定是最好的结果,需要根据数据的情况来指定,其中y是对方差的调整,p是对均值的调整都是从数据集中学习而来的。对于单张样本测试时,均值和方差来自于训练中累加的每个批次的均值和方差,最后取平均的结果作为预测时的均值和方差。过拟合模型在训练集上准确率很高,但是在真实场景下识别率很低。最好的解决方案是:增大数据集次优解:正则化:1.调节模型大小2.增加正则项(正则损失),对于大数值权值向量进行惩罚,鼓励更加分散的权重向量,使模型更倾向于用所有输入特征作决策。欠拟合模型训练效果不佳,在训练集上效果就不行,更不提测试集及其泛化能力了。DropoutDropout:让隐层的神经元以一定概率失活(不起作用),需要设置一个比例,将某一层的输出值舍弃(设置为0)。解释Dropout为什么能防止过拟合?1.更新梯度时参与计算的网络参数变少,降低模型容量。2.鼓励权重分散(通正则化)3.模型集成(很像集成学习 投票)细节问题:在dropout之后需要保持训练层和预测层的输出水平一致。超参数调优超参数是人为设计的,在模型设计阶段就需要指定。网格索搜,随机搜索。一般先采用随机搜索确定大致范围再使用网格搜索精细查找。使用标尺空间后,我们在不同量纲下分布比较均衡。
305
武汉植物园~ 武汉植物园~ 武汉植物园~ 武汉植物园~
无标签
武汉植物园~
博客主页 wyのblog I know you are here. 百度统计
鄂ICP备2023003777号-1 本站已运行 1 年 41 天 18 小时 4 分 自豪地使用 Typecho 建站,并搭配 MyDiary 主题 Copyright © 2023 ~ 2024. wyのblog All rights reserved.
打赏图
打赏博主
欢迎
搜 索
足 迹
分 类
  • 默认分类
  • Code
  • 日记
  • 音乐
  • 游戏
  • 阅读
  • 计划
  • 图片
  • 旅游
  • 影视