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


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

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

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

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

  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像素的圖像。不用到完全連接或者池化層。

配置

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

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)。

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)

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


免責聲明!

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



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