生成式模型底层原理通关笔记

生成式模型底层原理通关笔记

引言:从数据分布到生成新样本生成式模型的核心目标是从训练数据中学习潜在的概率分布 (p_{\text{data}}(x)),然后通过采样生成与训练数据类似的新样本。与判别式模型(如分类器)不同,生成式模型关注的是“数据是如何生成的”。本文将深入剖析几种主流生成式模型(如变分自编码器、生成对抗网络和扩散模型)的底层原理,并通过可运行的代码示例帮助你快速上手。## 变分自编码器(VAE)原理与实战### 1. 核心思想VAE 通过编码器将输入数据 (x) 映射到隐变量 (z) 的后验分布 (q_\phi(z|x)),再通过解码器从 (z) 重构 (x)。其损失函数包含两部分:-重构损失:衡量生成数据与原始数据的差异(如 MSE 或交叉熵)。-KL 散度:约束后验分布 (q_\phi(z|x)) 接近先验分布 (p(z))(通常为标准正态分布)。### 2. 重参数化技巧为了反向传播,隐变量采样需要可微分:(z = \mu + \sigma \odot \epsilon),其中 (\epsilon \sim \mathcal{N}(0, I))。### 3. 代码示例:基于 PyTorch 的 VAEpythonimport torchimport torch.nn as nnimport torch.optim as optimfrom torch.utils.data import DataLoaderfrom torchvision import datasets, transforms# 定义 VAE 模型class VAE(nn.Module): def __init__(self, input_dim=784, hidden_dim=256, latent_dim=20): super(VAE, self).__init__() # 编码器 self.encoder = nn.Sequential( nn.Linear(input_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), ) self.fc_mu = nn.Linear(hidden_dim, latent_dim) # 均值 self.fc_logvar = nn.Linear(hidden_dim, latent_dim) # 对数方差 # 解码器 self.decoder = nn.Sequential( nn.Linear(latent_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, input_dim), nn.Sigmoid() # 输出概率值(0-1) ) def encode(self, x): h = self.encoder(x.view(x.size(0), -1)) mu = self.fc_mu(h) logvar = self.fc_logvar(h) return mu, logvar def reparameterize(self, mu, logvar): std = torch.exp(0.5 * logvar) eps = torch.randn_like(std) # 标准正态噪声 return mu + eps * std def decode(self, z): return self.decoder(z) def forward(self, x): mu, logvar = self.encode(x) z = self.reparameterize(mu, logvar) recon_x = self.decode(z) return recon_x, mu, logvar# 损失函数:重构损失 + KL 散度def vae_loss(recon_x, x, mu, logvar): # 二值交叉熵损失(适用于 MNIST 像素值 0/1) recon_loss = nn.functional.binary_cross_entropy(recon_x, x.view(-1, 784), reduction='sum') # KL 散度:D_KL(N(mu, sigma^2) || N(0, 1)) kl_loss = -0.5 * torch.sum(1 + logvar - mu.pow(2) - logvar.exp()) return recon_loss + kl_loss# 训练代码(简化版)def train_vae(model, dataloader, epochs=10): optimizer = optim.Adam(model.parameters(), lr=1e-3) for epoch in range(epochs): for batch_idx, (data, _) in enumerate(dataloader): optimizer.zero_grad() recon_batch, mu, logvar = model(data) loss = vae_loss(recon_batch, data, mu, logvar) loss.backward() optimizer.step() print(f'Epoch {epoch}: Loss = {loss.item():.2f}')# 示例运行(需先下载 MNIST 数据集)if __name__ == '__main__': transform = transforms.Compose([transforms.ToTensor()]) mnist = datasets.MNIST('./data', train=True, download=True, transform=transform) loader = DataLoader(mnist, batch_size=64, shuffle=True) vae = VAE() train_vae(vae, loader)注释:上述代码实现了完整的 VAE 训练流程。重参数化技巧通过reparameterize方法实现,确保梯度可以流经随机采样层。训练后,可通过解码随机采样的 (z \sim \mathcal{N}(0, I)) 生成新图像。—## 生成对抗网络(GAN)原理与实战### 1. 核心思想GAN 包含生成器 (G) 和判别器 (D) 两个网络:-生成器:将随机噪声 (z) 映射到数据空间,尝试欺骗判别器。-判别器:区分真实样本和生成样本。-极小极大博弈:(\min_G \max_D V(D,G) = \mathbb{E}{x \sim p{\text{data}}}[\log D(x)] + \mathbb{E}{z \sim p_z}[\log(1-D(G(z)))])### 2. 训练技巧- 交替更新:先训练判别器 (k) 步,再训练生成器 1 步。- 使用标签平滑或梯度惩罚(WGAN-GP)防止模式坍塌。### 3. 代码示例:简易 GAN(基于 MNIST)pythonimport torchimport torch.nn as nnimport torch.optim as optimfrom torch.utils.data import DataLoaderfrom torchvision import datasets, transforms# 生成器:从 100 维噪声生成 784 维图像class Generator(nn.Module): def __init__(self, noise_dim=100, hidden_dim=256): super(Generator, self).__init__() self.model = nn.Sequential( nn.Linear(noise_dim, hidden_dim), nn.ReLU(), nn.Linear(hidden_dim, hidden_dim * 2), nn.ReLU(), nn.Linear(hidden_dim * 2, 784), nn.Tanh() # 输出范围 [-1, 1] ) def forward(self, z): return self.model(z)# 判别器:区分真实/伪造图像class Discriminator(nn.Module): def __init__(self, input_dim=784, hidden_dim=256): super(Discriminator, self).__init__() self.model = nn.Sequential( nn.Linear(input_dim, hidden_dim), nn.LeakyReLU(0.2), # 避免死亡 ReLU nn.Linear(hidden_dim, hidden_dim // 2), nn.LeakyReLU(0.2), nn.Linear(hidden_dim // 2, 1), nn.Sigmoid() ) def forward(self, x): return self.model(x.view(x.size(0), -1))# 训练函数def train_gan(generator, discriminator, dataloader, epochs=50, noise_dim=100): g_optim = optim.Adam(generator.parameters(), lr=2e-4, betas=(0.5, 0.999)) d_optim = optim.Adam(discriminator.parameters(), lr=2e-4, betas=(0.5, 0.999)) criterion = nn.BCELoss() # 二值交叉熵 for epoch in range(epochs): for real_imgs, _ in dataloader: batch_size = real_imgs.size(0) real_labels = torch.ones(batch_size, 1) # 真实标签为 1 fake_labels = torch.zeros(batch_size, 1) # 伪造标签为 0 # 训练判别器:最大化 log(D(real)) + log(1-D(fake)) d_optim.zero_grad() real_pred = discriminator(real_imgs) d_real_loss = criterion(real_pred, real_labels) noise = torch.randn(batch_size, noise_dim) fake_imgs = generator(noise) fake_pred = discriminator(fake_imgs.detach()) # 阻止梯度流入生成器 d_fake_loss = criterion(fake_pred, fake_labels) d_loss = d_real_loss + d_fake_loss d_loss.backward() d_optim.step() # 训练生成器:最小化 log(1-D(fake)) 等价于最大化 log(D(fake)) g_optim.zero_grad() noise = torch.randn(batch_size, noise_dim) fake_imgs = generator(noise) fake_pred = discriminator(fake_imgs) g_loss = criterion(fake_pred, real_labels) # 让判别器误认为伪造样本为真 g_loss.backward() g_optim.step() print(f'Epoch {epoch}: D Loss = {d_loss.item():.4f}, G Loss = {g_loss.item():.4f}')# 示例运行(需先下载 MNIST 数据集)if __name__ == '__main__': transform = transforms.Compose([transforms.ToTensor(), transforms.Normalize([0.5], [0.5])]) mnist = datasets.MNIST('./data', train=True, download=True, transform=transform) loader = DataLoader(mnist, batch_size=64, shuffle=True) gen = Generator() disc = Discriminator() train_gan(gen, disc, loader)注释:此代码实现了标准 GAN 训练。注意生成器使用Tanh输出,与数据归一化到[-1,1]匹配。判别器使用LeakyReLU防止梯度消失。训练后,通过gen(torch.randn(1, 100))即可生成新图像。—## 扩散模型(Diffusion Model)原理简介### 1. 前向扩散过程逐步向数据添加高斯噪声,直到变成纯噪声:(q(x_t | x{t-1}) = \mathcal{N}(x_t; \sqrt{1-\beta_t} x_{t-1}, \beta_t I))。### 2. 反向去噪过程学习神经网络 (\epsilon_\theta(x_t, t)) 预测添加的噪声,然后逐步去噪:(x_{t-1} = \frac{1}{\sqrt{\alpha_t}} \left( x_t - \frac{\beta_t}{\sqrt{1-\bar{\alpha}t}} \epsilon\theta(x_t, t) \right))。### 3. 训练目标最小化预测噪声与真实噪声的 MSE:(\mathbb{E}{t, x_0, \epsilon} \left[ | \epsilon - \epsilon\theta(x_t, t) |^2 \right])。### 4. 代码片段:噪声预测网络(简化版)pythonclass DiffusionModel(nn.Module): def __init__(self, T=1000): super().__init__() # 定义噪声调度表(beta 从 1e-4 到 0.02 线性增加) self.betas = torch.linspace(1e-4, 0.02, T) self.alphas = 1 - self.betas self.alpha_bars = torch.cumprod(self.alphas, dim=0) self.T = T # 简单的 U-Net 结构(此处省略复杂实现) self.net = nn.Sequential( nn.Linear(784 + 1, 256), # 输入:图像 + 时间步 t nn.ReLU(), nn.Linear(256, 256), nn.ReLU(), nn.Linear(256, 784) ) def forward(self, x_t, t): # 将时间步 t 归一化到 [0,1] t_embed = t / self.T # 拼接图像和时间嵌入 x = torch.cat([x_t, t_embed.unsqueeze(1).expand(-1, 784)], dim=1) return self.net(x) def sample(self, n=1): # 从纯噪声开始反向去噪 x = torch.randn(n, 784) for t in reversed(range(self.T)): t_tensor = torch.full((n,), t, dtype=torch.float) eps_pred = self.net(x, t_tensor) # 简化去噪公式(实际需考虑方差调度) x = (x - self.betas[t] / torch.sqrt(1 - self.alpha_bars[t]) * eps_pred) / torch.sqrt(self.alphas[t]) return x注释:此代码仅展示扩散模型的核心思想。实际实现需使用 U-Net 等复杂结构,并包含方差调度。扩散模型通过迭代去噪生成高质量样本,是目前最先进的生成模型之一(如 DALL-E 2、Stable Diffusion)。—## 总结本文从基础原理出发,通过代码示例演示了三种主流生成式模型的实现:-VAE:通过隐变量和变分推断生成多样化样本,适合连续数据。-GAN:通过对抗训练生成逼真样本,训练需平衡生成器和判别器。-扩散模型:通过逐步去噪生成高保真样本,计算成本较高但效果最佳。实战要点:- VAE 的 KL 散度需与重构损失平衡,避免后验坍塌。- GAN 训练需注意模式坍塌,可使用 WGAN-GP 或标签平滑改进。- 扩散模型的高质量生成依赖于噪声调度设计和大量采样步骤。生成式模型的核心在于对数据分布的建模与采样。理解这些底层原理后,你可以灵活应用于图像生成、文本生成、药物分子设计等领域。建议读者运行代码并调整超参数,观察生成样本的变化,深入体会模型的工作原理。