生成式對抗網絡GANpython
一、 基本GANgit
在論文《Generative Adversarial Nets》提出的GAN是最原始的框架,能夠當作極大極小博弈的過程,所以稱爲「對抗網絡」。通常包含兩個部分:生成器(Generator)和判別器(Discriminator)。訓練的過程是無監督學習。github
先總結一下訓練的過程。通常而言,輸入是一個一維向量z,它從先驗生成。假設如今Generator生成的是圖像。咱們知道,無監督學習目的是學習數據集中的特徵(或者說分佈),假設真實的分佈爲,而Generator的生成圖像的過程其實隱式地定義了一個學習到的分佈。把生成的圖像輸入到Discriminator中即,計算的是樣原本自於真實分佈而不是由生成的機率,由於Discriminator最終只有一個輸出。上述不管是Generator或者Discriminator都是通常常見的網絡,以下圖:算法
如上所說,訓練的過程是極大極小的博弈過程,概括成下式:網絡
即Generator但願極大化Discriminator誤判的機率,而Discriminator極小化把生成樣本判成來自真實data的機率。論文中證實,上式的最優解在於。框架
能夠看到,學習到的樣本分佈(或者特徵表示)並無一個顯式的結果,這算是GAN的一個缺點了。訓練的過程是同時訓練兩個網絡,因爲Discriminator能夠更好地指導Generator的調整,因此通常會讓Discriminator循環的次數更多。最優化過程使用的是梯度降低算法,以下:dom
疑惑:在訓練D的時候,按照公式應該是一個極大化的過程,爲何可使用SGD呢?所以我以爲上式應該是不對的,以前應該缺乏一個負號轉換成一個極小化的問題。ide
而開始時,可能會很接近於0,這使得log函數也接近於0,最終結果是梯度降低時因爲迴流梯度太小沒法更新淺層網絡。所以,論文建議訓練開始時能夠求解極大化。函數
二、深度卷積生成對抗網絡DCGAN學習
論文《UNSUPERVISED REPRESENTATION L EARNING WITH DEEP CONVOLUTIONAL GENERATIVE ADVERSARIAL NETWORKS》提出DCGAN,能夠當作是GAN應用在CNN的嘗試。論文更多的是在CNN工程上的嘗試經驗,因爲GAN在訓練時的不穩定性,所以提出了幾點改變:
一、把全部的pooling層用strided convolution替代。在D網絡便是跨步長的卷積,在G網絡則是上採樣(此處稱爲fractional-strided,但不少代碼實現彷佛都用了deconv,在tensorflow有這樣一個函數)。
二、在G和D都應用BN,可是在G的輸出層和D的輸入層不該用BN。
三、移除全鏈接層
四、在G中的激活函數使用RELU,但在輸出層使用的是Tanh
五、在D中的激活函數所有使用Leaky ReLu。
結構圖以下:
這裏主要看它的實現過程。代碼來自https://github.com/carpedm20/DCGAN-tensorflow/blob/master/model.py 。
D網絡部分和通常的卷積網絡沒有什麼區別,主要最後一步是把feature map進行一個flatten的操做,而後所有feed到一個sigmoid的單元,即下式的h4。
h0 = lrelu(conv2d(image, self.df_dim, name='d_h0_conv')) h1 = lrelu(self.d_bn1(conv2d(h0, self.df_dim*2, name='d_h1_conv'))) h2 = lrelu(self.d_bn2(conv2d(h1, self.df_dim*4, name='d_h2_conv'))) h3 = lrelu(self.d_bn3(conv2d(h2, self.df_dim*8, name='d_h3_conv'))) h4 = linear(tf.reshape(h3, [self.batch_size, -1]), 1, 'd_h3_lin') return tf.nn.sigmoid(h4), h4
注意這裏的conv2d實現時已經加上了bias。
在G網絡部分,主要關注z到project and reshape部分和如何進行fractional-strided convolution。
對於project and reshape,代碼中的實現是:
self.z_, self.h0_w, self.h0_b = linear(z, self.gf_dim*8*s16*s16, 'g_h0_lin', with_w=True) self.h0 = tf.reshape(self.z_, [-1, s16, s16, self.gf_dim * 8])
其中linear()函數是經過matrix相乘把z變成self.gf_dim*8*s16*s16
大小的向量。而後經過
reshape
獲得
feature maps
。
而對於
fractional-strided convolution,這裏使用一個函數deconv2d(),代碼以下:
w = tf.get_variable('w', [k_h, k_w, output_shape[-1], input_.get_shape()[-1]],initializer=tf.random_normal_initializer(stddev=stddev)) deconv = tf.nn.conv2d_transpose(input_, w, output_shape=output_shape, strides=[1, d_h, d_w, 1]) biases = tf.get_variable('biases', [output_shape[-1]], initializer=tf.constant_initializer(0.0)) deconv = tf.reshape(tf.nn.bias_add(deconv, biases), deconv.get_shape())
經過一個tf.nn.conv2d_transpose()函數實現反捲積。但有一點注意的是,tf.nn.conv2d_transpose()函數不是什麼shape均可以輸出的,驗證是否正確的方法是,把output與卷積核w作一次卷積,若是獲得的shape和input的一致,表明是正確的。
能夠參考http://stackoverflow.com/questions/35488717/confused-about-conv2d-transpose 。
三、條件GAN conditional GAN
條件GAN,我認爲不少blog是寫錯了的,它和條件機率應該是沒有關係的。GAN的一個很大的優勢是,它的輸入很靈活沒有過大的限制。而條件GAN實際上是在通常輸入時添加了額外的input,這做爲一個可控制的變量去指導着網絡的訓練。由於基本GAN的訓練應該是無方向(這裏表達不許確)的。
一個簡單的網絡以下:
Y做爲額外的輸入的變量,是可控的。在論文《Conditional Generative Adversarial Nets》中的一個例子是訓練mnist,其中y則是0~9的標籤的一個one-hot的編碼向量。
此外,因爲GAN輸入的靈活,能夠很容易想到能夠加入多模態的信息對網絡訓練進行指導,事實上已經有了很多的嘗試。