生成对抗网络(GANs)训练起来很有挑战性。
这是因为其架构包含一个生成器模型和一个判别器模型,它们在一个零和博弈中竞争。这意味着一个模型的改进是以另一个模型的性能下降为代价的。结果是训练过程非常不稳定,经常导致失败,例如生成器总是生成相同的图像或生成无意义的图像。
因此,在配置和训练 GAN 模型时,可以使用许多启发式方法或最佳实践(称为“GAN 技巧”)。这些启发式方法是从业者多年来在各种问题上测试和评估了数百甚至数千种配置操作组合后,才艰难地获得的。
其中一些启发式方法实现起来很有挑战性,特别是对于初学者。
此外,对于给定项目,可能需要其中一些或全部,尽管可能不清楚应该采用哪种子集启发式方法,这需要进行实验。这意味着从业者必须随时准备好在短时间内实现给定的启发式方法。
在本教程中,您将学习如何实现一套最佳实践或 GAN 技巧,您可以直接复制粘贴到您的 GAN 项目中。
阅读本教程后,您将了解
- 开发生成对抗网络时,实用启发式方法或技巧的最佳来源。
- 如何从头开始为深度卷积 GAN 模型架构实现七个最佳实践。
- 如何实现 Soumith Chintala 的 GAN 技巧演示和列表中的四个额外最佳实践。
通过我的新书《Python 生成对抗网络》**启动您的项目**,其中包括**分步教程**和所有示例的 **Python 源代码**文件。
让我们开始吧。

如何实现技巧以训练稳定的生成对抗网络
图片由 BLM Nevada 拍摄,保留部分权利。
教程概述
本教程分为三个部分;它们是:
- 训练稳定 GAN 的启发式方法
- 深度卷积 GAN 的最佳实践
- 使用步进卷积进行下采样
- 使用步进卷积进行上采样
- 使用 LeakyReLU
- 使用批归一化
- 使用高斯权重初始化
- 使用 Adam 随机梯度下降
- 将图像缩放到 [-1,1] 范围
- Soumith Chintala 的 GAN 技巧
- 使用高斯潜在空间
- 分离真实和虚假图像批次
- 使用标签平滑
- 使用噪声标签
训练稳定 GAN 的启发式方法
GANs 难以训练。
在撰写本文时,关于如何设计和训练 GAN 模型还没有完善的理论基础,但已有大量的启发式方法或“**技巧**”,它们在实践中已被经验证明效果良好。
因此,在开发 GAN 模型时,需要考虑并实现一系列最佳实践。
也许最重要的两个建议配置和训练参数来源是:
- Alec Radford 等人于 2015 年发表的引入 DCGAN 架构的论文。
- Soumith Chintala 于 2016 年的演讲及相关的“**GAN 技巧**”列表。
在本教程中,我们将探讨如何实现这两个来源中最重要的最佳实践。
深度卷积 GAN 的最佳实践
在设计和训练稳定的 GAN 模型方面,也许最重要的进展之一是 Alec Radford 等人于 2015 年发表的题为《使用深度卷积生成对抗网络的无监督表征学习》的论文。
在论文中,他们描述了深度卷积 GAN(DCGAN)方法,该方法已成为 GAN 开发的事实标准。
在本节中,我们将介绍如何为 DCGAN 模型架构实现七个最佳实践。
1. 使用步进卷积进行下采样
判别器模型是一个标准的卷积神经网络模型,它将图像作为输入,并且必须输出一个二元分类,判断图像是真实的还是伪造的。
在深度卷积网络中,通常使用池化层来对输入和特征图进行下采样,以降低网络的深度。
DCGAN 不推荐这样做,而是建议使用步进卷积进行下采样。
这涉及像往常一样定义一个卷积层,但将默认的二维步长 (1,1) 更改为 (2,2)。这样做会使输入下采样,特别是将输入的宽度和高度减半,从而使输出特征图的面积变为四分之一。
下面的示例演示了使用单个隐藏卷积层实现这一点,该层通过将“`strides`”参数设置为 (2,2) 来使用下采样步进卷积。其效果是模型将输入从 64x64 下采样到 32x32。
1 2 3 4 5 6 7 8 |
# 使用步进卷积进行下采样的示例 from keras.models import Sequential from keras.layers import Conv2D # 定义模型 model = Sequential() model.add(Conv2D(64, kernel_size=(3,3), strides=(2,2), padding='same', input_shape=(64,64,3))) # 总结模型 model.summary() |
运行示例显示了卷积层输出的形状,其中特征图的面积是四分之一。
1 2 3 4 5 6 7 8 9 |
_________________________________________________________________ 层(类型) 输出形状 参数数量 ================================================================= conv2d_1 (Conv2D) (None, 32, 32, 64) 1792 ================================================================= 总参数:1,792 可训练参数:1,792 不可训练参数: 0 _________________________________________________________________ |
2. 使用步进卷积进行上采样
生成器模型必须根据来自潜在空间的随机点作为输入来生成输出图像。
实现此目的的推荐方法是使用带有步进卷积的转置卷积层。这是一种特殊类型的层,它执行反向卷积操作。直观地,这意味着将步长设置为 2x2 将产生相反的效果,即上采样输入而不是在正常卷积层的情况下进行下采样。
通过堆叠带有步进卷积的转置卷积层,生成器模型能够将给定输入缩放到所需的输出尺寸。
下面的示例演示了使用单个隐藏转置卷积层来实现这一点,该层通过将“`strides`”参数设置为 (2,2) 来使用上采样步进卷积。
其效果是模型将输入从 64x64 上采样到 128x128。
1 2 3 4 5 6 7 8 |
# 上采样与步进卷积的例子 from keras.models import Sequential from keras.layers import Conv2DTranspose # 定义模型 model = Sequential() model.add(Conv2DTranspose(64, kernel_size=(4,4), strides=(2,2), padding='same', input_shape=(64,64,3))) # 总结模型 model.summary() |
运行示例显示了卷积层输出的形状,其中特征图的面积是四倍。
1 2 3 4 5 6 7 8 9 |
_________________________________________________________________ 层(类型) 输出形状 参数数量 ================================================================= conv2d_transpose_1 (Conv2DTr (None, 128, 128, 64) 3136 ================================================================= 总参数:3,136 可训练参数:3,136 不可训练参数: 0 _________________________________________________________________ |
想从零开始开发GAN吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
3. 使用 LeakyReLU
修正线性激活单元(简称 ReLU)是一种简单的计算,它直接返回提供的输入值,如果输入值小于或等于 0.0,则返回 0.0。
它已成为开发深度卷积神经网络的一般最佳实践。
GAN 的最佳实践是使用 ReLU 的变体,该变体允许一些小于零的值,并学习每个节点中的截止点。这称为泄漏修正线性激活单元,简称 LeakyReLU。
可以为 LeakyReLU 指定负斜率,建议默认值为 0.2。
最初,建议在生成器模型中使用 ReLU,在判别器模型中使用 LeakyReLU,但最近,建议在两个模型中都使用 LeakyReLU。
下面的示例演示了在判别器模型的卷积层之后使用默认斜率为 0.2 的 LeakyReLU。
1 2 3 4 5 6 7 8 9 10 11 |
# 在判别器模型中使用 leakyrelu 的示例 from keras.models import Sequential 从 keras.layers 导入 Conv2D 从 keras.层 导入 BatchNormalization from keras.layers import LeakyReLU # 定义模型 model = Sequential() model.add(Conv2D(64, kernel_size=(3,3), strides=(2,2), padding='same', input_shape=(64,64,3))) model.add(LeakyReLU(0.2)) # 总结模型 model.summary() |
运行示例演示了模型的结构,其中单个卷积层后跟着激活层。
1 2 3 4 5 6 7 8 9 10 11 |
_________________________________________________________________ 层(类型) 输出形状 参数数量 ================================================================= conv2d_1 (Conv2D) (None, 32, 32, 64) 1792 _________________________________________________________________ leaky_re_lu_1 (LeakyReLU) (None, 32, 32, 64) 0 ================================================================= 总参数:1,792 可训练参数:1,792 不可训练参数: 0 _________________________________________________________________ |
4. 使用批归一化
批归一化将前一层的激活标准化为零均值和单位方差。这具有稳定训练过程的效果。
批归一化分别在判别器和生成器模型中卷积和转置卷积层的激活之后使用。
它被添加到模型中,在隐藏层之后,但在激活层(如 LeakyReLU)之前。
下面的示例演示了在判别器模型的 Conv2D 层之后但在激活层之前添加 Batch Normalization 层。
1 2 3 4 5 6 7 8 9 10 11 12 |
# 在判别器模型中使用批归一化的示例 from keras.models import Sequential 从 keras.layers 导入 Conv2D 从 keras.层 导入 BatchNormalization from keras.layers import LeakyReLU # 定义模型 model = Sequential() model.add(Conv2D(64, kernel_size=(3,3), strides=(2,2), padding='same', input_shape=(64,64,3))) model.add(BatchNormalization()) model.add(LeakyReLU(0.2)) # 总结模型 model.summary() |
运行示例显示了批量归一化在卷积层输出和激活函数之间所需的用法。
1 2 3 4 5 6 7 8 9 10 11 12 13 |
_________________________________________________________________ 层(类型) 输出形状 参数数量 ================================================================= conv2d_1 (Conv2D) (None, 32, 32, 64) 1792 _________________________________________________________________ batch_normalization_1 (Batch (None, 32, 32, 64) 256 _________________________________________________________________ leaky_re_lu_1 (LeakyReLU) (None, 32, 32, 64) 0 ================================================================= 总参数:2,048 可训练参数:1,920 不可训练参数:128 _________________________________________________________________ |
5. 使用高斯权重初始化
在训练神经网络之前,必须将模型权重(参数)初始化为小的随机变量。
论文中报告的 DCAGAN 模型的最佳实践是使用均值为零、标准差为 0.02 的零中心高斯分布(正态或钟形分布)初始化所有权重。
下面的示例演示了如何定义一个均值为 0,标准差为 0.02 的随机高斯权重初始化器,用于生成器模型中的转置卷积层。
同一个权重初始化器实例可以用于给定模型中的每个层。
1 2 3 4 5 6 7 8 |
# 在生成器模型中进行高斯权重初始化的示例 from keras.models import Sequential from keras.layers import Conv2DTranspose from keras.initializers import RandomNormal # 定义模型 model = Sequential() init = RandomNormal(mean=0.0, stddev=0.02) model.add(Conv2DTranspose(64, kernel_size=(4,4), strides=(2,2), padding='same', kernel_initializer=init, input_shape=(64,64,3))) |
6. 使用 Adam 随机梯度下降
随机梯度下降,简称 SGD,是用于优化卷积神经网络模型权重的标准算法。
训练算法有许多变体。训练 DCGAN 模型的最佳实践是使用 Adam 版本的随机梯度下降,学习率为 0.0002,beta1 动量值为 0.5,而不是默认值 0.9。
当优化判别器和生成器模型时,推荐使用此配置的 Adam 优化算法。
下面的示例演示了如何配置 Adam 随机梯度下降优化算法以训练判别器模型。
1 2 3 4 5 6 7 8 9 10 |
# 训练判别器模型时使用 adam 的示例 from keras.models import Sequential 从 keras.layers 导入 Conv2D from keras.optimizers import Adam # 定义模型 model = Sequential() model.add(Conv2D(64, kernel_size=(3,3), strides=(2,2), padding='same', input_shape=(64,64,3))) # 编译模型 opt = Adam(lr=0.0002, beta_1=0.5) model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy']) |
7. 将图像缩放到 [-1,1] 范围
建议使用双曲正切激活函数作为生成器模型的输出。
因此,还建议将用于训练判别器的真实图像缩放,使其像素值在 [-1,1] 范围内。这样,判别器将始终接收像素值在相同范围内的真实和伪造图像作为输入。
通常,图像数据作为 NumPy 数组加载,像素值是 8 位无符号整数 (uint8) 值,范围为 [0, 255]。
首先,必须将数组转换为浮点值,然后重新缩放到所需范围。
下面的示例提供了一个函数,该函数将适当地将 NumPy 数组中加载的图像数据缩放到所需的 [-1,1] 范围。
1 2 3 4 5 6 7 8 9 |
# 图像缩放函数示例 # 将图像数据从 [0,255] 缩放到 [-1,1] def scale_images(images): # 从 unit8 转换为 float32 images = images.astype('float32') # 从 [0,255] 缩放到 [-1,1] images = (images - 127.5) / 127.5 return images |
Soumith Chintala 的 GAN 技巧
Soumith Chintala 是 DCGAN 论文的共同作者之一,他在 2016 年 NIPS 会议上发表了题为《如何训练 GAN?》的演讲,总结了许多技巧和窍门。
该视频可在 YouTube 上观看,强烈推荐。这些技巧的摘要也以 GitHub 仓库的形式提供,名为《如何训练 GAN?使 GAN 工作的小贴士和技巧》。
这些技巧借鉴了 DCGAN 论文以及其他地方的建议。
在本节中,我们将回顾如何实现上一节中未涵盖的四个额外的 GAN 最佳实践。
1. 使用高斯潜在空间
潜在空间定义了生成器模型输入的形状和分布,用于生成新图像。
DCGAN 建议从均匀分布中采样,这意味着潜在空间的形状是一个超立方体。
最新的最佳实践是从标准高斯分布中采样,这意味着潜在空间的形状是一个超球面,均值为零,标准差为一。
下面的示例演示了如何从 100 维潜在空间中生成 500 个随机高斯点,这些点可以用作生成器模型的输入;每个点都可以用来生成一张图像。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 从高斯潜在空间采样的示例 from numpy.random import randn # 在潜在空间中生成点作为生成器的输入 def generate_latent_points(latent_dim, n_samples): # 在潜在空间中生成点 x_input = randn(latent_dim * n_samples) # 重塑为网络的输入批次 x_input = x_input.reshape((n_samples, latent_dim)) return x_input # 潜在空间大小 n_dim = 100 # 要生成的样本数量 n_samples = 500 # 生成样本 samples = generate_latent_points(n_dim, n_samples) # 总结 print(samples.shape, samples.mean(), samples.std()) |
运行示例总结了 500 个点的生成,每个点包含 100 个随机高斯值,均值接近零,标准差接近 1,例如标准高斯分布。
1 |
(500, 100) -0.004791256735601787 0.9976912528950904 |
2. 分离真实和虚假图像批次
判别器模型使用随机梯度下降与小批量进行训练。
最佳实践是使用单独的真实和虚假图像批次更新判别器,而不是将真实和虚假图像合并到单个批次中。
这可以通过对 `train_on_batch()` 函数进行两次单独的调用来更新判别器模型的权重来实现。
下面的代码片段演示了如何在训练判别器模型的内部代码循环中执行此操作。
1 2 3 4 5 6 7 8 9 |
... # 获取随机选择的“真实”样本 X_real, y_real = ... # 更新判别器模型权重 discriminator.train_on_batch(X_real, y_real) # 生成“虚假”示例 X_fake, y_fake = ... # 更新判别器模型权重 discriminator.train_on_batch(X_fake, y_fake) |
3. 使用标签平滑
在训练判别器模型时,通常使用类别标签 1 表示真实图像,类别标签 0 表示虚假图像。
这些被称为硬标签,因为标签值是精确或清晰的。
一种好的做法是使用软标签,例如对于真实图像使用略大于或小于 1.0 的值,对于虚假图像使用略大于 0.0 的值,其中每个图像的变动是随机的。
这通常被称为标签平滑,在训练模型时可以起到正则化作用。
下面的示例演示了如何定义 1,000 个正类标签(class=1),并按照推荐将标签值统一平滑到 [0.7,1.2] 范围。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# 正标签平滑的例子 from numpy import ones from numpy.random import random # 将 class=1 平滑到 [0.7, 1.2] 的示例 def smooth_positive_labels(y): return y - 0.3 + (random(y.shape) * 0.5) # 生成“真实”类别标签 (1) n_samples = 1000 y = ones((n_samples, 1)) # 平滑标签 y = smooth_positive_labels(y) # 汇总平滑标签 print(y.shape, y.min(), y.max()) |
运行示例总结了平滑值的最小值和最大值,表明它们接近预期值。
1 |
(1000, 1) 0.7003103006957805 1.1997858934066357 |
有一些建议认为只需要对正类标签进行平滑,并且要将其值小于 1.0。然而,您也可以平滑负类标签。
下面的示例演示了生成 1,000 个负类标签(class=0),并按照推荐将标签值统一平滑到 [0.0, 0.3] 范围。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
# 负标签平滑示例 from numpy import zeros from numpy.random import random # 将 class=0 平滑到 [0.0, 0.3] 的示例 def smooth_negative_labels(y): return y + random(y.shape) * 0.3 # 生成“虚假”类别标签 (0) n_samples = 1000 y = zeros((n_samples, 1)) # 平滑标签 y = smooth_negative_labels(y) # 汇总平滑标签 print(y.shape, y.min(), y.max()) |
4. 使用噪声标签
训练判别器模型时使用的标签始终是正确的。
这意味着假图像总是标记为类别 0,真实图像总是标记为类别 1。
建议在这些标签中引入一些错误,即一些假图像被标记为真实,一些真实图像被标记为假。
如果您使用单独的批次更新判别器以处理真实和虚假图像,这可能意味着随机将一些虚假图像添加到真实图像批次中,或者随机将一些真实图像添加到虚假图像批次中。
如果您使用真实和虚假图像的组合批次更新判别器,这可能涉及随机翻转某些图像上的标签。
下面的示例通过创建 1,000 个真实(class=1)标签样本并以 5% 的概率翻转它们来演示这一点,然后对 1,000 个虚假(class=0)标签样本进行相同的操作。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
# 噪声标签示例 from numpy import ones from numpy import zeros from numpy.random import choice # 随机翻转一些标签 def noisy_labels(y, p_flip): # 确定要翻转的标签数量 n_select = int(p_flip * y.shape[0]) # 选择要翻转的标签 flip_ix = choice([i for i in range(y.shape[0])], size=n_select) # 就地反转标签 y[flip_ix] = 1 - y[flip_ix] return y # 生成“真实”类别标签 (1) n_samples = 1000 y = ones((n_samples, 1)) # 以 5% 的概率翻转标签 y = noisy_labels(y, 0.05) # 汇总标签 print(y.sum()) # 生成“虚假”类别标签 (0) y = zeros((n_samples, 1)) # 以 5% 的概率翻转标签 y = noisy_labels(y, 0.05) # 汇总标签 print(y.sum()) |
尝试运行几次示例。
结果显示,大约 50 个“1”被翻转为正标签的 1(例如,1,0000 的 5%),大约 50 个“0”被翻转为负标签的 1。
1 |
950.049.0 |
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
论文
- 使用深度卷积生成对抗网络的无监督表征学习, 2015.
- 教程:生成对抗网络,NIPS, 2016.
- 训练 GAN 的改进技术, 2016.
API
文章
- ganhacks:如何训练 GAN?使 GAN 正常工作的技巧和窍门
- Ian Goodfellow,GAN 简介,NIPS 2016.
- Soumith Chintala,《如何训练 GAN》,NIPS 2016 对抗训练研讨会.
总结
在本教程中,您学习了如何实现一套最佳实践或 GAN 技巧,您可以直接复制粘贴到您的 GAN 项目中。
具体来说,你学到了:
- 开发生成对抗网络时,实用启发式方法或技巧的最佳来源。
- 如何从头开始为深度卷积 GAN 模型架构实现七个最佳实践。
- 如何实现 Soumith Chintala 的 GAN 技巧演示和列表中的四个额外最佳实践。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
先生,如果我们将 GAN 应用于用于分类的数值而不是图像,或者 GAN 仅作用于图像吗?
大部分工作都集中在使用 GANs 处理图像数据。
在其他数据上也有一些应用,例如文本和时间序列。
那么为什么要使用 GAN 进行分类呢?假设我们想要高分类精度,那么判别器就会被迫在生成质量较差的图像上进行训练,因为我们希望判别器“赢得比赛”以获得更好的分类。我是否遗漏了什么,或者这有点计算浪费?如果我们不训练生成器,我们也不会使用大量生成的数据(这应该是使用 SGAN 的重点),因为我们想要强制提前停止,对吗?那么有没有办法既能做好分类器又能做好生成器呢?你能用一个糟糕的生成器做出一个好的分类器而不称之为计算浪费吗??顺便再次感谢您的出色工作!
当所有其他模型都失败时,GAN 适用于分类。它们可用于半监督学习,当您有大量未标记数据和少量已标记数据时。
GANs 的关键是对两个模型进行对抗性训练。当你孤立地训练一个模型时,例如只训练生成器或只训练判别器,它就无法工作。
如果你想训练一个单一模型,你可以直接训练一个分类模型。你应该把它作为比较点,并且只有当 GAN 表现更好时才使用它。
真是一篇有帮助的帖子!我将它们应用到了生成狗图像的 Kaggle 竞赛中。虽然我没有得到完美逼真的狗,但这些 GAN 技巧显著提高了结果。
谢谢!
干得好,非常棒!
嗨,Jason,
我想知道是否有推荐的批次大小以提高性能。目前我比较了 32 和 256。批次大小为 32 的训练时间更长,结果也比批次大小为 256 的差。这背后有什么原因吗?
很好的问题!
在大多数问题上,较小的批量似乎更好,例如 32、64。
过多的数据似乎会导致一个模型比另一个模型学习得更快,例如它变得不稳定并且出现故障模式。
我明白了,谢谢。但是,较小的批量是否意味着每个 epoch 的训练时间更长?
是的。
关于 3. 使用标签平滑的问题。
如果值大于 1,这会影响损失函数吗?
我假设像交叉熵这样的东西会给出不同的结果?
至于使用噪声标签,有什么直觉可以解释为什么这更好?
这个想法是为了操纵损失函数对问题的看法,从而对其进行偏置。
你好 Jason?我可以用 GAN 来分类吗?
您可以使用判别器作为通过迁移学习进行判别的基础。
非常感谢。
不客气。
嗨,Jason,
很棒的文章!我对正类标签的平滑感到好奇,使用了您电子书中 train() 方法的结构。在 generate_real_samples() 辅助方法中应用此技术时,在 train() 方法中创建反转标签以鼓励更好的输出图像时,也应该使用平滑吗?
这似乎是合乎逻辑的。您的想法?
感谢您的帮助!(顺便说一句,您的电子书太棒了!)
好问题。
嗯...也许吧。
也许可以尝试有和没有的情况,并确认一下。
我刚刚在几个实验中运行了它,它似乎有点正则化。酷!
干得好!
当我应用标签平滑时,判别器在真实样本上的准确率等于零。有没有什么原因?
忽略准确度,专注于损失,特别是学习曲线。
还要关注周期性生成的图像,比如每隔几个 epoch。
我也有同样的问题,想知道这是为什么;也许我遗漏了一些基本的东西?
Jason,你有什么想法,为什么会这样?
你好 Jason,感谢你的精彩文章!
建议同时使用标签平滑和噪声标签吗?
另外,我读到 Soumith (https://github.com/soumith/ganhacks) 推荐判别器使用 SGD,生成器使用 Adam。你对此有什么看法?
也许在您的特定 GAN 模型上尝试一下。
我没有发现需要使用它们中的任何一个。
你好 Jason,一如既往的精彩博客。
这些原则也可以应用于训练自动编码器吗?例如
1) 编码器层使用 ReLU,解码器层使用 LeakyReLU
2) 解码器网络最后一层使用 ‘tanh’ 激活函数等。
通常情况下,不是。这些技巧主要针对 GANs 及其不稳定的训练过程。
自编码器训练起来非常稳定。
在模式崩溃和稳定性方面,浅层判别器网络是否比深层判别器网络表现更好?例如,您 pix2pix 帖子中的判别器与具有更多层的判别器相比。
另外,这篇帖子非常有帮助。谢谢。
这真的取决于模型的配置和数据集的具体情况。
在我的案例中,更深层次的模型发挥了作用。
此外,如果我们翻转标签,会导致判别器产生偏差/混淆,从而阻止生成器创建相同的特征来欺骗判别器。我对于翻转部分标签(4. 使用噪声标签)背后的直觉是否正确?
一点点噪音是好的——它能让模型持续学习,太多的噪音会让人困惑。
你好 Jason,教程太棒了!!!
我刚刚购买了您的书,并且正在尝试您推荐的一些技巧。按照您提供的完整代码运行后,得到了以下学习曲线(不是很理想)
https://drive.google.com/file/d/1C6rJP0NfynCpyV5THhfz_INphLH6E3Pn/view?usp=sharing
然后我将其更改为判别器使用 SGD,生成器使用 ReLU,但没有明显的改进。
https://drive.google.com/file/d/1uv-u8dePjApo8gC1N-bipfbUAwUbNfm_/view?usp=sharing
获得最佳提升的是使用标签平滑和噪声标签(在之前的更改之后)
1. 仅使用标签平滑
https://drive.google.com/file/d/1bbUkzODyF6m_qb1IinO_bt9dkRJWVEj5/view?usp=sharing
2. 同时使用标签平滑和噪声标签
https://drive.google.com/file/d/118b72LaAuCtq9zfmofIBGyPIXxUkb1Ke/view?usp=sharing
但生成器损失仍趋近于零,这让我认为它可能以某种方式用垃圾欺骗了判别器,这可能吗?我认为这最后一种设置生成的图像证实了我的信念。
https://drive.google.com/file/d/1mCOpn7Vj7-PqERXY9tHnfIpSoLkyo4xU/view?usp=sharing
尽管你看到中间有些东西试图成为一个八,但在我看来它仍然超级嘈杂,甚至重复。
我仍然在努力将生成器损失提高到 1.0 以上,正如你所建议的,有什么想法吗?
我认为判别器未能检测到虚假样本的情况多于未能检测到真实样本的情况,这也许就是为什么生成器容易用垃圾欺骗判别器,也许只在一个批次(真实或虚假)上应用噪声会有所帮助。我假设两个判别器损失应该大致相似。
进展不错,胡安!
也许模型对您的数据集来说太小/不够强大?
尝试大幅度扩展它们,或者从另一个类似项目中获取可行的模型架构作为起点?
也许尝试减少您的数据集(大小或复杂性),看看是否可以开始一些工作。
尝试各种方法来更多地了解困难的原因。
告诉我进展如何。
我忘了说我所有的实验都使用了 MNIST (数字 8) 数据集,抱歉。我在生成噪声标签时犯了一些错误,但我纠正了它们,得到了这个结果
https://drive.google.com/file/d/1fTvUrWsaddvxM8gx6aM24gCVAkvF1arg/view?usp=sharing
判别器在虚假样本上的损失仍然远高于 MNIST 示例的“可接受值”,生成器仍然趋向于零,我将尝试调整一些超参数,或者我将尝试使用一个不太复杂的数字,例如 1,看看是否能得到更好的结果
谢谢
暂时忽略准确率,专注于损失和生成图像的质量。
好文!
我想知道在训练生成器时,生成图像的标签是否也应该使用平滑和噪声标签?
噪声标签在某些情况下会有帮助。也许在你的模型上尝试一下,比较结果。
嗨,Jason,
感谢您的精彩教程。我阅读了您所有关于 GANs 的教程。我想将 GAN 用于我的论文中的数据增强。我发现判别器和生成器收敛到大约 0.7, 0.8 的学习率。但是经过多次迭代后,生成器没有产生好的结果。它只生成图像的全局结构,没有任何细节。我不明白这意味着什么?
GAN 不收敛
https://machinelearning.org.cn/faq/single-faq/why-is-my-gan-not-converging
也许尝试调整您的模型架构?
也许可以尝试一些 GAN 技巧
https://machinelearning.org.cn/how-to-code-generative-adversarial-network-hacks/
嗨,Jason,
我正在为一个项目研究 AnoVAEGAN,您的资源非常有帮助。
然而,我注意到在大约 60-70 个 epoch 后,生成器和判别器的损失值达到平衡。结果不如预期,我希望生成器能进一步改进。(生成更清晰细致的图像)
向判别器输入图像添加噪声和标签平滑会有帮助吗?您还有其他技巧建议尝试吗?
也许可以尝试上面的某些方法,看看哪种在您的特定情况下效果最好。
嗨,Jason,
我正在处理多分类问题(4 个类别),我不明白如何在独热编码标签上应用标签平滑,例如 1 0 0 0 应该变成什么?
例如,[1.3, 0.2, 0.14, 0.19]
只需添加一个非常小的随机数即可。
你好 jason,
你的文章很棒。我有一个关于批归一化的问题
每当我添加批归一化时,结果就会变差,模型无法收敛!!!!
我发现这个问题反复出现,但没有公认的解决方案
(Python 3.9 - Spyder 的实现)