生成模型概述#
什么是生成模型?#
生成模型(Generative Models) 学习数据的分布,能够生成新的样本。
与判别模型的区别#
| 特性 | 判别模型 | 生成模型 |
|---|---|---|
| 目标 | P(y|x) | P(x) 或 P(x,y) |
| 任务 | 分类、回归 | 生成、密度估计 |
| 示例 | CNN、RNN | VAE、GAN |
应用场景#
- 图像生成:生成新图像
- 文本生成:生成文本
- 数据增强:生成训练数据
- 风格迁移:转换图像风格
变分自编码器(VAE)#
概述#
VAE(Variational Autoencoder) 结合自编码器和变分推断。
结构#
编码器:x → z (潜在变量)
解码器:z → x̂ (重构)关键创新#
1. 潜在空间#
将输入编码到潜在空间 z,而不是固定编码。
2. 变分推断#
学习潜在变量的分布:
$$ z \sim \mathcal{N}(\mu, \sigma^2) $$其中 $\mu$ 和 $\sigma$ 由编码器输出。
3. 重参数化技巧#
$$ z = \mu + \sigma \odot \varepsilon, \quad \varepsilon \sim \mathcal{N}(0, I) $$损失函数#
$$ L = L_{\text{reconstruction}} + L_{\text{KL}} $$其中:
- 重构损失:$L_{\text{reconstruction}} = -\log P(x|z)$
- KL散度:$L_{\text{KL}} = \text{KL}(q(z|x) \| p(z))$
优点#
- 生成连续样本
- 潜在空间可解释
- 训练稳定
缺点#
- 生成质量不如GAN
- 可能产生模糊图像
生成对抗网络(GAN)#
概述#
GAN(Generative Adversarial Network) 通过对抗训练生成样本。
核心思想#
两个网络对抗:
- 生成器(Generator):生成假样本
- 判别器(Discriminator):区分真假样本
训练过程#
1. 训练判别器:最大化区分真假
2. 训练生成器:最小化被识破的概率
3. 交替训练,直到平衡数学表示#
目标函数:
$$ \min_G \max_D V(D, G) = \mathbb{E}[\log D(x)] + \mathbb{E}[\log(1 - D(G(z)))] $$其中:
- $D(x)$ :判别器对真实样本的输出
- $D(G(z))$ :判别器对生成样本的输出
训练步骤#
1. 训练判别器#
$$ \max_D \mathbb{E}[\log D(x)] + \mathbb{E}[\log(1 - D(G(z)))] $$2. 训练生成器#
$$ \min_G \mathbb{E}[\log(1 - D(G(z)))] $$GAN变体#
1. DCGAN#
使用卷积层的GAN。
特点:
- 使用转置卷积
- BatchNorm
- ReLU/LeakyReLU
2. WGAN#
使用Wasserstein距离。
改进:
- 训练更稳定
- 损失函数有意义
3. StyleGAN#
高质量人脸生成。
特点:
- 风格混合
- 渐进式训练
优点#
- 生成质量高
- 无需显式密度估计
缺点#
- 训练不稳定
- 模式崩塌
- 难以评估
扩散模型(Diffusion Models)#
概述#
扩散模型 通过逐步去噪生成样本。
原理#
前向过程(加噪)#
逐步添加噪声:
$$ x_0 \rightarrow x_1 \rightarrow x_2 \rightarrow \ldots \rightarrow x_T $$其中 $x_T$ 是纯噪声。
反向过程(去噪)#
学习去噪过程:
$$ x_T \rightarrow x_{T-1} \rightarrow \ldots \rightarrow x_1 \rightarrow x_0 $$训练目标#
学习去噪网络:
$$ L = \mathbb{E}[\|\varepsilon - \varepsilon_\theta(x_t, t)\|^2] $$其中 $\varepsilon_\theta$ 是去噪网络。
应用#
- DALL·E 2:文本到图像
- Stable Diffusion:开源图像生成
- Sora:视频生成
优点#
- 生成质量极高
- 训练稳定
- 可控生成
自回归模型#
概述#
自回归模型 逐个生成元素。
原理#
$$ P(x) = P(x_1) \cdot P(x_2|x_1) \cdot P(x_3|x_1,x_2) \cdot \ldots $$示例#
PixelRNN/PixelCNN#
逐像素生成图像。
GPT#
逐token生成文本。
优点#
- 训练稳定
- 可解释性强
缺点#
- 生成速度慢(顺序生成)
- 长序列困难
代码实现#
VAE实现#
import torch
import torch.nn as nn
import torch.nn.functional as F
class VAE(nn.Module):
def __init__(self, input_dim, latent_dim):
super(VAE, self).__init__()
# 编码器
self.encoder = nn.Sequential(
nn.Linear(input_dim, 512),
nn.ReLU(),
nn.Linear(512, 256),
nn.ReLU()
)
self.fc_mu = nn.Linear(256, latent_dim)
self.fc_logvar = nn.Linear(256, latent_dim)
# 解码器
self.decoder = nn.Sequential(
nn.Linear(latent_dim, 256),
nn.ReLU(),
nn.Linear(256, 512),
nn.ReLU(),
nn.Linear(512, input_dim),
nn.Sigmoid()
)
def encode(self, x):
h = self.encoder(x)
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 = self.decode(z)
return recon, mu, logvar
# 损失函数
def vae_loss(recon_x, x, mu, logvar):
# 重构损失
recon_loss = F.binary_cross_entropy(recon_x, x, reduction='sum')
# KL散度
kl_loss = -0.5 * torch.sum(1 + logvar - mu.pow(2) - logvar.exp())
return recon_loss + kl_lossGAN实现#
class Generator(nn.Module):
def __init__(self, latent_dim, img_dim):
super(Generator, self).__init__()
self.model = nn.Sequential(
nn.Linear(latent_dim, 256),
nn.LeakyReLU(0.2),
nn.Linear(256, 512),
nn.LeakyReLU(0.2),
nn.Linear(512, 1024),
nn.LeakyReLU(0.2),
nn.Linear(1024, img_dim),
nn.Tanh()
)
def forward(self, z):
return self.model(z)
class Discriminator(nn.Module):
def __init__(self, img_dim):
super(Discriminator, self).__init__()
self.model = nn.Sequential(
nn.Linear(img_dim, 1024),
nn.LeakyReLU(0.2),
nn.Dropout(0.3),
nn.Linear(1024, 512),
nn.LeakyReLU(0.2),
nn.Dropout(0.3),
nn.Linear(512, 256),
nn.LeakyReLU(0.2),
nn.Dropout(0.3),
nn.Linear(256, 1),
nn.Sigmoid()
)
def forward(self, x):
return self.model(x)
# 训练循环
def train_gan(generator, discriminator, dataloader, epochs):
g_optimizer = torch.optim.Adam(generator.parameters(), lr=0.0002)
d_optimizer = torch.optim.Adam(discriminator.parameters(), lr=0.0002)
criterion = nn.BCELoss()
for epoch in range(epochs):
for batch_idx, real_data in enumerate(dataloader):
batch_size = real_data.size(0)
# 训练判别器
d_optimizer.zero_grad()
# 真实样本
real_labels = torch.ones(batch_size, 1)
d_real_output = discriminator(real_data)
d_real_loss = criterion(d_real_output, real_labels)
# 生成样本
z = torch.randn(batch_size, latent_dim)
fake_data = generator(z)
fake_labels = torch.zeros(batch_size, 1)
d_fake_output = discriminator(fake_data.detach())
d_fake_loss = criterion(d_fake_output, fake_labels)
d_loss = d_real_loss + d_fake_loss
d_loss.backward()
d_optimizer.step()
# 训练生成器
g_optimizer.zero_grad()
z = torch.randn(batch_size, latent_dim)
fake_data = generator(z)
g_output = discriminator(fake_data)
g_loss = criterion(g_output, real_labels) # 欺骗判别器
g_loss.backward()
g_optimizer.step()扩散模型(简化版)#
class DiffusionModel(nn.Module):
def __init__(self, input_dim):
super(DiffusionModel, self).__init__()
self.denoise_net = nn.Sequential(
nn.Linear(input_dim + 1, 512), # +1 for time step
nn.ReLU(),
nn.Linear(512, 512),
nn.ReLU(),
nn.Linear(512, input_dim)
)
def forward(self, x_t, t):
# 将时间步t添加到输入
t_embed = t.unsqueeze(-1).expand(-1, x_t.size(-1))
x_with_t = torch.cat([x_t, t_embed], dim=-1)
return self.denoise_net(x_with_t)
# 训练(简化版)
def train_diffusion(model, dataloader, T=1000):
optimizer = torch.optim.Adam(model.parameters())
for epoch in range(epochs):
for x_0 in dataloader:
# 随机时间步
t = torch.randint(0, T, (x_0.size(0),))
# 添加噪声
noise = torch.randn_like(x_0)
alpha_t = 1 - t.float() / T
x_t = torch.sqrt(alpha_t).unsqueeze(-1) * x_0 + \
torch.sqrt(1 - alpha_t).unsqueeze(-1) * noise
# 预测噪声
predicted_noise = model(x_t, t)
# 损失
loss = F.mse_loss(predicted_noise, noise)
optimizer.zero_grad()
loss.backward()
optimizer.step()总结#
- VAE:变分推断,训练稳定但质量一般
- GAN:对抗训练,质量高但训练困难
- 扩散模型:去噪过程,质量极高
- 自回归模型:顺序生成,稳定但慢
关键要点:
- 生成模型学习数据分布
- GAN训练不稳定但质量高
- 扩散模型是当前主流
- 不同模型适用于不同场景