【CV論文閱讀】生成式對抗網絡GAN


生成式對抗網絡GAN

1、  基本GAN

在論文《Generative Adversarial Nets》提出的GAN是最原始的框架,可以看成極大極小博弈的過程,因此稱為“對抗網絡”。一般包含兩個部分:生成器(Generator)和判別器(Discriminator)。訓練的過程是無監督學習。

先總結一下訓練的過程。一般而言,輸入是一個一維向量z,它從先驗生成。假設現在Generator生成的是圖像。我們知道,無監督學習目的是學習數據集中的特征(或者說分布),假設真實的分布為,而Generator的生成圖像的過程其實隱式地定義了一個學習到的分布。把生成的圖像輸入到Discriminator中即,計算的是樣本來自於真實分布而不是由生成的概率,因為Discriminator最終只有一個輸出。上述無論是Generator或者Discriminator都是一般常見的網絡,如下圖:

如上所說,訓練的過程是極大極小的博弈過程,歸納成下式:

即Generator希望極大化Discriminator誤判的概率,而Discriminator極小化把生成樣本判成來自真實data的概率。論文中證明,上式的最優解在於

可以看到,學習到的樣本分布(或者特征表示)並沒有一個顯式的結果,這算是GAN的一個缺點了。訓練的過程是同時訓練兩個網絡,由於Discriminator可以更好地指導Generator的調整,所以一般會讓Discriminator循環的次數更多。最優化過程使用的是梯度下降算法,如下:

疑惑:在訓練D的時候,按照公式應該是一個極大化的過程,為什么可以使用SGD呢?因此我覺得上式應該是不對的,之前應該缺少一個負號轉換成一個極小化的問題。

而開始時,可能會很接近於0,這使得log函數也接近於0,最終結果是梯度下降時由於回流梯度過小無法更新淺層網絡。因此,論文建議訓練開始時可以求解極大化

 

2、深度卷積生成對抗網絡DCGAN

論文《UNSUPERVISED REPRESENTATION L EARNING WITH DEEP CONVOLUTIONAL GENERATIVE ADVERSARIAL NETWORKS》提出DCGAN,可以看成是GAN應用在CNN的嘗試。論文更多的是在CNN工程上的嘗試經驗,由於GAN在訓練時的不穩定性,因此提出了幾點改變:

1、把所有的pooling層用strided convolution替代。在D網絡即是跨步長的卷積,在G網絡則是上采樣(此處稱為fractional-strided,但很多代碼實現似乎都用了deconv,在tensorflow有這樣一個函數)。

2、在G和D都應用BN,但是在G的輸出層和D的輸入層不應用BN。

3、移除全連接層

4、在G中的激活函數使用RELU,但在輸出層使用的是Tanh

5、在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

 

3、條件GAN conditional GAN

條件GAN,我認為很多blog是寫錯了的,它和條件概率應該是沒有關系的。GAN的一個很大的優點是,它的輸入很靈活沒有過大的限制。而條件GAN其實是在一般輸入時添加了額外的input,這作為一個可控制的變量去指導着網絡的訓練。因為基本GAN的訓練應該是無方向(這里表達不准確)的。

一個簡單的網絡如下:

Y作為額外的輸入的變量,是可控的。在論文《Conditional Generative Adversarial Nets》中的一個例子是訓練mnist,其中y則是0~9的標簽的一個one-hot的編碼向量。

此外,由於GAN輸入的靈活,可以很容易想到可以加入多模態的信息對網絡訓練進行指導,事實上已經有了不少的嘗試。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM