生成对抗网络(GAN)是一种用于训练生成模型(例如用于生成图像的深度卷积神经网络)的架构。
尽管 GAN 模型能够为给定的数据集生成新的、看似真实的示例,但除了尝试弄清楚生成器输入到潜在空间与生成的图像之间的复杂关系之外,没有办法控制生成的图像类型。
条件生成对抗网络(简称 cGAN)是一种 GAN 类型,它涉及生成器模型对图像的条件生成。图像生成可以基于类别标签(如果可用)进行条件设置,从而实现给定类型的图像的定向生成。
在本教程中,您将学习如何开发一个条件生成对抗网络,用于定向生成服装。
完成本教程后,您将了解:
- GAN 生成随机样本的局限性可以通过条件生成对抗网络来克服。
- 如何开发和评估一个无条件生成对抗网络,用于生成服装照片。
- 如何开发和评估一个条件生成对抗网络,用于生成服装照片。
开始您的项目,阅读我的新书《Python 生成对抗网络》,其中包含分步教程和所有示例的Python 源代码文件。
让我们开始吧。

如何从头开始开发条件生成对抗网络
照片来自 Big Cypress National Preserve,部分权利保留
教程概述
本教程分为五个部分;它们是:
- 条件生成对抗网络
- Fashion-MNIST 服装照片数据集
- Fashion-MNIST 的无条件 GAN
- Fashion-MNIST 的条件 GAN
- 条件服装生成
条件生成对抗网络
生成对抗网络(简称 GAN)是一种用于训练基于深度学习的生成模型的架构。
该架构由生成器和判别器模型组成。生成器模型负责生成新的、看似真实的示例,理想情况下这些示例与数据集中真实的示例无法区分。判别器模型负责将给定图像分类为真实(来自数据集)或假(生成的)。
这些模型以零和或对抗的方式一起训练,使得判别器的改进以生成器能力的降低为代价,反之亦然。
GAN 在图像合成方面非常有效,也就是说,为目标数据集生成新的图像示例。有些数据集包含额外信息,例如类别标签,并且我们希望利用这些信息。
例如,MNIST 手写数字数据集具有相应整数的类别标签,CIFAR-10 小型物体照片数据集具有照片中相应物体的类别标签,Fashion-MNIST 服装数据集具有相应服装的类别标签。
在 GAN 模型中使用类别标签信息有两个动机。
- 改进 GAN。
- 定向图像生成。
与输入图像相关的额外信息,例如类别标签,可用于改进 GAN。这种改进可能体现在更稳定的训练、更快的训练以及/或质量更好的生成图像。
类别标签也可用于定向生成特定类型的图像。
GAN 模型的一个局限性在于它可能会生成该域中的随机图像。潜在空间中的点与生成的图像之间存在关系,但这种关系复杂且难以映射。
或者,GAN 可以以这样一种方式进行训练,即生成器和判别器模型都以类别标签为条件。这意味着当训练好的生成器模型作为独立模型用于生成域中的图像时,可以生成特定类型或类别标签的图像。
通过对生成对抗网络进行一些额外信息 y 的条件设置,可以将其扩展为条件模型。……通过对模型进行条件设置,可以指导数据生成过程。这种条件设置可以基于类别标签
——《条件生成对抗网络》,2014年。
例如,在 MNIST 的情况下,可以生成特定的手写数字,例如数字 9;在 CIFAR-10 的情况下,可以生成特定的物体照片,例如“青蛙”;在 Fashion MNIST 数据集的情况下,可以生成特定的服装,例如“连衣裙”。
这种模型称为条件生成对抗网络,简称 CGAN 或 cGAN。
cGAN 最初由 Mehdi Mirza 和 Simon Osindero 在其 2014 年的论文“Conditional Generative Adversarial Nets”中提出。在论文中,作者的动机是希望指导生成器模型的图像生成过程。
…通过对模型进行条件设置,可以指导数据生成过程。这种条件设置可以基于类别标签
——《条件生成对抗网络》,2014年。
他们的模型在 MNIST 手写数字数据集上得到了验证,其中类别标签被进行独热编码并与生成器和判别器模型的输入连接起来。
下图总结了模型架构。

条件生成对抗网络中条件生成器和条件判别器的示例。
摘自“条件生成对抗网络”,2014 年。
生成对抗网络模型的设计和训练已经有了许多进展,其中最著名的是深度卷积 GAN(简称 DCGAN),它概述了模型配置和训练过程,这些过程能够可靠地实现 GAN 模型在各种问题上的稳定训练。基于 DCGAN 的模型的条件训练可以简称为 CDCGAN 或 cDCGAN。
有许多方法可以将类别标签编码并整合到判别器和生成器模型中。最佳实践是使用一个嵌入层,然后是一个具有线性激活的全连接层,该层将嵌入缩放到图像大小,然后再将其作为额外的通道或特征图连接到模型中。
这个建议的一个版本在 2015 年的论文“Deep Generative Image Models using a Laplacian Pyramid of Adversarial Networks”中进行了描述。
…我们还探讨了该模型的一个类别条件版本,其中一个向量 c 对标签进行编码。这通过将 c 通过一个线性层并将其输出重塑为单个平面特征图,然后将其与第一层的映射图连接起来,从而集成到 Gk 和 Dk 中。
— Deep Generative Image Models using a Laplacian Pyramid of Adversarial Networks, 2015.
这个建议后来被添加到“GAN Hacks”列表中,作为设计和训练 GAN 模型时的启发式建议,总结如下:
16:条件 GAN 中的离散变量
– 使用嵌入层
– 添加到图像的附加通道
– 保持嵌入维度低,并上采样以匹配图像通道大小
尽管 GAN 可以基于类别标签进行条件设置,即所谓的类别条件 GAN,但它们也可以基于其他输入进行条件设置,例如图像,在 GAN 用于图像到图像翻译任务的情况下。
在本教程中,我们将开发一个 GAN,特别是 DCGAN,然后对其进行更新,以便在 cGAN 中使用类别标签,特别是 cDCGAN 模型架构。
想从零开始开发GAN吗?
立即参加我为期7天的免费电子邮件速成课程(附示例代码)。
点击注册,同时获得该课程的免费PDF电子书版本。
Fashion-MNIST 服装照片数据集
Fashion-MNIST 数据集被提议作为 MNIST 数据集一个更具挑战性的替代数据集。
它是一个包含 60,000 张 28x28 像素的小型方形灰度图像的数据集,图像内容是 10 种类型的服装物品,例如鞋子、T 恤、连衣裙等。
Keras 通过 fashion_mnist.load_dataset() 函数提供对 Fashion-MNIST 数据集的访问。它返回两个元组,一个包含标准训练数据集的输入和输出元素,另一个包含标准测试数据集的输入和输出元素。
下面的示例加载数据集并总结了加载数据集的形状。
注意:第一次加载数据集时,Keras 会自动下载该图像的压缩版本,并将其保存在您的主目录下,位于 ~/.keras/datasets/。下载速度很快,因为数据集压缩后只有大约 25 兆字节。
1 2 3 4 5 6 7 |
# 加载 fashion_mnist 数据集的示例 from keras.datasets.fashion_mnist import load_data # 将图像加载到内存中 (trainX, trainy), (testX, testy) = load_data() # 总结数据集的形状 print('Train', trainX.shape, trainy.shape) print('Test', testX.shape, testy.shape) |
运行示例会加载数据集并打印图像训练和测试分割的输入和输出组件的形状。
我们可以看到训练集中有 6 万个样本,测试集中有 1 万个样本,并且每个图像都是 28 x 28 像素的正方形。
1 2 |
训练 (60000, 28, 28) (60000,) 测试 (10000, 28, 28) (10000,) |
图像是灰色的,背景为黑色(像素值为 0),服装为白色(像素值接近 255)。这意味着如果绘制这些图像,它们将大部分是黑色的,中间有一个白色的服装。
我们可以使用 matplotlib 库和 imshow() 函数绘制训练数据集中的一些图像,并通过“cmap”参数指定颜色映射为“gray”,以正确显示像素值。
1 2 |
# 绘制原始像素数据 pyplot.imshow(trainX[i], cmap='gray') |
或者,当我们将颜色反转,将背景显示为白色,服装显示为黑色时,图像会更容易查看。
现在图像大部分是白色,感兴趣区域是黑色,因此它们更容易查看。这可以通过使用反向灰度颜色映射来实现,如下所示:
1 2 |
# 绘制原始像素数据 pyplot.imshow(trainX[i], cmap='gray_r') |
下面的示例以 10x10 的方格绘制了训练数据集中的前 100 张图像。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 加载 fashion_mnist 数据集的示例 from keras.datasets.fashion_mnist import load_data from matplotlib import pyplot # 将图像加载到内存中 (trainX, trainy), (testX, testy) = load_data() # 绘制训练数据集中的图像 for i in range(100): # 定义子图 pyplot.subplot(10, 10, 1 + i) # 关闭轴线 pyplot.axis('off') # 绘制原始像素数据 pyplot.imshow(trainX[i], cmap='gray_r') pyplot.show() |
运行该示例会创建一个包含 MNIST 训练数据集中 100 张图像的图,这些图像排列成一个 10x10 的方格。

Fashion MNIST 数据集的前 100 件服装图。
我们将使用训练数据集中的图像作为训练生成对抗网络的基础。
具体来说,生成器模型将学习如何使用判别器生成新的、看似真实的服装,判别器将尝试区分来自 Fashion MNIST 训练数据集的真实图像和生成器模型输出的新图像。
这是一个相对简单的问题,不需要复杂的生成器或判别器模型,尽管它确实需要生成灰度输出图像。
Fashion-MNIST 的无条件 GAN
在本节中,我们将为 Fashion-MNIST 数据集开发一个无条件 GAN。
第一步是定义模型。
判别器模型以一张 28x28 的灰度图像作为输入,并输出一个二元预测,判断图像是真实的(类别=1)还是假的(类别=0)。它被实现为一个适度的卷积神经网络,采用了 GAN 设计的最佳实践,例如使用斜率为 0.2 的 LeakyReLU 激活函数,使用 2x2 步长进行下采样,以及使用学习率为 0.0002、动量为 0.5 的随机梯度下降的 Adam 版本。
下面的 define_discriminator() 函数实现了这一点,定义并编译了判别器模型并返回它。图像的输入形状被参数化为一个默认函数参数,以便您以后可以使用该函数处理您自己的图像数据。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# 定义独立的判别器模型 def define_discriminator(in_shape=(28,28,1)): model = Sequential() # 下采样 model.add(Conv2D(128, (3,3), strides=(2,2), padding='same', input_shape=in_shape)) model.add(LeakyReLU(alpha=0.2)) # 下采样 model.add(Conv2D(128, (3,3), strides=(2,2), padding='same')) model.add(LeakyReLU(alpha=0.2)) # 分类器 model.add(Flatten()) model.add(Dropout(0.4)) model.add(Dense(1, activation='sigmoid')) # 编译模型 opt = Adam(lr=0.0002, beta_1=0.5) model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy']) return model |
生成器模型以潜在空间中的一个点作为输入,并输出一个 28x28 的灰度图像。这是通过使用一个全连接层来解释潜在空间中的点并提供足够的激活来实现的,这些激活可以重塑为低分辨率输出图像的多个副本(在此例中为 128 个)(例如 7x7)。然后使用转置卷积层将其上采样两次,每次将大小加倍,面积扩大四倍。该模型采用最佳实践,例如 LeakyReLU 激活、核大小是步长大小的因子,以及输出层中的双曲正切(tanh)激活函数。
下面的 define_generator() 函数定义了生成器模型,但故意不编译它,因为它不直接进行训练,然后返回模型。潜在空间的大小被参数化为一个函数参数。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
# 定义独立的生成器模型 def define_generator(latent_dim): model = Sequential() # 7x7 图像的基础 n_nodes = 128 * 7 * 7 model.add(Dense(n_nodes, input_dim=latent_dim)) model.add(LeakyReLU(alpha=0.2)) model.add(Reshape((7, 7, 128))) # 上采样到 14x14 model.add(Conv2DTranspose(128, (4,4), strides=(2,2), padding='same')) model.add(LeakyReLU(alpha=0.2)) # 上采样到 28x28 model.add(Conv2DTranspose(128, (4,4), strides=(2,2), padding='same')) model.add(LeakyReLU(alpha=0.2)) # 生成 model.add(Conv2D(1, (7,7), activation='tanh', padding='same')) return model |
接下来,可以定义一个 GAN 模型,将生成器模型和判别器模型组合成一个更大的模型。这个更大的模型将用于训练生成器中的模型权重,使用判别器模型计算的输出和误差。判别器模型是单独训练的,因此,在这个更大的 GAN 模型中,模型权重被标记为不可训练,以确保只有生成器模型的权重被更新。这个对判别器权重可训练性的改变仅在训练组合 GAN 模型时有效,而在单独训练判别器时无效。
这个更大的 GAN 模型以潜在空间中的一个点作为输入,使用生成器模型生成一个图像,该图像作为输入馈送给判别器模型,然后输出或分类为真实或假。
下面的 define_gan() 函数实现了这一点,将已定义的生成器和判别器模型作为输入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
# 定义组合的生成器和判别器模型,用于更新生成器 def define_gan(generator, discriminator): # 使判别器中的权重不可训练 discriminator.trainable = False # 连接它们 model = Sequential() # 添加生成器 model.add(generator) # 添加判别器 model.add(discriminator) # 编译模型 opt = Adam(lr=0.0002, beta_1=0.5) model.compile(loss='binary_crossentropy', optimizer=opt) return model |
现在我们已经定义了GAN模型,我们需要训练它。但是,在训练模型之前,我们需要输入数据。
第一步是加载和准备 Fashion MNIST 数据集。我们只需要训练数据集中的图像。这些图像是黑白的,因此我们必须添加一个额外的通道维度来将它们转换为三维,这符合我们模型卷积层的期望。最后,像素值必须缩放到 [-1,1] 的范围,以匹配生成器模型的输出。
下面的 load_real_samples() 函数实现了这一点,返回加载和缩放后的 Fashion MNIST 训练数据集,准备好进行建模。
1 2 3 4 5 6 7 8 9 10 11 |
# 加载 fashion mnist 图像 def load_real_samples(): # 加载数据集 (trainX, _), (_, _) = load_data() # 扩展到3D,例如添加通道 X = expand_dims(trainX, axis=-1) # 从整数转换为浮点数 X = X.astype('float32') # 从 [0,255] 缩放到 [-1,1] X = (X - 127.5) / 127.5 return X |
在每次更新 GAN 模型时,我们将需要一批(或半批)真实图像。一个简单的方法是每次从数据集中选择一个随机图像样本。
下面的 generate_real_samples() 函数实现了这一点,它将准备好的数据集作为参数,选择并返回 Fashion MNIST 图像的随机样本及其对应的类别标签给判别器,特别是类别=1,表示它们是真实图像。
1 2 3 4 5 6 7 8 9 |
# 选择真实样本 def generate_real_samples(dataset, n_samples): # 选择随机实例 ix = randint(0, dataset.shape[0], n_samples) # 选择图像 X = dataset[ix] # 生成类别标签 y = ones((n_samples, 1)) return X, y |
接下来,我们需要为生成器模型提供输入。这些是来自潜在空间的随机点,特别是高斯分布的随机变量。
generate_latent_points() 函数实现了这一点,它接受潜在空间的大小作为参数,以及所需的点数,并将它们作为生成器模型的输入样本批次返回。
1 2 3 4 5 6 7 |
# 在潜在空间中生成点作为生成器的输入 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 |
接下来,我们需要使用潜在空间中的点作为生成器的输入,以生成新的图像。
下面的 generate_fake_samples() 函数实现了这一点,它接受生成器模型和潜在空间的大小作为参数,然后生成潜在空间中的点并将它们用作生成器模型的输入。该函数返回生成的图像及其对应的类别标签,供判别器模型使用,特别是类别=0,表示它们是假的或生成的。
1 2 3 4 5 6 7 8 9 |
# 使用生成器生成 n 个假示例,并带有类别标签 def generate_fake_samples(generator, latent_dim, n_samples): # 在潜在空间中生成点 x_input = generate_latent_points(latent_dim, n_samples) # 预测输出 X = generator.predict(x_input) # 创建类别标签 y = zeros((n_samples, 1)) return X, y |
我们现在准备好拟合GAN模型了。
该模型训练了 100 个训练周期,这是一个任意的数字,因为模型在大约 20 个周期后开始生成逼真的服装。使用了 128 个样本的批次大小,每个训练周期涉及 60,000/128,即约 468 个真实和虚假样本的批次以及模型更新。
首先,判别器模型会更新为半批次的真实样本,然后是半批次的虚假样本,两者共同构成一个批次的权重更新。然后通过复合 GAN 模型更新生成器。重要的是,虚假样本的类别标签被设置为 1 或真实。这会在下一个批次中更新生成器,使其在生成真实样本方面做得更好。
下面的 train() 函数实现了这一点,它接受定义的模型、数据集和潜在维度的尺寸作为参数,并使用默认参数对周期数和批次大小进行参数化。生成器模型将在训练结束时保存。
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 |
# 训练生成器和判别器 def train(g_model, d_model, gan_model, dataset, latent_dim, n_epochs=100, n_batch=128): bat_per_epo = int(dataset.shape[0] / n_batch) half_batch = int(n_batch / 2) # 手动枚举 epoch for i in range(n_epochs): # 枚举训练集中的批次 for j in range(bat_per_epo): # 获取随机选择的“真实”样本 X_real, y_real = generate_real_samples(dataset, half_batch) # 更新判别器模型权重 d_loss1, _ = d_model.train_on_batch(X_real, y_real) # 生成“假”示例 X_fake, y_fake = generate_fake_samples(g_model, latent_dim, half_batch) # 更新判别器模型权重 d_loss2, _ = d_model.train_on_batch(X_fake, y_fake) # 准备潜在空间中的点作为生成器的输入 X_gan = generate_latent_points(latent_dim, n_batch) # 为伪样本创建反转标签 y_gan = ones((n_batch, 1)) # 通过判别器的误差更新生成器 g_loss = gan_model.train_on_batch(X_gan, y_gan) # 总结此批次的损失 print('>%d, %d/%d, d1=%.3f, d2=%.3f g=%.3f' % (i+1, j+1, bat_per_epo, d_loss1, d_loss2, g_loss)) # 保存生成器模型 g_model.save('generator.h5') |
然后,我们可以定义潜在空间的大小,定义所有三个模型,并在加载的 fashion MNIST 数据集上进行训练。
1 2 3 4 5 6 7 8 9 10 11 12 |
# 潜在空间的大小 latent_dim = 100 # 创建判别器 discriminator = define_discriminator() # 创建生成器 generator = define_generator(latent_dim) # 创建GAN gan_model = define_gan(generator, discriminator) # 加载图像数据 dataset = load_real_samples() # 训练模型 train(generator, discriminator, gan_model, dataset, latent_dim) |
将所有这些联系在一起,完整的示例如下。
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 |
# 在 fashion MNIST 数据集上训练无条件 GAN 的示例 from numpy import expand_dims from numpy import zeros from numpy import ones from numpy.random import randn from numpy.random import randint from keras.datasets.fashion_mnist import load_data from keras.optimizers import Adam from keras.models import Sequential from keras.layers import Dense from keras.layers import Reshape from keras.layers import Flatten 从 keras.layers 导入 Conv2D from keras.layers import Conv2DTranspose from keras.layers import LeakyReLU from keras.layers import Dropout # 定义独立的判别器模型 def define_discriminator(in_shape=(28,28,1)): model = Sequential() # 下采样 model.add(Conv2D(128, (3,3), strides=(2,2), padding='same', input_shape=in_shape)) model.add(LeakyReLU(alpha=0.2)) # 下采样 model.add(Conv2D(128, (3,3), strides=(2,2), padding='same')) model.add(LeakyReLU(alpha=0.2)) # 分类器 model.add(Flatten()) model.add(Dropout(0.4)) model.add(Dense(1, activation='sigmoid')) # 编译模型 opt = Adam(lr=0.0002, beta_1=0.5) model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy']) return model # 定义独立的生成器模型 def define_generator(latent_dim): model = Sequential() # 7x7 图像的基础 n_nodes = 128 * 7 * 7 model.add(Dense(n_nodes, input_dim=latent_dim)) model.add(LeakyReLU(alpha=0.2)) model.add(Reshape((7, 7, 128))) # 上采样到 14x14 model.add(Conv2DTranspose(128, (4,4), strides=(2,2), padding='same')) model.add(LeakyReLU(alpha=0.2)) # 上采样到 28x28 model.add(Conv2DTranspose(128, (4,4), strides=(2,2), padding='same')) model.add(LeakyReLU(alpha=0.2)) # 生成 model.add(Conv2D(1, (7,7), activation='tanh', padding='same')) return model # 定义组合的生成器和判别器模型,用于更新生成器 def define_gan(generator, discriminator): # 使判别器中的权重不可训练 discriminator.trainable = False # 连接它们 model = Sequential() # 添加生成器 model.add(generator) # 添加判别器 model.add(discriminator) # 编译模型 opt = Adam(lr=0.0002, beta_1=0.5) model.compile(loss='binary_crossentropy', optimizer=opt) return model # 加载 fashion mnist 图像 def load_real_samples(): # 加载数据集 (trainX, _), (_, _) = load_data() # 扩展到3D,例如添加通道 X = expand_dims(trainX, axis=-1) # 从整数转换为浮点数 X = X.astype('float32') # 从 [0,255] 缩放到 [-1,1] X = (X - 127.5) / 127.5 return X # 选择真实样本 def generate_real_samples(dataset, n_samples): # 选择随机实例 ix = randint(0, dataset.shape[0], n_samples) # 选择图像 X = dataset[ix] # 生成类别标签 y = ones((n_samples, 1)) 返回 X, y # 在潜在空间中生成点作为生成器的输入 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 个假示例,并带有类别标签 def generate_fake_samples(generator, latent_dim, n_samples): # 在潜在空间中生成点 x_input = generate_latent_points(latent_dim, n_samples) # 预测输出 X = generator.predict(x_input) # 创建类别标签 y = zeros((n_samples, 1)) 返回 X, y # 训练生成器和判别器 def train(g_model, d_model, gan_model, dataset, latent_dim, n_epochs=100, n_batch=128): bat_per_epo = int(dataset.shape[0] / n_batch) half_batch = int(n_batch / 2) # 手动枚举 epoch for i in range(n_epochs): # 枚举训练集中的批次 for j in range(bat_per_epo): # 获取随机选择的“真实”样本 X_real, y_real = generate_real_samples(dataset, half_batch) # 更新判别器模型权重 d_loss1, _ = d_model.train_on_batch(X_real, y_real) # 生成“假”示例 X_fake, y_fake = generate_fake_samples(g_model, latent_dim, half_batch) # 更新判别器模型权重 d_loss2, _ = d_model.train_on_batch(X_fake, y_fake) # 准备潜在空间中的点作为生成器的输入 X_gan = generate_latent_points(latent_dim, n_batch) # 为伪样本创建反转标签 y_gan = ones((n_batch, 1)) # 通过判别器的误差更新生成器 g_loss = gan_model.train_on_batch(X_gan, y_gan) # 总结此批次的损失 print('>%d, %d/%d, d1=%.3f, d2=%.3f g=%.3f' % (i+1, j+1, bat_per_epo, d_loss1, d_loss2, g_loss)) # 保存生成器模型 g_model.save('generator.h5') # 潜在空间的大小 latent_dim = 100 # 创建判别器 discriminator = define_discriminator() # 创建生成器 generator = define_generator(latent_dim) # 创建GAN gan_model = define_gan(generator, discriminator) # 加载图像数据 dataset = load_real_samples() # 训练模型 train(generator, discriminator, gan_model, dataset, latent_dim) |
在一般的硬件上运行此示例可能需要很长时间。
我建议在 GPU 硬件上运行此示例。如果您需要帮助,可以通过使用 AWS EC2 实例来快速开始训练模型。请参阅教程。
判别器在真实和虚假样本上的损失,以及生成器的损失,会在每个批次后报告。
注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能有所不同。考虑运行示例几次并比较平均结果。
在这种情况下,在整个训练过程中,判别器和生成器的损失值都约为 0.6 到 0.7。
1 2 3 4 5 6 |
... >100, 464/468, d1=0.681, d2=0.685 g=0.693 >100, 465/468, d1=0.691, d2=0.700 g=0.703 >100, 466/468, d1=0.691, d2=0.703 g=0.706 >100, 467/468, d1=0.698, d2=0.699 g=0.699 >100, 468/468, d1=0.699, d2=0.695 g=0.708 |
训练结束时,生成器模型将以文件名“generator.h5”保存到文件中。
加载此模型后,可用于从 fashion MNIST 数据集中生成新的、随机但逼真的样本。
下面的示例加载保存的模型并生成 100 件随机服装。
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 30 31 32 33 |
# 加载生成器模型并生成图像的示例 from keras.models import load_model from numpy.random import randn from matplotlib import pyplot # 在潜在空间中生成点作为生成器的输入 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 # 创建并保存生成的图像图(反转灰度) def show_plot(examples, n): # 绘制图像 for i in range(n * n): # 定义子图 pyplot.subplot(n, n, 1 + i) # 关闭轴线 pyplot.axis('off') # 绘制原始像素数据 pyplot.imshow(examples[i, :, :, 0], cmap='gray_r') pyplot.show() # 加载模型 model = load_model('generator.h5') # 生成图像 latent_points = generate_latent_points(100, 100) # 生成图像 X = model.predict(latent_points) # 绘制结果 show_plot(X, 10) |
运行此示例将创建一个包含 100 件随机生成的服装的图,并将其排列成一个 10x10 的网格。
注意:由于算法或评估程序的随机性,或数值精度的差异,您的结果可能有所不同。考虑运行示例几次并比较平均结果。
在这种情况下,我们可以看到各种服装,如鞋子、毛衣和裤子。大多数物品看起来相当逼真,并且可能来自 fashion MNIST 数据集。但它们并不完美,因为有些毛衣只有一只袖子,而有些鞋子则像一团乱麻。

使用无条件 GAN 生成 100 件服装的示例。
Fashion-MNIST 的条件 GAN
在本节中,我们将通过更新上一节中开发的无条件 GAN,为 Fashion-MNIST 数据集开发一个条件 GAN。
在 Keras 中设计具有多个输入的模型是使用函数式 API 的最佳方式,而不是像上一节那样使用顺序 API。我们将使用函数式 API 来重新实现判别器、生成器和复合模型。
从判别器模型开始,定义了一个新的第二个输入,它接受一个整数作为图像的类别标签。这使得输入图像取决于提供的类别标签。
然后,类别标签通过一个大小为 50 的 Embedding 层。这意味着 Fashion MNIST 数据集中的 10 个类别(0 到 9)中的每一个都将映射到一个由判别器模型学习的不同的 50 元素向量表示。
然后,Embedding 层的输出被传递到一个具有线性激活的完全连接层。重要的是,该完全连接层的激活次数足以重塑为 28x28 图像的一个通道。激活被重塑为单个 28x28 激活图,并与输入图像连接。这使得它看起来像下一个卷积层的双通道输入图像。
下面的 define_discriminator() 函数实现了对判别器模型的这一更新。在 Embedding 层之后,输入图像的参数化形状也用于定义完全连接层的激活数量,以重塑其输出。函数中还参数化了问题中的类别数量并进行了设置。
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 30 31 32 33 |
# 定义独立的判别器模型 def define_discriminator(in_shape=(28,28,1), n_classes=10): # 标签输入 in_label = Input(shape=(1,)) # 分类输入的嵌入 li = Embedding(n_classes, 50)(in_label) # 扩展到图像尺寸,具有线性激活 n_nodes = in_shape[0] * in_shape[1] li = Dense(n_nodes)(li) # 重塑为附加通道 li = Reshape((in_shape[0], in_shape[1], 1))(li) # 图像输入 in_image = Input(shape=in_shape) # 将标签作为通道连接 merge = Concatenate()([in_image, li]) # 下采样 fe = Conv2D(128, (3,3), strides=(2,2), padding='same')(merge) fe = LeakyReLU(alpha=0.2)(fe) # 下采样 fe = Conv2D(128, (3,3), strides=(2,2), padding='same')(fe) fe = LeakyReLU(alpha=0.2)(fe) # 展平特征图 fe = Flatten()(fe) # Dropout fe = Dropout(0.4)(fe) # 输出 out_layer = Dense(1, activation='sigmoid')(fe) # 定义模型 model = Model([in_image, in_label], out_layer) # 编译模型 opt = Adam(lr=0.0002, beta_1=0.5) model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy']) return model |
为了使架构更清晰,下面是判别器模型的图。
该图显示了两个输入:首先是通过嵌入(左侧)的类别标签,然后是图像(右侧),以及它们如何连接成一个双通道的 28x28 图像或特征图(中间)。模型的其余部分与上一节设计的判别器相同。

条件生成对抗网络中判别器模型的图
接下来,必须更新生成器模型以接受类别标签。这使得潜在空间中的点取决于提供的类别标签。
与判别器一样,类别标签通过嵌入层进行传递,以将其映射到唯一的 50 元素向量,然后通过具有线性激活的完全连接层进行传递,然后再进行重塑。在这种情况下,完全连接层的激活被重塑为一个 7x7 的特征图。这是为了匹配无条件生成器模型的 7x7 特征图激活。新的 7x7 特征图作为另一个通道添加到现有的 128 个通道中,总共得到 129 个特征图,然后像以前的模型一样进行上采样。
下面的 define_generator() 函数实现了这一点,就像我们在判别器模型中所做的那样,它也对类别数量进行了参数化。
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 30 31 |
# 定义独立的生成器模型 def define_generator(latent_dim, n_classes=10): # 标签输入 in_label = Input(shape=(1,)) # 分类输入的嵌入 li = Embedding(n_classes, 50)(in_label) # 线性乘法 n_nodes = 7 * 7 li = Dense(n_nodes)(li) # 重塑为附加通道 li = Reshape((7, 7, 1))(li) # 图像生成器输入 in_lat = Input(shape=(latent_dim,)) # 7x7 图像的基础 n_nodes = 128 * 7 * 7 gen = Dense(n_nodes)(in_lat) gen = LeakyReLU(alpha=0.2)(gen) gen = Reshape((7, 7, 128))(gen) # 合并图像生成和标签输入 merge = Concatenate()([gen, li]) # 上采样到 14x14 gen = Conv2DTranspose(128, (4,4), strides=(2,2), padding='same')(merge) gen = LeakyReLU(alpha=0.2)(gen) # 上采样到 28x28 gen = Conv2DTranspose(128, (4,4), strides=(2,2), padding='same')(gen) gen = LeakyReLU(alpha=0.2)(gen) # 输出 输出层 = Conv2D(1, (7,7), activation='tanh', padding='same')(gen) # 定义模型 模型 = Model([in_lat, in_label], out_layer) return model |
为了帮助理解新的模型架构,下图提供了新条件生成器的模型图。
在这种情况下,您可以看到左侧的100维潜在空间输入点和随后的调整大小,以及右侧的新类别标签输入和嵌入层,然后是两个特征图集的连接(中心)。模型的其余部分与无条件情况相同。

条件生成对抗网络中生成器模型的图
最后,需要更新复合GAN模型。
新的GAN模型将以潜在空间中的一个点作为输入,并以类别标签作为输入,然后生成一个关于输入是真实还是伪造的预测。
使用函数式API设计模型时,重要的是要将生成器生成的图像输出以及类别标签输入显式地连接起来,作为判别器模型的输入。这允许相同的类别标签输入流向生成器并流向判别器。
下面的`define_gan()`函数实现了GAN的条件版本。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
# 定义组合的生成器和判别器模型,用于更新生成器 def define_gan(g_model, d_model): # 使判别器中的权重不可训练 d_model.trainable = False # 从生成器模型获取噪声和标签输入 gen_noise, gen_label = g_model.input # 从生成器模型获取图像输出 gen_output = g_model.output # 将生成器的图像输出和标签输入连接作为判别器的输入 gan_output = d_model([gen_output, gen_label]) # 定义gan模型,以噪声和标签作为输入,输出分类结果 model = Model([gen_noise, gen_label], gan_output) # 编译模型 opt = Adam(lr=0.0002, beta_1=0.5) model.compile(loss='binary_crossentropy', optimizer=opt) return model |
下图总结了复合GAN模型。
重要的是,它显示了完整的生成器模型,将潜在空间中的点和类别标签作为输入,并将生成器的输出与相同的类别标签作为判别器模型的输入(图底部最后一个框),以及输出一个单一的真实或伪造的类别标签分类。

条件生成对抗网络中复合生成器和判别器模型的图
从无条件GAN到条件GAN的转换中最困难的部分已经完成,即模型架构的定义和配置。
接下来,所有剩余的工作是更新训练过程以也使用类别标签。
首先,必须更新`load_real_samples()`和`generate_real_samples()`函数,用于加载数据集和选择样本批次,以利用训练数据集中的真实类别标签。重要的是,`generate_real_samples()`函数现在返回图像、服装标签以及用于判别器的类别标签(类别=1)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
# 加载 fashion mnist 图像 def load_real_samples(): # 加载数据集 (trainX, trainy), (_, _) = load_data() # 扩展到3D,例如添加通道 X = expand_dims(trainX, axis=-1) # 从整数转换为浮点数 X = X.astype('float32') # 从 [0,255] 缩放到 [-1,1] X = (X - 127.5) / 127.5 return [X, trainy] # 选择真实样本 def generate_real_samples(dataset, n_samples): # 分割为图像和标签 images, labels = dataset # 选择随机实例 ix = randint(0, images.shape[0], n_samples) # 选择图像和标签 X, labels = images[ix], labels[ix] # 生成类别标签 y = ones((n_samples, 1)) return [X, labels], y |
接下来,必须更新`generate_latent_points()`函数,使其也生成一个随机选择的整数类别标签数组,与随机选择的潜在空间点一起。
然后必须更新`generate_fake_samples()`函数,在生成新的伪造图像时,使用这些随机生成的类别标签作为生成器模型的输入。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
# 在潜在空间中生成点作为生成器的输入 def generate_latent_points(latent_dim, n_samples, n_classes=10): # 在潜在空间中生成点 x_input = randn(latent_dim * n_samples) # 重塑为网络的输入批次 z_input = x_input.reshape(n_samples, latent_dim) # 生成标签 labels = randint(0, n_classes, n_samples) return [z_input, labels] # 使用生成器生成 n 个假示例,并带有类别标签 def generate_fake_samples(generator, latent_dim, n_samples): # 在潜在空间中生成点 z_input, labels_input = generate_latent_points(latent_dim, n_samples) # 预测输出 images = generator.predict([z_input, labels_input]) # 创建类别标签 y = zeros((n_samples, 1)) return [images, labels_input], y |
最后,必须更新`train()`函数,以便在更新判别器和生成器模型时检索并使用类别标签。
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 |
# 训练生成器和判别器 def train(g_model, d_model, gan_model, dataset, latent_dim, n_epochs=100, n_batch=128): bat_per_epo = int(dataset[0].shape[0] / n_batch) half_batch = int(n_batch / 2) # 手动枚举 epoch for i in range(n_epochs): # 枚举训练集中的批次 for j in range(bat_per_epo): # 获取随机选择的“真实”样本 [X_real, labels_real], y_real = generate_real_samples(dataset, half_batch) # 更新判别器模型权重 d_loss1, _ = d_model.train_on_batch([X_real, labels_real], y_real) # 生成“假”示例 [X_fake, labels], y_fake = generate_fake_samples(g_model, latent_dim, half_batch) # 更新判别器模型权重 d_loss2, _ = d_model.train_on_batch([X_fake, labels], y_fake) # 准备潜在空间中的点作为生成器的输入 [z_input, labels_input] = generate_latent_points(latent_dim, n_batch) # 为伪样本创建反转标签 y_gan = ones((n_batch, 1)) # 通过判别器的误差更新生成器 g_loss = gan_model.train_on_batch([z_input, labels_input], y_gan) # 总结此批次的损失 print('>%d, %d/%d, d1=%.3f, d2=%.3f g=%.3f' % (i+1, j+1, bat_per_epo, d_loss1, d_loss2, g_loss)) # 保存生成器模型 g_model.save('cgan_generator.h5') |
将所有这些结合起来,用于时装MNIST数据集的条件深度卷积生成对抗网络的完整示例列在下面。
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 |
# 在时装MNIST数据集上训练条件GAN的示例 from numpy import expand_dims from numpy import zeros from numpy import ones from numpy.random import randn from numpy.random import randint from keras.datasets.fashion_mnist import load_data from keras.optimizers import Adam from keras.models import Model from keras.layers import Input from keras.layers import Dense from keras.layers import Reshape from keras.layers import Flatten 从 keras.layers 导入 Conv2D from keras.layers import Conv2DTranspose from keras.layers import LeakyReLU 从 keras.layers 导入 Dropout from keras.layers import Embedding from keras.layers import Concatenate # 定义独立的判别器模型 def define_discriminator(in_shape=(28,28,1), n_classes=10): # 标签输入 in_label = Input(shape=(1,)) # 分类输入的嵌入 li = Embedding(n_classes, 50)(in_label) # 扩展到图像尺寸,具有线性激活 n_nodes = in_shape[0] * in_shape[1] li = Dense(n_nodes)(li) # 重塑为附加通道 li = Reshape((in_shape[0], in_shape[1], 1))(li) # 图像输入 in_image = Input(shape=in_shape) # 将标签作为通道连接 merge = Concatenate()([in_image, li]) # 下采样 fe = Conv2D(128, (3,3), strides=(2,2), padding='same')(merge) fe = LeakyReLU(alpha=0.2)(fe) # 下采样 fe = Conv2D(128, (3,3), strides=(2,2), padding='same')(fe) fe = LeakyReLU(alpha=0.2)(fe) # 展平特征图 fe = Flatten()(fe) # Dropout fe = Dropout(0.4)(fe) # 输出 out_layer = Dense(1, activation='sigmoid')(fe) # 定义模型 model = Model([in_image, in_label], out_layer) # 编译模型 opt = Adam(lr=0.0002, beta_1=0.5) model.compile(loss='binary_crossentropy', optimizer=opt, metrics=['accuracy']) return model # 定义独立的生成器模型 def define_generator(latent_dim, n_classes=10): # 标签输入 in_label = Input(shape=(1,)) # 分类输入的嵌入 li = Embedding(n_classes, 50)(in_label) # 线性乘法 n_nodes = 7 * 7 li = Dense(n_nodes)(li) # 重塑为附加通道 li = Reshape((7, 7, 1))(li) # 图像生成器输入 in_lat = Input(shape=(latent_dim,)) # 7x7 图像的基础 n_nodes = 128 * 7 * 7 gen = Dense(n_nodes)(in_lat) gen = LeakyReLU(alpha=0.2)(gen) gen = Reshape((7, 7, 128))(gen) # 合并图像生成和标签输入 merge = Concatenate()([gen, li]) # 上采样到 14x14 gen = Conv2DTranspose(128, (4,4), strides=(2,2), padding='same')(merge) gen = LeakyReLU(alpha=0.2)(gen) # 上采样到 28x28 gen = Conv2DTranspose(128, (4,4), strides=(2,2), padding='same')(gen) gen = LeakyReLU(alpha=0.2)(gen) # 输出 输出层 = Conv2D(1, (7,7), activation='tanh', padding='same')(gen) # 定义模型 模型 = Model([in_lat, in_label], out_layer) return model # 定义组合的生成器和判别器模型,用于更新生成器 def define_gan(g_model, d_model): # 使判别器中的权重不可训练 d_model.trainable = False # 从生成器模型获取噪声和标签输入 gen_noise, gen_label = g_model.input # 从生成器模型获取图像输出 gen_output = g_model.output # 将生成器的图像输出和标签输入连接作为判别器的输入 gan_output = d_model([gen_output, gen_label]) # 定义gan模型,以噪声和标签作为输入,输出分类结果 model = Model([gen_noise, gen_label], gan_output) # 编译模型 opt = Adam(lr=0.0002, beta_1=0.5) model.compile(loss='binary_crossentropy', optimizer=opt) return model # 加载 fashion mnist 图像 def load_real_samples(): # 加载数据集 (trainX, trainy), (_, _) = load_data() # 扩展到3D,例如添加通道 X = expand_dims(trainX, axis=-1) # 从整数转换为浮点数 X = X.astype('float32') # 从 [0,255] 缩放到 [-1,1] X = (X - 127.5) / 127.5 return [X, trainy] # # 选择真实样本 def generate_real_samples(dataset, n_samples): # 分割为图像和标签 images, labels = dataset # 选择随机实例 ix = randint(0, images.shape[0], n_samples) # 选择图像和标签 X, labels = images[ix], labels[ix] # 生成类别标签 y = ones((n_samples, 1)) return [X, labels], y # 在潜在空间中生成点作为生成器的输入 def generate_latent_points(latent_dim, n_samples, n_classes=10): # 在潜在空间中生成点 x_input = randn(latent_dim * n_samples) # 重塑为网络的输入批次 z_input = x_input.reshape(n_samples, latent_dim) # 生成标签 labels = randint(0, n_classes, n_samples) return [z_input, labels] # 使用生成器生成 n 个假示例,并带有类别标签 def generate_fake_samples(generator, latent_dim, n_samples): # 在潜在空间中生成点 z_input, labels_input = generate_latent_points(latent_dim, n_samples) # 预测输出 images = generator.predict([z_input, labels_input]) # 创建类别标签 y = zeros((n_samples, 1)) return [images, labels_input], y # 训练生成器和判别器 def train(g_model, d_model, gan_model, dataset, latent_dim, n_epochs=100, n_batch=128): bat_per_epo = int(dataset[0].shape[0] / n_batch) half_batch = int(n_batch / 2) # 手动枚举 epoch for i in range(n_epochs): # 枚举训练集中的批次 for j in range(bat_per_epo): # 获取随机选择的“真实”样本 [X_real, labels_real], y_real = generate_real_samples(dataset, half_batch) # 更新判别器模型权重 d_loss1, _ = d_model.train_on_batch([X_real, labels_real], y_real) # 生成“假”示例 [X_fake, labels], y_fake = generate_fake_samples(g_model, latent_dim, half_batch) # 更新判别器模型权重 d_loss2, _ = d_model.train_on_batch([X_fake, labels], y_fake) # 准备潜在空间中的点作为生成器的输入 [z_input, labels_input] = generate_latent_points(latent_dim, n_batch) # 为伪样本创建反转标签 y_gan = ones((n_batch, 1)) # 通过判别器的误差更新生成器 g_loss = gan_model.train_on_batch([z_input, labels_input], y_gan) # 总结此批次的损失 print('>%d, %d/%d, d1=%.3f, d2=%.3f g=%.3f' % (i+1, j+1, bat_per_epo, d_loss1, d_loss2, g_loss)) # 保存生成器模型 g_model.save('cgan_generator.h5') # 潜在空间的大小 latent_dim = 100 # 创建判别器 d_model = define_discriminator() # 创建生成器 g_model = define_generator(latent_dim) # 创建GAN gan_model = define_gan(g_model, d_model) # 加载图像数据 dataset = load_real_samples() # 训练模型 train(g_model, d_model, gan_model, dataset, latent_dim) |
运行示例可能需要一些时间,建议使用GPU硬件,但并非必需。
运行结束后,模型将保存到名为‘cgan_generator.h5‘的文件中。
条件服装生成
在本节中,我们将使用训练好的生成器模型来有条件地生成新的服装图片。
我们可以更新我们生成新图像的代码示例,使其现在可以根据类别标签生成条件图像。我们可以为每个类别标签生成10个示例,并按列排列。
完整的示例如下所示。
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 30 31 32 33 34 35 36 37 38 39 40 41 |
# 加载生成器模型并生成图像的示例 from numpy import asarray from numpy.random import randn from numpy.random import randint from keras.models import load_model from matplotlib import pyplot # 在潜在空间中生成点作为生成器的输入 def generate_latent_points(latent_dim, n_samples, n_classes=10): # 在潜在空间中生成点 x_input = randn(latent_dim * n_samples) # 重塑为网络的输入批次 z_input = x_input.reshape(n_samples, latent_dim) # 生成标签 labels = randint(0, n_classes, n_samples) return [z_input, labels] # 创建并保存生成的图像图 def save_plot(examples, n): # 绘制图像 for i in range(n * n): # 定义子图 pyplot.subplot(n, n, 1 + i) # 关闭轴线 pyplot.axis('off') # 绘制原始像素数据 pyplot.imshow(examples[i, :, :, 0], cmap='gray_r') pyplot.show() # 加载模型 model = load_model('cgan_generator.h5') # 生成图像 latent_points, labels = generate_latent_points(100, 100) # 指定标签 labels = asarray([x for _ in range(10) for x in range(10)]) # 生成图像 X = model.predict([latent_points, labels]) # 将范围从[-1,1]缩放到[0,1] X = (X + 1) / 2.0 # 绘制结果 save_plot(X, 10) |
运行示例将加载保存的条件GAN模型,并使用它生成100件服装。
服装按列组织。从左到右,它们是“T恤”、“裤子”、“套头衫”、“连衣裙”、“外套”、“凉鞋”、“衬衫”、“运动鞋”、“包”和“踝靴”。
我们不仅可以看到随机生成的服装看起来合理,而且它们也与预期的类别匹配。

使用条件GAN生成的100件服装示例。
扩展
本节列出了一些您可能希望探索的扩展本教程的想法。
- 潜在空间大小。通过改变潜在空间的大小进行实验,并查看对生成图像质量的影响。
- 嵌入大小。通过使类别标签嵌入变小或变大来试验其大小,并查看对生成图像质量的影响。
- 备用架构。更新模型架构,将类别标签连接到生成器和/或判别器模型中的其他位置,可能使用不同的维度,并查看对生成图像质量的影响。
如果您探索了这些扩展中的任何一个,我很想知道。
请在下面的评论中发布您的发现。
进一步阅读
如果您想深入了解,本节提供了更多关于该主题的资源。
文章
- 第20章。深度生成模型,深度学习,2016年。
- 第8章。生成深度学习,Python深度学习,2017年。
论文
- 生成对抗网络, 2014.
- 教程:生成对抗网络,NIPS, 2016.
- 使用深度卷积生成对抗网络的无监督表征学习, 2015
- 条件生成对抗网络, 2014.
- 使用条件对抗网络进行图像到图像翻译, 2017.
- 用于卷积人脸生成的条件生成对抗网络, 2015.
API
- Keras数据集API。
- Keras 序列模型 API
- Keras卷积层API
- 我如何“冻结”Keras层?
- MatplotLib API
- NumPy 随机抽样 (numpy.random) API
- NumPy 数组操作例程
文章
- 如何训练GAN?让GAN生效的技巧
- Fashion-MNIST项目,GitHub.
- 在CIFAR-10上训练条件DC-GAN(代码),2018年。
- GAN:从零到英雄 第二部分 GAN的条件生成, 2018.
- Keras-GAN项目。生成对抗网络的Keras实现,GitHub.
- 条件深度卷积GAN(CDCGAN)– Keras实现,GitHub.
总结
在本教程中,您学习了如何开发一个条件生成对抗网络,以有针对性地生成服装。
具体来说,你学到了:
- GAN 生成随机样本的局限性可以通过条件生成对抗网络来克服。
- 如何开发和评估一个无条件生成对抗网络,用于生成服装照片。
- 如何开发和评估一个条件生成对抗网络,用于生成服装照片。
你有什么问题吗?
在下面的评论中提出你的问题,我会尽力回答。
很酷,谢谢。
谢谢Keith。
太棒了。感谢您传播如此有价值的知识。
如果我想训练判别器,会怎么样?因为在当前模型中我们只训练了生成器。如果我错了,请纠正我。
请帮我理解一下,生成器需要多少样本才能生成与原始分布相似的新样本?GAN的输入样本有最小数量限制吗?
谢谢
Shravan
不,生成器和判别器是同时训练的。
在半监督GAN方面有许多出色的工作,可以以很少的真实样本训练分类器。
不错的博文。
您是否有关于在Android上部署pytorch或tensorflow基础GAN模型的博客?
我急需它。
没有,抱歉。
嗨 Jason,但您将判别器权重设置为`trainable`为False
# 使判别器中的权重不可训练
d_model.trainable = False
我现在不理解了。
仅在复合模型的上下文中。
要了解有关在不同上下文中冻结权重的更多信息,请参阅
– 如何冻结层并进行微调?
https://keras.org.cn/getting_started/faq/
非常多的精彩博文!我对您的GAN书感到非常兴奋。我想几年前我催促过您写一本!– 您的忠实读者。
谢谢!也谢谢你催促我,Ken!
我对此感到非常兴奋。
肯
请在这里列出书名好吗
此致
Partha
Ken指的是我即将出版的GAN书籍。
书名将是“Generative Adversarial Networks with Python”。
大约一到两周内就可以出版了。
我不明白,在训练复合无意识GAN时,生成器如何通过传递1作为输出标签来产生好结果?它不应该是0吗?
在无条件GAN训练中。
无条件GAN已训练。
也许我不理解你的问题?
这是很疯狂的事情。
基本上,我们正在训练生成器来欺骗判别器,在这种情况下,生成器是有条件地依赖于特定类别标签的。判别器会促使判别器将特定的生成图像与类别标签相关联。
如果这一切对您来说都是新的,也许可以从这里开始
https://machinelearning.org.cn/what-are-generative-adversarial-networks-gans/
您好,先生,
我非常欣赏您的工作。我有一个问题,我想用这种技术,但是作为输入我有一个图像,然后我将其馈送到生成器以获得另一个图像,然后将其馈送到判别器,但问题是所有教程都从随机输入开始。
您是否有可以帮助我的博客或代码?
听起来您可能对图像到图像翻译感兴趣。
这会有帮助
https://machinelearning.org.cn/a-gentle-introduction-to-pix2pix-generative-adversarial-network/
很棒的文章,谢谢!我有两个问题。
首先,您在判别器和生成器中都使用了标签的嵌入层。我看不到嵌入层在为您做什么。只有10个标签,为什么50维向量比普通的独热编码向量更有用(毕竟,十个独热编码向量是正交的,因此它们尽可能区分)。那么,拥有嵌入层的算法动机是什么?
其次,为什么还要跟一个密集层?同样,独热编码标签向量似乎是我们所需要的一切,但在这里我们已经将它们转换成了50维向量。密集层完成了哪些必要的工作?
谢谢!
好问题。
嵌入层提供了类别标签的投影,这是一种分布式的表示,可用于条件化图像生成和分类。
这种分布式表示可以按比例放大,并以类似滤波器图的结构很好地插入模型中。
还有其他将类别标签引入模型的方法,但据报道,这种方法更有效。为什么?这是一个难题,而且可能无法在短期内解决。大多数GAN的发现都是经验性的。
尝试将独热编码向量与G的z进行连接,并为D提供第二个输入,然后比较结果。
嗨,Jason,
感谢您提供如此有用和详细的信息。您是否有解释嵌入思想更透彻的参考资料,或者能提供更多直观解释吗?我明白为什么您会为单词/句子使用嵌入,因为那里存在语义相似性的概念,但不明白为什么在像这样的数据集(或简单的MNIST)上,嵌入层是有意义的。它实际上只是重塑独热编码的一种方式吗?谢谢!
嵌入是类别数据的独热编码的替代方案。
它在单词方面很受欢迎,但也可用于任何类别或顺序数据。
在无条件GAN代码中,为什么判别器模型的权重可以针对纯粹的真实样本和伪造样本分别更新?
# 更新判别器模型权重
d_loss1, _ = d_model.train_on_batch(X_real, y_real)
# 更新判别器模型权重
d_loss2, _ = d_model.train_on_batch(X_fake, y_fake)
基本上,判别器是二元分类。如果所有样本都是纯粹的真实(=1)或纯粹的伪造(=0),二元分类将无法收敛。为什么不将`X_real`和`X_fake`组合起来,然后将样本输入判别器,后者将分类真实和伪造样本,例如:
d_loss, _ = d_model.train_on_batch([X_real, X_fake], [y_real, y_fake] )
你可以这样做,但据报道,单独的批次更新可以使判别器模型相对于生成器的性能保持稳定(例如,它不会变得更好——更快)。
更多信息在这里
https://machinelearning.org.cn/how-to-code-generative-adversarial-network-hacks/
感谢这个非常有用的教程!
我总是收到这类警告
“W0829 11:18:47.925395 14568 training.py:2197] 可训练权重与已收集的可训练权重之间存在差异,您是否在调用`model.compile`后设置了
model.trainable
?”这是否意味着我做了一些不同的事情,或者这是您也看到的问题。模型可以运行,所以这重要吗?
您可以安全地忽略该警告 – 我们有点滥用了Keras🙂
嗨 Janson,非常棒的教程!运行您的代码时,我卡在某个地方了
我们定义了“define_discriminator(in_shape=(28,28,1))”,其形状为(28,28,1),然后我们调用它来执行
“d_model.train_on_batch(X_real, y_real)”,其中样本大小为64(错误消息如下)
ValueError: Error when checking model input: the list of Numpy arrays that you are passing to your model is not the size the model expected. Expected to see 1 array(s), but instead got the following list of 64 arrays: [, , …
我对深度学习很陌生,不知道如何解决这个问题。
抱歉,我在尝试复制您的代码时发现了一个错误。请忽略我的问题。
没问题!
听到这个消息我很难过,我这里有一些建议可能会有帮助
https://machinelearning.org.cn/faq/single-faq/why-does-the-code-in-the-tutorial-not-work-for-me
在训练循环中,鉴别器模型实例‘d_model’是如何训练的,当同一个实例在‘define_GAN’方法中被设置为 trainable=False 时?
Setting trainable=False only effects the generator, it does not effect the discriminator.
看这里
https://keras.org.cn/getting-started/faq/#how-can-i-freeze-keras-layers
非常感谢!这是一篇写得清晰、结构良好且极具启发性的教程。我喜欢所有详细的解释以及附带的代码。优秀!
谢谢!
谢谢 Jason!这是一个非常好的教程。我继续进行了一些进一步的实验,但遇到了一些问题。我正在尝试实现一个带有谱归一化的 cSAGAN,但出于某种原因,鉴别器会引发一个错误 ‘NoneType’ object has no attribute ‘_inbound_nodes’。
这让我很困扰,因为相同的注意力层在与 Keras Sequential() 工作的非条件 SAGAN 一起使用时效果很好。只有当注意力添加到这个函数式 Keras 模型时,问题才会出现。
我需要您就问题所在提供一些见解。
不确定我能否帮助您解决自定义代码的问题,抱歉。也许可以尝试发布到 Stack Overflow?
我最终解决了!是我自己的一个非常愚蠢的错误。但我仍然想再次感谢您发表了这篇对我项目起基础作用的文章。您做得非常棒!
很高兴听到这个消息,干得好!
你好,
使用 Embedding 层是否会为每个类别分割潜在空间?我的意思是,您是否可以使用此方法让生成器生成例如 T 恤 + 鞋子的组合?
是的!可能。
嗨,Jason
您认为可以训练带有多个条件的条件 GAN 吗?例如,我想训练一个画家,根据非彩色输入图片和颜色标签来为输入图片上色?
是的。我认为 InfoGAN 有多个条件。
是的,这听起来像是图像到图像的翻译和一点条件 GAN。试试看!让我知道您的进展。
我目前在学习 MC-GAN 论文,但 Info GAN 也看起来很有趣。稍后一定会尝试一下。
很酷。期待听到您的进展。
Jason,一篇很棒的文章!感谢您的付出。
不客气。
一如既往,Brownlee 的作品很棒。我意识到这对您来说并不意外,但您可以通过更改以下几行代码,在 MNIST(数字)数据集上运行几乎相同的 cGAN。
1. 替换
from tensorflow.keras.datasets.fashion_mnist import load_data
用
from tensorflow.keras.datasets.mnist import load_data
注意:我个人使用 tensorflow 版本的 keras
2. 替换所有实例
opt = Adam(lr=0.0002, beta_1=0.5)
用
opt = Adam(lr=0.0001, beta_1=0.5) # 学习率只需要降低
我提到这个(几乎显而易见)的事实是因为对我来说,cGAN 比简单的 GAN 产生更好、更有趣的结果。其他人提供的教程会给出一些代码,然后随意地建议,“显而易见的是,正在生成可识别的数字”。
特别是,我欣赏您对 Keras 函数式 API 方法的解释。
我确实希望有一种简单的方法可以图形化地说明一阶和二阶导数估计的等价物,以便更好地“看到”为什么有些尝试失败而另一些尝试成功。我知道对近似值的近似很难可视化,但沿此方向进行一些工作会很棒,因为单数字度量几乎不能诊断内部发生的事情。例如(仅作说明),它可能在鼻子和下巴上做得很好,但在眼睛和耳朵上做得不好。我相信有许多人在寻找更好的方法,使这些权重估计更具科学性,减少艺术性。我相信您对此有一些深刻的见解。
再次,精彩的作品,感谢您精彩的解释。
感谢您的反馈和好评。
评估 GANs 仍然具有挑战性,这里的一些指标可能会给您一些启发
https://machinelearning.org.cn/how-to-evaluate-generative-adversarial-networks/
感谢您的回复,并为我指出了您的教程。您可能会认为我是一个数学上的野蛮人,在看到我尝试过的某些事情后,但我的兴趣在于“有效的东西”。如果有什么有用的观察,我相信您会比我做得更优雅。我的观察是基于有限的几次实验——我对我每个月取得的成就感到惊讶。
仅仅出于兴趣,我有一套学习率和 betas,它们对我来说,对 MNIST 和 FASHION_MNIST 数据集都能稳定地产生良好的结果。我知道学习率和 betas不是 GANs 研究的前沿,但我对收敛的窄范围感到惊讶。
define_discriminator opt 设置为
opt = Adam(lr=0.0008, beta_1=0.1)
define_gan opt 设置为
opt = Adam(lr=0.0006, beta_1=0.05)
我阅读了您关于衡量 GANs 结果好坏的大纲。这篇教程很有趣,但对我来说,您在指出 d1 和 d2 应该约为 0.6,而 g 应该约为 0.8 时,您的观点最为重要。根据我有限的一般经验,如果我能将 d1、d2 和 g 的值保持在这些值的合理范围内,那么我很快就会收敛。如果我要收敛,那么我需要首先获得良好的学习率和动量估计。
对此,您在关于探索潜在空间的教程中指出,如果损失值超出范围,您可能需要重新开始分析。根据这个观点,我尝试了以下操作,并将其添加到您关于探索潜在空间的教程的训练函数中。实质上,它会保存模型最近的副本,其中损失值低于 1.0,并在损失值超出任意边界时恢复模型并“重试”。令人惊讶的是,它似乎确实能从中断的地方继续,并且似乎可以避免重新开始整个分析。
我还试图理解关于生成图像的“最大清晰度”是什么意思。就像任何统计分析一样,知道“最大值”对于理解我们已经走了多远或理论上可以走多远至关重要。虽然我认识到使用正态分布数来表示潜在空间在数学上的有用性,但它在实践中似乎并不重要——-3.0 和 3.0 之间的均匀分布(平坦峰度)效果与正态分布一样好。我发现以下方法效果很好。
这并不十分巧妙,但它表明,我认为,潜在空间中的点不必随机分布,但它们必须不同且分散,并且确保潜在空间均匀覆盖(如代码所示)可能是有益的,并且潜在空间不必是高斯分布的。我还没有自己确定这一点是否在实践中适用于各种问题——您显然会更了解。
最后,对于潜在空间的探索,我的 GPU 似乎没有足够的内存来使用 n_batch = 128,所以我使用的是 n_batch = 64。
如果我做了什么非常愚蠢的事情,请随时告诉我。🙂
非常令人印象深刻,感谢分享!
您应该考虑更全面地写一篇博文来总结您的发现。
我很抱歉在您的网站评论区发布了这么多内容。您的作品好得令人惊叹,而且一个人只有在尝试了不同的方法并在互联网上搜索更好的材料后才会意识到这一点。正如您所建议的,我的计划是在我解决一些问题后发布一篇博文。
但是,是的,我在上一条评论中确实做了并且报告了一些真正愚蠢的事情,我想纠正一下……我复制了地址,而不是使用“copy”模块并创建备份。当然,我只能轻松地用生成器和 gan 函数来做这件事。编译后的鉴别器在后台继续工作,逐渐提高其区分真实和虚假的能力,而在前面,生成器模型通过调整来创建更好的假数据。从某种意义上说,这就是人类学习的方式——“缓慢”的鉴别器随着时间的推移而逐渐改进,而生成器则迎头赶上。
通过“备份”生成器和 gan 模型,我能够给每一次分析很多“第二次机会”来收敛(不超出范围)。为了强制收敛(无论最终模型有多好),我使用了以下代码
我将在更好地理解限制后发布一篇博文,并广泛引用您的精彩作品。
感谢分享。
GANs 可以用于非图像数据吗?
是的,但至少据我所见,它们不如专门的生成模型有效。
您的模型在使用 mnist 数据集运行时失败,但在使用 fashion_mnist 数据集时运行完美,我无法理解哪里出了问题。d1_loss 和 d2_loss 都变成了 0.00,而 gan_loss 飙升。您能给个提示,哪里出了问题吗?
如果您更改数据集,您可能需要针对更改来调整模型。
您能告诉我怎么做吗?麻烦您了!
我手动构建了两个模型,而且比这个更大,但仍然两个损失都归零。
我使用了 mnist 数字数据。
我不知道我错过了什么!!!!麻烦帮我解决一下。
是的,这是一个大话题,也许可以从这里开始
https://machinelearning.org.cn/start-here/#gans
你好 Jason,我在 EMNIST 数据集上遇到了一些问题。
您能基本解释一下如何将我们的模型应用于 26 类或其他数据集吗?我对这个领域是新手,我没有理解链接中的任何内容。我不知道该怎么办……
我实现了您的代码来处理我的数据集,但 d1_loss 和 d2_loss 收敛到 0,gan_loss 也上升到 10。
对于 26 类,您是否尝试过 26 位 one-hot 编码?
嘿,谢谢 Jason。非常棒的文章!
我想知道 CGAN 是否可以用于回归问题。因为在许多 GAN 中,只有 CGAN 具有 y 标签。但我不确定如何将其应用于非图像问题。例如,我想生成一些合成数据。我有一些真实的 y,x 数据点。y = f(x1,x2,x3,x4)。y 是 x1~x4 的非线性函数。我有数百个 [x1,x2, x3, x4, y] 数据。但是,我想获得更多数据,因为真实数据很难获得。所以基本上我想生成 x1_fake, x2_fake, x3_fake, x4_fake, 和 y_fake,其中 y_fake 仍然是 x1_fake~x4_fake 的相同非线性函数,即 y_fake = f(x1_fake, x2_fake, x3_fake, x4_fake)。是否可以使用 CGAN 生成此类合成数据集?
谢谢。
是的,您可以基于数值变量进行条件化。需要不同的损失函数和激活函数。我建议进行实验。
我调整了模型的学习率、批量大小、周期,但没有用。
或许可以尝试这里的一些建议
https://machinelearning.org.cn/how-to-code-generative-adversarial-network-hacks/
Jason,请耐心解答这个初学者的问题。
我难以理解您在实现 cGANs 时的一些语法。
在 define_discriminator() 和 define_generator() 中,您都有成对的括号。
示例
define_discriminator()
第 6 行: li = Embedding(n_classes, 50)(in_label)
第 9 行: li = Dense(n_nodes)(li)
define_generator()
第 16 行: gen = Dense(n_nodes)(in_lat)
第 17 行: gen = LeakyReLU(alpha=0.2)(gen)
这些行末尾的额外 (in_label), (li), (in_lat), (gen) 是什么意思?
您的GAN代码不需要这个。
这是功能API,也许可以从这里开始
https://machinelearning.org.cn/keras-functional-api-deep-learning/
嗨,Jason!
一如既往,非常棒的解释!
如何修改GAN来创建n个离散值,即类别,具有不同的类?例如:n_class1=10,n_class2=15,n_class=18?
有什么初步想法或例子吗?
提前感谢,
Tobias
谢谢。
使用贝叶斯模型要好得多。这只是一个关于GAN如何工作的演示,也是一个生成表格数据的糟糕示例。
请指导我如何修改此代码以将其用于CelebA数据集。我是否可以实现与RGB相同的方式,并且一张图片有多个标签?
这是我在这里回答的一个常见问题
https://machinelearning.org.cn/faq/single-faq/can-you-change-the-code-in-the-tutorial-to-___
嗨,Jason!
非常好的解释!谢谢!
我想知道是否有人预先训练了CGAN或GAN模型,以便我们可以直接用于迁移学习?特别是我对Celebra面部数据感兴趣。
再次感谢,
Joel
谢谢!
可能有预训练的,很抱歉,我没有。
谢谢Jason,非常清晰,对我这样的初学者来说真的很有用。
我有一个关于训练部分实现的问题。
为什么您在准备作为生成器输入的潜在点时,应该使用一半批量来生成真实和虚假样本,但使用整批(n_batch)?
X_real, y_real = generate_real_samples(dataset, half_batch)
X_fake, y_fake = generate_fake_samples(g_model, latent_dim, half_batch)
X_gan = generate_latent_points(latent_dim, n_batch)
谢谢。
这是训练GAN的常用技巧,您可以在这里了解更多信息。
https://machinelearning.org.cn/how-to-train-stable-generative-adversarial-networks/
感谢您的快速回复。我查看了您给我的链接,没有找到关于使用一半批量和n批量的信息。您能否在此解释一下?
来自那篇文章
非常感谢您的帮助,Jason。
不客气。
它是功能API,可用于在模型中创建分支。
在顺序模型中,您无法做到这一点。
同意。
嗨,Jason!
非常好的解释。帮助我澄清了很多疑虑。
但我有一个请求——您能否为“上下文编码器:通过修复学习特征”做出类似的解释?
谢谢!!
谢谢!
好建议。
感谢教程,我一直在学习您提供的所有GAN教程,这非常有帮助!
我尝试在不同的数据集上训练这个条件GAN,效果很好。现在我正尝试在具有不同类别数量(3和5)的数据集上进行训练。我已更改了所有方法中的n_classes以及训练和加载网络后的标签生成,当然。但是,我得到了一个IndexError,并且无法解决。您能否快速建议对数据集中的类别数量需要进行哪些更改?
祝好!
谢谢,很高兴听到这个。
很抱歉听到您在适应示例时遇到麻烦。
也许可以确认输出层中的节点数与目标变量中的类别数匹配,并且目标变量已正确进行独热编码。
嗨 Jason,感谢教程!我有一个关于以下的问题
如果每个标签代表产品的长度、宽度和高度,那么如何不仅输入标签,还将长度、宽度和高度输入模型?因为我想在模型生成结果中看到不同长度、宽度和高度的变化。谢谢!
这是一个有趣的想法,您可能想研究使用infogan,并为每个元素设置一个参数。
谢谢。我将阅读您的infogan文章。
(https://machinelearning.org.cn/how-to-develop-an-information-maximizing-generative-adversarial-network-infogan-in-keras/)
目前,我想生成的模型是监督学习,但使用InfoGAN应该是无监督模型。也许我还是用CGAN来生成和控制结果?
我建议您使用您认为最适合您项目的技术。
例如,我输入各种产品的几何特征x、y、z,然后输出产品的工艺参数。例如:输入(x,y,z)和输出(温度、压力、速度),
当输入新产品的几何特征x、y、z时,模型是否可以预测产品的工艺参数?
这取决于数据,但是的,这正是监督学习的设计目的。
也许这个框架会有帮助
https://machinelearning.org.cn/how-to-define-your-machine-learning-problem/
嗨,Jason,
我有一个关于条件GAN中标签的问题。而不是几个类别,比如从0到9的整数,标签是否可以由连续均匀分布(0,1)生成?这样会有几百个标签输入生成器或判别器。
您认为这合理还是可行?非常感谢!
我看不出为什么不。
我必须做哪些更改才能使用3通道图像进行训练?我已将input_shape更改为(dim, dim, 3),但仍然收到错误:ValueError: Input 0 of layer conv2d is incompatible with the layer: expected axis -1 of input shape to have value 4 but received input with shape [None, dim, dim, 2]
也许从这个模型开始,并将其改编为条件模型。
https://machinelearning.org.cn/how-to-develop-a-generative-adversarial-network-for-a-cifar-10-small-object-photographs-from-scratch/
我不得不更改条件GAN的Embedding层维度,否则tf会报错说它无法将(32,1,50)重塑为(32,7,7)。
我将50更改为49,因为 li = Embedding(n_classes,49)(in_label)。
我是否遗漏了什么,或者这是一个笔误?
这很奇怪,很抱歉听到这个。
您是否复制了所有其他代码示例而未作修改?
您的库是否是最新的?
这些提示有帮助吗?
https://machinelearning.org.cn/faq/single-faq/why-does-the-code-in-the-tutorial-not-work-for-me
不,因为我没有购买这本书,所以没有代码。我找到了问题,我当时问这个问题真是太傻了!很明显,我在生成器中重塑之前遗漏了一个Dense层!
感谢您的及时回复。
很高兴听到您解决了问题!
嗨,Jason,
又一篇很棒的文章。
如果条件DCGAN的标签(条件)输入变为某个尺寸的面部标志图像(例如28,28的灰度图),那么条件DCGAN将如何变化?在这种情况下,生成器应该生成与标志图像相对应的图像,判别器也应该根据标志条件“判断”图像。
具体来说,我很难理解在define_discriminator方法中in_label和li应该是什么。
变化不大,也许只是根据新的输入形状调整模型。
你好,
非常感谢这个教程!我真的很需要它。
只有一个问题,如果我使用自定义数据集,尺寸为(64,64,3)而不是(28,28,1),那么生成器和判别器需要进行哪些更改?
这真的让我很困扰,我知道这很简单,但我可能忽略了什么。
谢谢你的帮助。
更改判别器预期的输入形状,并可能添加更多层来支持更大的图像。
在生成器中添加更多层以确保输出形状与预期大小匹配。
有多少层以及是什么类型——您需要通过反复试验来找到答案。
谢谢,我会看看这个。
还有一件事,我的数据集加载为tf批次数据集(使用keras的image_dataset_from_directory)。如何调整代码来训练这个而不是Fashion MNIST?
抱歉,我不知道“tf batch dataset”。
你好,
感谢详细的博客!我正试图改进一个在小型不平衡数据集上训练的分类器,我正在考虑使用CGAN来扩展我的数据集并使其平衡,但是现在的问题来了:我是否可以使用整个数据集(训练、验证和测试)来训练我的CGAN,然后使用生成的图像来扩展和平衡我的分类器?或者我应该只使用训练集?我有点困惑,因为使用整个数据集是否完全可以,因为生成的图像将来自不同的分布。我找不到任何答案来解决我的困惑,所以您怎么看?
我很困惑,因为在这种情况下,我的分类器将在我用来生成这些数据集的生成图像上进行验证和测试。
您只将其应用于您的训练数据。
不,我认为仅将训练数据集用于训练GAN作为您的实验的一部分是有效的。
关于您下面的精彩帖子,
https://machinelearning.org.cn/generative-adversarial-network-loss-functions/
我的问题是g_loss越低越好吗?
因为我认为您的代码和解释暗示了以下陈述:
“实际上,这也实现为一个二分类问题,类似于判别器。而不是最大化损失,我们可以翻转真实和虚假图像的标签并最小化交叉熵。”
我正尝试对上面的cDCGAN使用贝叶斯优化方法,在定义评估函数以寻找更大的g_loss或更小的g_loss(平均而言)时感到迷茫。
我已经对上面的代码进行了500个epoch的训练,但找不到g_loss是下降还是上升。
顺便说一句,感谢您的帖子。工作很棒!
总的来说,对于GAN来说,不是。
https://machinelearning.org.cn/faq/single-faq/why-is-my-gan-not-converging
嗨 Jason,谢谢这个。
快速问题,embedding是否适用于浮点数?我不想只为输入使用整数,我也想使用浮点数,这可能吗?
谢谢。
Embedding层一般而言?是的。
嗨,Jason,
我一直在关注您的博客、文章和新闻通讯已有几年了!
您对如何将GAN应用于文档生成有什么建议吗?
提前感谢。
谢谢!
我建议使用“语言模型”进行文档生成,而不是GAN。
https://machinelearning.org.cn/?s=language+models&post_type=post&submit=Search
嗨,Jason,
我的问题很基础,但如果您能回答,我将不胜感激。
假设我拥有1D数据,并且希望在两个模型中都只使用密集层。这是我的disc模型定义的代码:
def define_discriminator(in_shape=(10,1), n_classes=8)
# label input
in_label = Input(shape=(1,))
li = Embedding(n_classes, 50)(in_label)
n_nodes = in_shape[0]
li = Dense(n_nodes)(li)
# reshape to additional channel
li = Reshape((n_nodes, 1))(li)
in_data = Input(shape=in_shape)
# concat label as a channel
merge = Concatenate()([in_data, li])
hidden1 = Dense(64, activation=’relu’)(merge)
hidden2 = Dense(64, activation=’relu’)(hidden1)
# output
out_layer = Dense(1, activation=’sigmoid’)(hidden2)
# 定义模型
model = Model([in_data, in_label], out_layer)
# 编译模型
opt = Adam(lr=0.0002, beta_1=0.5)
model.compile(loss=’binary_crossentropy’, optimizer=opt, metrics=[‘accuracy’])
return model
问题是,当我使用d_model.predict()时,输出是3维而不是2维。实际上,形状应该是(64, 1),但却是(64, 10, 1),其中10是输入维度。请告诉我我在这里遗漏了什么。
也许可以查看模型的图或摘要,以确认其构建方式符合您的意图。
如何将cGAN应用于多标签图像增强?
好问题。我还没有研究过,也许可以尝试一下,看看什么对您的应用效果好。
告诉我进展如何。
嗨,Jason,
我想知道是否可以检查点(checkpoint)您的GAN模型。由于典型的指标,如损失和准确率,不适用于GAN,我们需要定义自定义指标。使用keras,我们可以轻松地为像disc模型这样的分类器做到这一点,但我不知道如何为gen模型做到这一点。请假设我们有一个分析生成图像质量的指标。
不完全是,因为损失与图像质量无关。
如果您愿意,可以在每次手动执行的epoch后保存。
嗨,感谢您提供的这个精彩教程。有没有办法使用多个条件向量?我们可以使用多个条件向量然后将它们连接起来吗?
不客气。
也许可以。您可能需要进行实验和/或查阅相关文献以了解相关方法。
感谢您教我机器学习。2个问题。
我注意到train_on_batch传入的是一半批次的真实和虚假数据。权重是否仅在加载完整批次时更新?
为什么我们要为映射10个类使用如此高的50维Embedding?
权重在每次批量更新后都会更新。
50维embedding很常见,您可以尝试其他选项。
嗨 Jason,感谢这个精彩的教程!
我正尝试为时间序列数据创建条件GAN,所以我的模型使用的是LSTM而不是CNN。我在如何重塑输入和标签Embedding方面遇到了麻烦。
在我的情况下,而不是28x28的图像,我有一个时间序列样本,形状为:time_steps, n_features
如您所知,LSTM需要输入为[n_samples, time_steps, n_features]
但现在我还需要添加标签,我将得到4维而不是3维。
您对此有什么建议吗?
非常感谢!
也许这会有帮助。
https://machinelearning.org.cn/faq/single-faq/what-is-the-difference-between-samples-timesteps-and-features-for-lstm-input
嗨,Jason,
感谢您提供如此精彩的文章。
在您的代码中生成虚假图像时;
但是根据论文,我看到其他人使用真实标签输入(与真实图像样本相同)和z_input来生成虚假图像,然后根据此虚假图像测试d模型权重。但这似乎不会影响模型。我想问哪个是正确的?有什么区别吗?
谢谢!
有很多不同类型的模型。
也许可以尝试小的修改,看看什么适合您的应用。
嗨,Jason,
我正在将条件GAN用于我的时间序列数据生成。根据我的应用,生成器损失在某个点收敛然后增加。如何在我模型中包含提前停止,以便当g_loss低于某个阈值时,训练应该终止并保存模型。
通常GAN不会收敛。
https://machinelearning.org.cn/faq/single-faq/why-is-my-gan-not-converging
嗨 Jason,我正尝试将您的条件GAN代码应用于CT扫描数据集,输入图像为256x256。我在判别器和生成器模型中添加了一些额外的层。下面显示了我修改的生成器代码示例。修改后的代码训练需要数小时,但没有显示任何错误或结果。您知道是什么出了问题吗?谢谢。
# linear multiplication
n_nodes = 4 * 4
li = Dense(n_nodes)(li)
# reshape to additional channel
li = Reshape((4, 4, 1))(li)
# image generator input
in_lat = Input(shape=(latent_dim,))
# foundation for 4×4 image
n_nodes = 1024 * 4 * 4
gen = Dense(n_nodes)(in_lat)
gen = LeakyReLU(alpha=0.2)(gen)
gen = Reshape((4, 4, 1024))(gen)
# 合并图像生成和标签输入
merge = Concatenate()([gen, li])
# 上采样到 8x8
gen = Conv2DTranspose(512, (5,5), strides=(2,2), padding=’same’)(merge)
gen = LeakyReLU(alpha=0.2)(gen)
# 上采样到 16x16
gen = Conv2DTranspose(256, (5,5), strides=(2,2), padding=’same’)(gen)
gen = LeakyReLU(alpha=0.2)(gen)
# 上采样到 32x32
gen = Conv2DTranspose(128, (5,5), strides=(2,2), padding=’same’)(gen)
gen = LeakyReLU(alpha=0.2)(gen)
# 上采样到 64x64
gen = Conv2DTranspose(64, (5,5), strides=(2,2), padding=’same’)(gen)
gen = LeakyReLU(alpha=0.2)(gen)
# 上采样到 128x128
gen = Conv2DTranspose(32, (5,5), strides=(2,2), padding=’same’)(gen)
gen = LeakyReLU(alpha=0.2)(gen)
# 上采样到 256x256
gen = Conv2DTranspose(16, (5,5), strides=(2,2), padding=’same’)(gen)
gen = LeakyReLU(alpha=0.2)(gen)
# output
out_layer = Conv2D(1, (256,256), activation=’tanh’, padding=’same’)(gen)
也许这些建议中的一些会对您有所帮助
https://machinelearning.org.cn/faq/single-faq/how-do-i-speed-up-the-training-of-my-model
你好 David,我是一名学生,也在为一个项目生成 256×256 的图像。你能分享一下你做的项目的代码吗?
你好 Jason,我有一个关于加载模型并继续训练的问题。当一个 epoch 结束时,我将 g_model 保存到 h5。如果我想用模型继续训练,我需要保存哪个模型?需要保存 d_model 和 gan model 吗?谢谢。
我猜测你需要保存/加载 G 和 D 以及复合模型。
这有助于我继续训练。感谢您的回复。
不客气。
感谢您的回复。我成功实现了继续训练。
非常感谢您所做的一切,Jason。很棒。
为什么不保存 gan_model 并加载它呢!?
我在您的代码和我的代码中都尝试过,但未能成功!
您能加载 gan_model 并测试一下吗?
不客气。
复合模型仅在训练期间使用,然后被丢弃。
我使用了来自 (http://vision.ucsd.edu/~leekc/ExtYaleDatabase/ExtYaleB.html) 的数据集,并希望通过 Conditional gan 生成人脸图像,我参考了 (https://github.com/GANs-in-Action/gans-in-action/blob/master/chapter-8/Chapter_8_CGAN.ipynb) 和 (https://github.com/ mvedang/Conditional-GAN-CIFAR-10) 的网络架构,但无论我训练多少次,生成的图像仍然是噪声。
即使我调整了判别器和生成器的参数,例如层、神经元等,生成的结果仍然是噪声。
你能帮我修正我构建的生成器和判别器模型吗?代码和结果链接:https://colab.research.google.com/drive/14ul6BeXpVnlO3TVmfvSiR0kkYUuWfvn-?usp=sharing
生成器
def build_cgan_generator(z_dim)
z_input = Input(shape=(z_dim,))
label_input = Input(shape=(1,),dtype=’int32′)
label_embedding = Embedding(classes,output_dim=z_dim,input_length=1)(label_input)
label_embedding = Flatten()(label_embedding)
join_represent = Multiply()([z_input,label_embedding])
x = Dense(4*4*256)(join_represent)
x = Reshape((4,4,256))(x)#4*4*256
x = Conv2DTranspose(64,kernel_size=3,padding=’same’,strides=2)(x)#8*8*64
#x = BatchNormalization(momentum=0.8)(x)
x = LeakyReLU(0.01)(x)
x = Conv2DTranspose(128,kernel_size=3,padding=’same’,strides=2)(x)#16*16*128
#x = BatchNormalization(momentum=0.8)(x)
x = LeakyReLU(0.01)(x)
x = Conv2DTranspose(64,kernel_size=3,padding=’same’,strides=2)(x)#32*32*64
#x = BatchNormalization(momentum=0.8)(x)
x = LeakyReLU(0.01)(x)
x = Conv2DTranspose(32,kernel_size=3,padding=’same’,strides=2)(x)#64*64*32
#x = BatchNormalization(momentum=0.8)(x)
x = LeakyReLU(0.01)(x)
x = Conv2DTranspose(3,kernel_size=4,padding=’same’,strides=2)(x)#128*128*3
output = keras.layers.Activation(‘tanh’)(x)
model = keras.Model([z_input,label_input],output)
tf.keras.utils.plot_model(model,to_file=’generator.png’,show_shapes=True)
return model
判别器
def build_cgan_discriminator(img_shape)
img_input = Input(shape=img_shape)
label_input = Input(shape=(1,))
label_embedding = Embedding(classes,output_dim=np.prod((img_shape[0],img_shape[1],1)),input_length=1)(label_input)
label_embedding = Flatten()(label_embedding)
label_embedding = Reshape((img_shape[0],img_shape[1],1))(label_embedding)
concatenated = Concatenate(axis=-1)([img_input, label_embedding])
x=layers.Conv2D(64,kernel_size=3,strides=2,padding=’same’)(concatenated)
x=LeakyReLU(0.01)(x)
x=layers.Conv2D(64,kernel_size=3,strides=2,padding=’same’)(x)
#x = BatchNormalization(momentum=0.8)(x)
x=LeakyReLU(0.01)(x)
x=layers.Conv2D(128,kernel_size=3,strides=2,padding=’same’)(x)
#x = BatchNormalization(momentum=0.8)(x)
x=LeakyReLU(0.01)(x)
x=layers.Conv2D(64,kernel_size=3,strides=2,padding=’same’)(x)
#x = BatchNormalization(momentum=0.8)(x)
x=LeakyReLU(0.01)(x)
x=Flatten()(x)
x=layers.Dropout(0.4)(x)
outputs = layers.Dense(1,activation=’sigmoid’,name=’Output’)(x)
model = keras.Model([img_input,label_input],outputs)
tf.keras.utils.plot_model(model,to_file=’discriminator.png’,show_shapes=True)
return model
抱歉,我没有能力审查/调试您的代码。也许这些提示会有帮助
https://machinelearning.org.cn/faq/single-faq/can-you-read-review-or-debug-my-code
非常感谢您所做的一切。
我在不同的数据集上实现了 cGAN。但是生成器的损失在增加,而且生成器和判别器的准确率在不同的 epoch 和 batch size 下都是 100%。
您能帮我解释一下为什么吗?
一般来说,损失不是衡量 GAN 性能的好指标
https://machinelearning.org.cn/faq/single-faq/why-is-my-gan-not-converging
或许可以尝试多运行几次这个例子?
也许可以尝试调整模型配置?
你好 sear,
我们如何将 cgan 用于 celeba 数据集?
不确定是否合适。
Sear,请您帮帮我;如何修改此代码以用于 celebA 数据集?我可以实现相同的效果吗,例如它是 RGB 并且一张图片有多个标签?
也许这个教程会有帮助
https://machinelearning.org.cn/how-to-interpolate-and-perform-vector-arithmetic-with-faces-using-a-generative-adversarial-network/
非常感谢 Sear!
不客气。
你好 Jason,您的教程非常有帮助。所以我想出了一个疯狂的想法,采用这个例子生成 60000 个假样本,并用它们来训练您另一个教程中的时尚 MNIST 分类网络,令我惊讶的是,生成的 数据集在验证集上的准确率比真实的训练数据集高得多。我没有更改示例中的任何内容,只是更改了训练集,结果在 10 个 epoch 内准确率就超过了 99%,而真实的只有大约 90%。考虑到基准测试中的最佳方法能达到 ~96% (https://paperswithcode.com/sota/image-classification-on-fashion-mnist),这似乎好得令人难以置信,所以我想问问您是否知道这可能是什么原因?
这可能意味着您的假样本不够逼真。这是一个棘手的问题。但从这个角度想,如果您的假样本太简单而无法识别并用于训练,那么机器将学不到任何有用的东西。就像给你一些没有挑战性的练习一样,即使做很多,你也没有学到任何东西。
你好 Adrian,谢谢回复。但如果假样本不够好,无法替代训练集,那么我应该预期验证集(GAN 生成器从未见过的部分数据集)的准确率会低得多。我感到困惑的是,为什么一个独立的、仅用 60k 假样本训练的简单分类网络,在验证集上的准确率比用官方 60k 样本训练的要高,我原以为会是相反的情况。
除非我能看到您生成的数据,否则我无法真正判断。但一种可能的解释是:如果原始样本是一个更大的问题(例如,识别一千个物体),而生成的样本只是一个更小的问题(例如,识别狗还是汽车),那么您很可能会发现后者的准确率高于前者。证明您实际上并没有做得更好的一种方法是使用生成的样本来训练您的网络,并使用官方样本进行验证。
希望这有帮助!
我又回来研究您这项出色的工作。
我不明白的是,d_model 的信息是如何通过 gan_model 如此快速地传输到 g_model 的。我继续进行修改,以下是训练循环中的一个神秘部分,我暴露并重用了某些计算。
[X_real, labels_real], y_real = generate_real_samples(dataset, n_batch)
d_learning_rate = calculate_learning_rate(lr/g_loss, counter)
K.set_value(d_model.optimizer.learning_rate, d_learning_rate)
d_loss1, _ = d_model.train_on_batch([X_real, labels_real], y_real)
z_input, labels = generate_latent_points(latent_dim, n_batch)
X_fake = g_model.predict([z_input, labels])
y_fake = zeros((n_batch, 1))
d_loss2, _ = d_model.train_on_batch([X_fake, labels], y_fake)
y_gan = ones((n_batch, 1))
g_learning_rate = calculate_learning_rate(lr, counter)
K.set_value(gan_model.optimizer.learning_rate, g_learning_rate)
g_loss = gan_model.train_on_batch([z_input, labels], y_gan)
if (j%10==0)
print(‘>%d/%d, %d/%d, d1=%.3f, d2=%.3f g=%.3f’ %
(i+1,n_epochs, j+1, bat_per_epo, d_loss1, d_loss2, g_loss))
您可以看到我没有在每个循环中重新计算潜在点。这在执行时间上几乎没有区别,但它说明了我在每个循环开始时只需要计算潜在点,然后重复使用它们。这一切都让我更加困惑。据我所知,g_model 的权重在它们通过 gan_model(它们唯一可能被更新的地方)时会被更新。所以这一切似乎都在后台发生。
我还直接操作学习率,并在 gan_model 似乎要崩溃时降低 d_model 的速率。
def calculate_learning_rate(lr, counter)
lr = lr * 0.998
return lr
这似乎比操作权重效果更好。
希望我没有做任何出格的事情。
再次感谢您出色的工作。
你好 Jason,这个条件 GAN 结构能否用于一维惯性传感器数据生成?
为什么不行?您遇到什么问题了吗?
因为大多数情况都用于图像生成而不是一维传感器数据。所以,我不能确定它是否能很好地工作。
我相信它应该可以工作,但我看不到您的数据。唯一能确认的方法就是尝试!
非常感谢您所做的一切。
我想实现这段代码来生成数据(数据增强),以便平衡数据,然后进行分类
问题是如何修改这段代码以用于信用卡欺诈检测数据集,以生成欺诈交易类别 1?
谢谢您,先生,提供如此有用的信息。您能提供此代码的数据集吗?非常感谢您!
你好 Ayat……你可以在以下位置找到数据集
http://yann.lecun.com/exdb/mnist/
此致,
你好,先生,
您的博客在我学习 C-GAN 的基础知识方面帮助了我很多。我正在将 C-GAN 应用于一个物理模型来学习理论中的相变。
如果我想生成中间标签(训练中未包含)的数据(例如模型中的图像像素),该怎么办?
谢谢
你好 Harry……感谢您的反馈!您可能会发现以下内容很有趣
https://www.toptal.com/machine-learning/generative-adversarial-networks
尊敬的先生,
我有 10 个类别标签,但它们都在 (0,1) 范围内,例如 [0.20169,0.22169,…..],那么在上面的代码中我应该取多少 n_classes?我尝试了 n_class=10,但 d_loss 变为零,我没有得到预期的输出。
你好 Shubh,
你可能正在处理回归问题并实现零预测误差。
或者,你可能正在处理分类问题并实现 100% 的准确率。
这很不寻常,原因有很多,包括:
你不小心在训练集上评估了模型性能。
你的保留数据集(训练集或验证集)太小或不具代表性。
你的代码中引入了一个错误,它正在做一些与你预期不同的事情。
你的预测问题很容易或微不足道,可能不需要机器学习。
最常见的原因是你的保留数据集太小或不代表更广泛的问题。
可以通过以下方法解决:
使用 k 折交叉验证来估计模型性能,而不是训练/测试拆分。
收集更多数据。
使用不同的数据拆分进行训练和测试,例如 50/50。
尊敬的先生,
我修改了上面的代码供我使用,但我遇到了一个问题,即我有 10 个标签,它们是介于 0 和 1 之间的实数,所以当我使用上面的代码时,由于 embedding 层会出现错误。我该如何解决?
你好 Shubh……你遇到的确切错误是什么,这样我才能更好地帮助你?一般来说,我无法调试您的代码,但如果您能提供确切的错误消息,有些内容可能会立即显现。
你好,先生,
非常感谢您提供的这个博文,它对我帮助很大。我在训练 gan 时遇到了一个问题。我将代码改编到了我的具体情况(6×6 图像),但训练阶段的输出与您明显不同。似乎我只改变了输入形状和输出(上采样和下采样也已修改),但没有别的。
我的输出是
>1, 1/20, d_loss_real=18834628.000, d_loss_fake=0.696 g_loss=0.690
>1, 2/20, d_loss_real=915644.875, d_loss_fake=0.701 g_loss=0.686
>1, 3/20, d_loss_real=35437.840, d_loss_fake=0.706 g_loss=0.681
>1, 4/20, d_loss_real=0.000, d_loss_fake=0.713 g_loss=0.676
>1, 5/20, d_loss_real=0.000, d_loss_fake=0.719 g_loss=0.669
…
>100, 18/20, d_loss_real=0.000, d_loss_fake=0.023 g_loss=3.808
>100, 19/20, d_loss_real=0.000, d_loss_fake=0.022 g_loss=3.819
>100, 20/20, d_loss_real=0.000, d_loss_fake=0.024 g_loss=3.763
WARNING:tensorflow:已编译加载的模型,但编译的指标尚未构建。在训练或评估模型之前,`model.compile_metrics`将为空。
我该如何解决?
你好 Adrian……以下讨论可能会让你感兴趣
https://stackoverflow.com/questions/67970389/warningtensorflowcompiled-the-loaded-model-but-the-compiled-metrics-have-yet
https://github.com/theAIGuysCode/yolov4-deepsort/issues/79
你好,请告诉我如何通过 GAN 保存生成的图像,等待您的答复。
你好 Ahtisham……以下内容可能对您有帮助
https://stackoverflow.com/questions/71452209/save-gan-generated-images-one-by-one
你好先生,
如何使用包含一行文本、宽度和高度不同的图像的数据集,例如 h=200,w=2048,而不是 n×n 作为 cGan 输入?我尝试过使用 resize,但它失真了。
你好 M.M……您可能会发现以下资源很有趣
https://machinelearning.org.cn/how-to-load-convert-and-save-images-with-the-keras-api/
你好,谢谢回复。
问/我正在研究一个课题(通过 cGAN 进行数据增强),用于阿拉伯文本手写图像。数据集包含大尺寸和不同尺寸(M*N)的图像。
我尝试使用您发送的代码将图像转换为方形尺寸(N*N),但结果,图像不清晰可读,我们可以在 cGAN 中使用这些不清晰的图像并得到结果吗?以便在下一步用于文本识别?
– 是否有更好的方法来防止图像在转换为(N*N)时失真,
或者
– 我可以在 cGAN 中使用不同尺寸的图像作为输入,而不是调整它们的大小吗?
嗨,Jason,
非常感谢这个 cGAN 的教程!
对于 cGAN,它可以接受标签(通过独热编码)来生成具有相应对象的靶向图像。您能否告诉我是否可以训练一个 cGAN 模型来生成包含多个(例如两个或三个)靶向对象的图像?例如,如果我们想生成包含“连衣裙”、“衬衫”和“包”的图像,那么输入标签向量可以是 [0, 0, 0, 1, 0, 0, 1, 0, 1, 0](使用“1”激活我们想要的 对象)。我只是想知道这对于 cGAN 模型是否可行?
非常感谢!
你好 Dee……我强烈推荐以下资源来支持您对 GAN 的理解
https://machinelearning.org.cn/tour-of-generative-adversarial-network-models/
太棒了!感谢这个精彩的教程!
感谢您的支持和反馈 Cristian!我们非常感激!
你好先生,感谢您提供如此精彩的教程,我非常欣赏。
但是我有一个问题……我有一个任务叫做人脸表情生成器,使用 GAN。所以基本上它是一个“生成器”,可以根据 1 个静态图像输入修改表情。例如,我有一张愤怒的图像。当我将其输入“生成器”时,它可以修改为悲伤、中性、厌恶等其他表情。
这个方法(CGAN)适合我的任务吗?
另外,我正在使用 Kaggle 上的 AffectNet-HQ 数据集。
谢谢您。
嗨,先生,感谢您制作这个精彩的教程。
但是我有一个问题,我有一个任务是制作一个人脸表情生成器,使用 GAN。基本上,这个“生成器”可以创建一个人脸图像来显示不同的表情。例如,从一张静态的脸部图像,它可以被修改,使其显示悲伤、快乐或其他表情。
我的问题是这个方法(CGAN)适合我的任务吗?
另外,我正在使用 Kaggle 上的 AffectNet-HQ 数据集……
提前谢谢。
你好 Calvin……你很受欢迎!是的,请继续使用 CGAN,并让我们知道您的发现。
如果我只使用 CGAN,生成的图像结果可以逼真吗?
您好先生,非常感谢您提供如此精彩的教程。但我是一个深度学习新手,您能给我一些替换数据集的教程或博客吗?我想使用您的代码来训练另一个数据集,请问代码需要做哪些修改?非常期待您的回复!
你好 Roy……你很受欢迎!以下资源可以帮助您了解如何将新数据应用于训练好的模型。
https://machinelearning.org.cn/update-neural-network-models-with-more-data/
谢谢您,先生,但我想使用的数据集告诉我需要使用 coco api。这如何与您的 CGAN 代码结合使用?
你好 David,我是一名学生,也在为一个项目生成 256×256 的图像。你能分享一下你做的项目的代码吗?
我可以使用相同的代码但使用不同的数据集,它会工作吗?例如,用于生成数字的数据集。
你好 Hithesh……当然!一旦您使用新数据实现了模型,请告诉我们您是否有任何问题。
更多关于 GAN 的信息可以在这里找到
https://machinelearning.org.cn/start-here/#gans
如何确保条件(即本例中的类别标签)被使用?是什么阻止了网络(d 和 g)忽略条件而表现得像无条件情况?谢谢。
你好 Ting……这是一个很棒的问题!以下资源提供了一些关键的见解。
https://openaccess.thecvf.com/content/CVPR2022W/CLVision/papers/Laria_Transferring_Unconditional_to_Conditional_GANs_With_Hyper-Modulation_CVPRW_2022_paper.pdf
我如何将其用于时间序列预测
你好 MSM……以下资源是一个很好的起点
https://dl.acm.org/doi/abs/10.1145/3604237.3626855
我能使用 pix2pix gan 将我的图像转换成动漫风格吗?
请给我建议
当然!有什么问题我们可以帮助您解决吗?
非常感谢您提供这些信息!我注意到条件GAN适用于分类类型的问题。换句话说,条件输入是离散值。如果条件输入是连续的(例如,给定年龄作为条件输入来生成人脸)该怎么办?我知道有两篇关于这个的论文(https://ieeexplore.ieee.org/document/9983478),但它们看起来非常复杂。您是否有可能写一篇关于它的博客文章?我认为这会非常有趣。非常感谢!
感谢您的推荐!我们会认真考虑。
您好,我正在尝试生成一个cdcgan模型。训练过程还可以。当我尝试为特定类别采样图像时,生成的图像有很多噪点。但是,当我为随机类别采样图像时,生成的图像符合我的预期。您在这方面有什么经验吗?
供您参考,这是生成不同类别图像的代码
batch_size = 9 * opt.n_classes
dataloader = DataLoader(
dataset,
batch_size=batch_size,
shuffle=True
)
noise = torch.tensor(
np.random.normal(0, 1, (batch_size, opt.latent_dim)),
dtype=torch.float32,
device=device
)
real_imgs, real_labels = next(iter(dataloader))
real_labels = F.one_hot(torch.arange(6, device=’cuda’), 6)[real_labels].float()
gen_imgs = generator(noise, real_labels)
————————————————————————————–
这是生成特定类别标签的代码
noise = torch.tensor(
np.random.normal(0, 1, (batch_size, opt.latent_dim)),
dtype=torch.float32,
device=device
)
real_labels = [0] * batch_size
real_labels = F.one_hot(torch.arange(6, device=’cuda’), 6)[real_labels].float()
gen_imgs = generator(noise, real_labels)
您好 J……看起来您生成特定类别标签的方式可能存在问题。在您为特定类别生成图像的代码中,您需要确保所有标签都对应您要针对的特定类别。以下是您的代码的修改版本:
### 为特定类别采样图像
1. **指定您要生成的类别:**
– 假设您想为类别 0 生成图像。
python
import torch
import torch.nn.functional as F
import numpy as np
# 指定目标类别
target_class = 0
# 要生成的样本数量
batch_size = 9 # 根据需要调整
# 生成随机噪声
noise = torch.tensor(
np.random.normal(0, 1, (batch_size, opt.latent_dim)),
dtype=torch.float32,
device=device
)
# 为特定类别创建标签
real_labels = torch.full((batch_size,), target_class, dtype=torch.long, device=device)
real_labels = F.one_hot(real_labels, num_classes=opt.n_classes).float()
# 生成图像
gen_imgs = generator(noise, real_labels)
### 关键点
1. **噪声生成:**
– 确保噪声生成正确:
np.random.normal(0, 1, (batch_size, opt.latent_dim))
。2. **标签创建:**
– 创建一个包含目标类别标签的张量:
torch.full((batch_size,), target_class, dtype=torch.long, device=device)
。– 将标签转换为独热编码:
F.one_hot(real_labels, num_classes=opt.n_classes).float()
。3. **生成过程:**
– 将噪声和独热编码的标签传递给生成器。
### 解释
– **噪声:** 噪声向量在两种情况下应保持一致。
– **标签:** 在为特定类别生成时,确保所有标签都相同且已正确进行独热编码。
### 可能存在的问题
1. **生成器训练:** 确保生成器针对每个类别进行了充分的训练。如果某些类别代表性不足或更难学习,这些类别的生成图像可能会更嘈杂。
2. **批归一化:** 如果在生成器中使用批归一化,有时在为特定类别生成图像时可能会出现问题。尝试在评估模式下评估生成器(
generator.eval()
)。### 故障排除技巧
– **类别不平衡:** 如果您的数据集存在类别不平衡,请确保您的训练过程能够正确处理。
– **潜在空间探索:** 有时,探索潜在空间的不同区域有助于提高特定类别的图像质量。
– **训练质量:** 检查您的训练过程的质量,包括生成器和判别器的损失曲线。
如果这些步骤未能解决问题,请考虑分享更多关于您的模型架构和训练过程的细节,以便进一步故障排除。