上一篇文章--[GAN學習系列3]采用深度學習和 TensorFlow 實現(xiàn)圖片修復(上)中键思,我們先介紹了對于圖像修復的背景直撤,需要利用什么信息來對缺失的區(qū)域進行修復,以及將圖像當做概率分布采樣的樣本來看待摔癣,通過這個思路來開始進行圖像的修復模叙。
這篇文章將繼續(xù)介紹原文的第二部分,利用對抗生成網(wǎng)絡來快速生成假圖片新啼。目錄如下:
- 第二步:快速生成假的圖片
- 從未知的概率分布中學習生成新的樣本
- [ML-Heavy] 建立 GAN 模型
- 采用 G(z) 生成假的圖片
- [ML-Heavy] 訓練 DCGAN
- 目前的 GAN 和 DCGAN 實現(xiàn)
- [ML-Heavy] TensorFlow 實現(xiàn) DCGAN
- 在你的數(shù)據(jù)集上運行 DCGAN 模型
同樣的追城,標題帶有 [ML-Heavy] 的會介紹比較多的細節(jié),可以選擇跳過燥撞。
第二步:快速生成假的圖片
從未知的概率分布中學習生成新的樣本
與其考慮如何計算概率密度函數(shù)座柱,現(xiàn)在在統(tǒng)計學中更好的方法是采用一個生成模型來學習如何生成新的、隨機的樣本物舒。過去生成模型一直是很難訓練或者非常難以實現(xiàn)辆布,但最近在這個領域已經(jīng)有了一些讓人驚訝的進展坊萝。Yann LeCun在這篇 Quora 上的問題“最近在深度學習有什么潛在的突破的領域”中給出了一種訓練生成模型(對抗訓練)方法的介紹瞳脓,并將其描述為過去十年內(nèi)機器學習最有趣的想法:
Yann LeCun 在回答中簡單介紹了 GAN 的基本原理泳桦,也就是兩個網(wǎng)絡相互博弈的過程。
實際上涵叮,深度學習還有其他方法來訓練生成模型惭蹂,比如 Variational Autoencoders(VAEs)。但在本文割粮,主要介紹對抗生成網(wǎng)絡(GANs)
[ML-Heavy] 建立 GAN 模型
GANs 這個想法是 Ian Goodfellow 在其帶有里程碑意義的論文“Generative Adversarial Nets” (GANs)發(fā)表在 2014 年的 Neural Information Processing Systems (NIPS) 會議上后開始火遍整個深度學習領域的盾碗。這個想法就是我們首先定義一個簡單并眾所周知的概率分布,并表示為舀瓢,在本文后面廷雅,我們用 表示在[-1,1)(包含-1,但不包含1)范圍的均勻分布京髓。用表示從這個分布中采樣航缀,如果是一個五維的,我們可以利用下面一行的 Python 代碼來進行采樣得到堰怨,這里用到 numpy這個庫:
z = np.random.uniform(-1, 1, 5)
array([ 0.77356483, 0.95258473, -0.18345086, 0.69224724, -0.34718733])
現(xiàn)在我們有一個簡單的分布來進行采樣芥玉,接下來可以定義一個函數(shù)G(z)
來從原始的概率分布中生成樣本,代碼例子如下所示:
def G(z):
...
return imageSample
z = np.random.uniform(-1, 1, 5)
imageSample = G(z)
那么問題來了备图,怎么定義這個G(Z)
函數(shù)灿巧,讓它實現(xiàn)輸入一個向量然后返回一張圖片呢?答案就是采用一個深度神經(jīng)網(wǎng)絡揽涮。對于深度神經(jīng)網(wǎng)絡基礎抠藕,網(wǎng)絡上有很多的介紹,本文就不再重復介紹了蒋困。這里推薦的一些參考有斯坦福大學的 CS231n 課程盾似、Ian Goodfellow 等人編著的《深度學習》書籍、形象解釋圖像的核心以及論文"A guide to convolution arithmetic for deep learning"家破。
通過深度學習可以有多種方法來實現(xiàn)G(z)
函數(shù)颜说。在原始的 GAN 論文中提出一種訓練方法并給出初步的實驗結(jié)果,這個方法得到了極大的發(fā)展和改進汰聋。其中一種想法就是在論文“Unsupervised Representation Learning with Deep Convolutional Generative Adversarial Networks”中提出的门粪,這篇論文的作者是 Alec Radford, Luke Metz, and Soumith Chintala,發(fā)表在 2016 年的 International Conference on Learning Representations (ICLR)會議上烹困,這個方法因為提出采用深度卷積神經(jīng)網(wǎng)絡玄妈,被稱為 DCGANs,它主要采用小步長卷積( fractionally-strided convolution)方法來上采樣圖像髓梅。
那么什么是小步長卷積以及如何實現(xiàn)對圖片的上采樣呢拟蜻? Vincent Dumoulin and Francesco Visin’s 在論文"A guide to convolution arithmetic for deep learning"以及 Github 項目都給出了這種卷積算術的詳細介紹,Github 地址如下:
https://github.com/vdumoulin/conv_arithmetic
上述 Github 項目給出了非常直觀的可視化枯饿,如下圖所示酝锅,這讓我們可以很直觀了解小步長卷積是如何工作的。
首先奢方,你要知道一個正常的卷積操作是一個卷積核劃過輸入?yún)^(qū)域(下圖中藍色區(qū)域)后生成一個輸出區(qū)域(下圖的綠色區(qū)域)搔扁。這里爸舒,輸出區(qū)域的尺寸是小于輸入?yún)^(qū)域的。(當然稿蹲,如果你還不知道扭勉,可以先看下斯坦福大學的CS231n 課程或者論文"A guide to convolution arithmetic for deep learning"。)
接下來苛聘,假設輸入是 3x3涂炎。我們的目標是通過上采樣讓輸出尺寸變大。你可以認為小步長卷積就是在像素之間填充 0 值來拓展輸入?yún)^(qū)域的方法设哗,然后再對輸入?yún)^(qū)域進行卷積操作唱捣,正如下圖所示,得到一個 5x5 的輸出熬拒。
注意爷光,對于作為上采樣的卷積層有很多不同的名字,比如全卷積(full convolution), 網(wǎng)絡內(nèi)上采樣(in-network upsampling), 小步長卷積(fractionally-strided convolution), 反向卷積(backwards convolution), 反卷積(deconvolution), 上卷積(upconvolution), 轉(zhuǎn)置卷積(transposed convolution)澎粟。這里并不鼓勵使用反卷積(deconvolution)這個詞語蛀序,因為在數(shù)學運算或者計算機視覺的其他應用中,這個詞語有著其他完全不同的意思活烙,這是一個非常頻繁使用的詞語徐裸。
現(xiàn)在利用小步長卷積作為基礎,我們可以實現(xiàn)G(z)
函數(shù)啸盏,讓它接收一個的向量輸入重贺,然后輸出一張尺寸是 64x64x3 的彩色圖片,其網(wǎng)絡結(jié)構如下圖所示:
在 DCGAN 這篇論文中還提出了其他的一些技巧和改進來訓練 DCGANs回懦,比如采用批歸一化(batch normalization)或者是 leaky ReLUs 激活函數(shù)气笙。
采用 G(z) 生成假的圖片
現(xiàn)在先讓我們暫停并欣賞下這種G(z)
網(wǎng)絡結(jié)構的強大,在 DCGAN 論文中給出了如何采用一個臥室圖片數(shù)據(jù)集訓練 一個 DCGAN 模型怯晕,然后采用G(z)
生成如下的圖片潜圃,它們都是生成器網(wǎng)絡 G 認為的臥室圖片,注意舟茶,下面這些圖片都是原始訓練數(shù)據(jù)集沒有的谭期!
此外,你還可以對 z
輸入實現(xiàn)一個向量算術操作吧凉,下圖就是一個例子:
[ML-Heavy] 訓練 DCGAN
現(xiàn)在我們定義好了G(z)
隧出,也知道它的能力有多強大,問題來了阀捅,怎么訓練呢胀瞪?我們需要確定很多隱變量(或者說參數(shù)),這也是采用對抗網(wǎng)絡的原因了饲鄙。
首先赏廓,我們先定義幾個符號涵紊。表示訓練數(shù)據(jù),但概率分布未知幔摸,表示從已知的概率分布采樣的樣本,一般從高斯分布或者均勻分布采樣颤练,z
也被稱為隨機噪聲既忆,最后一個,就是 G 網(wǎng)絡生成的數(shù)據(jù)嗦玖,也可以說是生成概率分布患雇。
接著介紹下判別器(discriminator,D)網(wǎng)絡宇挫,它是輸入一批圖片x
苛吱,然后返回該圖片來自訓練數(shù)據(jù)的概率。如果來自訓練數(shù)據(jù)器瘪,D 應該返回一個接近 1 的數(shù)值翠储,否則應該是一個接近 0 的值來表示圖片是假的,來自 G 網(wǎng)絡生成的橡疼。在 DCGANs 中援所,D 網(wǎng)絡是一個傳統(tǒng)的卷積神經(jīng)網(wǎng)絡,如下圖所示欣除,一個包含4層卷積層和1層全連接層的卷積神經(jīng)網(wǎng)絡結(jié)構住拭。
因此,訓練 D 網(wǎng)絡的目標有以下兩個:
- 如果
x
來自訓練數(shù)據(jù)集历帚,最大化D(x)
滔岳; - 如果
x
是來自 G 生成的數(shù)據(jù),最小化D(x)
挽牢。
對應的 G 網(wǎng)絡的目標就是要欺騙 D 網(wǎng)絡谱煤,生成以假亂真的圖片。它生成的圖片也是 D 的輸入卓研,所以 G 的目標就是最大化D(G(z))
趴俘,也等價于最小化1-D(G(z))
,因為 D 其實是一個概率估計奏赘,且輸出范圍是在 0 到 1 之間寥闪。
正如論文提到的,訓練對抗網(wǎng)絡就如同在實現(xiàn)一個最小化最大化游戲(minimax game)磨淌。如下面的公式所示疲憋,第一項是對真實數(shù)據(jù)分布的期望,第二項是對生成數(shù)據(jù)的期望值梁只。
訓練的步驟如下圖所示缚柳,具體可以看下我之前寫的文章[GAN學習系列2] GAN的起源有簡單介紹了這個訓練過程埃脏,或者是看下 GAN 論文[5]的介紹
目前的 GAN 和 DCGAN 實現(xiàn)
目前在 Github 上有許多 GAN 和 DCGAN 的實現(xiàn)(原文是寫于2016年八月份,現(xiàn)在的話代碼就更多了):
- https://github.com/goodfeli/adversarial
- https://github.com/tqchen/mxnet-gan
- https://github.com/Newmu/dcgan_code
- https://github.com/soumith/dcgan.torch
- https://github.com/carpedm20/DCGAN-tensorflow
- https://github.com/openai/improved-gan
- https://github.com/mattya/chainer-DCGAN
- https://github.com/jacobgil/keras-dcgan
本文實現(xiàn)的代碼是基于 https://github.com/carpedm20/DCGAN-tensorflow
[ML-Heavy] TensorFlow 實現(xiàn) DCGAN
這部分的實現(xiàn)的源代碼可以在如下 Github 地址:
https://github.com/bamos/dcgan-completion.tensorflow
當然秋忙,主要實現(xiàn)部分代碼是來自 https://github.com/carpedm20/DCGAN-tensorflow 彩掐。但采用這個項目主要是方便實現(xiàn)下一部分的圖像修復工作。
主要實現(xiàn)代碼是在model.py
中的類DCGAN
灰追。采用類來實現(xiàn)模型是有助于訓練后保存中間層的狀態(tài)以及后續(xù)的加載使用堵幽。
首先,我們需要定義生成器和判別器網(wǎng)絡結(jié)構弹澎。在ops.py
會定義網(wǎng)絡結(jié)構用到的函數(shù)朴下,如linear
,conv2d_transpose
, conv2d
以及 lrelu
。代碼如下所示
def generator(self, z):
self.z_, self.h0_w, self.h0_b = linear(z, self.gf_dim*8*4*4,
'g_h0_lin', with_w=True)
self.h0 = tf.reshape(self.z_, [-1, 4, 4, self.gf_dim * 8])
h0 = tf.nn.relu(self.g_bn0(self.h0))
self.h1, self.h1_w, self.h1_b = conv2d_transpose(h0,
[self.batch_size, 8, 8, self.gf_dim*4], name='g_h1', with_w=True)
h1 = tf.nn.relu(self.g_bn1(self.h1))
h2, self.h2_w, self.h2_b = conv2d_transpose(h1,
[self.batch_size, 16, 16, self.gf_dim*2], name='g_h2', with_w=True)
h2 = tf.nn.relu(self.g_bn2(h2))
h3, self.h3_w, self.h3_b = conv2d_transpose(h2,
[self.batch_size, 32, 32, self.gf_dim*1], name='g_h3', with_w=True)
h3 = tf.nn.relu(self.g_bn3(h3))
h4, self.h4_w, self.h4_b = conv2d_transpose(h3,
[self.batch_size, 64, 64, 3], name='g_h4', with_w=True)
return tf.nn.tanh(h4)
def discriminator(self, image, reuse=False):
if reuse:
tf.get_variable_scope().reuse_variables()
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, [-1, 8192]), 1, 'd_h3_lin')
return tf.nn.sigmoid(h4), h4
當初始化這個類的時候苦蒿,就相當于用上述函數(shù)來構建了這個模型殴胧。我們需要創(chuàng)建兩個 D 網(wǎng)絡來共享參數(shù),一個的輸入是真實數(shù)據(jù)佩迟,另一個是來自 G 網(wǎng)絡的生成數(shù)據(jù)团滥。
self.G = self.generator(self.z)
self.D, self.D_logits = self.discriminator(self.images)
self.D_, self.D_logits_ = self.discriminator(self.G, reuse=True)
接下來是定義損失函數(shù)。這里采用的是 D 的輸出之間的交叉熵函數(shù)音五,并且它的效果也不錯惫撰。D 是期望對真實數(shù)據(jù)的預測都是 1,對生成的假數(shù)據(jù)預測都是 0躺涝,相反厨钻,生成器 G 希望 D 的預測都是 1。代碼的實現(xiàn)如下:
self.d_loss_real = tf.reduce_mean(
tf.nn.sigmoid_cross_entropy_with_logits(self.D_logits,
tf.ones_like(self.D)))
self.d_loss_fake = tf.reduce_mean(
tf.nn.sigmoid_cross_entropy_with_logits(self.D_logits_,
tf.zeros_like(self.D_)))
self.d_loss = self.d_loss_real + self.d_loss_fake
self.g_loss = tf.reduce_mean(
tf.nn.sigmoid_cross_entropy_with_logits(self.D_logits_,
tf.ones_like(self.D_)))
接著是分別對 G 和 D 的參數(shù)聚集到一起坚嗜,方便后續(xù)的梯度計算:
t_vars = tf.trainable_variables()
self.d_vars = [var for var in t_vars if 'd_' in var.name]
self.g_vars = [var for var in t_vars if 'g_' in var.name]
現(xiàn)在才有 ADAM 作為優(yōu)化器來計算梯度夯膀,ADAM 是一個深度學習中常用的自適應非凸優(yōu)化方法,它相比于隨機梯度下降方法苍蔬,不需要手動調(diào)整學習率诱建、動量(momentum)以及其他的超參數(shù)。
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)
定義好模型和訓練策略后碟绑,接下來就是開始輸入數(shù)據(jù)進行訓練了俺猿。在每個 epoch 中,先采樣一個 mini-batch 的圖片格仲,然后運行優(yōu)化器來更新網(wǎng)絡押袍。有趣的是如果 G 只更新一次,D 的 loss 是不會變?yōu)?的凯肋。此外谊惭,在后面額外調(diào)用d_loss_fake
和d_loss_real
會增加不必要的計算量,并且也是多余的,因為它們的數(shù)值在d_optim
和g_optim
計算的時候已經(jīng)計算到了圈盔。這里你可以嘗試優(yōu)化這部分代碼豹芯,然后發(fā)送一個 PR 到原始的 Github 項目中。
for epoch in xrange(config.epoch):
...
for idx in xrange(0, batch_idxs):
batch_images = ...
batch_z = np.random.uniform(-1, 1, [config.batch_size, self.z_dim]) \
.astype(np.float32)
# Update D network
_, summary_str = self.sess.run([d_optim, self.d_sum],
feed_dict={ self.images: batch_images, self.z: batch_z })
# Update G network
_, summary_str = self.sess.run([g_optim, self.g_sum],
feed_dict={ self.z: batch_z })
# Run g_optim twice to make sure that d_loss does not go to zero
# (different from paper)
_, summary_str = self.sess.run([g_optim, self.g_sum],
feed_dict={ self.z: batch_z })
errD_fake = self.d_loss_fake.eval({self.z: batch_z})
errD_real = self.d_loss_real.eval({self.images: batch_images})
errG = self.g_loss.eval({self.z: batch_z})
完整的代碼可以在 https://github.com/bamos/dcgan-completion.tensorflow/blob/master/model.py 中查看
在你的數(shù)據(jù)集上運行 DCGAN 模型
如果你跳過上一小節(jié)驱敲,但希望運行一些代碼:這部分的實現(xiàn)的源代碼可以在如下 Github 地址:
https://github.com/bamos/dcgan-completion.tensorflow
當然铁蹈,主要實現(xiàn)部分代碼是來自 https://github.com/carpedm20/DCGAN-tensorflow 。但采用這個項目主要是方便實現(xiàn)下一部分的圖像修復工作癌佩。但必須注意的是木缝,如果你沒有一個可以使用 CUDA 的 GPU 顯卡,那么訓練網(wǎng)絡將會非常慢围辙。
首先需要克隆兩份項目代碼,地址分別如下:
https://github.com/bamos/dcgan-completion.tensorflow
http://cmusatyalab.github.io/openface
第一份就是作者的項目代碼放案,第二份是采用 OpenFace 的預處理圖片的 Python 代碼姚建,并不需要安裝它的 Torch 依賴包。先創(chuàng)建一個新的工作文件夾吱殉,然后開始克隆掸冤,如下所示:
git clone https://github.com/cmusatyalab/openface.git
git clone https://github.com/bamos/dcgan-completion.tensorflow.git
接著是安裝 Python2 版本的 OpenCV和 dlib(采用 Python2 版本是因為 OpenFace 采用這個版本,當然你也可以嘗試修改為適應 Python3 版本)友雳。對于 OpenFace 的 Python 庫安裝稿湿,可以查看其安裝指導教程,鏈接如下:
http://cmusatyalab.github.io/openface/setup/
此外押赊,如果你沒有采用一個虛擬環(huán)境饺藤,那么需要加入sudo
命令來運行setup.py
實現(xiàn)全局的安裝 OpenFace,當然如果安裝這部分有問題流礁,也可以采用 OpenFace 的 docker 鏡像安裝涕俗。安裝的命令如下所示
cd openface
pip2 install -r requirements.txt
python2 setup.py install
models/get-models.sh
cd ..
接著就是下載一些人臉圖片數(shù)據(jù)集了,這里并不要求它們是否帶有標簽神帅,因為不需要再姑。目前開源可選的數(shù)據(jù)集包括
- MS-Celeb-1M--https://www.microsoft.com/en-us/research/project/msr-image-recognition-challenge-irc/
- CelebA--http://mmlab.ie.cuhk.edu.hk/projects/CelebA.html
- CASIA-WebFace--http://www.cbsr.ia.ac.cn/english/CASIA-WebFace-Database.html
- FaceScrub--http://vintage.winklerbros.net/facescrub.html
- LFW--http://vis-www.cs.umass.edu/lfw/
- MegaFace--http://megaface.cs.washington.edu/
然后將數(shù)據(jù)集放到目錄dcgan-completion.tensorflow/data/your-dataset/raw
下表示其是原始的圖片。
接著采用 OpenFace 的對齊工具來預處理圖片并調(diào)整成64x64
的尺寸:
./openface/util/align-dlib.py data/dcgan-completion.tensorflow/data/your-dataset/raw align innerEyesAndBottomLip data/dcgan-completion.tensorflow/data/your-dataset/aligned --size 64
最后是整理下保存對齊圖片的目錄找御,保證只包含圖片而沒有其他的子文件夾:
cd dcgan-completion.tensorflow/data/your-dataset/aligned
find . -name '*.png' -exec mv {} . \;
find . -type d -empty -delete
cd ../../..
然后確保已經(jīng)安裝了 TensorFlow元镀,那么可以開始訓練 DCGAN了:
./train-dcgan.py --dataset ./data/your-dataset/aligned --epoch 20
在samples
文件夾中可以查看保存的由 G 生成的圖片。這里作者是采用手上有的兩個數(shù)據(jù)集 CASIA-WebFace 和 FaceScrub 進行訓練霎桅,并在訓練 14 個 epochs 后栖疑,生成的結(jié)果如下圖所示:
還可以通過 TensorBoard 來查看 loss 的變化:
tensorboard --logdir ./logs
小結(jié)
這就是本文的第二部分內(nèi)容,主要是介紹了 DCGAN 的基本原理以及代碼實現(xiàn)哆档,還有就是訓練前的準備和開始訓練蔽挠,訓練的實驗結(jié)果。
在下一篇將介紹最后一步內(nèi)容,如何利用 DCGAN 來實現(xiàn)圖像修復的工作澳淑!
歡迎關注我的微信公眾號--機器學習與計算機視覺比原,或者掃描下方的二維碼,在后臺留言杠巡,和我分享你的建議和看法量窘,指正文章中可能存在的錯誤,大家一起交流氢拥,學習和進步蚌铜!
我的個人博客:http://ccc013.github.io/
CSDN 博客:https://blog.csdn.net/lc013/article/details/84845439
推薦閱讀