在開始本文以前,讓咱們先看看一則報道:html
人民網訊 據英國廣播電視公司10月25日報道,由人工智能創做的藝術做品以432000美圓(約合300萬人民幣)的高價成功拍賣。python
看起來一則不起眼的新聞,其實意義深遠,它意味着人們開始承認計算機創做的藝術價值,那些沾沾自喜認爲不會被人工智能取代的藝術家也要瑟瑟發抖了。git
這幅由人工智能創做的做品長啥樣,有啥過人之處?github
嗯,以我這種外行人士看來,實在不怎麼樣,但這不意味着人工智能不行。要知道,AlphaGo初出道時,也只敢挑戰一下樊麾這樣的二流棋手,接下來挑戰頂級棋手李世石,人類還能勉力一戰,等進化到AlphaGo Master,零封人類棋手。然而這尚未完,AlphaGo Zero再也不學習人類棋譜,徹底經過自學,碾壓AlphaGo Master,對付人類棋手,更如咱們捏死一隻螞蟻那麼容易。web
因此說,儘管人工智能創做的第一副做品如同鬼畫桃符,但其潛力無可限量。算法
那麼,接下來咱們會探討如何創做出一幅名畫?No. No.bash
創做一副畫並非那麼容易。這幅名爲《埃德蒙·貝拉米肖像》的畫做是由巴黎一個名爲「顯而易見」(Obvious)的藝術團體創做利用人工智能技術創做而成,這幅做品是用算法和15000幅從14世紀到20世紀的肖像畫數據製做而成。網絡
咱們尚未那個條件去創做一副人工智能的畫做,但咱們能夠先從基本的着手,生成手寫數字。手寫數字對於機器學習的同窗來講,太熟悉不過了。既然是老朋友了,那讓咱們開始吧!機器學習
首先回顧一下《實戰生成對抗網絡[1]:簡介》這篇文章的內容,GAN由生成器和判別器組成。簡單起見,咱們選擇簡單的二層神經網絡來實現生成器和判別器。函數
實現生成器並不難,咱們採起的全鏈接網絡拓撲結構爲:100 --> 128 --> 784,最後的輸出爲784是由於MNIST數據集就是由28 x 28像素的灰度圖像組成。代碼以下:
G_W1 = tf.Variable(initializer([100, 128]), name='G_W1')
G_b1 = tf.Variable(tf.zeros(shape=[128]), name='G_b1')
G_W2 = tf.Variable(initializer([128, 784]), name='G_W2')
G_b2 = tf.Variable(tf.zeros(shape=[784]), name='G_b2')
theta_G = [G_W1, G_W2, G_b1, G_b2]
def generator(z):
G_h1 = tf.nn.relu(tf.matmul(z, G_W1) + G_b1)
G_log_prob = tf.matmul(G_h1, G_W2) + G_b2
G_prob = tf.nn.sigmoid(G_log_prob)
return G_prob
複製代碼
判別器正好相反,以MNIST圖像做爲輸入並返回一個表明真實圖像的機率的標量,代碼以下:
D_W1 = tf.Variable(initializer(shape=[784, 128]), name='D_W1')
D_b1 = tf.Variable(tf.zeros(shape=[128]), name='D_b1')
D_W2 = tf.Variable(initializer(shape=[128, 1]), name='D_W2')
D_b2 = tf.Variable(tf.zeros(shape=[1]), name="D_W2")
theta_D = [D_W1, D_W2, D_b1, D_b2]
def discriminator(x):
D_h1 = tf.nn.relu(tf.matmul(x, D_W1) + D_b1)
D_logit = tf.matmul(D_h1, D_W2) + D_b2
D_prob = tf.nn.sigmoid(D_logit)
return D_prob, D_logit
複製代碼
在論文arXiv: 1406.2661, 2014中給出了訓練算法的僞代碼:
TensorFlow中的優化器只能作最小化,由於爲了最大化損失函數,咱們在僞代碼給出的損失函數前加上一個負號。
D_loss = -tf.reduce_mean(tf.log(D_real) + tf.log(1. - D_fake))
G_loss = -tf.reduce_mean(tf.log(D_fake))
複製代碼
接下來定義優化器:
# 僅更新D(X)的參數, var_list=theta_D
D_solver = tf.train.AdamOptimizer().minimize(D_loss, var_list=theta_D)
# 僅更新G(X)的參數, var_list=theta_G
G_solver = tf.train.AdamOptimizer().minimize(G_loss, var_list=theta_G)
複製代碼
最後進行迭代,更新參數:
for it in range(60000):
X_mb, _ = mnist.train.next_batch(mb_size)
_, D_loss_curr = sess.run([D_solver, D_loss], feed_dict={X: X_mb, Z: sample_Z(mb_size, Z_dim)})
_, G_loss_curr = sess.run([G_solver, G_loss], feed_dict={Z: sample_Z(mb_size, Z_dim)})
複製代碼
整個流程下來,其實和以前的深度學習算法差很少,很是容易理解。算法是否是有效果呢?咱們能夠將迭代過程當中生成的手寫數字顯示出來:
嗯,結果雖然有點差強人意,但差很少是手寫數字的字形,並且隨着迭代,愈來愈接近手寫數字,能夠說GAN算法仍是有效的。
一個簡單的GAN網絡就這麼幾行代碼就能搞定,看樣子生成一副畫也沒有什麼難的。先不要這麼樂觀,其實,GAN網絡中的坑仍是很多,好比在迭代過程當中,就出現過以下提示:
Iter: 9000
D loss: nan
G_loss: nan
複製代碼
從代碼中咱們能夠看出,GAN網絡依然採用的梯度降低法來迭代求解參數。梯度降低的啓動會選擇一個減少所定義問題損失的方向,可是咱們並無一個辦法來確保利用GAN網絡能夠進入納什均衡的狀態,這是一個高維度的非凸優化目標。網絡試圖在接下來的步驟中最小化非凸優化目標,最終有可能致使進入振盪而不是收斂到底層正式目標。
另外還有模型坍塌、計數、角度以及全局結構方面的問題,要解決這些問題,須要使用一些特殊的技巧和方法,後面咱們深刻各類GAN模型時將會探討。
本文完整的代碼請參考: github.com/mogoweb/aie…