ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

AI-For-Beginners 课程深度解析:生成对抗网络(GANs)原理、训练实战与风格迁移实现

AI-For-Beginners 课程深度解析:生成对抗网络(GANs)原理、训练实战与风格迁移实现 教程人工智能机器学习深度学习【免费下载链接】AI-For-Beginners12 Weeks, 24 Lessons, AI for All!项目地址https://gitcode.com/GitHub_Trending/ai/AI-For-Beginners点击查看免费下载生成对抗网络Generative Adversarial NetworksGAN是本课程中继 VAE 之后最核心的生成模型架构。本文以 AI-For-Beginners 仓库 第 10 课的 GAN 教学文档为主体结合仓库内完整的 TensorFlow/Keras 实现、PyTorch 实现 与 风格迁移 Notebook系统讲解 GAN 的架构设计、两阶段对抗训练流程、训练中常见的失败模式以及基于 VGG 特征的神经风格迁移方案。阅读本文后你将能够独立理解并复现一个可用 MNIST 数据集训练的最小 GAN并掌握训练 DCGAN 与风格迁移的关键工程细节。一、为什么需要 GAN从 VAE 的局限说起在前面的课程中我们学习了生成模型generative models——即能够生成与训练数据集中样本相似的新图像的模型变分自编码器VAE是生成模型的典型例子。但当我们试图用 VAE 生成真正有意义的内容时例如一幅分辨率足够高的绘画作品就会发现训练往往无法良好收敛。VAE 依赖重建误差与 KL 散度来约束隐空间生成的图像容易模糊、缺乏清晰的局部结构与纹理细节。针对这类生成有内容、有细节的图像的使用场景就需要学习另一种专门为生成模型设计的架构——生成对抗网络GAN。GAN 的核心思想非常直接让两个神经网络相互对抗、共同进化。一个网络负责伪造另一个网络负责鉴别在持续的博弈中双方的能力都不断提高最终生成器能够以假乱真。✅ 小词典生成器Generator接收一个随机向量将其映射为一张输出图像。判别器Discriminator接收一张图像判断它到底是来自训练数据集的真实图像real还是由生成器伪造出来的图像fake。本质上它是一个二分类的图像分类器。1.1 判别器Discriminator的架构判别器的架构与普通的图像分类网络没有本质区别。最简单的情况下它可以是一个全连接分类器但在实际课程实现中它几乎总是采用卷积网络——基于卷积网络的 GAN 被称为DCGANDeep Convolutional GAN。一个 CNN 判别器由以下层组成若干组卷积 池化操作空间尺寸逐层递减通道数逐层增加一个或多个全连接层把卷积特征压缩成特征向量最终接一个二分类输出sigmoid 输出 0~1 的真实性概率。✅ 这里的池化pooling是一种缩小图像尺寸的技术。池化层通过将某一层中神经元的输出分组、合并为下一层的单个神经元来降低数据维度。——《卷积神经网络》中关于池化层的定义。以仓库中 GANTF.ipynb 的 DCGAN 判别器为例它使用Conv2D卷积层配合LeakyReLU、Dropout、BatchNormalization、ZeroPadding2D逐步将 28×28 的图像下采样为 1×1 的单值输出discriminator Sequential() discriminator.add(Conv2D(32, kernel_size3, strides2, input_shape(28,28,1), paddingsame)) discriminator.add(LeakyReLU(alpha0.2)) discriminator.add(Dropout(0.25)) discriminator.add(Conv2D(64, kernel_size3, strides2, paddingsame)) discriminator.add(ZeroPadding2D(padding((0,1),(0,1)))) discriminator.add(BatchNormalization(momentum0.8)) discriminator.add(LeakyReLU(alpha0.2)) discriminator.add(Dropout(0.25)) discriminator.add(Conv2D(128, kernel_size3, strides2, paddingsame)) discriminator.add(BatchNormalization(momentum0.8)) discriminator.add(LeakyReLU(alpha0.2)) discriminator.add(Dropout(0.25)) discriminator.add(Conv2D(256, kernel_size3, strides1, paddingsame)) discriminator.add(BatchNormalization(momentum0.8)) discriminator.add(LeakyReLU(alpha0.2)) discriminator.add(Dropout(0.25)) discriminator.add(Flatten()) discriminator.add(Dense(1, activationsigmoid)) discriminator.compile(lossbinary_crossentropy, optimizeroptimizer)代码位置GANTF.ipynb 中的 DCGAN 判别器1.2 生成器Generator的架构生成器稍微更有挑战性一些。你可以把它理解为一个反转的判别器输入是一个隐向量latent vector代替判别器中的特征向量先经过一个全连接层把它变换到所需的尺寸/形状再经过逆卷积deconvolution 上采样upscaling逐步把特征图放大为完整图像。这很像 自编码器课程 中的decoder解码器部分。✅ 因为卷积层本质上是一个滑过图像的线性滤波器所以逆卷积与卷积在数学实现上非常类似可以用同一套层逻辑来实现在 Keras 中对应Conv2DTranspose在 PyTorch 中对应ConvTranspose2d。以仓库 GANTF.ipynb 的 DCGAN 生成器为例它先用Dense把 100 维噪声映射为 7×7×128 的特征图再用UpSampling2DConv2DTranspose逐步放大generator Sequential() generator.add(Dense(128 * 7 * 7, activationrelu, input_dim100)) generator.add(Reshape((7, 7, 128))) generator.add(UpSampling2D()) generator.add(Conv2DTranspose(128, kernel_size3, paddingsame)) generator.add(BatchNormalization(momentum0.8)) generator.add(Activation(relu)) generator.add(UpSampling2D()) generator.add(Conv2DTranspose(64, kernel_size3, paddingsame)) generator.add(BatchNormalization(momentum0.8)) generator.add(Activation(relu)) generator.add(Conv2DTranspose(1, kernel_size3, paddingsame)) generator.add(Activation(tanh)) generator.compile(lossbinary_crossentropy, optimizeroptimizer, metrics[accuracy]) generator.summary()该模型总参数量约 85.6 万输入 100 维噪声、输出 28×28×1 的 MNIST 风格灰度图。代码位置GANTF.ipynb 中的 DCGAN 生成器二、GAN 的两阶段训练流程GAN 之所以被称为对抗adversarial是因为生成器与判别器之间存在持续的竞争判别器试图识别伪造图像生成器试图骗过判别器。在这一博弈过程中双方都在不断改进最终网络学会生成越来越逼真的图像。训练分两个阶段交替进行阶段一训练判别器这一任务相当直接由生成器用随机噪声生成一批伪造图像打上标签0fake从输入数据集中取一批真实图像打上标签1real将两批图像混合送入判别器计算判别器损失discriminator loss执行反向传播更新判别器参数。阶段二训练生成器这一阶段稍显巧妙因为我们并不知道生成器的期望输出应该是什么取出整个 GAN 网络——生成器后接判别器输入一批随机向量并把期望输出设置为1对应真实图像即我们希望生成器生成的图像能骗过判别器冻结判别器参数此步骤中不希望更新判别器执行反向传播只更新生成器参数。⚠️ 关键细节由于生成器是通过欺骗冻结后的判别器来学习判别器的梯度会指导生成器向更逼真的方向更新。在 GANTF.ipynb 中这一过程通过对抗网络adversarial model实现——先把判别器设为trainable False再把生成器与判别器拼接成一个整体模型discriminator.trainable False adversarial Sequential() adversarial.add(generator) adversarial.add(discriminator) adversarial.compile(lossbinary_crossentropy, optimizeroptimizer)训练主循环每轮迭代做两个阶段如下batch 32 for cnt in range(3000): ## 训练判别器 random_index np.random.randint(0, len(X_train) - batch//2) legit_images X_train[random_index : random_index batch//2].reshape(batch//2, 28, 28) gen_noise np.random.normal(0, 1, (batch//2,100)) syntetic_images generator.predict(gen_noise) x_combined_batch np.concatenate((legit_images, syntetic_images)) y_combined_batch np.concatenate((np.ones((batch//2, 1)), np.zeros((batch//2, 1)))) d_loss discriminator.train_on_batch(x_combined_batch, y_combined_batch) ## 训练生成器 noise np.random.normal(0, 1, (batch,100)) y_mislabled np.ones((batch, 1)) g_loss adversarial.train_on_batch(noise, y_mislabled)在 PyTorch 版本 GANPyTorch.ipynb 中判别器损失由两部分构成disc_real disc(imgs) disc_real_loss loss_fn(disc_real, real_labels) disc_fake disc(generated.detach()) disc_fake_loss loss_fn(disc_fake, fake_labels) d_loss (disc_real_loss disc_fake_loss) / 2.0其中generated.detach()保证在判别器阶段不会把梯度回传到生成器。如何判断训练是否健康在理想情况下生成器损失和判别器损失都不会显著下降而是在某个区间内振荡oscillate——这恰恰说明两个网络都在持续改进博弈处于动态平衡之中。2.1 生成器与判别器中的实用技巧仓库中的两个 Notebook 都使用了若干对抗训练必备的小技巧可以总结为三点TensorFlow 版注释明确说明用 LeakyReLU 代替 ReLULeakyReLU 在负数区间不是恒为 0而是斜率很小的线性函数。这对生成器尤其重要因为当激活值落入 ReLU 的负区间输出恒为 0时梯度会消失LeakyReLU 能让梯度继续传播。使用 Batch Normalization 稳定训练批量归一化把每一层的输出分布拉回标准范围显著提升 GAN 这种不稳定训练的稳定性。最后一层激活用tanh生成器输出被压缩到 [-1, 1]与输入数据归一化后的范围一致MNIST 数据同样被线性缩放到 [-1,1]。PyTorch 版本中对应的超参数与网络定义同样体现了这些原则lr 2e-4 weight_decay 8e-9 beta1 0.5 beta2 0.999 batch_size 256 epochs 100 class Generator(nn.Module): def __init__(self): super().__init__() self.linear1 nn.Linear(100, 256) self.bn1 nn.BatchNorm1d(256, momentum0.2) self.linear2 nn.Linear(256, 512) self.bn2 nn.BatchNorm1d(512, momentum0.2) self.linear3 nn.Linear(512, 1024) self.bn3 nn.BatchNorm1d(1024, momentum0.2) self.linear4 nn.Linear(1024, 784) self.tanh nn.Tanh() self.leaky_relu nn.LeakyReLU(0.2) def forward(self, input): hidden1 self.leaky_relu(self.bn1(self.linear1(input))) hidden2 self.leaky_relu(self.bn2(self.linear2(hidden1))) hidden3 self.leaky_relu(self.bn3(self.linear3(hidden2))) generated self.tanh(self.linear4(hidden3)).view(input.shape[0], 1, 28, 28) return generated三、GAN 训练中的常见问题GAN 以难以训练而闻名。课程中明确指出了以下几类典型问题3.1 模式坍缩Mode Collapse所谓模式坍缩是指生成器学会只生成某一种能骗过判别器的成功图像而不是输出多样化的图像。例如在 MNIST 上生成器可能只学会画0而永远不会生成其他数字。这是 GAN 训练中最臭名昭著的问题之一。3.2 对超参数极度敏感经常可以看到一个 GAN 无论如何都不收敛然而把学习率调小一点点训练就突然收敛了。这说明 GAN 对学习率、批大小、归一化策略等超参数的选择非常敏感需要耐心做超参数扫描。3.3 生成器与判别器的平衡在很多情况下判别器损失会很快降到接近 0——这意味着判别器已经过于强大导致生成器再也无法从它那里学到有用的梯度。要克服这一点可以尝试为生成器和判别器设置不同的学习率当判别器损失已经过低时跳过判别器的训练步骤即该轮只更新生成器。3.4 高分辨率图像训练困难与自编码器面临的问题相同堆叠过多卷积层做重建会产生伪影artifacts。这个问题的典型解法是渐进式生长progressive growing先只用少量层在低分辨率图像上训练然后逐步解锁或新增层让模型一步步向高分辨率过渡。另一种思路是在层与层之间增加额外的连接、同时训练多个分辨率——详见论文Multi-Scale Gradient GANsarXiv:1903.06048。四、从 DCGAN 到 PyTorch 的工程细节4.1 DCGAN 与权重初始化PyTorch 版 Notebook 的 DCGAN 部分DCGenerator/DCDiscriminator完全使用ConvTranspose2d与Conv2d并按照DCGAN 论文arXiv:1511.06434的建议做权重初始化def weights_init(model): classname model.__class__.__name__ if classname.find(Conv) ! -1: nn.init.normal_(model.weight.data, 0.0, 0.02) elif classname.find(BatchNorm) ! -1: nn.init.normal_(model.weight.data, 1.0, 0.02) nn.init.constant_(model.bias.data, 0)生成器输出层使用padding(2,2)与output_padding(1,1)来精确控制最终特征图尺寸为 28×28判别器对输入图像执行2.0 * imgs - 1.0的缩放保证与生成器 tanh 输出的 [-1,1] 范围对齐。4.2 训练进度可视化两个 Notebook 都提供了plotn/dcplotn辅助函数每若干 epoch 用随机噪声采样生成 5 张图像并绘图直观观察生成质量的演进。Keras 版在每 500 次迭代打印一次判别器与生成器的损失值例如训练日志中可见如下趋势epoch 0 到 epoch 3000epoch: 0, [Discriminator :: d_loss: 0.601463], [ Generator :: loss: 0.640677] epoch: 500, [Discriminator :: d_loss: 0.192001], [ Generator :: loss: 12.124918] ... epoch: 2500, [Discriminator :: d_loss: 0.491767], [ Generator :: loss: 2.633016]损失数值的振荡而非单调下降正是 GAN 训练健康进行的信号。五、风格迁移Style TransferGAN 是生成艺术图像的绝佳工具但课程还介绍了另一项极具艺术性的技术——风格迁移style transfer。它接收一张内容图像content image并利用**风格图像style image**的滤镜特征对内容图像进行重绘使输出同时保留内容图像的结构与风格图像的笔触质感。5.1 原理与三种损失其工作方式如下从随机噪声图像出发也可以从内容图像出发但为了便于理解从随机噪声开始更简单优化目标是生成一张既接近内容图像、又接近风格图像的新图像。这个目标由两个损失函数刻画内容损失content loss基于 CNN 在若干层从当前图像与内容图像提取的特征来计算。课程实现中采用 VGG16 中间层特征定义为0.5 * sum((当前特征 - 内容目标特征)^2)见 StyleTransfer.ipynb 中的content_loss函数风格损失style loss以巧妙方式用Gram 矩阵Gram matrices比较当前图像与风格图像的风格。Gram 矩阵描述的是特征通道之间的相关性因此它捕捉的是纹理风格而不是内容结构为了让图像更平滑、去除噪声还引入全变分损失variation loss / total variation loss它计算相邻像素的平均差异主优化循环通过梯度下降或其它优化算法调整当前图像使总损失最小化——总损失是上述三种损失的加权和L(x) α·L_content(x, i) β·L_style(x, s) γ·L_total_variation(x)课程示例StyleTransfer.ipynb中使用 TensorFlow/Keras 加载VGG16去掉全连接顶层、ImageNet 预训练权重并设vgg.trainable False通过tf.keras.Model([vgg.input], outputs)抽取 VGG 指定层如block1_conv2、block2_conv2、block3_conv3、block4_conv3、block5_conv3等的中间特征输入图像被预处理为 VGG 期望的格式preprocess_input风格与内容各由一组特征层决定。 与 GAN 的区别风格迁移不是训练一个新网络而是直接优化一张像素图像VGG 在这里只是固定的特征提取器全程冻结。5.2 使用自己的图像实践课程的挑战任务建议你用自己的内容图像与风格图像运行 StyleTransfer.ipynb。Notebook 中给出的示例是用 curl 下载一张猫的照片作为内容图、一张 Franz Marc 风格画作作为风格图并统一缩放为 512×512 后再开始优化。读者可直接把这两张图替换为自己的图片路径。六、课程任务与自我练习建议Notebook 练习GAN NotebookTensorFlow/KerasGAN NotebookPyTorch风格迁移示例StyleTransfer.ipynb另附 Keras 变体 StyleTransfer_Keras.ipynb课程作业重新打开本课关联的两个 Notebook 之一用自己的图像重新训练 GAN看看能生成什么内容。也可以参考课程提示用CIFAR-10 数据集中的某个类别尝试让 DCGAN 生成彩色图像或使用艺术家的绘画作品作为训练集。延伸阅读GAN 原始论文arXiv:1406.2661DCGAN 论文arXiv:1511.06434DCGAN PyTorch 官方教程pytorch.org/tutorials/beginner/dcgan_faces_tutorial.html本课程 DCGAN 架构与权重初始化均参考该教程七、小结本课的核心收获可以概括为三点GAN 是生成模型的对抗式答案当 VAE 在高分辨率、细节丰富的生成任务上收敛困难时GAN 通过生成器-判别器的零和博弈来逼近真实数据分布训练有章可循但需精心调参两阶段交替更新、冻结判别器、LeakyReLU BatchNorm tanh 的组合以及模式坍缩、超参数敏感、平衡维护等问题的应对策略都是实践中的必修课生成思想可以延伸风格迁移证明了用损失函数直接优化像素同样能创造艺术图像其内容损失、风格损失Gram 矩阵与全变分损失的三元组合是理解深度学习风格化任务的重要范式。若想深入动手请直接运行上述三个 Notebook——它们全部依赖常见的深度学习框架TensorFlow/Keras 或 PyTorch并内置了数据加载、模型定义、训练循环与可视化代码是学习 GAN 与风格迁移最直接的实战入口。赞分享教程人工智能机器学习深度学习【免费下载链接】AI-For-Beginners12 Weeks, 24 Lessons, AI for All!项目地址https://gitcode.com/GitHub_Trending/ai/AI-For-Beginners点击查看免费下载相关推荐AI-For-Beginners 课程解读生成对抗网络GAN原理、实战训练与风格迁移完整指南AI For Beginners 课程解读生成对抗网络GAN原理、实战训练与风格迁移完整指南 生成对抗网络Generative Adversarial教程人工智能机器学习深度学习生成对抗网络 GAN 实战指南对抗式训练、训练难题与风格迁移 —— AI-For-Beginners 课程详解生成对抗网络 GAN 实战指南对抗式训练、训练难题与风格迁移 —— AI For Beginners 课程详解 本指南深入讲解 AI For Beginner教程人工智能机器学习深度学习AI-For-Beginners 第 10 课深度解析生成对抗网络GAN与风格迁移实战AI For Beginners 第 10 课深度解析生成对抗网络GAN与风格迁移实战 导读 本文基于 AI For Beginners 开源课程 第 1教程人工智能机器学习深度学习上一篇洛雪音乐六音音源修复插件一键解决资源不存在播放报错下一篇Windows 快捷键冲突3 步查到占用全局热键的进程创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进