Generative Adversarial Nets(GAN Tensorflow)
Generative Adversarial Nets(簡稱GAN)是一種非常流行的神經網絡。 它最初是由Ian Goodfellow等人在NIPS 2014論文中介紹的。 這篇論文引發了很多關於神經網絡對抗性訓練的興趣,論文的引用次數已接近2700+。 許多變形的GAN出現了:DCGAN,Sequence-GAN,LSTM-GAN等。在NIPS 2016中,甚至會有整個專門針對對抗訓練的研討會!
首先,讓我們回顧一下這篇論文的要點。 之後,我們將嘗試使用TensorFlow和MNIST數據實現GAN。
Generative Adversarial Nets
考慮兩個人,一個是制造假幣的犯罪分子,另一個是鑒別假幣的警察。 我們可以想象下犯罪分子的目標
- 成為一個成功偽造假幣的犯罪分子,從而欺騙警察的“法眼”,這樣警察就不能分辨出偽造的錢和真錢之間的區別
- 維護“正義”,警察希望盡可能地發現假幣
在此,我們看到了犯罪分子和警察之間存在利益沖突。 這種情況可以看成是一個博弈論中的minimax Game。 我們把這個過程稱為對抗過程。
生成對抗網絡(GAN)可以看成是對抗過程中的一個特例,其中警察和犯罪份子可以分別modeled as 神經網絡。 第一個網絡生成數據,第二個網絡試圖分辨真實數據和第一個網絡生成的假數據之間的差異。 第二個網絡將輸出表示實際數據概率
在GAN中,第一個網絡被稱為生成器G(Z)(Generator Net),第二個網絡被稱為判別器D(X)(Discriminator Net)。
若達到了minimax Game中的最優的平衡點,第一個網絡將非常的神奇的能夠對實際數據進行建模(生成“實際數據”,騙過判別器D(X)),第二個網絡將輸出0.5的概率,i.e. 第一個網絡的輸出=真實數據。
到這裏,你可能會萌生一個問題,“GAN應該怎麽被訓練呢?”。 這是因為數據的概率分布Pdata可能是一個非常復雜的分布,非常難以推斷。 因此,如果有一臺生成器可以從Pdata
GAN Implementation
根據GAN的定義,我們需要兩個網絡。 網絡的形式可以是五花八門的,無論是像convnet或只是一個兩層神經網絡復雜的網絡都是ok的。 為了方便起見,G(z)和D(X)都使用兩層的神經網絡。使用的框架為TensorFlow。
# Discriminator Net X = tf.placeholder(tf.float32, shape=[None, 784], name=‘X‘) D_W1 = tf.Variable(xavier_init([784, 128]), name=‘D_W1‘) D_b1 = tf.Variable(tf.zeros(shape=[128]), name=‘D_b1‘) D_W2 = tf.Variable(xavier_init([128, 1]), name=‘D_W2‘) D_b2 = tf.Variable(tf.zeros(shape=[1]), name=‘D_b2‘) theta_D = [D_W1, D_W2, D_b1, D_b2] # Generator Net Z = tf.placeholder(tf.float32, shape=[None, 100], name=‘Z‘) G_W1 = tf.Variable(xavier_init([100, 128]), name=‘G_W1‘) G_b1 = tf.Variable(tf.zeros(shape=[128]), name=‘G_b1‘) G_W2 = tf.Variable(xavier_init([128, 784]), name=‘G_W2‘) G_b2 = tf.Variable(tf.zeros(shape=[784]), name=‘G_b2‘) theta_G = [G_W1, G_W2, G_b1, G_b2] def generator(z): G_h1 = tf.nn.relu(tf.matmul(z, 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 discriminator(x): D_h1 = tf.nn.relu(tf.matmul(x, 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_logitView Code
根據上面的代碼,generator(z)函數接受一個100維向量並return 786維向量,即MNIST圖像(28x28)。 註意,z(G(z))是先驗的。 以上述方式,生成器k學習先驗分布(隱變量z)到實際分布Pdata之間的映射。
discriminator(x)函數接受MNIST圖像並返回表示真實MNIST圖像概率的標量。
現在,闡述下Adversarial Process是如何訓練GAN的。 以下是論文中的訓練算法:
G_sample = generator(Z) D_real, D_logit_real = discriminator(X) D_fake, D_logit_fake = discriminator(G_sample) D_loss = -tf.reduce_mean(tf.log(D_real) + tf.log(1. - D_fake)) G_loss = -tf.reduce_mean(tf.log(D_fake))View Code
在上面,我們使用負號作為損失函數,TensorFlow優化器只能做最小化。
另外,根據其它資料的建議,最好使用tf.reduce_mean(tf.log(D_fake))最大化,而不是最小化上述算法中的tf.reduce_mean(1 - tf.log(D_fake))。
然後,我們可以開始對抗訓練了:
# Only update D(X)‘s parameters, so var_list = theta_D D_solver = tf.train.AdamOptimizer().minimize(D_loss, var_list=theta_D) # Only update G(X)‘s parameters, so var_list = theta_G G_solver = tf.train.AdamOptimizer().minimize(G_loss, var_list=theta_G) def sample_Z(m, n): ‘‘‘Uniform prior for G(Z)‘‘‘ return np.random.uniform(-1., 1., size=[m, n]) for it in range(1000000): X_mb, _ = mnist.train.next_batch(mb_size) _, D_loss_curr = sess.run([D_solver, D_loss], feed_dict={X: X_mb, Z: sample_Z(mb_size, Z_dim)}) _, G_loss_curr = sess.run([G_solver, G_loss], feed_dict={Z: sample_Z(mb_size, Z_dim)})View Code
到此,我們已經完成了! 我們可以通過抽樣查看培訓過程:
Generative Adversarial Nets(GAN Tensorflow)