生成对抗网络与图像合成技术:理论、演进与应用

Source

生成对抗网络与图像合成技术:理论、演进与应用

目录

生成对抗网络与图像合成技术:理论、演进与应用

第一章 引言

1.1 研究背景

1.2 研究意义

1.3 本文主要贡献与结构

第二章 GAN:基础理论与核心挑战

2.1 基本框架与训练动力学

2.2 关键挑战与局限性

第三章 GAN的核心演进与变体

3.1 架构创新:DCGAN

3.2 损失函数革新:WGAN与LSGAN

3.3 精细化控制:StyleGAN系列

第四章 GAN在图像合成任务中的应用

4.1 图像生成与编辑

4.2 风格迁移(Style Transfer)

4.3 图像超分辨率(Super-Resolution)

4.4 图像修复与补全(Image Inpainting)

第五章 挑战与未来展望

第六章 结论

参考文献


摘要:生成对抗网络(Generative Adversarial Networks, GANs)作为深度学习领域最具开创性的框架之一,彻底改变了图像合成技术的发展轨迹。本文系统性地论述了GAN的核心理论基础、训练动力学及其面临的关键挑战(如模式崩溃、训练不稳定性)。文章重点剖析了为解决这些挑战而诞生的一系列里程碑式变体,如DCGAN、WGAN、StyleGAN等,并深入探讨了其在图像生成、风格迁移、图像超分辨率、图像修复等核心计算机视觉任务中的应用原理与性能表现。最后,本文对GAN未来的研究方向,包括训练稳定性、可控生成、与大模型的融合以及伦理问题进行了展望。本研究旨在为读者提供一个全面而深入的技术视角,理解GAN如何推动图像合成技术迈向逼真化、可控化和实用化的新阶段。

关键词:生成对抗网络;图像合成;深度学习;计算机视觉;模式崩溃;风格迁移;超分辨率


第一章 引言

1.1 研究背景

在GAN出现之前,图像合成领域主要由变分自编码器(VAEs)和自回归模型(如PixelRNN)主导。这些模型虽然能够生成数据,但往往存在生成图像模糊、生成速度慢或似然函数难以计算等问题。2014年,Ian Goodfellow等人提出了生成对抗网络(GANs)[1],其通过一个生成器(Generator)和一个判别器(Discriminator)的极小极大博弈(Minimax Game) 进行训练,提供了一种无需显式定义似然函数即可学习数据分布的新范式。该框架能够生成极其逼真、细节丰富的图像,迅速成为人工智能领域的研究热点。

1.2 研究意义

GAN的研究意义深远且多维:

  1. 理论价值:GAN提供了一种全新的无监督和半监督学习范式,推动了概率生成模型和深度学习理论的发展。

  2. 技术价值:它极大地提升了图像合成的质量与多样性,在多个视觉任务中达到了 state-of-the-art 的性能。

  3. 应用价值:GAN技术在影视娱乐(特效制作)、电子商务(虚拟试衣)、医学影像(数据增强)、自动驾驶(场景生成)等领域展现出巨大的应用潜力。

1.3 本文主要贡献与结构

本文的主要贡献在于对GAN的技术演进脉络进行了系统性的梳理,并对其在不同图像合成任务中的应用机制进行了深入的对比分析。全文结构如下:第二章将介绍GAN的基础理论与训练挑战;第三章将详细论述GAN的各种变体及其改进原理;第四章将聚焦于GAN在风格迁移、超分辨率等具体任务中的应用;第五章将讨论当前面临的开放性挑战与未来研究方向;第六章为总结。

第二章 GAN:基础理论与核心挑战

2.1 基本框架与训练动力学

GAN的核心思想来源于博弈论中的纳什均衡。它由两个神经网络构成:

  • 生成器(G, Generator):其输入通常是随机噪声向量z(从先验分布p_z(z)中采样),目标是将z映射到数据空间,生成足以“以假乱真”的样本G(z),试图欺骗判别器。

  • 判别器(D, Discriminator):其输入是真实数据样本x或生成样本G(z),目标是正确区分输入的真伪,输出一个标量,代表输入为真实数据的概率。

二者的价值函数V(G, D)表示为:
min⁡Gmax⁡DV(D,G)=Ex∼pdata(x)[log⁡D(x)]+Ez∼pz(z)[log⁡(1−D(G(z)))]minG​maxD​V(D,G)=Ex∼pdata​(x)​[logD(x)]+Ez∼pz​(z)​[log(1−D(G(z)))]
生成器G试图最小化该函数,而判别器D试图最大化它,形成一个动态的博弈过程。

2.2 关键挑战与局限性

尽管思想巧妙,原始GAN面临着几个公认的难题:

  1. 训练不稳定性(Training Instability):生成器和判别器的训练需要保持精妙的平衡。任何一方的过强都会导致训练无法继续(例如,判别器太强会导致生成器梯度消失)。

  2. 模式崩溃(Mode Collapse):生成器倾向于只生成少数几种甚至单一模式的样本,无法覆盖真实数据的所有多样性。

  3. 评估指标缺乏(Lack of Evaluation Metrics):如何客观、定量地评估生成图像的质量和多样性是一个长期挑战。常用的指标包括初始分数(IS)[2]和弗雷歇初始距离(FID)[3],后者因其与人类感知的一致性更受青睐。

第三章 GAN的核心演进与变体

为解决上述挑战,研究人员提出了大量改进方案。

3.1 架构创新:DCGAN

Radford等人提出的深度卷积生成对抗网络(DCGAN)[4]是首个将CNN成功引入GAN的工作。其核心贡献包括:

  • 使用转置卷积(Transposed Convolution) 进行上采样。

  • 在生成器和判别器中使用批归一化(Batch Normalization)

  • 移除全连接层,使用深度卷积架构。

  • 生成器使用ReLU激活,输出层使用Tanh;判别器使用LeakyReLU。
    DCGAN提供了稳定训练CNN架构的蓝图,并证明了GAN可以学习到有意义的潜在空间表示。

3.2 损失函数革新:WGAN与LSGAN

原始GAN的JS散度在训练中容易导致梯度问题。Wasserstein GAN (WGAN) [5]引入了Wasserstein距离(Earth-Mover距离) 来衡量分布差异。其价值函数为:
min⁡Gmax⁡D∈1−LipschitzEx∼pdata[D(x)]−Ez∼pz[D(G(z))]minG​maxD∈1−Lipschitz​Ex∼pdata​​[D(x)]−Ez∼pz​​[D(G(z))]
通过权重裁剪梯度惩罚(WGAN-GP)[6]来强制判别器满足1-Lipschitz条件,WGAN极大改善了训练稳定性,并基本解决了模式崩溃问题。

最小二乘GAN(LSGAN)[7]则将判别器的损失函数替换为最小二乘损失,为生成样本提供更平滑的梯度,也能有效提升训练稳定性。

3.3 精细化控制:StyleGAN系列

NVIDIA提出的StyleGAN[8]及其后续版本StyleGAN2[9]、StyleGAN3[10]将图像生成质量推向了新的高度。其核心创新在于:

  • 风格迁移思想:重新设计了生成器架构,通过自适应实例归一化(AdaIN) 将潜在编码z映射到一个中间潜在空间(W空间),该空间解耦性更好,允许对生成图像的风格(如发型、肤色、姿态)进行精细、分离的控制。

  • 解耦学习:实现了高水平的风格混合(Style Mixing)和随机变化(Stochastic Variation)。

  • 消除 artifacts:StyleGAN2分析了并消除了StyleGAN中常见的“液滴”artifacts。

  • 等变性改善:StyleGAN3进一步改善了模型对平移、旋转等变换的等变性,生成更加自然的内容。

第四章 GAN在图像合成任务中的应用

4.1 图像生成与编辑

这是GAN最直接的应用。从生成手写数字(MNIST)、人脸(CelebA)到复杂场景(ImageNet),GAN证明了其生成高保真图像的能力。基于潜在空间的可解释性,用户可以通过编辑潜在向量z来实现语义图像编辑,如添加微笑、改变年龄等(如InterFaceGAN)。

4.2 风格迁移(Style Transfer)

虽然最初由Gatys等人基于优化提出,但GAN提供了更快的前向风格迁移方案。CycleGAN[11]和Pix2Pix[12]是该领域的代表性工作。

  • Pix2Pix:使用条件GAN(cGAN) 和U-Net架构作为生成器,在成对数据上学习图像到图像的映射(如语义分割图→照片)。

  • CycleGAN:引入了循环一致性损失(Cycle-Consistency Loss),无需成对数据即可实现风格迁移(如马→斑马,照片→莫奈画风)。

4.3 图像超分辨率(Super-Resolution)

SRGAN[13]首次将GAN引入超分辨率任务,其核心贡献在于提出了感知损失(Perceptual Loss),该损失结合了内容损失(基于VGG网络的特征重建) 和对抗损失,而非传统的像素级MSE损失。这使得模型能够重建出感知上更逼真、细节更丰富的高分辨率图像,尽管PSNR/SSIM指标可能不高。

4.4 图像修复与补全(Image Inpainting)

图像修复旨在填充图像中的缺失或损坏区域。Context Encoder[14]和DeepFill[15]等基于GAN的模型,通过结合对抗损失和重建损失,能够根据周围上下文信息,生成视觉上合理且语义一致的内容来填充空白区域。

第五章 挑战与未来展望

尽管取得了巨大成功,GAN仍面临诸多挑战:

  1. 训练稳定性与模式崩溃:虽经改善,但未根本解决。寻求理论上有保证的、稳定的训练算法仍是核心问题。

  2. 可控制性与解耦表示:如何更好地理解和控制潜在空间,实现高度解耦的、符合人类直觉的属性编辑是未来重点。

  3. 与扩散模型等新兴技术的融合:近期,扩散模型(Diffusion Models) 在图像生成质量上已展现出超越GAN的潜力。未来研究可能是GAN与扩散模型优势的融合,例如利用GAN的快速生成能力。

  4. 计算资源与效率:训练高分辨率GAN需要巨大的计算资源和时间,开发更高效的架构和训练方法是实用化的关键。

  5. 伦理与社会影响:GAN生成的“深度伪造(Deepfakes)”技术带来了巨大的伦理和社会挑战。开发有效的伪造检测技术和制定相关法规至关重要。

第六章 结论

生成对抗网络无疑是一场技术革命,它重新定义了图像合成的边界。从最初不稳定的概念验证,到如今能够生成以假乱真的高分辨率图像,GAN的发展历程充满了架构和理论上的创新。通过不断改进损失函数(如WGAN)、设计新型网络结构(如StyleGAN)、并成功应用于风格迁移、超分辨率等一系列任务,GAN证明了其强大的能力和灵活性。尽管面临着稳定性、可控性和伦理等方面的持续挑战,但其作为一项 foundational technology,将继续推动人工智能和计算机视觉领域向前发展。未来的研究将在追求更高生成质量的同时,更加注重模型的稳定性、可控性、效率及其负责任的应用。


参考文献

[1] Goodfellow, I., et al. (2014). Generative adversarial nets. Advances in neural information processing systems.
[2] Salimans, T., et al. (2016). Improved techniques for training gans. Advances in neural information processing systems.
[3] Heusel, M., et al. (2017). Gans trained by a two time-scale update rule converge to a local nash equilibrium. Advances in neural information processing systems.
[4] Radford, A., Metz, L., & Chintala, S. (2015). Unsupervised representation learning with deep convolutional generative adversarial networks. arXiv preprint arXiv:1511.06434.
[5] Arjovsky, M., Chintala, S., & Bottou, L. (2017). Wasserstein generative adversarial networks. International conference on machine learning.
[6] Gulrajani, I., et al. (2017). Improved training of wasserstein gans. Advances in neural information processing systems.
[7] Mao, X., et al. (2017). Least squares generative adversarial networks. Proceedings of the IEEE international conference on computer vision.
[8] Karras, T., Laine, S., & Aila, T. (2019). A style-based generator architecture for generative adversarial networks. Proceedings of the IEEE/CVF conference on computer vision and pattern recognition.
[9] Karras, T., et al. (2020). Analyzing and improving the image quality of stylegan. Proceedings of the IEEE/CVF conference on computer vision and pattern recognition.
[10] Karras, T., et al. (2021). Alias-free generative adversarial networks. Advances in Neural Information Processing Systems.
[11] Zhu, J. Y., et al. (2017). Unpaired image-to-image translation using cycle-consistent adversarial networks. Proceedings of the IEEE international conference on computer vision.
[12] Isola, P., et al. (2017). Image-to-image translation with conditional adversarial networks. Proceedings of the IEEE conference on computer vision and pattern recognition.
[13] Ledig, C., et al. (2017). Photo-realistic single image super-resolution using a generative adversarial network. Proceedings of the IEEE conference on computer vision and pattern recognition.
[14] Pathak, D., et al. (2016). Context encoders: Feature learning by inpainting. Proceedings of the IEEE conference on computer vision and pattern recognition.
[15] Yu, J., et al. (2018). Generative image inpainting with contextual attention. Proceedings of the IEEE conference on computer vision and pattern recognition.

好的,我将为您提供一系列GAN及其变体的详细代码实现,包含完整的模型架构、损失函数、训练循环和评估指标。

## 1. 基础GAN实现

```python
import torch
import torch.nn as nn
import torch.optim as optim
import torchvision
import torchvision.transforms as transforms
from torch.utils.data import DataLoader
from torchvision.utils import make_grid
import matplotlib.pyplot as plt
import numpy as np
import os

# 设置设备
device = torch.device("cuda" if torch.cuda.is_available() else "cpu")
print(f"Using device: {device}")

# 生成器模型
class Generator(nn.Module):
    def __init__(self, latent_dim=100, img_channels=1, feature_map_size=64):
        super(Generator, self).__init__()
        self.latent_dim = latent_dim
        self.main = nn.Sequential(
            # 输入: (latent_dim, 1, 1)
            nn.ConvTranspose2d(latent_dim, feature_map_size * 8, 4, 1, 0, bias=False),
            nn.BatchNorm2d(feature_map_size * 8),
            nn.ReLU(True),
            
            # 输出: (feature_map_size*8, 4, 4)
            nn.ConvTranspose2d(feature_map_size * 8, feature_map_size * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(feature_map_size * 4),
            nn.ReLU(True),
            
            # 输出: (feature_map_size*4, 8, 8)
            nn.ConvTranspose2d(feature_map_size * 4, feature_map_size * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(feature_map_size * 2),
            nn.ReLU(True),
            
            # 输出: (feature_map_size*2, 16, 16)
            nn.ConvTranspose2d(feature_map_size * 2, feature_map_size, 4, 2, 1, bias=False),
            nn.BatchNorm2d(feature_map_size),
            nn.ReLU(True),
            
            # 输出: (feature_map_size, 32, 32)
            nn.ConvTranspose2d(feature_map_size, img_channels, 4, 2, 1, bias=False),
            nn.Tanh()  # 输出范围: [-1, 1]
            # 最终输出: (img_channels, 64, 64)
        )

    def forward(self, x):
        x = x.view(-1, self.latent_dim, 1, 1)
        return self.main(x)

# 判别器模型
class Discriminator(nn.Module):
    def __init__(self, img_channels=1, feature_map_size=64):
        super(Discriminator, self).__init__()
        self.main = nn.Sequential(
            # 输入: (img_channels, 64, 64)
            nn.Conv2d(img_channels, feature_map_size, 4, 2, 1, bias=False),
            nn.LeakyReLU(0.2, inplace=True),
            
            # 输出: (feature_map_size, 32, 32)
            nn.Conv2d(feature_map_size, feature_map_size * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(feature_map_size * 2),
            nn.LeakyReLU(0.2, inplace=True),
            
            # 输出: (feature_map_size*2, 16, 16)
            nn.Conv2d(feature_map_size * 2, feature_map_size * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(feature_map_size * 4),
            nn.LeakyReLU(0.2, inplace=True),
            
            # 输出: (feature_map_size*4, 8, 8)
            nn.Conv2d(feature_map_size * 4, feature_map_size * 8, 4, 2, 1, bias=False),
            nn.BatchNorm2d(feature_map_size * 8),
            nn.LeakyReLU(0.2, inplace=True),
            
            # 输出: (feature_map_size*8, 4, 4)
            nn.Conv2d(feature_map_size * 8, 1, 4, 1, 0, bias=False),
            nn.Sigmoid()  # 输出真实概率
        )

    def forward(self, x):
        return self.main(x).view(-1, 1)

# 初始化模型
latent_dim = 100
img_channels = 1
img_size = 64

generator = Generator(latent_dim, img_channels).to(device)
discriminator = Discriminator(img_channels).to(device)

# 定义损失函数和优化器
criterion = nn.BCELoss()
lr = 0.0002
beta1 = 0.5

optimizer_G = optim.Adam(generator.parameters(), lr=lr, betas=(beta1, 0.999))
optimizer_D = optim.Adam(discriminator.parameters(), lr=lr, betas=(beta1, 0.999))

# 数据加载和预处理
transform = transforms.Compose([
    transforms.Resize(img_size),
    transforms.CenterCrop(img_size),
    transforms.ToTensor(),
    transforms.Normalize((0.5,), (0.5,))  # 将范围从[0,1]归一化到[-1,1]
])

dataset = torchvision.datasets.MNIST(root='./data', train=True, 
                                    download=True, transform=transform)
dataloader = DataLoader(dataset, batch_size=128, shuffle=True, num_workers=2)

# 训练函数
def train_gan(num_epochs=50):
    fixed_noise = torch.randn(64, latent_dim, device=device)
    real_label = 1.0
    fake_label = 0.0
    
    for epoch in range(num_epochs):
        for i, (real_imgs, _) in enumerate(dataloader):
            batch_size = real_imgs.size(0)
            real_imgs = real_imgs.to(device)
            
            # 训练判别器:最大化 log(D(x)) + log(1 - D(G(z)))
            discriminator.zero_grad()
            
            # 真实图像
            label = torch.full((batch_size, 1), real_label, device=device)
            output = discriminator(real_imgs)
            errD_real = criterion(output, label)
            errD_real.backward()
            D_x = output.mean().item()
            
            # 生成假图像
            noise = torch.randn(batch_size, latent_dim, device=device)
            fake_imgs = generator(noise)
            label.fill_(fake_label)
            output = discriminator(fake_imgs.detach())
            errD_fake = criterion(output, label)
            errD_fake.backward()
            D_G_z1 = output.mean().item()
            
            errD = errD_real + errD_fake
            optimizer_D.step()
            
            # 训练生成器:最大化 log(D(G(z)))
            generator.zero_grad()
            label.fill_(real_label)
            output = discriminator(fake_imgs)
            errG = criterion(output, label)
            errG.backward()
            D_G_z2 = output.mean().item()
            optimizer_G.step()
            
            if i % 100 == 0:
                print(f'[{epoch}/{num_epochs}][{i}/{len(dataloader)}] '
                      f'Loss_D: {errD.item():.4f} Loss_G: {errG.item():.4f} '
                      f'D(x): {D_x:.4f} D(G(z)): {D_G_z1:.4f}/{D_G_z2:.4f}')
        
        # 每个epoch保存生成的图像
        with torch.no_grad():
            fake = generator(fixed_noise).detach().cpu()
            grid = make_grid(fake, nrow=8, normalize=True)
            plt.figure(figsize=(8, 8))
            plt.imshow(np.transpose(grid, (1, 2, 0)))
            plt.axis('off')
            plt.savefig(f'gan_samples_epoch_{epoch}.png')
            plt.close()
    
    # 保存模型
    torch.save(generator.state_dict(), 'generator.pth')
    torch.save(discriminator.state_dict(), 'discriminator.pth')

# 开始训练
train_gan()
```

## 2. DCGAN实现

```python
class DCGAN_Generator(nn.Module):
    """DCGAN生成器"""
    def __init__(self, latent_dim=100, img_channels=3, feature_map_size=64):
        super(DCGAN_Generator, self).__init__()
        self.latent_dim = latent_dim
        self.main = nn.Sequential(
            # 输入是Z,进入全连接层
            nn.ConvTranspose2d(latent_dim, feature_map_size * 8, 4, 1, 0, bias=False),
            nn.BatchNorm2d(feature_map_size * 8),
            nn.ReLU(True),
            
            # 输出尺寸: (feature_map_size*8, 4, 4)
            nn.ConvTranspose2d(feature_map_size * 8, feature_map_size * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(feature_map_size * 4),
            nn.ReLU(True),
            
            # 输出尺寸: (feature_map_size*4, 8, 8)
            nn.ConvTranspose2d(feature_map_size * 4, feature_map_size * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(feature_map_size * 2),
            nn.ReLU(True),
            
            # 输出尺寸: (feature_map_size*2, 16, 16)
            nn.ConvTranspose2d(feature_map_size * 2, feature_map_size, 4, 2, 1, bias=False),
            nn.BatchNorm2d(feature_map_size),
            nn.ReLU(True),
            
            # 输出尺寸: (feature_map_size, 32, 32)
            nn.ConvTranspose2d(feature_map_size, img_channels, 4, 2, 1, bias=False),
            nn.Tanh()
            # 输出尺寸: (img_channels, 64, 64)
        )

    def forward(self, x):
        x = x.view(-1, self.latent_dim, 1, 1)
        return self.main(x)

class DCGAN_Discriminator(nn.Module):
    """DCGAN判别器"""
    def __init__(self, img_channels=3, feature_map_size=64):
        super(DCGAN_Discriminator, self).__init__()
        self.main = nn.Sequential(
            # 输入: (img_channels, 64, 64)
            nn.Conv2d(img_channels, feature_map_size, 4, 2, 1, bias=False),
            nn.LeakyReLU(0.2, inplace=True),
            
            # 输出: (feature_map_size, 32, 32)
            nn.Conv2d(feature_map_size, feature_map_size * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(feature_map_size * 2),
            nn.LeakyReLU(0.2, inplace=True),
            
            # 输出: (feature_map_size*2, 16, 16)
            nn.Conv2d(feature_map_size * 2, feature_map_size * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(feature_map_size * 4),
            nn.LeakyReLU(0.2, inplace=True),
            
            # 输出: (feature_map_size*4, 8, 8)
            nn.Conv2d(feature_map_size * 4, feature_map_size * 8, 4, 2, 1, bias=False),
            nn.BatchNorm2d(feature_map_size * 8),
            nn.LeakyReLU(0.2, inplace=True),
            
            # 输出: (feature_map_size*8, 4, 4)
            nn.Conv2d(feature_map_size * 8, 1, 4, 1, 0, bias=False),
            nn.Sigmoid()
        )

    def forward(self, x):
        return self.main(x).view(-1, 1)
```

## 3. WGAN-GP实现

```python
class WGAN_GP_Generator(nn.Module):
    """WGAN-GP生成器"""
    def __init__(self, latent_dim=100, img_channels=3, feature_map_size=64):
        super(WGAN_GP_Generator, self).__init__()
        self.latent_dim = latent_dim
        self.main = nn.Sequential(
            nn.ConvTranspose2d(latent_dim, feature_map_size * 8, 4, 1, 0, bias=False),
            nn.BatchNorm2d(feature_map_size * 8),
            nn.ReLU(True),
            
            nn.ConvTranspose2d(feature_map_size * 8, feature_map_size * 4, 4, 2, 1, bias=False),
            nn.BatchNorm2d(feature_map_size * 4),
            nn.ReLU(True),
            
            nn.ConvTranspose2d(feature_map_size * 4, feature_map_size * 2, 4, 2, 1, bias=False),
            nn.BatchNorm2d(feature_map_size * 2),
            nn.ReLU(True),
            
            nn.ConvTranspose2d(feature_map_size * 2, feature_map_size, 4, 2, 1, bias=False),
            nn.BatchNorm2d(feature_map_size),
            nn.ReLU(True),
            
            nn.ConvTranspose2d(feature_map_size, img_channels, 4, 2, 1, bias=False),
            nn.Tanh()
        )

    def forward(self, x):
        x = x.view(-1, self.latent_dim, 1, 1)
        return self.main(x)

class WGAN_GP_Discriminator(nn.Module):
    """WGAN-GP判别器(Critic)"""
    def __init__(self, img_channels=3, feature_map_size=64):
        super(WGAN_GP_Discriminator, self).__init__()
        self.main = nn.Sequential(
            nn.Conv2d(img_channels, feature_map_size, 4, 2, 1, bias=False),
            nn.LeakyReLU(0.2, inplace=True),
            
            nn.Conv2d(feature_map_size, feature_map_size * 2, 4, 2, 1, bias=False),
            nn.InstanceNorm2d(feature_map_size * 2),
            nn.LeakyReLU(0.2, inplace=True),
            
            nn.Conv2d(feature_map_size * 2, feature_map_size * 4, 4, 2, 1, bias=False),
            nn.InstanceNorm2d(feature_map_size * 4),
            nn.LeakyReLU(0.2, inplace=True),
            
            nn.Conv2d(feature_map_size * 4, feature_map_size * 8, 4, 2, 1, bias=False),
            nn.InstanceNorm2d(feature_map_size * 8),
            nn.LeakyReLU(0.2, inplace=True),
            
            nn.Conv2d(feature_map_size * 8, 1, 4, 1, 0, bias=False)
            # 注意:没有Sigmoid激活函数
        )

    def forward(self, x):
        return self.main(x).view(-1)

def compute_gradient_penalty(D, real_samples, fake_samples):
    """计算梯度惩罚"""
    alpha = torch.rand(real_samples.size(0), 1, 1, 1, device=real_samples.device)
    interpolates = (alpha * real_samples + (1 - alpha) * fake_samples).requires_grad_(True)
    d_interpolates = D(interpolates)
    
    fake = torch.ones(real_samples.size(0), device=real_samples.device)
    
    gradients = torch.autograd.grad(
        outputs=d_interpolates,
        inputs=interpolates,
        grad_outputs=fake,
        create_graph=True,
        retain_graph=True,
        only_inputs=True,
    )[0]
    
    gradients = gradients.view(gradients.size(0), -1)
    gradient_penalty = ((gradients.norm(2, dim=1) - 1) ** 2).mean()
    return gradient_penalty

def train_wgan_gp(num_epochs=50, n_critic=5, lambda_gp=10):
    """训练WGAN-GP"""
    generator = WGAN_GP_Generator(latent_dim).to(device)
    discriminator = WGAN_GP_Discriminator().to(device)
    
    optimizer_G = optim.Adam(generator.parameters(), lr=0.0001, betas=(0.5, 0.9))
    optimizer_D = optim.Adam(discriminator.parameters(), lr=0.0001, betas=(0.5, 0.9))
    
    for epoch in range(num_epochs):
        for i, (real_imgs, _) in enumerate(dataloader):
            real_imgs = real_imgs.to(device)
            batch_size = real_imgs.size(0)
            
            # 训练判别器(Critic)
            for _ in range(n_critic):
                optimizer_D.zero_grad()
                
                # 真实图像
                real_validity = discriminator(real_imgs)
                
                # 生成假图像
                z = torch.randn(batch_size, latent_dim, device=device)
                fake_imgs = generator(z)
                fake_validity = discriminator(fake_imgs.detach())
                
                # 计算梯度惩罚
                gradient_penalty = compute_gradient_penalty(
                    discriminator, real_imgs.data, fake_imgs.data
                )
                
                # WGAN损失加上梯度惩罚
                errD = -torch.mean(real_validity) + torch.mean(fake_validity) + lambda_gp * gradient_penalty
                errD.backward()
                optimizer_D.step()
            
            # 训练生成器
            optimizer_G.zero_grad()
            
            fake_imgs = generator(z)
            fake_validity = discriminator(fake_imgs)
            errG = -torch.mean(fake_validity)
            errG.backward()
            optimizer_G.step()
            
            if i % 100 == 0:
                print(f'[{epoch}/{num_epochs}][{i}/{len(dataloader)}] '
                      f'Loss_D: {errD.item():.4f} Loss_G: {errG.item():.4f}')
```

## 4. CycleGAN实现

```python
class ResidualBlock(nn.Module):
    """残差块"""
    def __init__(self, in_features):
        super(ResidualBlock, self).__init__()
        self.block = nn.Sequential(
            nn.ReflectionPad2d(1),
            nn.Conv2d(in_features, in_features, 3),
            nn.InstanceNorm2d(in_features),
            nn.ReLU(inplace=True),
            nn.ReflectionPad2d(1),
            nn.Conv2d(in_features, in_features, 3),
            nn.InstanceNorm2d(in_features),
        )

    def forward(self, x):
        return x + self.block(x)

class GeneratorResNet(nn.Module):
    """CycleGAN生成器"""
    def __init__(self, input_channels=3, output_channels=3, n_residual_blocks=9):
        super(GeneratorResNet, self).__init__()
        
        # 初始卷积块
        model = [
            nn.ReflectionPad2d(3),
            nn.Conv2d(input_channels, 64, 7),
            nn.InstanceNorm2d(64),
            nn.ReLU(inplace=True),
        ]
        
        # 下采样
        in_features = 64
        out_features = in_features * 2
        for _ in range(2):
            model += [
                nn.Conv2d(in_features, out_features, 3, stride=2, padding=1),
                nn.InstanceNorm2d(out_features),
                nn.ReLU(inplace=True),
            ]
            in_features = out_features
            out_features = in_features * 2
        
        # 残差块
        for _ in range(n_residual_blocks):
            model += [ResidualBlock(in_features)]
        
        # 上采样
        out_features = in_features // 2
        for _ in range(2):
            model += [
                nn.ConvTranspose2d(in_features, out_features, 3, stride=2, padding=1, output_padding=1),
                nn.InstanceNorm2d(out_features),
                nn.ReLU(inplace=True),
            ]
            in_features = out_features
            out_features = in_features // 2
        
        # 输出层
        model += [
            nn.ReflectionPad2d(3),
            nn.Conv2d(64, output_channels, 7),
            nn.Tanh(),
        ]
        
        self.model = nn.Sequential(*model)

    def forward(self, x):
        return self.model(x)

class Discriminator(nn.Module):
    """CycleGAN判别器"""
    def __init__(self, input_channels=3):
        super(Discriminator, self).__init__()
        
        def discriminator_block(in_filters, out_filters, normalize=True):
            layers = [nn.Conv2d(in_filters, out_filters, 4, stride=2, padding=1)]
            if normalize:
                layers.append(nn.InstanceNorm2d(out_filters))
            layers.append(nn.LeakyReLU(0.2, inplace=True))
            return layers
        
        self.model = nn.Sequential(
            *discriminator_block(input_channels, 64, normalize=False),
            *discriminator_block(64, 128),
            *discriminator_block(128, 256),
            *discriminator_block(256, 512),
            nn.ZeroPad2d((1, 0, 1, 0)),
            nn.Conv2d(512, 1, 4, padding=1)
        )

    def forward(self, x):
        return self.model(x)

class CycleGAN:
    """CycleGAN训练框架"""
    def __init__(self):
        self.G_AB = GeneratorResNet().to(device)  # 从A域到B域的生成器
        self.G_BA = GeneratorResNet().to(device)  # 从B域到A域的生成器
        self.D_A = Discriminator().to(device)     # A域的判别器
        self.D_B = Discriminator().to(device)     # B域的判别器
        
        self.optimizer_G = optim.Adam(
            list(self.G_AB.parameters()) + list(self.G_BA.parameters()),
            lr=0.0002, betas=(0.5, 0.999)
        )
        self.optimizer_D_A = optim.Adam(self.D_A.parameters(), lr=0.0002, betas=(0.5, 0.999))
        self.optimizer_D_B = optim.Adam(self.D_B.parameters(), lr=0.0002, betas=(0.5, 0.999))
        
        self.criterion_GAN = nn.MSELoss()
        self.criterion_cycle = nn.L1Loss()
        self.criterion_identity = nn.L1Loss()
    
    def train(self, real_A, real_B):
        # 身份损失
        same_B = self.G_AB(real_B)
        loss_identity_B = self.criterion_identity(same_B, real_B) * 5.0
        
        same_A = self.G_BA(real_A)
        loss_identity_A = self.criterion_identity(same_A, real_A) * 5.0
        
        # GAN损失
        fake_B = self.G_AB(real_A)
        pred_fake = self.D_B(fake_B)
        loss_GAN_AB = self.criterion_GAN(pred_fake, torch.ones_like(pred_fake))
        
        fake_A = self.G_BA(real_B)
        pred_fake = self.D_A(fake_A)
        loss_GAN_BA = self.criterion_GAN(pred_fake, torch.ones_like(pred_fake))
        
        # 循环一致性损失
        recovered_A = self.G_BA(fake_B)
        loss_cycle_ABA = self.criterion_cycle(recovered_A, real_A) * 10.0
        
        recovered_B = self.G_AB(fake_A)
        loss_cycle_BAB = self.criterion_cycle(recovered_B, real_B) * 10.0
        
        # 总生成器损失
        loss_G = (loss_GAN_AB + loss_GAN_BA + 
                 loss_cycle_ABA + loss_cycle_BAB + 
                 loss_identity_A + loss_identity_B)
        
        self.optimizer_G.zero_grad()
        loss_G.backward()
        self.optimizer_G.step()
        
        # 判别器A损失
        pred_real = self.D_A(real_A)
        loss_D_real = self.criterion_GAN(pred_real, torch.ones_like(pred_real))
        
        pred_fake = self.D_A(fake_A.detach())
        loss_D_fake = self.criterion_GAN(pred_fake, torch.zeros_like(pred_fake))
        
        loss_D_A = (loss_D_real + loss_D_fake) * 0.5
        
        self.optimizer_D_A.zero_grad()
        loss_D_A.backward()
        self.optimizer_D_A.step()
        
        # 判别器B损失
        pred_real = self.D_B(real_B)
        loss_D_real = self.criterion_GAN(pred_real, torch.ones_like(pred_real))
        
        pred_fake = self.D_B(fake_B.detach())
        loss_D_fake = self.criterion_GAN(pred_fake, torch.zeros_like(pred_fake))
        
        loss_D_B = (loss_D_real + loss_D_fake) * 0.5
        
        self.optimizer_D_B.zero_grad()
        loss_D_B.backward()
        self.optimizer_D_B.step()
        
        return loss_G.item(), loss_D_A.item(), loss_D_B.item()
```

## 5. SRGAN实现

```python
class ResidualBlock(nn.Module):
    """SRGAN残差块"""
    def __init__(self, channels):
        super(ResidualBlock, self).__init__()
        self.conv1 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
        self.bn1 = nn.BatchNorm2d(channels)
        self.prelu = nn.PReLU()
        self.conv2 = nn.Conv2d(channels, channels, kernel_size=3, padding=1)
        self.bn2 = nn.BatchNorm2d(channels)

    def forward(self, x):
        residual = x
        out = self.conv1(x)
        out = self.bn1(out)
        out = self.prelu(out)
        out = self.conv2(out)
        out = self.bn2(out)
        out += residual
        return out

class SRGAN_Generator(nn.Module):
    """SRGAN生成器"""
    def __init__(self, scale_factor=4):
        super(SRGAN_Generator, self).__init__()
        self.scale_factor = scale_factor
        
        # 初始卷积层
        self.conv1 = nn.Conv2d(3, 64, kernel_size=9, padding=4)
        self.prelu = nn.PReLU()
        
        # 残差块
        self.residual_blocks = nn.Sequential(*[ResidualBlock(64) for _ in range(16)])
        
        # 后续卷积层
        self.conv2 = nn.Conv2d(64, 64, kernel_size=3, padding=1)
        self.bn2 = nn.BatchNorm2d(64)
        
        # 上采样块
        upsample_blocks = []
        for _ in range(scale_factor // 2):
            upsample_blocks.append(
                nn.Conv2d(64, 256, kernel_size=3, padding=1)
            )
            upsample_blocks.append(nn.PixelShuffle(2))
            upsample_blocks.append(nn.PReLU())
        self.upsample = nn.Sequential(*upsample_blocks)
        
        # 最终卷积层
        self.conv3 = nn.Conv2d(64, 3, kernel_size=9, padding=4)
    
    def forward(self, x):
        initial = self.prelu(self.conv1(x))
        x = self.residual_blocks(initial)
        x = self.bn2(self.conv2(x))
        x += initial  # 跳跃连接
        x = self.upsample(x)
        x = self.conv3(x)
        return torch.tanh(x)

class SRGAN_Discriminator(nn.Module):
    """SRGAN判别器"""
    def __init__(self):
        super(SRGAN_Discriminator, self).__init__()
        self.features = nn.Sequential(
            # 输入: (3, 96, 96)
            nn.Conv2d(3, 64, kernel_size=3, stride=1, padding=1),
            nn.LeakyReLU(0.2, inplace=True),
            
            nn.Conv2d(64, 64, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(64),
            nn.LeakyReLU(0.2, inplace=True),
            
            nn.Conv2d(64, 128, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(128),
            nn.LeakyReLU(0.2, inplace=True),
            
            nn.Conv2d(128, 128, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(128),
            nn.LeakyReLU(0.2, inplace=True),
            
            nn.Conv2d(128, 256, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(256),
            nn.LeakyReLU(0.2, inplace=True),
            
            nn.Conv2d(256, 256, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(256),
            nn.LeakyReLU(0.2, inplace=True),
            
            nn.Conv2d(256, 512, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(512),
            nn.LeakyReLU(0.2, inplace=True),
            
            nn.Conv2d(512, 512, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(512),
            nn.LeakyReLU(0.2, inplace=True),
        )
        
        self.classifier = nn.Sequential(
            nn.AdaptiveAvgPool2d(1),
            nn.Conv2d(512, 1024, kernel_size=1),
            nn.LeakyReLU(0.2, inplace=True),
            nn.Conv2d(1024, 1, kernel_size=1),
            nn.Sigmoid()
        )
    
    def forward(self, x):
        x = self.features(x)
        x = self.classifier(x)
        return x.view(-1, 1)

class VGGFeatureExtractor(nn.Module):
    """VGG特征提取器(用于感知损失)"""
    def __init__(self):
        super(VGGFeatureExtractor, self).__init__()
        vgg19 = torchvision.models.vgg19(pretrained=True)
        self.feature_extractor = nn.Sequential(*list(vgg19.features.children())[:35])
        
        for param in self.feature_extractor.parameters():
            param.requires_grad = False
    
    def forward(self, x):
        return self.feature_extractor(x)

def train_srgan(generator, discriminator, feature_extractor, 
                dataloader, num_epochs=100):
    """训练SRGAN"""
    criterion_GAN = nn.BCELoss()
    criterion_content = nn.L1Loss()
    criterion_perceptual = nn.L1Loss()
    
    optimizer_G = optim.Adam(generator.parameters(), lr=1e-4)
    optimizer_D = optim.Adam(discriminator.parameters(), lr=1e-4)
    
    for epoch in range(num_epochs):
        for i, (lr_imgs, hr_imgs) in enumerate(dataloader):
            lr_imgs, hr_imgs = lr_imgs.to(device), hr_imgs.to(device)
            
            # 训练判别器
            optimizer_D.zero_grad()
            
            # 真实图像
            real_labels = torch.ones(hr_imgs.size(0), 1, device=device)
            real_output = discriminator(hr_imgs)
            loss_D_real = criterion_GAN(real_output, real_labels)
            
            # 生成图像
            fake_imgs = generator(lr_imgs)
            fake_labels = torch.zeros(hr_imgs.size(0), 1, device=device)
            fake_output = discriminator(fake_imgs.detach())
            loss_D_fake = criterion_GAN(fake_output, fake_labels)
            
            loss_D = loss_D_real + loss_D_fake
            loss_D.backward()
            optimizer_D.step()
            
            # 训练生成器
            optimizer_G.zero_grad()
            
            # GAN损失
            gen_output = discriminator(fake_imgs)
            loss_GAN = criterion_GAN(gen_output, real_labels)
            
            # 内容损失(像素级)
            loss_content = criterion_content(fake_imgs, hr_imgs)
            
            # 感知损失(特征级)
            real_features = feature_extractor(hr_imgs)
            fake_features = feature_extractor(fake_imgs)
            loss_perceptual = criterion_perceptual(fake_features, real_features.detach())
            
            # 总损失
            loss_G = loss_content + 1e-3 * loss_GAN + 0.006 * loss_perceptual
            loss_G.backward()
            optimizer_G.step()
            
            if i % 100 == 0:
                print(f'Epoch [{epoch}/{num_epochs}], Step [{i}/{len(dataloader)}], '
                      f'Loss_D: {loss_D.item():.4f}, Loss_G: {loss_G.item():.4f}, '
                      f'Loss_content: {loss_content.item():.4f}, '
                      f'Loss_perceptual: {loss_perceptual.item():.4f}')
```

## 6. 评估指标实现

```python
def calculate_fid(real_imgs, fake_imgs, batch_size=50):
    """计算Fréchet Inception Distance (FID)"""
    inception_model = torchvision.models.inception_v3(pretrained=True, 
                                                     transform_input=False).to(device)
    inception_model.eval()
    
    def get_activations(images):
        activations = []
        for i in range(0, len(images), batch_size):
            batch = images[i:i+batch_size].to(device)
            with torch.no_grad():
                pred = inception_model(batch)
            activations.append(pred.cpu())
        return torch.cat(activations, 0)
    
    real_acts = get_activations(real_imgs)
    fake_acts = get_activations(fake_imgs)
    
    mu_real, sigma_real = real_acts.mean(0), torch.cov(real_acts.t())
    mu_fake, sigma_fake = fake_acts.mean(0), torch.cov(fake_acts.t())
    
    diff = mu_real - mu_fake
    covmean = torch.sqrt(sigma_real @ sigma_fake)
    
    if torch.isnan(covmean).any():
        covmean = sigma_real @ sigma_fake
        covmean = torch.sqrt(covmean + torch.eye(covmean.size(0)) * 1e-6)
    
    fid = diff.dot(diff) + torch.trace(sigma_real + sigma_fake - 2 * covmean)
    return fid.item()

def calculate_is(images, batch_size=32, splits=10):
    """计算Inception Score (IS)"""
    inception_model = torchvision.models.inception_v3(pretrained=True, 
                                                     transform_input=False).to(device)
    inception_model.eval()
    
    preds = []
    for i in range(0, len(images), batch_size):
        batch = images[i:i+batch_size].to(device)
        with torch.no_grad():
            pred = torch.nn.functional.softmax(inception_model(batch), dim=1)
        preds.append(pred.cpu())
    
    preds = torch.cat(preds, 0)
    scores = []
    for i in range(splits):
        part = preds[i * preds.size(0) // splits: (i + 1) * preds.size(0) // splits, :]
        kl = part * (torch.log(part) - torch.log(torch.mean(part, 0, keepdim=True)))
        kl = torch.mean(torch.sum(kl, 1))
        scores.append(torch.exp(kl))
    
    return torch.mean(torch.stack(scores)), torch.std(torch.stack(scores))

# 使用示例
def evaluate_model(generator, test_loader):
    """评估生成模型"""
    generator.eval()
    all_fake_imgs = []
    all_real_imgs = []
    
    with torch.no_grad():
        for real_imgs, _ in test_loader:
            noise = torch.randn(real_imgs.size(0), latent_dim, device=device)
            fake_imgs = generator(noise)
            
            all_fake_imgs.append(fake_imgs.cpu())
            all_real_imgs.append(real_imgs.cpu())
    
    fake_imgs = torch.cat(all_fake_imgs, 0)
    real_imgs = torch.cat(all_real_imgs, 0)
    
    # 计算评估指标
    fid_score = calculate_fid(real_imgs, fake_imgs)
    is_mean, is_std = calculate_is(fake_imgs)
    
    print(f'FID: {fid_score:.4f}')
    print(f'IS: {is_mean:.4f} ± {is_std:.4f}')
    
    return fid_score, is_mean
```

这些代码提供了从基础GAN到先进变体的完整实现,包含了:
1. **基础GAN**:完整的训练框架
2. **DCGAN**:使用卷积结构的改进版本
3. **WGAN-GP**:带有梯度惩罚的Wasserstein GAN
4. **CycleGAN**:无配对图像转换
5. **SRGAN**:超分辨率生成对抗网络
6. **评估指标**:FID和IS计算

每个实现都包含了详细的技术细节和训练逻辑,可以直接用于研究和实验。