生成手寫字體,手寫制作
chanong
安妮(Anne) 編輯自O(shè)'Reilly
量子比特出品| 公眾號QbitAI
生成對抗網(wǎng)絡(luò)是過去20 年來機(jī)器學(xué)**領(lǐng)域最酷的想法。第——章
自從Ian Goodfellow 和蒙特利爾大學(xué)的同事兩年前提出這一概念以來,生成對抗網(wǎng)絡(luò)(GAN) 的發(fā)展勢頭一直強(qiáng)勁。
在O'Reilly 上發(fā)表的這篇文章中,作者為初學(xué)者解答了有關(guān)GAN 基礎(chǔ)知識的問題,并教大家如何使用GAN 創(chuàng)建一個(gè)可以生成手寫數(shù)字的程序。
本教程由Jon Bruner(管理硬件、互聯(lián)網(wǎng)、制造和電子領(lǐng)域出版物的O'Reilly 編輯團(tuán)隊(duì)成員)和Adit Deshpande(加州大學(xué)洛杉磯分校計(jì)算機(jī)科學(xué)專業(yè)二年級學(xué)生)創(chuàng)建。
Qubit 提示:本文中描述的所有代碼都可以在GitHub 上下載。
https://github.com/jonbruner/generative-adversarial-networks
立即開始您的GAN 之旅——
簡介GAN 是學(xué)**創(chuàng)建類似于已知輸入數(shù)據(jù)的合成數(shù)據(jù)的神經(jīng)網(wǎng)絡(luò)。研究人員現(xiàn)在能夠使用GAN 來合成從臥室到專輯封面的照片序列,并且它們還表現(xiàn)出了反映高階語義邏輯的不可思議的能力。
雖然這些例子相當(dāng)復(fù)雜,但構(gòu)建一個(gè)可以生成簡單圖像的GAN 并不困難。在本教程中,您將從頭開始學(xué)**如何構(gòu)建一個(gè)分析手寫數(shù)字圖像的GAN,以及如何訓(xùn)練它生成新圖像。其實(shí)說白了,就是教神經(jīng)網(wǎng)絡(luò)如何寫字。
上圖是本教程中構(gòu)建的GAN 生成的示例圖像。
GAN 架構(gòu)GAN 包括兩種模型:生成模型和判別模型。
判別模型是一種分類器,用于確定特定圖像是數(shù)據(jù)集中的真實(shí)圖像還是人工創(chuàng)建的假圖像。這基本上是卷積神經(jīng)網(wǎng)絡(luò)(CNN)形式的二元分類器。
生成模型通過反卷積神經(jīng)網(wǎng)絡(luò)將隨機(jī)輸入值轉(zhuǎn)換為圖像。
在幾次訓(xùn)練迭代的過程中,鑒別器和生成器的權(quán)重和偏差通過反向傳播進(jìn)行訓(xùn)練。鑒別器學(xué)**如何從生成器生成的一堆假數(shù)字圖像中找到真正的數(shù)字圖像。同時(shí),生成器學(xué)**如何通過鑒別器的反饋生成欺騙性圖像,從而阻止鑒別器識別。
準(zhǔn)備工作我們將創(chuàng)建一個(gè)可以生成手寫數(shù)字的GAN,旨在愚弄最好的分類器(當(dāng)然包括人類)。使用Google 的開源TensorFlow 在GPU 上輕松訓(xùn)練神經(jīng)網(wǎng)絡(luò)。
TensorFlow下載地址:
https://www.tensorflow.org/
我們希望您在學(xué)**本教程之前對TensorFlow 有一定的了解。如果您以前沒有遇到過這種情況,我們建議您先閱讀相關(guān)文章和教程。
加載MNIST 數(shù)據(jù)首先,我們需要將一系列真實(shí)的手寫數(shù)字圖像輸入到分類器中。這可以被認(rèn)為是判別器的參考。這里使用的深度學(xué)**基準(zhǔn)數(shù)據(jù)集MNIST是一個(gè)手寫數(shù)字圖片的數(shù)據(jù)庫,其中每張圖片都是0到9的單個(gè)數(shù)字,并且每張圖片都有抗鋸齒,這是一張灰度圖像。該數(shù)據(jù)庫包含由美國國家標(biāo)準(zhǔn)技術(shù)研究所收集、由人口普查局員工和高中生編寫的70,000 張數(shù)字圖像。
MNIST 數(shù)據(jù)集鏈接(英文):
http://yann.lecun.com/exdb/mnist/
讓我們首先導(dǎo)入TensorFlow 和其他有用的數(shù)據(jù)庫。首先,我們需要使用TensorFlow 的便捷函數(shù)導(dǎo)入MNIST 圖像。該函數(shù)也可以稱為read_data_sets。
您創(chuàng)建的MNIST 變量包含圖像和標(biāo)簽,數(shù)據(jù)集分為訓(xùn)練集和驗(yàn)證集(盡管標(biāo)簽不是本教程的關(guān)注點(diǎn))。可以通過調(diào)用mnist中的next_batch來獲取,所以我們加載圖片來看一下。
該圖像最初格式化為784 像素列,可以轉(zhuǎn)換為28x28 像素圖像并在PyPlot 中顯示。
如果我們再次運(yùn)行上面的單元格,我們將看到來自MNIST 訓(xùn)練集的不同圖像。
判別網(wǎng)絡(luò)判別器采用圖像大小為28x28x1 的輸入圖像,并返回單個(gè)標(biāo)量值,該標(biāo)量值描述輸入圖像—— 的置信度,并確定其是否來自MNIST 圖像的卷積神經(jīng)網(wǎng)絡(luò)。集或發(fā)電機(jī)。
判別器的結(jié)構(gòu)與TensorFlow中的樣本CNN分類模型密切相關(guān)。它有兩個(gè)具有5 5 像素特征的卷積層和兩個(gè)計(jì)算圖像中每個(gè)像素的權(quán)重增量的全連接層。
創(chuàng)建神經(jīng)網(wǎng)絡(luò)后,您通常需要初始化權(quán)重和偏差,您可以使用tf.get_variable 完成該任務(wù)。權(quán)重用截?cái)嗾龖B(tài)分布初始化,偏差用0 初始化。
tf.nn.conv2d() 是TensorFlow 的標(biāo)準(zhǔn)卷積函數(shù)。它包含四個(gè)參數(shù):第一個(gè)參數(shù)是輸入圖像(輸入體積)(本例中為28x28像素圖像),第二個(gè)參數(shù)是濾波器/權(quán)重矩陣,最后:您還可以更改“stride”和“padding”的卷積。這兩個(gè)參數(shù)控制輸出圖像的大小。
事實(shí)上,上面是一個(gè)常規(guī)的簡單二元分類器,所以如果你是CNN 的新手,你應(yīng)該熟悉它。
定義了判別器之后,我們需要回顧一下生成模型。模型的整個(gè)結(jié)構(gòu)基于Tim O’Shea 編寫的簡單生成器代碼。
代碼鏈接:
https://github.com/osh/KerasGAN
事實(shí)上,您可以將生成器視為一種反卷積神經(jīng)網(wǎng)絡(luò)。判別器是典型的CNN,可以將2D 或3D 像素值矩陣轉(zhuǎn)換為概率。然而,生成器需要d 維向量,并且需要轉(zhuǎn)換為28*28 圖像。 ReLU 和批量歸一化通常用于穩(wěn)定每一層的輸出。
該神經(jīng)網(wǎng)絡(luò)使用三個(gè)卷積層和插值,直到形成28*28 像素的圖像。
向輸出層添加了tf.sigmoid() 激活函數(shù)。這會壓縮灰度以顯示白色或黑色,從而產(chǎn)生更清晰的圖像。
生成樣本圖像定義了生成器和判別函數(shù)后,我們來看看未經(jīng)訓(xùn)練的生成器會生成什么樣的樣本。
首先,打開TensorFlow 并為生成器創(chuàng)建一個(gè)占位符。占位符的形式為None x z_dimensions,其中關(guān)鍵字None 表示其值可以在會話期間確定。通常,您使用None 作為第一個(gè)維度,因此批量大小是可變的。如果使用關(guān)鍵字None,則不需要指定batch_size。
接下來,創(chuàng)建一個(gè)變量來保存生成器的輸出( generated_image_output ) 并使用輸入隨機(jī)噪聲向量對其進(jìn)行初始化。 np.random.normal() 函數(shù)具有三個(gè)參數(shù),前兩個(gè)參數(shù)定義正態(tài)分布的平均值和標(biāo)準(zhǔn)差,最后一個(gè)定義向量的形狀(1 x 100) 。
接下來,您需要初始化所有變量,將z_batch 放入占位符中,并運(yùn)行這部分代碼。
sess.run() 函數(shù)有兩個(gè)參數(shù)。第一個(gè)參數(shù)稱為“get”參數(shù),定義計(jì)算所需的值。在這種情況下,我想看看生成器輸出什么。如果您查看最后一個(gè)代碼片段,您可以看到生成函數(shù)的輸出存儲在generated_image_output 中。使用generated_image_output 作為第一個(gè)參數(shù)。
第二個(gè)參數(shù)對應(yīng)輸入字典,可以在運(yùn)行時(shí)替換計(jì)算圖。這就是您在占位符中輸入的內(nèi)容。在此示例中,我們需要在之前定義的z_placeholder 中輸入z_batch 變量,并在PyPlot 中將圖像大小調(diào)整為28*28 像素。
看起來是正確的噪音。接下來,我們需要訓(xùn)練生成網(wǎng)絡(luò)的權(quán)重和偏差,將隨機(jī)數(shù)轉(zhuǎn)換為可辨別的數(shù)字。我們再看一下?lián)p失函數(shù)和優(yōu)化。
訓(xùn)練GAN 由于存在兩個(gè)損失函數(shù),構(gòu)建和調(diào)試GAN 變得很復(fù)雜。一種鼓勵(lì)生成器創(chuàng)建更好的圖像,另一種鼓勵(lì)標(biāo)識符區(qū)分哪些圖像是真實(shí)的,哪些是由生成器生成的。
同時(shí)訓(xùn)練生成器和鑒別器。如果鑒別器善于區(qū)分圖像來自何處,則生成器還可以適當(dāng)調(diào)整權(quán)重和偏差以產(chǎn)生更真實(shí)的圖像。
該網(wǎng)絡(luò)的輸入和輸出是:
因此,首先讓我們考慮一下您的網(wǎng)絡(luò)需要什么。判別器的目標(biāo)是將MNIST 圖像正確標(biāo)記為真,而判別器生成的標(biāo)簽為假。計(jì)算鑒別器的兩個(gè)損失。一種是損失Dx和1(代表MNIST真實(shí)圖像),另一種是損失Dg和0(代表生成圖像)。在TensorFlow的tf.nn.sigmoid_cross_entropy_with_logits()函數(shù)中運(yùn)行該函數(shù),計(jì)算Dx和0以及Dg和1之間的交叉熵?fù)p失。
sigmoid_cross_entropy_with_logits 在未縮放的值上運(yùn)行,而不是在0 和1 之間的概率值。查看鑒別器的最后一行。這里沒有softmax或sigmoid函數(shù)層。如果鑒別器變得“飽和”,或者有足夠的信心在給定生成的圖像的情況下返回0,則鑒別器的梯度下降變得毫無用處。
tf.reduce_mean() 函數(shù)選擇交叉熵函數(shù)返回的矩陣中所有元素的平均值。這是一種將損失減少到單個(gè)標(biāo)量值而不是向量或矩陣的方法。
接下來,讓我們設(shè)置生成器的損失函數(shù)。我希望生成的網(wǎng)絡(luò)圖像能夠欺騙鑒別器。給定生成的圖像,判別器可以輸出接近1 的值并計(jì)算Dg 和1 之間的損失。
現(xiàn)在損失函數(shù)已經(jīng)完成,我們需要定義優(yōu)化器。生成網(wǎng)絡(luò)優(yōu)化器只需要升級生成器權(quán)重,而不需要升級判別器。同樣,在訓(xùn)練判別器時(shí),我們需要修改生成器的權(quán)重。
為了使它們不同,我們需要?jiǎng)?chuàng)建兩個(gè)變量列表。一個(gè)包含鑒別器權(quán)重和偏差,另一個(gè)包含生成器權(quán)重和偏差。因此,命名TensorFlow 變量需要仔細(xì)考慮。
接下來,您需要制定兩個(gè)優(yōu)化器,通常選擇具有自適應(yīng)學(xué)**率和動量的Adam 優(yōu)化算法。調(diào)用Adam 最小值函數(shù)并指定要更新的變量——。這是訓(xùn)練生成器時(shí)的生成器權(quán)重和偏差,以及訓(xùn)練判別器時(shí)的判別器權(quán)重和偏差。
我們?yōu)殍b別器設(shè)置了兩種不同的訓(xùn)練方案。一種使用真實(shí)圖像來訓(xùn)練鑒別器,另一種使用生成的“假圖像”來訓(xùn)練鑒別器。有時(shí)你需要使用不同的學(xué)**率或單獨(dú)使用它們來調(diào)整學(xué)**的其他方面。
你說的其他方面是什么意思?代碼下載鏈接:
https://github.com/jonbruner/ezgan
GAN 收斂很困難,通常需要很長時(shí)間來訓(xùn)練。 TensorBoard 允許您跟蹤訓(xùn)練過程。您可以繪制標(biāo)量屬性(例如損失)、查看訓(xùn)練中的樣本圖像以及查看神經(jīng)網(wǎng)絡(luò)內(nèi)的拓?fù)洹?
想了解更多關(guān)于TensorBoard 的信息嗎?鏈接:
https://www.tensorflow.org/get_started/summaries_and_tensorboard
如果您在自己的計(jì)算機(jī)上運(yùn)行此腳本,請確保包含以下單元格:接下來,在終端窗口中運(yùn)行tensorboard —logdir=tensorboard/,并在瀏覽器中輸入http://localhost:6006以打開TensorBoard。
接下來,給鑒別器一些簡單的原始訓(xùn)練迭代。這種方法有助于形成對生成器有用的梯度。
接下來,繼續(xù)主訓(xùn)練循環(huán)。在訓(xùn)練生成器時(shí),我們需要向生成器輸入一個(gè)隨機(jī)z 向量,并將其輸出傳遞給判別器(這是前面定義的Dg 變量)。生成器的權(quán)重和偏差的改變主要是為了產(chǎn)生可以欺騙鑒別器的圖像。
要訓(xùn)練判別器,請從MNIST 數(shù)據(jù)集中為其提供一組正例,并將它們用作負(fù)例,以便在生成的圖像上再次訓(xùn)練判別器。
訓(xùn)練GAN 通常需要很長時(shí)間,因此如果您是本教程的新手,我們建議您暫時(shí)不要運(yùn)行此代碼塊。但是,您可以首先運(yùn)行以下代碼塊來生成預(yù)訓(xùn)練模型。
如果您想自己運(yùn)行這段代碼,請做好長時(shí)間等待的準(zhǔn)備。在相對較快的GPU 上大約需要3 小時(shí),在桌面CPU 上可能需要更長的時(shí)間10 倍。
所以我建議你跳過上面的內(nèi)容,直接運(yùn)行下一個(gè)單元格。您可以將經(jīng)過10 小時(shí)訓(xùn)練的模型加載到快速GPU 機(jī)器上,并嘗試經(jīng)過訓(xùn)練的GAN。
訓(xùn)練并不容易眾所周知,訓(xùn)練GAN 很困難。如果沒有正確的超參數(shù)、網(wǎng)絡(luò)架構(gòu)和訓(xùn)練過程,鑒別器將壓倒生成器。
一種常見的失敗模式是鑒別器壓倒了生成器,生成的圖像被明確定義為假圖像。如果判別器是絕對確定的,則生成器就沒有斜率可以減小。這就是為什么我們構(gòu)建一個(gè)產(chǎn)生未縮放輸出的判別器,而不是通過sigmoid 函數(shù)將輸出推至0 或1。
在另一種常見的故障模式(模態(tài)崩潰)中,生成器發(fā)現(xiàn)并利用鑒別器中的弱點(diǎn)。當(dāng)生成大量相似圖像時(shí),無論生成器的輸入z 變量如何,都可以識別這一點(diǎn)。模態(tài)崩潰可以通過“加強(qiáng)”鑒別器來修復(fù),例如通過調(diào)整訓(xùn)練速率或重新配置層。
研究人員已經(jīng)找到了幾種幫助構(gòu)建穩(wěn)定GAN 的小方法。
想讓你的GAN也穩(wěn)定嗎?代碼鏈接:
https://github.com/soumith/ganhacks
結(jié)論GAN 具有重塑我們每天互動的數(shù)字世界的巨大潛力。這個(gè)領(lǐng)域還很年輕,因此下一個(gè)新的GAN 發(fā)現(xiàn)可能來自您。
附加信息1. Ian Goodfellow 及其合作伙伴于2014 年發(fā)表的GAN 論文
論文鏈接:
https://arxiv.org/abs/1406.2661
2. Goodfellow 最近的教程揭開了GAN 的神秘面紗。
教程鏈接:
https://arxiv.org/abs/1701.00160
3. Alec Radford、Luke Metz、Soumith Chintala 等人的論文。它介紹了本教程生成器中使用的復(fù)雜GAN 的基本結(jié)構(gòu)。
論文鏈接:
https://arxiv.org/abs/1511.06434
GitHub 上的DCGAN 代碼:
https://github.com/Newmu/dcgan_code
【就這樣】
筆記
量子比特組建了一個(gè)針對自動駕駛相關(guān)領(lǐng)域?qū)W**的學(xué)生和一線工程師的自動駕駛技術(shù)小組。任何人都可以添加量子比特微信(qbitbot),關(guān)注“自動駕駛”申請參與~
招聘
Qubit正在招聘編輯、記者、運(yùn)營、產(chǎn)品等職位,辦公地點(diǎn)將位于北京中關(guān)村。相關(guān)詳情請?jiān)诠娞枌υ捊缑婊貜?fù)“招募”。








