y0k1n0的小破站 - 扩散模型
type: channel
link: http://y0k1n0.online/index.php/tag/%E6%89%A9%E6%95%A3%E6%A8%A1%E5%9E%8B/
items: [NeurIPS 2023]PreDiff:Precipitation Nowcasting with Latent Diffusion Models
items: stable diffusion代码阅读笔记

[NeurIPS 2023]PreDiff:Precipitation Nowcasting with Latent Diffusion Models
type: item
date: 2025-11-30T00:00:00+08:00
description: PreDiff:Precipitation Nowcasting with Latent Diffusion Modelsintroduction这部分首先介绍了降水预报的重要性，并说明随着数据量的增长，一些深度学习方法的出现已经对齐传统数值方法的性能；接着指出现有的深度学习方法的缺陷：由于地球气候系统的复杂性，现有模型无法捕捉多种可能的未来状态，并倾向于生成忽略关键细节的模糊预报，为此，能够表征系统固定不确定性的概率模型应运而生。接着作者介绍了扩散模型相较于对抗生成网络和自回归模型的优势以及其在地球预报系统中的起步阶段的现实，指出了现在这种纯数据驱动的研究缺乏来自动态系统先验知识约束的问题，并由此提出了作者的基于Earthformer的pre-diff模型。Method这节作者介绍了他的思路：将降水预报问题建模为时空预测问题。输入：$y = [y^j]_{j = 1} ^{L_{in}}\in \mathbb{R}^{L_{in}\times H\times W\times C}$输出：$x = [x^j]_{j = 1} ^{L_{out}}\in \mathbb{R}^{L_{out}\times H\times W\times C}$模型：在给定输入$y$下建立其条件概率分布$p(x|y)$同时，作者还给出了模型的推理过程示意图：模型将输入序列通过编码得到对应的潜在向量$z_{cond}$，然后将潜在向量$z_{cond}$和纯噪声一起送入模型，通过逐步去噪获得预测图像$\hat{x}$。其中先验知识对齐到相应章节再聊。Preliminary: Diffusion Models这部分简要介绍了一下扩散模型：前向加噪：$q(x_t|x_{t-1}) = \mathcal{N}\left(x_t; \sqrt{\alpha_t}x_{t-1}, (1-\alpha_t)\boldsymbol{I}\right)(1 \leq t \leq T)$，其中$x_0\sim p(x)$是真实数据，$x_T \sim \mathcal{N}(0, \boldsymbol{I})$ 是随机噪声反向去噪：$p_{\theta}(x_{0:T}) = p(x_T)\prod_{t=1}^{T} p_{\theta}(x_{t-1}\mid x_t)$，这也是一个马尔科夫链过程，其中反向去噪的每一步都是一个高斯分布$p_{\theta}(x_{t-1}\mid x_t) = \mathcal{N}\left(\mu_{\theta}(x_t, t),\, \Sigma_{\theta}(x_t, t)\right)$，表示模型从$x_t$步预测得到$x_{t-1}$步的过程。为了方便理解，本文在重新推导一下扩散模型的前向过程和反向过程。重参数化技巧首先需要理解VAE所引入的重参数化技巧：在VAE中，编码器的输出是隐变量的分布参数，然后从分布中采样隐变量$z\sim q(z|x)=\mathcal{N}(\mu(x), \sigma^2(x)I)$解码器基于$z$重构输入$x$，损失函数包含重构损失和KL散度损失如果直接采样 $z \sim q(z|x)$，则梯度无法从$z$传递到编码器的参数$\mu$和$\sigma^2$，因为采样操作会 “阻断” 梯度流。为此可以为隐变量的分布引入可训练参数，假设$\epsilon \sim \mathcal{N}(0, I)$， 编码器输出的隐变量的分布为$z=\mu(x)+\sigma(x)*\epsilon$，这样即可保证输出的分布与原分布一致的前提下，不丢失梯度信息高斯分布的条件概率公式前向过程最直接的前向加噪过程的公式如下所示：$$ x_t = \sqrt{\alpha_t}\, x_{t-1} + \sqrt{1-\alpha_t}\, \epsilon_t,\quad \epsilon_t \sim \mathcal{N}(0,\boldsymbol{I}) $$其中，$\alpha_t$为权重参数将$x_{t-1}$用$x_{t-1} = \sqrt{\alpha_t}x_{t-2} + \sqrt{1-\alpha_t}$替代，以此迭代可得：$$ x_t = \sqrt{\bar{\alpha}_t}\, x_0 + \sqrt{1-\bar{\alpha}_t}\,\epsilon_t,\quad \epsilon_t \sim \mathcal{N}(0,\boldsymbol{I}), \bar{\alpha}_t = \prod_{s=1}^{t} \alpha_s $$考虑重参数化，实际上就是在均值上偏移$\sqrt{\bar{\alpha}_t}\, x_0$, 在方差上偏…

stable diffusion代码阅读笔记
type: item
date: 2024-09-24T22:25:00+08:00
description: stable diffusion代码阅读笔记本文参考的配置文件信息:AutoencoderKL:stable-diffusion\configs\autoencoder\autoencoder_kl_32x32x4.yamllatent-diffusion:stable-diffusion\configs\latent-diffusion\lsun_churches-ldm-kl-8.yamlldmmodulesdiffusionmodulesmodel.pyNromalize 函数def Normalize(in_channels, num_groups=32): """创建GroupNorm层 Args: in_channels: 输入通道数 num_groups: 分组数量. Defaults to 32. Returns: 返回一个 torch.nn.GroupNorm 层的实例 """ return torch.nn.GroupNorm(num_groups=num_groups, num_channels=in_channels, eps=1e-6, affine=True)这个方法定义了一个归一化层的方式,使用群归一化有利于提高训练速度和模型稳定性ResnetBlock类这个类定义了使用的残差块的模型,前向传播模型如下图所示注释代码如下:class ResnetBlock(nn.Module): def __init__(self, *, in_channels, out_channels=None, conv_shortcut=False, dropout, temb_channels=512): """Resnet模块实现 Args: in_channels: 输入通道数 dropout: Dropout率 out_channels: 输出通道数. Defaults to None. conv_shortcut: 是否使用卷积快速链接. Defaults to False. temb_channels: 时间嵌入通道数. Defaults to 512. """ super().__init__() self.in_channels = in_channels out_channels = in_channels if out_channels is None else out_channels self.out_channels = out_channels self.use_conv_shortcut = conv_shortcut self.norm1 = Normalize(in_channels) self.conv1 = torch.nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1) if temb_channels > 0: self.temb_proj = torch.nn.Linear(temb_channels, out_channels) self.norm2 = Normalize(out_channels) self.dropout = torch.nn.Dropout(dropout) self.conv2 = torch.nn.Conv2d(out_channels, out_channels, kernel_size=3, stride=1, padding=1) if self.in_channels != self.out_channels: if self.use_conv_shortcut: self.conv_shortcut = torch.nn.Conv2d(in_channels, out_channels, kernel_size=3, stride=1, padding=1) else: self.nin_shortcut = torch.nn.Conv2d(in_channels, out_channels, kernel_size=1, stride=1, padding=0) def forward(self, x, temb): """前线传播方法,用于计算输入张量x经过Resnet block后的输出 Args: x: 输入张量 temb: 时间嵌入 Returns: 残差块的输出 """ h = x h = self.norm1(h) h = nonlinearity(h) h = self.conv1(h) if temb is not None: h = h + self.temb_proj(nonlinearity(temb))[:,:,None,…