深度学习之生成对抗网络(8)WGAN-GP实战
生活随笔
收集整理的這篇文章主要介紹了
深度学习之生成对抗网络(8)WGAN-GP实战
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
深度學(xué)習(xí)之生成對(duì)抗網(wǎng)絡(luò)(8)WGAN-GP實(shí)戰(zhàn)
- 代碼修改
- 完整代碼
- WGAN
- WGAN_train
代碼修改
?WGAN-GP模型可以在原來(lái)GAN代碼實(shí)現(xiàn)的基礎(chǔ)上僅做少量修改。WGAN-GP模型的判別器D的輸出不再是樣本類別的概率,輸出不需要加Sigmoid激活函數(shù)。同時(shí)添加梯度懲罰項(xiàng),實(shí)現(xiàn)如下:
def gradient_penalty(discriminator, batch_x, fake_image):# 梯度懲罰項(xiàng)計(jì)算函數(shù)batchsz = batch_x.shape[0]# 每個(gè)樣本均隨機(jī)采樣t,用于差值,[b, h, w, c]t = tf.random.uniform([batchsz, 1, 1, 1])# 自動(dòng)擴(kuò)展為x的形狀,[b, 1, 1, 1] => [b, h, w, c]t = tf.broadcast_to(t, batch_x.shape)# 在真假圖片之間做線性差值interplate = t * batch_x + (1 - t) * fake_image# 在梯度環(huán)境中計(jì)算D對(duì)差值樣本的梯度with tf.GradientTape() as tape:tape.watch([interplate]) # 加入梯度觀察列表d_interplote_logits = discriminator(interplate, training=True)grads = tape.gradient(d_interplote_logits, interplate)# 計(jì)算每個(gè)樣本的梯度的范數(shù):grads:[b, h, w, c] => [b, -1]grads = tf.reshape(grads, [grads.shape[0], -1])gp = tf.norm(grads, axis=1) # [b]# 計(jì)算梯度懲罰項(xiàng)gp = tf.reduce_mean((gp - 1) ** 2)return gp
?WGAN判別器的損失函數(shù)計(jì)算與GAN不一樣,WGAN是直接最大化真實(shí)樣本的輸出值,最小化生成樣本的輸出值,并沒有交叉熵計(jì)算的過(guò)程。代碼實(shí)現(xiàn)如下:
?WGAN生成器G的損失函數(shù)是只需要最大化生成樣本在判別器D的輸出值即可,同樣沒有交叉熵的計(jì)算步驟。代碼實(shí)現(xiàn)如下:
?WGAN的朱訓(xùn)練邏輯基本相同,與原始的GAN相比,判別器D的作用是作為一個(gè)EM距離的計(jì)量器存在,因此判別器越準(zhǔn)確,對(duì)生成器越有利,可以在訓(xùn)練一個(gè)Step時(shí)訓(xùn)練判別器D多次,訓(xùn)練G一次,從而獲得較為準(zhǔn)確的EM距離估計(jì)。
完整代碼
WGAN
import tensorflow as tf from tensorflow import keras from tensorflow.keras import layersclass Generator(keras.Model):def __init__(self):super(Generator, self).__init__()# z: [b, 100] => [b, 3*3*512] => [b, 3, 3, 512] => [b, 64, 64, 3]self.fc = layers.Dense(3*3*512)self.conv1 = layers.Conv2DTranspose(256, 3, 3, 'valid')self.bn1 = layers.BatchNormalization()self.conv2 = layers.Conv2DTranspose(128, 5, 2, 'valid')self.bn2 = layers.BatchNormalization()self.conv3 = layers.Conv2DTranspose(3, 4, 3, 'valid')def call(self, inputs, training=None):# [z, 100] => [z, 3*3*512]x = self.fc(inputs)x = tf.reshape(x, [-1, 3, 3, 512])x = tf.nn.leaky_relu(x)#x = tf.nn.leaky_relu(self.bn1(self.conv1(x), training=training))x = tf.nn.leaky_relu(self.bn2(self.conv2(x), training=training))x = self.conv3(x)x = tf.tanh(x)return xclass Discriminator(keras.Model):def __init__(self):super(Discriminator, self).__init__()# [b, 64, 64, 3] => [b, 1]self.conv1 = layers.Conv2D(64, 5, 3, 'valid')self.conv2 = layers.Conv2D(128, 5, 3, 'valid')self.bn2 = layers.BatchNormalization()self.conv3 = layers.Conv2D(256, 5, 3, 'valid')self.bn3 = layers.BatchNormalization()# [b, h, w ,c] => [b, -1]self.flatten = layers.Flatten()self.fc = layers.Dense(1)def call(self, inputs, training=None):x = tf.nn.leaky_relu(self.conv1(inputs))x = tf.nn.leaky_relu(self.bn2(self.conv2(x), training=training))x = tf.nn.leaky_relu(self.bn3(self.conv3(x), training=training))# [b, h, w, c] => [b, -1]x = self.flatten(x)# [b, -1] => [b, 1]logits = self.fc(x)return logitsdef main():d = Discriminator()g = Generator()x = tf.random.normal([2, 64, 64, 3])z = tf.random.normal([2, 100])prob = d(x)print(prob)x_hat = g(z)print(x_hat.shape)if __name__ == '__main__':main()WGAN_train
import os import numpy as np import tensorflow as tf from tensorflow import kerasfrom PIL import Image import glob from Chapter13.GAN import Generator, Discriminatorfrom Chapter13.dataset import make_anime_datasetos.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'def save_result(val_out, val_block_size, image_path, color_mode):def preprocess(img):img = ((img + 1.0) * 127.5).astype(np.uint8)# img = img.astype(np.uint8)return imgpreprocesed = preprocess(val_out)final_image = np.array([])single_row = np.array([])for b in range(val_out.shape[0]):# concat image into a rowif single_row.size == 0:single_row = preprocesed[b, :, :, :]else:single_row = np.concatenate((single_row, preprocesed[b, :, :, :]), axis=1)# concat image row to final_imageif (b + 1) % val_block_size == 0:if final_image.size == 0:final_image = single_rowelse:final_image = np.concatenate((final_image, single_row), axis=0)# reset single rowsingle_row = np.array([])if final_image.shape[2] == 1:final_image = np.squeeze(final_image, axis=2)Image.fromarray(final_image).save(image_path)def celoss_ones(logits):# [b, 1]# [b] = [1, 1, 1, 1,]# loss = tf.keras.losses.categorical_crossentropy(y_pred=logits,# y_true=tf.ones_like(logits))return - tf.reduce_mean(logits)def celoss_zeros(logits):# [b, 1]# [b] = [1, 1, 1, 1,]# loss = tf.keras.losses.categorical_crossentropy(y_pred=logits,# y_true=tf.zeros_like(logits))return tf.reduce_mean(logits)def gradient_penalty(discriminator, batch_x, fake_image):# 梯度懲罰項(xiàng)計(jì)算函數(shù)batchsz = batch_x.shape[0]# 每個(gè)樣本均隨機(jī)采樣t,用于差值,[b, h, w, c]t = tf.random.uniform([batchsz, 1, 1, 1])# 自動(dòng)擴(kuò)展為x的形狀,[b, 1, 1, 1] => [b, h, w, c]t = tf.broadcast_to(t, batch_x.shape)# 在真假圖片之間做線性差值interplate = t * batch_x + (1 - t) * fake_image# 在梯度環(huán)境中計(jì)算D對(duì)差值樣本的梯度with tf.GradientTape() as tape:tape.watch([interplate]) # 加入梯度觀察列表d_interplote_logits = discriminator(interplate, training=True)grads = tape.gradient(d_interplote_logits, interplate)# 計(jì)算每個(gè)樣本的梯度的范數(shù):grads:[b, h, w, c] => [b, -1]grads = tf.reshape(grads, [grads.shape[0], -1])gp = tf.norm(grads, axis=1) # [b]# 計(jì)算梯度懲罰項(xiàng)gp = tf.reduce_mean((gp - 1) ** 2)return gpdef d_loss_fn(generator, discriminator, batch_z, batch_x, is_training):# 計(jì)算D的損失函數(shù)# 1. treat real image as real# 2. treat generated image as fakefake_image = generator(batch_z, is_training) # 假樣本d_fake_logits = discriminator(fake_image, is_training) # 假樣本的輸出d_real_logits = discriminator(batch_x, is_training) # 真樣本的輸出d_loss_real = celoss_ones(d_real_logits)d_loss_fake = celoss_zeros(d_fake_logits)# 計(jì)算梯度懲罰項(xiàng)gp = gradient_penalty(discriminator, batch_x, fake_image)# WGAN-GP D損失函數(shù)的定義,這里并不是計(jì)算交叉熵,而是直接最大化正樣本的輸出# 最小化假樣本的輸出和梯度懲罰項(xiàng)loss = d_loss_real + d_loss_fake + 10. * gpreturn loss, gpdef g_loss_fn(generator, discriminator, batch_z, is_training):# 生成器的損失函數(shù)fake_image = generator(batch_z, is_training)d_fake_logits = discriminator(fake_image, is_training)# WGAN-GP G損失函數(shù),最大化假樣本的輸出值loss = celoss_ones(d_fake_logits)return lossdef main():tf.random.set_seed(233)np.random.seed(233)assert tf.__version__.startswith('2.')# hyper parametersz_dim = 100epochs = 3000000batch_size = 512learning_rate = 0.0005is_training = Trueimg_path = glob.glob(r'/Users/xuruihang/Documents/faces_test/*.jpg')assert len(img_path) > 0dataset, img_shape, _ = make_anime_dataset(img_path, batch_size)print(dataset, img_shape)sample = next(iter(dataset))print(sample.shape, tf.reduce_max(sample).numpy(),tf.reduce_min(sample).numpy())dataset = dataset.repeat()db_iter = iter(dataset)generator = Generator()generator.build(input_shape=(4, z_dim))discriminator = Discriminator()discriminator.build(input_shape=(4, 64, 64, 3))z_sample = tf.random.normal([100, z_dim])g_optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate, beta_1=0.5)d_optimizer = tf.keras.optimizers.Adam(learning_rate=learning_rate, beta_1=0.5)for epoch in range(epochs):for _ in range(5):batch_z = tf.random.normal([batch_size, z_dim])batch_x = next(db_iter)# train Dwith tf.GradientTape() as tape:d_loss, gp = d_loss_fn(generator, discriminator, batch_z, batch_x, is_training)grads = tape.gradient(d_loss, discriminator.trainable_variables)d_optimizer.apply_gradients(zip(grads, discriminator.trainable_variables))batch_z = tf.random.normal([batch_size, z_dim])with tf.GradientTape() as tape:g_loss = g_loss_fn(generator, discriminator, batch_z, is_training)grads = tape.gradient(g_loss, generator.trainable_variables)g_optimizer.apply_gradients(zip(grads, generator.trainable_variables))if epoch % 100 == 0:print(epoch, 'd-loss:', float(d_loss), 'g-loss:', float(g_loss),'gp:', float(gp))z = tf.random.normal([100, z_dim])fake_image = generator(z, training=False)img_path = os.path.join('WGAN_iamges_test', 'wgan-%d.png' % epoch)save_result(fake_image.numpy(), 10, img_path, color_mode='P')if __name__ == '__main__':main()總結(jié)
以上是生活随笔為你收集整理的深度学习之生成对抗网络(8)WGAN-GP实战的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 深度学习之生成对抗网络(7)WGAN原理
- 下一篇: 春节快递不放假:顺丰每单加10块