We have seen the Generative Adversarial Nets (GAN) model in the previous post. We have also seen the arch nemesis of GAN, the VAE and its conditional variation: Conditional VAE (CVAE). Hence, it is only proper for us to study conditional variation of GAN, called Conditional GAN or CGAN for short. 我们在上一篇文章中看到了生成对抗网络(GAN)模型。我们还看到了 GAN 的死对头,VAE 及其条件变体:条件 VAE(CVAE)。因此,我们研究 GAN 的条件变体(称为条件 GAN 或简称 CGAN)是再合适不过的了。
CGAN: Formulation and Architecture
Recall, in GAN, we have two neural nets: the generator and the discriminator . Now, as we want to condition those networks with some vector , the easiest way to do it is to feed into both networks. Hence, our generator and discriminator are now and respectively. 回想一下,在 GAN 中,我们有两个神经网络:生成器 和鉴别器 。 现在,由于我们想用某个向量 来调节这些网络,最简单的方法是将 输入两个网络。因此,我们的生成器和鉴别器现在分别是 和 。
We can see it with a probabilistic point of view. is modeling the distribution of our data, given and , that is, our data is generated with this scheme . 我们可以用概率的角度来看待它。给定和,正在对我们的数据分布进行建模,也就是说,我们的数据是用这个方案生成的。
Likewise for the discriminator, now it tries to find discriminating label for and , that are modeled with . 同样对于鉴别器来说,现在它试图为 和 找到鉴别标签,用 建模。
Hence, we could see that both and is jointly conditioned to two variables or and . 因此,我们可以看到 和 都与两个变量 或 和 联合相关。
Now, the objective function is given by: 现在,目标函数如下:
If we compare the above loss to GAN loss, the difference only lies in the additional parameter in both and . 如果我们将上述损失与 GAN 损失进行比较,差异仅在于 和 中的附加参数 。
The architecture of CGAN is now as follows (taken from [1]): CGAN 的架构如下(取自[1]):
In contrast with the architecture of GAN, we now has an additional input layer in both discriminator net and generator net. 与 GAN 的架构相比,我们现在在鉴别器网络和生成器网络中都增加了一个输入层。
CGAN: Implementation in TensorFlow
I’d like to direct the reader to the previous post about GAN, particularly for the implementation in TensorFlow. Implementing CGAN is so simple that we just need to add a handful of lines to the original GAN implementation. So, here we will only look at those modifications. 我想引导读者阅读上一篇关于 GAN 的文章,特别是关于在 TensorFlow 中的实现。实现 CGAN 非常简单,我们只需要在原始 GAN 实现中添加几行代码即可。因此,我们在这里只讨论这些修改。
The problem we have here is how to incorporate the new variable into and . As we are trying to model the joint conditional, the simplest way to do it is to just concatenate both variables. Hence, in , we are concatenating and before we feed it into the networks. The same procedure is applied to . 我们这里的问题是如何将新变量 合并到 和 中。由于我们试图对联合条件进行建模,最简单的方法就是将两个变量连接起来。因此,在 中,我们在将其输入网络之前将 和 连接起来。同样的程序也适用于 。
Of course, as our inputs for and is now different than the original GAN, we need to modify our weights: 当然,由于我们对 和 的输入现在与原始 GAN 不同,我们需要修改我们的权重:
1 2 3 4 5 6 7
# Modify input to hidden weights for discriminator # 修改鉴别器隐藏权重的输入 D_W1 = tf.Variable(shape=[X_dim + y_dim, h_dim]))
# Modify input to hidden weights for generator # 修改生成器隐藏权重的输入 G_W1 = tf.Variable(shape=[Z_dim + y_dim, h_dim]))
That is, we just adjust the dimensionality of our weights. 也就是说,我们只是调整权重的维数。
Next, we just use our new networks: 接下来,我们只需使用我们的新网络:
1 2 3 4 5
# Add additional parameter y into all networks # 在所有网络中添加附加参数 y G_sample = generator(Z, y) D_real, D_logit_real = discriminator(X, y) D_fake, D_logit_fake = discriminator(G_sample, y)
And finally, when training, we also feed the value of into the networks: 最后,在训练时,我们还将 的值输入网络:
As an example above, we are training our GAN with MNIST data, and the conditional variable is the labels. 如上例,我们使用 MNIST 数据训练我们的 GAN,条件变量 是标签。
CGAN: Results
At test time, we want to generate new data samples with certain label. For example, we set the label to be 5, i.e. we want to generate digit “5”: 在测试时,我们希望生成具有特定标签的新数据样本。例如,我们将标签设置为 5,即我们希望生成数字“5”:
Above, we just sample , and then construct the conditional variables. In our example case, the conditional variables is a collection of one-hot vectors with value 1 in the 5th index. The last thing we need to is to run the network with those variables as inputs. 上面,我们只是对 进行采样,然后构造条件变量。在我们的示例中,条件变量是第 5 个索引中值为 1 的独热向量集合。我们需要做的最后一件事是使用这些变量作为输入来运行网络。
Here is the results: 结果如下:
Looks pretty much like digit 5, right? 看起来很像数字 5,对吧?
If we set our one-hot vectors to have value of 1 in the 7th index: 如果我们将独热向量设置为第 7 个索引中的值为 1:
Those results confirmed that have successfully trained our CGAN. 这些结果证实了我们的 CGAN 训练成功。
# cgan_pytorch.py import torch import torch.nn.functional as nn import torch.autograd as autograd import torch.optim as optim import numpy as np import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec import os from torch.autograd import Variable from tensorflow.examples.tutorials.mnist import input_data
for it inrange(100000): # Sample data z = Variable(torch.randn(mb_size, Z_dim)) X, c = mnist.train.next_batch(mb_size) X = Variable(torch.from_numpy(X)) c = Variable(torch.from_numpy(c.astype('float32')))
# Dicriminator forward-loss-backward-update G_sample = G(z, c) D_real = D(X, c) D_fake = D(G_sample, c)
import tensorflow as tf from tensorflow.examples.tutorials.mnist import input_data import numpy as np import matplotlib.pyplot as plt import matplotlib.gridspec as gridspec import os
""" ===================== TRAINING ======================== """
# 重置所有参数的梯度。在每次更新参数之后调用,以准备下一次反向传播。 defreset_grad(): for p in params: if p.grad isnotNone: data = p.grad.data p.grad = Variable(data.new().resize_as_(data).zero_())
# Print and plot every now and then # 每1000次迭代打印一次当前的损失值。 if it % 1000 == 0: print('Iter-{}; D_loss: {}; G_loss: {}'.format(it, D_loss.data.numpy(), G_loss.data.numpy()))
# 保存移动平均后的loss数据到CSV文件 withopen('out_gan_pytorch_1/loss_data_avg.csv', 'w', newline='') as file: writer = csv.writer(file) writer.writerow(["Iteration", "G_loss_avg", "D_loss_avg"]) # 写入表头 for i, (g_loss, d_loss) inenumerate(zip(G_losses_avg, D_losses_avg)): writer.writerow([i+window_size, g_loss, d_loss])
print("Averaged loss data has been saved to 'out_gan_pytorch_1/loss_data_avg.csv'") # loss_data.csv:包含所有迭代的原始loss数据 # loss_data_avg.csv:包含移动平均后的loss数据 # loss_data_ongoing.csv:在训练过程中定期保存的loss数据