機器學習中的DCGAN-Tensorflow:用於更穩定的訓練

自從Ian Goodfellow的論文以來,GAN已應用於許多領域,但其不穩定性一直存在問題。GAN必須解決極小極大(鞍點)問題,因此這個問題是固有的。

機器學習中的DCGAN-Tensorflow:用於更穩定的訓練

馬鞍點的滑稽表示

許多研究人員試圖通過各種方法解決GAN的這些困境。其中DCGAN已經取得了顯著的成果。DCGAN提出了穩定的GAN網絡結構。如果您根據本文的指導設計模型,可以看出模型訓練是穩定的。

穩定的深度卷積GANs的體系結構指南

•用 strided convolutions(判別器)和 fractional-strided convolutions (生成器)替換任何池化層 。

• 在生成器和判別器中使用 batchnorm

刪除完全連接的隱藏層以獲得更深層次的架構。

• 除了使用Tanh之外, 對生成器中的所有層使用ReLU激活

• 在判別器中對所有層使用LeakyReLU激活

生成器

機器學習中的DCGAN-Tensorflow:用於更穩定的訓練

DCGAN生成器的結構

首先,生成器項目和重塑噪聲分佈(100-dim陣列)到4x4x1024特徵映射。我們使用matmulreshape函數來實現它。然後,我們使用一系列四個fractionally-strided函數卷積(conv2d_transpose)來逐步創建64x64圖像。如上所述,batchnorm放置在每層的末尾,並且除輸出之外,relu作為激活函數。我們使用tanh作為輸出,所以輸出的像素範圍是[-1,1]。

def generator(self, input, reuse = False):
with tf.variable_scope("generator") as scope:
if reuse:
scope.reuse_variables()
G_FW1 = tf.get_variable('G_FW1', [self.n_noise, self.n_hidden], initializer = tf.random_normal_initializer(stddev=0.01))
G_Fb1 = tf.get_variable('G_Fb1', [self.n_hidden], initializer = tf.constant_initializer(0))
G_W1 = tf.get_variable('G_W1', [5,5,self.n_W2, self.n_W1], initializer = tf.truncated_normal_initializer(stddev=0.02))
G_W2 = tf.get_variable('G_W2', [5,5,self.n_W3, self.n_W2], initializer = tf.truncated_normal_initializer(stddev=0.02))
G_W3 = tf.get_variable('G_W3', [5,5,self.n_W4, self.n_W3], initializer = tf.truncated_normal_initializer(stddev=0.02))
G_W4 = tf.get_variable('G_W4', [5,5,self.image_channels, self.n_W4], initializer = tf.truncated_normal_initializer(stddev=0.02))
hidden = tf.nn.relu(
tf.matmul(input, G_FW1) + G_Fb1)
hidden = tf.reshape(hidden, [self.batch_size, 4,4,self.n_W1])
dconv1 = tf.nn.conv2d_transpose(hidden, G_W1, [self.batch_size, 8, 8, self.n_W2], [1, 2, 2, 1])
dconv1 = tf.nn.relu(tf.contrib.layers.batch_norm(dconv1,decay=0.9, epsilon=1e-5))
dconv2 = tf.nn.conv2d_transpose(dconv1, G_W2, [self.batch_size, 16, 16, self.n_W3], [1, 2, 2, 1])
dconv2 = tf.nn.relu(tf.contrib.layers.batch_norm(dconv2,decay=0.9, epsilon=1e-5))
dconv3 = tf.nn.conv2d_transpose(dconv2, G_W3, [self.batch_size, 32, 32, self.n_W4], [1, 2, 2, 1])
dconv3 = tf.nn.relu(tf.contrib.layers.batch_norm(dconv3,decay=0.9, epsilon=1e-5))
dconv4 = tf.nn.conv2d_transpose(dconv3, G_W4, [self.batch_size, 64, 64, self.image_channels], [1, 2, 2, 1])
#dconv4 = tf.nn.relu(tf.layers.batch_normalization(dconv3, training = 'True'))
output = tf.nn.tanh(dconv4)
return output
機器學習中的DCGAN-Tensorflow:用於更穩定的訓練

判別器

本文中使用的判別器與生成器具有對稱結構。與生成器相反,它通過減小圖像大小來訓練特徵映像。所以我們使用了步幅大小為2的conv2d。與生成器相同,batchnorm放置在每層的末尾。但是leaky relu被用作激活函數。

 def discriminator(self, input, reuse = False):
with tf.variable_scope("discriminator") as scope:
if reuse:
scope.reuse_variables()
D_W1 = tf.get_variable('D_W1', [5,5,self.image_channels, self.n_W5], initializer = tf.truncated_normal_initializer(stddev=0.02))
D_W2 = tf.get_variable('D_W2', [5,5,self.n_W5, self.n_W4], initializer = tf.truncated_normal_initializer(stddev=0.02))
D_W3 = tf.get_variable('D_W3', [5,5,self.n_W4, self.n_W3], initializer = tf.truncated_normal_initializer(stddev=0.02))
D_W4 = tf.get_variable('D_W4', [5,5,self.n_W3, self.n_W2], initializer = tf.truncated_normal_initializer(stddev=0.02))
D_FW1 = tf.get_variable('D_FW1', [4*4*self.n_W2, 1], initializer = tf.random_normal_initializer(stddev=0.01))
D_Fb1 = tf.get_variable('D_Fb1', [1], initializer = tf.constant_initializer(0))
conv1 = tf.nn.conv2d(input, D_W1, strides = [1, 2, 2, 1], padding='SAME')
conv1 = tf.nn.leaky_relu(conv1, alpha = 0.2)
conv2 = tf.nn.conv2d(conv1, D_W2, strides = [1, 2, 2, 1], padding='SAME')
conv2 = tf.nn.leaky_relu(tf.contrib.layers.batch_norm(conv2, decay=0.9, epsilon=1e-5), alpha = 0.2)
conv3 = tf.nn.conv2d(conv2, D_W3, strides = [1, 2, 2, 1], padding='SAME')
conv3 = tf.nn.leaky_relu(tf.contrib.layers.batch_norm(conv3, decay=0.9, epsilon=1e-5), alpha = 0.2)
conv4 = tf.nn.conv2d(conv3, D_W4, strides = [1, 2, 2, 1], padding='SAME')
conv4 = tf.nn.leaky_relu(tf.contrib.layers.batch_norm(conv4, decay=0.9, epsilon=1e-5), alpha = 0.2)
hidden = tf.reshape(conv4, [self.batch_size, 4*4*self.n_W2])
output = tf.nn.sigmoid(
tf.matmul(hidden, D_FW1) + D_Fb1)
return output
機器學習中的DCGAN-Tensorflow:用於更穩定的訓練

損失函數和優化器

損失函數和優化器與基本GAN相同。然而,根據該DCGAN論文的(對抗性訓練的細節)中,我們設置優化器的學習率0.0002bata1為0.5

def loss(self, X, Z):
g_out = self.generator(Z)
d_fake = self.discriminator(g_out, reuse = False)
d_real = self.discriminator(X, reuse = True)
d_loss = tf.reduce_mean(tf.log(d_real) + tf.log(1 - d_fake))
g_loss = tf.reduce_mean(tf.log(d_fake))
return d_loss, g_loss

def optimizer(self, d_loss, g_loss, learning_rate):
d_var_list = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='discriminator')
g_var_list = tf.get_collection(tf.GraphKeys.GLOBAL_VARIABLES, scope='generator')
#print('G_var_list:', len(G_var_list))
#print('D_var_list:', len(D_var_list))
d_opt = tf.train.AdamOptimizer(learning_rate, beta1 = 0.5).minimize(-d_loss,
var_list=d_var_list)
g_opt = tf.train.AdamOptimizer(learning_rate, beta1 = 0.5).minimize(-g_loss,
var_list=g_var_list)
return d_opt, g_opt
機器學習中的DCGAN-Tensorflow:用於更穩定的訓練

結果

數據集是從kaggle下載的。數據集下載地址(https://www.kaggle.com/scolianni/mnistasjpg)

機器學習中的DCGAN-Tensorflow:用於更穩定的訓練

DCGAN

機器學習中的DCGAN-Tensorflow:用於更穩定的訓練

BasicGAN

使用mnist數據集訓練了DCGAN和basicGAN模型。DCGAN生成比basicGAN更乾淨的圖像。當然,上述結果似乎是合理的,因為DCGAN具有比BasicGAN更復雜的結構並且具有更多參數。但是DCGAN中引入的方法甚至可以穩定地學習複雜的模型。這是DCGAN的貢獻。

此外,我還使用Celeb_A數據集訓練了兩個模型,其中有大約200k肖像照片。數據集下載地址(https://www.kaggle.com/jessicali9530/celeba-dataset)

機器學習中的DCGAN-Tensorflow:用於更穩定的訓練

DCGAN

機器學習中的DCGAN-Tensorflow:用於更穩定的訓練

BasicGAN

我們為DCGAN和BasicGAN模型訓練了9個週期。DCGAN不僅可以產生清晰的圖像,還可以表現出各種特徵,如眼鏡,妝容和鬍鬚。但它仍然看起來不自然。

這就是利用深度學習來實現人臉的創造。其他深度學習模型(如變分自編碼器自迴歸模型)也是生成模型的好示例。


分享到:


相關文章: