
【我們為什麼挑選這篇文章】這篇是非常完整的筆記了,寫出了 Ryan 這一年嘗試做的事,學到的經驗,還有在面對問題時中間的處理思路,有點難,但很好看,請笑納。(責任編輯:林子鈞)
本文作者 Ryan Dahl 是 Node.js 的創始人,應該算是軟體工程領域當之無愧的強人了。他和我們分享了自己在谷歌大腦見習項目一年中的工作,成果,失敗和思考。
去年,在通過對 TensorFlow 的研究得出一點點心得之後,我申請併入選了谷歌大腦舉辦的的首屆見習項目(Google Brain Residency Program)。該項目共邀請了 24 名在機器學習領域有著不同背景的人士,受邀者將在為期一年的時間裡和 Google 的科學家及工程師們在位於山景城的 Google 深度學習研究實驗室中共同探索最前沿的深度學習科技。
這個為期一年的項目已經結束了,在此我將就這一年的經歷作一個總結與分享。
最初擬定的目標是「修正」老電影或電視劇的畫面。想像一下,上世紀 90 年代電視劇的粗糙畫面或 60 年代的黑白電影,在色彩華麗的 4K 屏幕上播放的情景。
這應該是完全可行的:把 4K 視頻轉換成滿是顆粒感的、低分辨率的、甚至是只有黑白兩色的視頻並不難,之後再通過某個訓練出的監督模型來反轉這個過程就可以「修正」了。而且,有數不盡的數據訓練集,很棒不是嗎!
先別急著興奮——因為能做這事的技術還沒有出現……不過我們確實離目標越來越近了。
為了更好地實現這個目標,以科技之名,我再一次搬離了布魯克林來到了灣區。幾天後我的日常生活就變成了與 Google 的機器學習專家進行討論以及在龐大的軟體架構中四處探索。
如果你想跳過技術細節,可以直接跳到總結部分。

超分辨率的像素遞歸
眾所周知,在美劇《CSI 犯罪現場》中使用的縮放技術在現實中並不存在,你無法將照片放大到任意倍數。但可行的是,在放大照片的同時將像素可能構成的合理圖形進行推測並呈現,這也是實現我目標的第一步–逆向提高圖片的分辨率。
在文獻中,這一問題被稱之為「超分辨率」問題,是一個科學家們嘗試了很久都沒有解決的難題。
根據以往的經驗,我們認識到只是訓練一個卷積模型最小化低分辨率圖像與高分辨率圖像的平均像素差值無法徹底地解決這一問題。因為這一類模型訓練的目的是平均化輸入圖像和目標圖像的整體差值,這就導致了生成的圖片非常模糊。
對我們而言,理想模型應該針對不同區域做出一個最佳的選擇,儘可能的對細節做出全方位的優化。比如說,輸入一張模糊的樹的圖片,我們希望我們的模型能分別對樹的軀幹、樹枝、樹葉進行優化,哪怕原圖中沒有相應的細節也沒有關係。
起初,我們打算用條件型生成對抗網絡(conditional GAN)來解決這個問題,但經過幾次失敗的嘗試後,我們換成了另一種有望解決該問題的新型生產式模型—— PixelCNN。(換成 PixelCNN 不久,SRGAN 就發佈了,它用 GAN 來解決超分辨率問題並能輸出相當不錯的結果。)
PixelCNN 和傳統的卷積神經網絡十分不同,它將圖像生成問題轉化成了一個像素序列選擇問題。核心思想借鑑與於 LSTM(長短時記憶網絡)這樣的門控遞歸網絡,儘管他們通常被應用於單詞或字符序列的生成上,但無可否認效果是非常好的。 PixelCNN 巧妙地構建出一個卷積神經網絡(CNN),它能基於先前的像素的概率分佈來生成下一個像素,也就是說同時具備了序列模型和卷積神經網絡的特點。

讓我沒想到的是,通過 PixelCNN 生成的圖像看起來非常自然。與對抗網絡試圖在生成與鑑別中找到一個精確的平衡不同,PixelCNN 的目標只有一個,所以面對超參數的變化,它有更好的穩健性,也更容易被優化。
對於用 PixelCNN 解決超分辨率問題的首次嘗試,我試圖用 ImageNet 提供的圖片進行訓練,但事實證明這個目標還是有些太高了。(相較於很多生成式模型使用的 CIFAR-10、CelebA 或 LSUN 數據集,ImageNet 更加的複雜)我很快地就發現——像素來序列生成圖像的過程極其緩慢。
當輸出圖像的尺寸大於 64×64 時,生成一張圖片的耗時超過數個小時!但當我降低了輸出圖像的尺寸並使用臉部或臥室類的小型數據集後,就開始慢慢得到了一些振奮人心的結果了。
用名人臉部圖像數據集訓練出來的超分辨率像素遞歸模型所生成的高分辨率圖像。
左側為測試數據集所用的 8×8 低分辨率輸入圖像。中間為 PixelCNN 模型所輸出的 32×32 高分辨率圖像,右側是原始的 32×32 分辨率圖像。我們的模型優先整合臉部特徵,而後去合成較為逼真的頭髮與皮膚方面的細節。
就計算資源而言,在 Google 不會因 GPU 或 CPU 的數量而受限,所以如何擴大訓練的規模便成為該項目的另一個目標——因為即便採用這些小型的數據集,在單個 GPU 上完成訓練也要花上數週的時間。
異步隨機梯度下降(Asynchronous SGD)是最理想的分佈式訓練方法。使用這種方法,你可以用 N 台機器,每一台都獨立訓練同一模型,並在每個時間步長共享一次權重參數。
權重參數被託管在一台單獨的「參數服務器」上,該服務器在每個時間步長內都進行「遠程過程調用(RPC)」,以獲得最新數值並發送梯度更新。
如果整個數據流非常順暢,就可以通過增加線程的方式線性增加模型每秒內的訓練次數。但因為每個線程都是獨立訓練的,隨著線程數的增加會越來越容易導致在當前線程還沒有完成一次訓練或更新時,它所使用的權重就已經過期了。
如果是為瞭解決分類問題,這對神經網絡的影響不大,把訓練的規模擴增到幾十台機器不難。但 PixelCNN 卻對過時的梯度極其敏感,這就導致了通過增加硬件的