CGAN原理及tensorflow代码

1.首先说明一下CGAN的意义

GAN的原始模型有很多可以改进的缺点,首当其中就是“模型不可控”。从上面对GAN的介绍能够看出,模型以一个随机噪声为输入。显然,我们很难对输出的结构进行控制。例如,使用纯粹的GAN,我们可以训练出一个生成器:输入随机噪声,产生一张写着0-9某一个数字的图片。然而,在现实应用中,我们往往想要生成“指定”的一张图片。

2.直观解决方案

在GAN上增加一个额外的输入。也就是说,以前我们的生成模型是p_g(x),现在,我们的生成模型是在一个条件c的控制下产生p_g(x|c)。而这个c就是我们用来控制模型的额外的输入。

c可以是表示我们意图的一串编码,例如我们想要做0-9的手写数字生成,则c可以是一个10维的one-hot向量。则在训练过程中,我们将这些label加入到训练数据中,从而得到一个按照我们需求产生图片的生成器。

这就是Conditional Generative Adversarial Nets最基本的想法。这里要注意的是,这个c不但附加在了生成器上,同时也附加在了判别器上,相当于给了判别器一个额外的信息:现在这个图片是以条件c生成的?还是以条件c控制下的真正的图片?

3.训练目标

原文中有这样一张图,在其他博客中也常见到

对于GAN来说,我们训练的目标是:

\mathop{\min}_{G}\mathop{\max}_{D}V(D,G)=\mathbb{E}_{\boldsymbol{x}\sim p_{\text{data}}}\left[\log D(\boldsymbol{x})\right]+\mathbb{E}_{\boldsymbol{z}\sim p_z(\boldsymbol{z})}\left[\log(1-D(G(\boldsymbol{z})))\right].

而对于Conditional的GAN来说,训练目标只需要变成:

\mathop{\min}_{G}\mathop{\max}_{D}V(D,G)=\mathbb{E}_{\boldsymbol{x}\sim p_{\text{data}}}\left[\log D(\boldsymbol{x}|\boldsymbol{y})\right]+\mathbb{E}_{\boldsymbol{z}\sim p_z(\boldsymbol{z})}\left[\log(1-D(G(\boldsymbol{z}|\boldsymbol{y})|\boldsymbol{y}))\right].

(原文中的公式有误,后面一项的判别器D中忘了加以y为条件的概率)

其实这个改动形象一些表示就是将原来只接受一个输入z的生成器变成接受两个输入(z和y),将原来只接受一个输入x的判别器变成接受两个输入(x和y)。
 

CGAN代码如下:

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

#数据输入
mnist = input_data.read_data_sets('../../MNIST_data', one_hot=True)
mb_size = 64
Z_dim = 100
X_dim = mnist.train.images.shape[1]
y_dim = mnist.train.labels.shape[1]
h_dim = 128

#返回随机值
def xavier_init(size):
    in_dim = size[0]
    xavier_stddev = 1. / tf.sqrt(in_dim / 2.)
    return tf.random_normal(shape=size, stddev=xavier_stddev)

#X代表输入图片,应该是28*28,但是这里没有使用CNN,y是相应的label
""" Discriminator Net model """
X = tf.placeholder(tf.float32, shape=[None, 784])
y = tf.placeholder(tf.float32, shape=[None, y_dim])
#权重,CGAN的输入是将图片输入与label concat起来,所以权重维度为784+10
D_W1 = tf.Variable(xavier_init([X_dim + y_dim, h_dim]))
D_b1 = tf.Variable(tf.zeros(shape=[h_dim]))
#第二层有h_dim个节点
D_W2 = tf.Variable(xavier_init([h_dim, 1]))
D_b2 = tf.Variable(tf.zeros(shape=[1]))

theta_D = [D_W1, D_W2, D_b1, D_b2]

#D网络,这里是一个简单的神经网络,x是输入图片向量,y是相应的label
def discriminator(x, y):
    inputs = tf.concat(axis=1, values=[x, y])
    D_h1 = tf.nn.relu(tf.matmul(inputs, D_W1) + D_b1)
    D_logit = tf.matmul(D_h1, D_W2) + D_b2
    D_prob = tf.nn.sigmoid(D_logit)

    return D_prob, D_logit

#G网络参数,输入维度为Z_dim+y_dim,中间层有h_dim个节点,输出X_dim的数据
""" Generator Net model """
Z = tf.placeholder(tf.float32, shape=[None, Z_dim])
#权重
G_W1 = tf.Variable(xavier_init([Z_dim + y_dim, h_dim]))
G_b1 = tf.Variable(tf.zeros(shape=[h_dim]))

G_W2 = tf.Variable(xavier_init([h_dim, X_dim]))
G_b2 = tf.Variable(tf.zeros(shape=[X_dim]))

theta_G = [G_W1, G_W2, G_b1, G_b2]

#G网络
def generator(z, y):
    inputs = tf.concat(axis=1, values=[z, y])
    G_h1 = tf.nn.relu(tf.matmul(inputs, G_W1) + G_b1)
    G_log_prob = tf.matmul(G_h1, G_W2) + G_b2
    G_prob = tf.nn.sigmoid(G_log_prob)

    return G_prob

#噪声产生的函数
def sample_Z(m, n):
    return np.random.uniform(-1., 1., size=[m, n])


def plot(samples):
    fig = plt.figure(figsize=(4, 4))
    gs = gridspec.GridSpec(4, 4)
    gs.update(wspace=0.05, hspace=0.05)

    for i, sample in enumerate(samples):
        ax = plt.subplot(gs[i])
        plt.axis('off')
        ax.set_xticklabels([])
        ax.set_yticklabels([])
        ax.set_aspect('equal')
        plt.imshow(sample.reshape(28, 28), cmap='Greys_r')

    return fig

#生成网络,基本和GAN一致
G_sample = generator(Z, y)
D_real, D_logit_real = discriminator(X, y)
D_fake, D_logit_fake = discriminator(G_sample, y)
#优化式
D_loss_real = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=D_logit_real, labels=tf.ones_like(D_logit_real)))
D_loss_fake = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=D_logit_fake, labels=tf.zeros_like(D_logit_fake)))
D_loss = D_loss_real + D_loss_fake
G_loss = tf.reduce_mean(tf.nn.sigmoid_cross_entropy_with_logits(logits=D_logit_fake, labels=tf.ones_like(D_logit_fake)))
#训练
D_solver = tf.train.AdamOptimizer().minimize(D_loss, var_list=theta_D)
G_solver = tf.train.AdamOptimizer().minimize(G_loss, var_list=theta_G)


sess = tf.Session()
sess.run(tf.global_variables_initializer())
#输出图片在out文件夹
if not os.path.exists('out/'):
    os.makedirs('out/')

i = 0

for it in range(1000000):
    if it % 1000 == 0:
        #n_sample 是G网络测试用的Batchsize,为16,所以输出的png图有16张
        n_sample = 16

        Z_sample = sample_Z(n_sample, Z_dim)#输入的噪声,尺寸为batchsize*noise维度
        y_sample = np.zeros(shape=[n_sample, y_dim])#输入的label,尺寸为batchsize*label维度
        y_sample[:, 7] = 1 #输出7

        samples = sess.run(G_sample, feed_dict={Z: Z_sample, y:y_sample})#G网络的输入

        fig = plot(samples)
        plt.savefig('out/{}.png'.format(str(i).zfill(3)), bbox_inches='tight')#输出生成的图片
        i += 1
        plt.close(fig)
    #mb_size是网络训练时用的Batchsize,为100
    X_mb, y_mb = mnist.train.next_batch(mb_size)
    #Z_dim是noise的维度,为100
    Z_sample = sample_Z(mb_size, Z_dim)
    #交替最小化训练
    _, D_loss_curr = sess.run([D_solver, D_loss], feed_dict={X: X_mb, Z: Z_sample, y:y_mb})
    _, G_loss_curr = sess.run([G_solver, G_loss], feed_dict={Z: Z_sample, y:y_mb})
    #输出训练时的参数
    if it % 1000 == 0:
        print('Iter: {}'.format(it))
        print('D loss: {:.4}'. format(D_loss_curr))
        print('G_loss: {:.4}'.format(G_loss_curr))
        print()

生成效果如下:

为了方便理解,本文只用了最简单的神经网络,有时间会使用CNN重写该网络。

### 回答1: CGAN,全称为Conditional Generative Adversarial Networks,是一种在生成对抗网络(GAN)的基础上进行优化的算法,它可以根据传入的条件信息来生成特定类型的数据。在这个算法中,生成器和判别器都会接收一个额外的条件输入参数。 TensorFlow是一个广泛使用的深度学习框架,它提供了各种各样的函数和类来简化CGAN模型的实现过程。以下是一个使用TensorFlow实现CGAN代码示例: ``` import tensorflow as tf import numpy as np # 定义生成器和判别器的输入形状 noise_dim = 100 label_dim = 10 # 定义生成器的函数 def make_generator_model(): model = tf.keras.Sequential() model.add(tf.keras.layers.Dense(256, input_dim=noise_dim + label_dim, activation='relu')) model.add(tf.keras.layers.BatchNormalization()) model.add(tf.keras.layers.Dense(512, activation='relu')) model.add(tf.keras.layers.BatchNormalization()) model.add(tf.keras.layers.Dense(28 * 28 * 1, activation='sigmoid')) model.add(tf.keras.layers.Reshape((28, 28, 1))) return model # 定义判别器的函数 def make_discriminator_model(): model = tf.keras.Sequential() model.add(tf.keras.layers.Flatten(input_shape=(28, 28, 1))) model.add(tf.keras.layers.Dense(512, activation='relu')) model.add(tf.keras.layers.Dense(256, activation='relu')) model.add(tf.keras.layers.Dense(1, activation='sigmoid')) return model # 定义损失函数 cross_entropy = tf.keras.losses.BinaryCrossentropy(from_logits=True) def discriminator_loss(real_output, fake_output): real_loss = cross_entropy(tf.ones_like(real_output), real_output) fake_loss = cross_entropy(tf.zeros_like(fake_output), fake_output) total_loss = real_loss + fake_loss return total_loss def generator_loss(fake_output): return cross_entropy(tf.ones_like(fake_output), fake_output) # 定义优化器 generator_optimizer = tf.keras.optimizers.Adam(1e-4) discriminator_optimizer = tf.keras.optimizers.Adam(1e-4) # 定义训练过程 @tf.function def train_step(images, labels): noise = tf.random.normal([batch_size, noise_dim]) with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape: fake_labels = tf.random.uniform([batch_size, 1], maxval=label_dim, dtype=tf.int32) fake_labels = tf.one_hot(tf.reshape(fake_labels, [-1]), label_dim) generated_images = generator(tf.concat([noise, fake_labels], axis=1), training=True) real_output = discriminator(tf.concat([images, labels], axis=1), training=True) fake_output = discriminator(tf.concat([generated_images, fake_labels], axis=1), training=True) gen_loss = generator_loss(fake_output) disc_loss = discriminator_loss(real_output, fake_output) gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables) gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables) generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables)) discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables)) # 进行训练 EPOCHS = 100 batch_size = 128 generator = make_generator_model() discriminator = make_discriminator_model() for epoch in range(EPOCHS): for i in range(train_images.shape[0]//batch_size): images = train_images[i*batch_size:(i+1)*batch_size] labels = train_labels[i*batch_size:(i+1)*batch_size] train_step(images, labels) # 生成一些带有特定标签的图像 noise = tf.random.normal([10, noise_dim]) cond_labels = np.eye(label_dim)[np.arange(10)] generated_images = generator(tf.concat([noise, cond_labels], axis=1), training=False) ``` 上面的代码中,我们定义了生成器和判别器的模型结构和优化器。在训练过程中,我们使用TensorFlow的`GradientTape`记录损失函数的梯度,并根据反向传播算法来更新模型的参数,最终得到一个可以生成特定标签图像的CGAN模型。 ### 回答2: CGAN是一种生成对抗网络,可以用来生成符合特定条件(如标签)的图像。 Tensorflow作为一款流行的神经网络框架,可以实现CGAN网络。本文将介绍如何使用tensorflow实现CGAN的简单示例代码。 首先,我们需要准备数据集和标签。这里我们以MNIST手写数字数据集为例,选择其中的数字4和9作为我们的标签。我们使用tensorflow内置的MNIST数据集,然后创建两个新的数据集,一个只包含数字4的图片,另一个只包含数字9的图片。 接下来,我们需要编写CGAN网络的模型。我们假设生成器和判别器都是以卷积神经网络作为基础。 生成器是一个卷积神经网络,输入为一个噪声向量和标签,输出为一个28x28的图像。为了获得更好的效果,我们采用了ResNet的结构。 判别器是另一个卷积神经网络,输入为一个28x28的图像和标签,输出为一个二元值,表示输入是否是真实的图像。同时,我们也采用了ResNet的结构来提高判别器的性能。 我们将生成器和判别器组合起来,并使用交叉熵损失函数来优化网络的性能。 最后,我们需要编写训练代码,对生成器和判别器进行训练。我们使用Adam优化器,对损失函数进行优化,并将生成的图像保存在本地文件夹中。 在运行训练代码之后,我们可以得到生成器生成的样本图像,观察生成的图像是否符合我们的标签条件,以此来评估CGAN网络的性能。 以上就是使用tensorflow实现CGAN网络的简单示例代码,该代码可以用于生成符合特定条件的图像。当然,如果要应用到更复杂的数据集和场景中,需要对代码进行相应的修改和优化。 ### 回答3: CGAN是一种深度学习模型,它能够生成新的图像数据,同时还能对生成图像的样式进行控制。在TensorFlow中实现CGAN代码实例如下: 首先,需要加载一些必要的库,如numpy,matplotlib和tensorflow: import numpy as np import matplotlib.pyplot as plt import tensorflow as tf 接着,定义生成器和判别器网络。生成器网络将输入的随机向量转化成一张图像,而判别器网络则将输入的图像打上真或假的标签: def generator_model(): model = tf.keras.Sequential() model.add(tf.keras.layers.Dense(7*7*256, input_shape=(100,))) model.add(tf.keras.layers.Reshape((7, 7, 256))) model.add(tf.keras.layers.BatchNormalization()) model.add(tf.keras.layers.Conv2DTranspose(128, (5, 5), strides=(1, 1), padding='same')) model.add(tf.keras.layers.BatchNormalization()) model.add(tf.keras.layers.LeakyReLU()) model.add(tf.keras.layers.Conv2DTranspose(64, (5, 5), strides=(2, 2), padding='same')) model.add(tf.keras.layers.BatchNormalization()) model.add(tf.keras.layers.LeakyReLU()) model.add(tf.keras.layers.Conv2DTranspose(1, (5, 5), strides=(2, 2), padding='same', activation='tanh')) return model def discriminator_model(): model = tf.keras.Sequential() model.add(tf.keras.layers.Conv2D(64, (5, 5), strides=(2, 2), padding='same', input_shape=[28, 28, 1])) model.add(tf.keras.layers.LeakyReLU()) model.add(tf.keras.layers.Dropout(0.3)) model.add(tf.keras.layers.Conv2D(128, (5, 5), strides=(2, 2), padding='same')) model.add(tf.keras.layers.LeakyReLU()) model.add(tf.keras.layers.Dropout(0.3)) model.add(tf.keras.layers.Flatten()) model.add(tf.keras.layers.Dense(1)) return model 接下来,我们定义CGAN的训练过程。由于本次训练中将会用到真实图像和生成图像,因此需要定义d_loss和g_loss,使之能够同时对真实图像和生成的图像进行优化: @tf.function def train_step(images, labels): noise = tf.random.normal([BATCH_SIZE, LATENT_DIM]) with tf.GradientTape() as gen_tape, tf.GradientTape() as disc_tape: generated_images = generator([noise, labels], training=True) real_output = discriminator([images, labels], training=True) fake_output = discriminator([generated_images, labels], training=True) gen_loss = generator_loss(fake_output) disc_loss = discriminator_loss(real_output, fake_output) gradients_of_generator = gen_tape.gradient(gen_loss, generator.trainable_variables) gradients_of_discriminator = disc_tape.gradient(disc_loss, discriminator.trainable_variables) generator_optimizer.apply_gradients(zip(gradients_of_generator, generator.trainable_variables)) discriminator_optimizer.apply_gradients(zip(gradients_of_discriminator, discriminator.trainable_variables)) 在定义好train_step之后,我们可以通过循环来进行训练。在每个epoch结束后,我们会将生成器生成的示例图像和损失输出到终端: def train(dataset, epochs): for epoch in range(epochs): for image_batch, label_batch in dataset: train_step(image_batch, label_batch) display.clear_output(wait=True) generate_and_save_images(generator, epoch + 1, test_labels) print ('Time for epoch {} is {} sec'.format(epoch + 1, time.time()-start)) display.clear_output(wait=True) generate_and_save_images(generator, epochs, test_labels) train(train_dataset, EPOCHS) 最后是完整的训练代码
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值