上一節咱們提到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
這些改變在代碼中均可以看到。DCGAN論文中提到對CNN結構有三點重要的改變:python
配置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
入口程序,事先定義所需參數的值。
執行程序:
訓練一個模型: $ 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
epoch:訓練回合,默認爲25
learning_rate:Adam的學習率,默認爲0.0002
beta1:Adam的動量項(Momentum term of Adam),默認爲0.5
train_size:訓練圖像的個數,默認爲np.inf
batch_size:批圖像的個數,默認爲64。後面生成的圖片拼在一張圖,因此batch_size最好取平方,比如64,36等
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網絡
參數初始化,已講過的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:輸出通道。訓練mnist數據集時,y_dim=10,我想多是由於mnist是圖片數字,分爲10類。若是不是mnist,則默認爲none。
z_dim:噪聲z的維度,默認爲100
gf_dim:G第一個卷積層的過濾器個數,默認爲64
df_dim:D第一個卷積層的過濾器個數,默認爲64
gfc_dim:G第一個全連接層的G單元個數,默認爲1024
dfc_dim:D第一個全連接層的D單元個數,默認爲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
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這幾步是關於可視化,就無論了
經過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
代碼自定義了一個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維的向量。
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):
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倍。
和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