生成模型概述#

什么是生成模型?#

生成模型(Generative Models) 学习数据的分布,能够生成新的样本。

与判别模型的区别#

特性判别模型生成模型
目标P(y|x)P(x) 或 P(x,y)
任务分类、回归生成、密度估计
示例CNN、RNNVAE、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_loss

GAN实现#

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()

总结#

  1. VAE:变分推断,训练稳定但质量一般
  2. GAN:对抗训练,质量高但训练困难
  3. 扩散模型:去噪过程,质量极高
  4. 自回归模型:顺序生成,稳定但慢

关键要点

  • 生成模型学习数据分布
  • GAN训练不稳定但质量高
  • 扩散模型是当前主流
  • 不同模型适用于不同场景