【神經網絡與深度學習】DCGAN及其TensorFlow源碼

上一節咱們提到G和D由多層感知機定義。深度學習中對圖像處理應用最好的模型是CNN,那麼如何把CNN與GAN結合?DCGAN是這方面最好的嘗試之一。源碼:https://github.com/Newmu/dcgan_code 。DCGAN論文做者用theano實現的,他還放上了其餘人實現的版本,本文主要討論tensorflow版本。 
TensorFlow版本的源碼:https://github.com/carpedm20/DCGAN-tensorflowcss

DCGAN把上述的G和D換成了兩個卷積神經網絡(CNN)。但不是直接換就能夠了,DCGAN對卷積神經網絡的結構作了一些改變,以提升樣本的質量和收斂的速度,這些改變有:html

  • 取消全部pooling層。G網絡中使用轉置卷積(transposed convolutional layer)進行上採樣,D網絡中用加入strided的卷積代替pooling。
  • 在D和G中均使用batch normalization
  • 去掉FC層,使網絡變爲全卷積網絡
  • G網絡中使用ReLU做爲激活函數,最後一層使用tanh
  • D網絡中使用LeakyReLU做爲激活函數

這些改變在代碼中均可以看到。DCGAN論文中提到對CNN結構有三點重要的改變:python

  1. Allconvolutional net (Springenberg et al., 2014) 全卷積網絡 
    判別模型D:使用帶步長的卷積(strided convolutions)取代了的空間池化(spatial pooling),允許網絡學習本身的空間下采樣(spatial downsampling)。 
    Ÿ 生成模型G:使用微步幅卷積(fractional strided),允許它學習本身的空間上採樣(spatial upsampling)
  2. 在卷積特徵之上消除全鏈接層。 
    Ÿ (Mordvintsev et al.)提出的全局平均池化有助於模型的穩定性,但損害收斂速度。 
    GAN的第一層輸入:服從均勻分佈的噪聲向量Z,由於只有矩陣乘法,所以能夠被叫作全鏈接層,但結果會被reshape成4維張量,做爲卷積棧的開始。 
    對於D,最後的卷積層被flatten(把矩陣變成向量),而後使用sigmoid函數處理輸出。 
    生成模型:輸出層用Tanh函數,其它層用ReLU激活函數。 
    判別模型:全部層使用LeakyReLU
  3. Batch Normalization 批標準化。 
    解決因糟糕的初始化引發的訓練問題,使得梯度能傳播更深層次。穩定學習,經過歸一化輸入的單元,使它們平均值爲0,具備單位方差。 
    批標準化證實了生成模型初始化的重要性,避免生成模型崩潰:生成的全部樣本都在一個點上(樣本相同),這是訓練GANs常常遇到的失敗現象。 
    generator:100維的均勻分佈Z投影到小的空間範圍卷積表示,產生許多特徵圖。一系列四步卷積將這個表示轉換爲64x64像素的圖像。不用到徹底鏈接或者池化層。

配置git

Python 
TensorFlow 
SciPy 
pillow 
(可選)moviepy (https://github.com/Zulko/moviepy):用於可視化 
(可選)Align&Cropped Images.zip (http://mmlab.ie.cuhk.edu.hk/projects/CelebA.html):人臉數據集github

main.py

入口程序,事先定義所需參數的值。 
執行程序: 
訓練一個模型: 
$ python main.py --dataset mnist --is_trainTrue 
$ python main.py --dataset celebA --is_trainTrue --is_crop True 
測試一個已存在模型: 
$ python main.py --dataset mnist 
$ python main.py --dataset celebA --is_crop True 
你也可使用本身的dataset: 
$ mkdir data/DATASET_NAME 
添加圖片到data/DATASET_NAME … 
$ python main.py --dataset DATASET_NAME--is_train True 
$ python main.py --dataset DATASET_NAME 
訓練出多張以假亂真的圖片算法

源碼分析

flags配置network的參數,在命令行中能夠修改,好比 
$python main.py --image_size 96 --output_size 48 --dataset anime --is_crop True--is_train True --epoch 300
該套代碼參數主要以mnist數據集爲模板,若是要訓練別的數據集,能夠適當修改一些參數。mnist數據集能夠經過download.py下載。 
首先初始化model.py中的DCGAN,而後看是否須要訓練(is_train)。spring

FLAGS參數

epoch:訓練回合,默認爲25 
learning_rateAdam的學習率,默認爲0.0002 
beta1:Adam的動量項(Momentum term of Adam),默認爲0.5 
train_size:訓練圖像的個數,默認爲np.inf 
batch_size:批圖像的個數,默認爲64。batch_size6436 
input_height:所使用的圖像的圖像高度(將會被center cropped),默認爲108 
input_width:所使用的圖像的圖像寬度(將會被center cropped),若是沒有特別指定默認和input_height同樣 
output_height:所產生的圖像的圖像高度(將會被center cropped),默認爲64 
output_width:所產生的圖像的圖像寬度(將會被center cropped),若是沒有特別指定默認和output_height同樣 
dataset:所用數據集的名稱,在文件夾data裏面,能夠選擇celebA,mnist,lsun。也能夠本身下載圖片,把文件夾放到data文件夾裏面。 
input_fname_pattern:輸入的圖片類型,默認爲*.jpg 
checkpoint_dir:存放checkpoint的目錄名,默認爲checkpoint 
sample_dir:存放生成圖片的目錄名,默認爲samples 
train:訓練爲True,測試爲False,默認爲False 
crop:訓練爲True,測試爲False,默認爲False 
visualize:可視化爲True,不可視化爲False,默認爲False網絡

model.py

初始化參數

model.py定義了DCGAN類,包括9個函數

__init__()

參數初始化,已講過的input_height, input_width, crop, batch_size, output_height, output_width, dataset_name, input_fname_pattern, checkpoint_dir, sample_dir就再也不說了 
sample_num:大小和batch_size同樣 
y_dim:輸出通道。mnisty_dim=10,我想多是由於mnist是圖片數字,分爲10類。若是不是mnist,則默認爲none。 
z_dim:噪聲z的維度,默認爲100 
gf_dimG,默認爲64 
df_dimD,默認爲64 
gfc_dimGG,默認爲1024 
dfc_dimDD,默認爲1024 
c_dim:顏色通道,灰度圖像設爲1,彩色圖像設爲3,默認爲3 
其中self.d_bn1, self.d_bn2, g_bn0, g_bn1, g_bn2是batch標準化,見ops.py的batch_norm(object)。 
若是是mnist數據集,d_bn3, g_bn3都要batch_norm。 
self.data讀取數據集。 
而後創建模型(build_model)ide

build_model()

inputs的形狀爲[batch_size, input_height, input_width, c_dim]。 
若是crop=True,inputs的形狀爲[batch_size, output_height, output_width, c_dim]。 
輸入分爲樣本輸入inputs和抽樣輸入sample_inputs。 
噪聲z的形狀爲[None, z_dim],第一個None是batch的大小。 
而後取數據: 
self.G = self.generator(self.z)#返回[batch_size, output_height, output_width, c_dim]形狀的張量,也就是batch_size張圖
self.D, self.D_logits = self.discriminator(inputs)#返回的D爲是不是真樣本的sigmoid機率,D_logits是未經sigmoid處理
self.sampler = self.sampler(self.z)#至關於測試,通過G網絡模型,取樣,代碼和G很像,沒有G訓練的過程。 
self.D_, self.D_logits_ = self.discriminator(self.G, reuse=True) 
#D是真實數據,D_是假數據 
用交叉熵計算損失,共有:d_loss_real、d_loss_fake、g_loss 
self.d_loss_real = tf.reduce_mean( 
sigmoid_cross_entropy_with_logits(self.D_logits, tf.ones_like(self.D)))
 
self.d_loss_fake = tf.reduce_mean( 
sigmoid_cross_entropy_with_logits(self.D_logits_, tf.zeros_like(self.D_)))
 
self.g_loss = tf.reduce_mean( 
sigmoid_cross_entropy_with_logits(self.D_logits_, tf.ones_like(self.D_)))
 
tf.ones_like:新建一個與給定tensor大小一致的tensor,其所有元素爲1 
d_loss_real是真樣本輸入的損失,要讓D_logits接近於1,也就是D識別出真樣本爲真的 
d_loss_fake是假樣本輸入的損失,要讓D_logits_接近於0,D識別出假樣本爲假 
d_loss = d_loss_real + d_loss_fake是D的目標,要最小化這個損失 
g_loss:要讓D識別假樣本爲真樣本,G的目標是下降這個損失,D是提升這個損失函數

summary這幾步是關於可視化,就無論了

train()

經過Adam優化器最小化d_loss和g_loss。 
sample_z爲從-1到1均勻分佈的數,大小爲[sample_num, z_dim] 
從路徑中讀取原始樣本sample,大小爲[sample_num, output_height, output_width, c_dim] 
接下來進行epoch個訓練: 
將data總數分爲batch_idxs次訓練,每次訓練batch_size個樣本。產生的樣本爲batch_images。 
batch_z爲訓練的噪聲,大小爲[batch_num, z_dim] 
d_optim = tf.train.AdamOptimizer(config.learning_rate, beta1=config.beta1) \ 
.minimize(self.d_loss, var_list=self.d_vars)
 
g_optim = tf.train.AdamOptimizer(config.learning_rate, beta1=config.beta1) \ 
.minimize(self.g_loss, var_list=self.g_vars)
 
首先輸入噪聲z和batch_images,經過優化d_optim更新D網絡。 
而後輸入噪聲z,優化g_optim來更新G網絡。G網絡更新兩次,以避免d_loss爲0。這點不一樣於paper。 
這樣的訓練,每過100個能夠生成圖片看看效果。 
if np.mod(counter, 100) == 1

discriminator()

代碼自定義了一個conv2d,對tf.nn.conv2d稍加修改了。下面貼出tf.nn.conv2d解釋以下: 
tf.nn.conv2d(input, filter, strides, padding, use_cudnn_on_gpu=None, name=None) 
除去name參數用以指定該操做的name,與方法有關的一共五個參數: 
第一個參數input:指須要作卷積的輸入圖像,它要求是一個Tensor,具備[batch, in_height, in_width, in_channels]這樣的shape,具體含義是[訓練時一個batch的圖片數量, 圖片高度, 圖片寬度, 圖像通道數],注意這是一個4維的Tensor,要求類型爲float32和float64其中之一 
第二個參數filter:至關於CNN中的卷積核,它要求是一個Tensor,具備[filter_height, filter_width, in_channels, out_channels]這樣的shape,具體含義是[卷積核的高度,卷積核的寬度,圖像通道數,卷積核個數],要求類型與參數input相同,有一個地方須要注意,第三維in_channels,就是參數input的第四維 
第三個參數strides:卷積時在圖像每一維的步長,這是一個一維的向量,長度4 
第四個參數padding:string類型的量,只能是」SAME」,」VALID」其中之一,這個值決定了不一樣的卷積方式(後面會介紹) 
第五個參數:use_cudnn_on_gpu:bool類型,是否使用cudnn加速,默認爲true 
結果返回一個Tensor,這個輸出,就是咱們常說的feature map 
batch_norm(object) 
tf.contrib.layers.batch_norm的代碼見https://github.com/tensorflow/tensorflow/blob/master/tensorflow/contrib/layers/python/layers/layers.py 
batchnormalization來自於http://arxiv.org/abs/1502.03167 
加快訓練。 
這裏寫圖片描述 
激活函數lrelu見ops.py。四次卷積(其中三次卷積以前先批標準化)和激活以後。而後線性化,返回sigmoid函數處理後的結果。h3到h4的全鏈接至關於線性化,用一個矩陣將h3和h4鏈接起來,使h4是一個batch_size維的向量。

generator()

self.h0 = tf.reshape(self.z_, [-1, s_h16, s_w16, self.gf_dim * 8])改變z_的形狀。-1表明的含義是不用咱們本身指定這一維的大小,函數會自動計算,但列表中只能存在一個-1。(固然若是存在多個-1,就是一個存在多解的方程了) 
deconv2d() 
引用tf的反捲積函數tf.nn.conv2d_transpose或tf.nn.deconv2d。以tf.nn.conv2d_transpose爲例。 
defconv2d_transpose(value, filter, output_shape, strides,padding=」SAME」, data_format=」NHWC」, name=None):

  • value: 是一個4維的tensor,格式爲[batch, height, width, in_channels] 或者 [batch, in_channels,height, width]。
  • filter: 是一個4維的tensor,格式爲[height, width, output_channels, in_channels],過濾器的in_ channels的維度要和這個匹配。
  • output_shape: 一維tensor,表示反捲積操做的輸出shapeA
  • strides: 針對每一個輸入的tensor維度,滑動窗口的步長。
  • padding: 「VALID」或者」SAME」,padding算法
  • data_format: 「NHWC」或者」NCHW」 ,對應value的數據格式。
  • name: 可選,返回的tensor名。

deconv= tf.nn.conv2d_transpose(input_, w, output_shape=output_shape,strides=[1,d_h, d_w, 1]) 
第一個參數是輸入,即上一層的結果, 
第二個參數是輸出輸出的特徵圖維數,是個4維的參數, 
第三個參數卷積核的移動步長,[1, d_h, d_w, 1],其中第一個對應一次跳過batch中的多少圖片,第二個d_h對應一次跳過圖片中多少行,第三個d_w對應一次跳過圖片中多少列,第四個對應一次跳過圖像的多少個通道。這裏直接設置爲[1,2,2,1]。即每次反捲積後,圖像的滑動步長爲2,特徵圖會擴大縮小爲原來2*2=4倍。 
這裏寫圖片描述

sampler()

和generator結構同樣,用的也是它的參數。存在的意義可能在於共享參數? 
self.sampler = self.sampler(self.z, self.y)改成self.sampler = self.generator(self.z, self.y) 
報錯: 
這裏寫圖片描述
因此sampler的存在仍是有意義的。

load_mnist(), save(), load() 
這三個加載保存等就不仔細講了。

download.py和ops.py好像也沒什麼好講的。 
utils.py包含可視化等函數

參考: 
Springenberg, Jost Tobias, Dosovitskiy, Alexey, Brox, Thomas, and Riedmiller, Martin. Striving for simplicity: The all convolutional net. arXiv preprint arXiv:1412.6806, 2014. 
Mordvintsev, Alexander, Olah, Christopher, and Tyka, Mike. Inceptionism : Going deeper into neural networks.http://googleresearch.blogspot.com/2015/06/inceptionism-going-deeper-into-neural.html. Accessed: 2015-06-17. 
Radford A, Metz L, Chintala S. UnsupervisedRepresentation Learning with Deep Convolutional Generative AdversarialNetworks[J]. Computer Science, 2015. 
http://blog.csdn.net/nongfu_spring/article/details/54342861 
http://blog.csdn.net/solomon1558/article/details/52573596

相關文章
相關標籤/搜索