程序員想搞機器學習?看看Nodejs之父這一年摸爬滾打的心路歷程

做者 | Ryan Dahlhtml

編譯 | AI100(微信ID:rgznai100)算法

原文地址編程

去年,在我研究TensorFlow出了一番成果後,我開始申請Google Brain的首屆見習項目(Google Brain Residency Program),最後竟然成功了。受邀參加該項目的共有24人,每一個人都有着不一樣的機器學習背景。服務器

咱們24我的,須要在Google位於山景城的深度學習研究實驗室工做一年,天天跟Google的科學家和工程師們一塊兒,共同來作TensorFlow的前沿研究。想一想就把我給興奮壞了。微信

現在,這個爲期一年的項目已經結束了,確實收穫滿滿。我也但願把學到的一些東西,結合個人心得,總結一下,分享出來,但願能爲在機器學習的道路上耕耘的夥伴兒提供一些幫助。網絡

先說說我起初擬定的目標吧。個人目標是修正老電影或電視劇的畫面架構

想象一下,畫面粗糙的90年代電視劇,或是60年代黑白電影,要是能被修正爲色彩華麗的4K畫面,觀看體驗會有多棒!併發

而這事看上去徹底可行:咱們很輕鬆就能把4K視頻轉換成盡是顆粒感的、低分辨率的、甚至是隻有黑白兩色的視頻,只要訓練出某個監督模型來反轉這個過程就能夠了。並且,可用的訓練數據無窮無盡。咳咳,這個想法簡直太強悍了!框架

帶着這樣的目標,我再一次(上一次是爲Node.js項目)從紐約布魯克林搬到舊金山灣區,以更好地實現這項深度學習技術。幾天後,個人平常生活就變成了跟Google的深度學習專家進行討論、在Google龐大的軟件庫內瀏覽代碼,blablabla...機器學習

接下來我要開始大談這些日子以來,我所作的不少技術細節。固然,若是不想看,能夠直接跳到總結部分。

超分辨率的像素遞歸

衆所周知,FBI在《犯罪現場調查》(CSI)中所用的縮放技術是不可能實現的。沒人能任意放大照片。然而,在你放大照片圖像時把相關像素所構成的合理圖形呈現出來,這仍是有可能作到的。可以平滑地提高圖像分辨率,將是我實現目標的第一步。

該問題在本文中用 超分辨率 一詞來描述,好久之前人們就在嘗試解決它了。

據此,咱們認識到簡單使用ConvNet沒法完全解決該問題:它只是把你輸入的低分辨率圖像的像素間距(L2)最小化來輸出高分辨率圖像。這類損失函數所學到的,是輸出全部可能結果的平均值——所輸出的圖像看上去就比較模糊了。咱們想要的模型是這樣的:對於給定的低分辨率圖像,它能從全部可能的強化結果中選出那張特定的、效果最好的高分辨率圖像。若是是「強化」一張關於樹的模糊照片,咱們會但願它能給出枝、葉在位置上的一些細節,即使它們的位置並不是是枝、葉在樹上的實際位置。

某種條件型的GAN(生成式對抗網絡)看上去頗有但願,但構建起來較難,通過幾回失敗的嘗試後,咱們換成了另外一種新型的生產式模型:PixelCNN,它也比較有戲。(等咱們啓動以後,用GAN解決來超分辨率問題的SRGAN就發佈了,它生成的結果很是好。)

PixelCNN是一種奇怪的反直覺模型。它將圖像生成問題重寫成每次選擇一個像素序列。像LSTM(長短時記憶網絡)這樣的門控制遞歸網絡在序列生成方面是很是成功的,它一般會用在單詞或字符上。PixelCNN巧妙地構建出一個卷積神經網絡(CNN),它能基於先前的像素的機率分佈來精確生成像素。這是RNN和CNN的混合功能。

示意圖由 van den Oord 等人所繪

意外的是,PixelCNN所生成的圖像看起來很是天然。不像艱難平衡兩種目標的對抗網絡,該模型的目標只有一個,於是面對超參數的變化,它有更好的穩健性。也就是說,它更易於優化。

解決超分辨率問題的首次嘗試,我野心過大,選用了ImageNet來訓練PixelCNN。(跟CIFAR-十、CelebA或LSUN相比,ImageNet是個較難的數據集,不少生成式模型研究都在用它。)但很顯然,按像素來序列生成圖像的過程極其緩慢。輸出圖像的尺寸大於64x64時,耗時將超過數小時!然而,在我把圖像的尺寸限制到小尺寸,並使用臉部或臥室類的小型數據集後,得出的結果就開始使人激動了。

圖1:用名人臉部圖像數據集訓練出來的超分辨率像素遞歸模型所生成的高分辨率圖像。左側爲測試數據集所用的8x8低分辨率輸入圖像。中間爲PixelCNN模型所輸出的32x32高分辨率圖像,右側是原始的32x32分辨率圖像。咱們的模型優先整合臉部特徵,然後去合成較爲逼真的頭髮與皮膚方面的細節。

因爲在Google能夠獲取到無窮的計算資源,如何擴大訓練的規模便成爲該項目的另外一個目標——由於即使採用這些小型的數據集,在單個CPU上完成訓練也要花上數週的時間。

異步隨機梯度降低算法(Asynchronous SGD)是最理想的分佈式訓練方法。使用這種方法,你用N臺機器獨立來訓練同以個模型,但每一個時間步長都要共享一次權重參數。權重參數被託管在一臺單獨的「參數服務器」上,該服務器在每一個時間步長內都進行遠程過程調用(RPC),以得到最新數值併發送梯度更新。若是數據管道足夠好,你就能夠線性增長模型每秒內的訓練步數,方法是增長機器——由於機器之間互不依賴。然而,當機器增長時,因爲老機器更新了權重,新機器的權重會逐步過時或「落伍」。在分類網絡中,這裏的問題不大,把訓練的規模擴增到幾十臺機器不難。但PixelCNN卻對過期的梯度極其敏感,在它的異步隨機梯度降低算法內增長機器幾乎沒有任何收益。

另外一個方法,是用同步隨機梯度降低算法(Synchronous SGD)。使用這一方法,機器在每一個時間步長內都進行同步,且每臺機器的梯度都會被平均。它與隨機梯度降低算法在數學上是相同的。更多的機器會增大批尺寸。但同步隨機梯度降低算法(Sync SGD)容許各機器使用更小、更快的批尺寸,從而來增長每秒的步數(steps/sec)。

然而,同步隨機梯度降低算法也有它本身的問題。首先,它須要大量的機器常常進行同步,這必然致使停機時間的增長。其次,除非將每臺機器的批尺寸設爲1,不然它沒法經過增長機器來增長每秒訓練的步數。最終,我發現簡單的設置是用一臺機器安裝8個GPU來使用同步隨機梯度降低算法——但完成訓練仍需花上數天的時間。

採用大規模計算的另外一個辦法,是進行規模更大的超參數搜索。如何來肯定所用的批尺寸?把它們全都試一遍。在找到論文中所用的配置前,我嘗試過數百種配置。

如何定量評估結果,則是另一個難題。如何才能證實咱們的圖像比基準模型好?衡量超分辨率質量的典型方法,是對比強化圖像與原始圖像的對應像素點之間的距離(峯值信噪比,PSNR)。雖然說本模型輸出的臉部圖像在質量上明顯更好,但在像素對比上,平均看來它們還不如基準模型所輸出的模糊圖像。咱們嘗試用PixelCNN自己的類似度測量來證實咱們的樣本比基準版本有着更高的機率值,但一樣失敗了。最後,咱們把這項任務衆包給人類評估員——詢問他們哪些圖像看上去更真實。這倒奏效了。

具體的結果請查看這篇論文:超分辨率的像素遞歸

PixColor: 關於着色的嘗試

PixColor輸出的雙色模式

Slim的創造者Sergio Guadarrama一直在嘗試給圖像着色。他跟我說過一個試驗:用份量接口(該接口中圖像的灰度、顏色相互分離)獲取一張224×224×3的圖像,將其顏色通道降至28×28×2的超低分辨率,而後用雙線性插值法再把顏色通道放大,所得圖像與顏色分辨率很高的原始圖像相比幾乎沒有差異。

圖3:你須要的只是一些顏色。頂行是原始彩色圖像。中間行是下降採樣率後的真實色度圖像,尺寸縮小至28像素。底行是雙線性提升中間行的採樣率並結合原始灰度圖像的結果。

這代表,把問題變成僅預測低分辨率顏色,咱們就能夠簡化着色問題。我本來已準備好完全放棄PixelCNN了,由於它顯然沒法放大小圖像,但用來生成28×28×2的圖像仍是很可行的。經過將顏色數值簡化爲32個數字而非256,咱們進一步簡化了着色問題。

Sergio構建了一個「改進的」網絡,它可以清理低分辨率顏色的輸出,並將溢出邊界的顏色推回至正確位置——使用前饋式圖像對圖像卷積神經網絡進行訓練,損失僅爲L2。咱們還用一個預訓練好的ResNet做爲條件網絡,用以消解額外的損耗項需求,畢竟在超分辨率項目中咱們已經用過這樣的損耗項。

使用這些方法後,不管是衆包評估仍是用顏色直方圖相交評估,咱們都能得出ImageNet上最好的結果。事實證實,通過正確訓練的PixelCNN能夠很好地模擬圖像統計數據,不發生任何模式崩潰。

圖7:實驗室顏色空間中的顏色通道的邊緣統計數據。左:每種方法的直方圖以藍色顯示,ImageNet的測試數據集直方圖以黑色顯示。右圖:顏色通道的直方圖相交。

因爲模型爲每一個灰度輸入的可能着色聲明瞭一個機率分佈,咱們能夠對該分佈進行屢次取樣,以獲取同一輸入的不一樣着色。下圖用結構類似度(SSIM) 很好地展現了分佈的多樣性: 

圖8:爲證實咱們的模型可生成不一樣的樣本,咱們用多尺度SSIM對比了同一輸入的兩種輸出。上圖顯示了ImageNet測試數據集的SSIM距離直方圖。圖中在多個SSIM間距上分別顯示了每對圖像。SSIM值爲1表示兩張圖像徹底相同。

該模型離遠未完美。ImageNet儘管龐大,但不能表明全部的圖像。而該模型在處理非ImageNet圖像時並不理想。咱們發現,真實的黑白照片(不一樣於彩色轉化爲灰度的黑白照)會得出不一樣的統計數據,並能出現不少彩色照片中所沒有的物體。好比,Model T汽車的彩色照片很少,ImageNet圖像集中可能一張都沒有。採用更大的數據集和更好的數據擴增,也許能簡化這些問題。

想了解圖像質量的話,能夠來看看這些圖:

做爲對比,下面是用其餘算法來處理同一ImageNet測試數據集的結果:

最後,完整的細節都在咱們的論文中: PixColor: Pixel Recursive Colorization

失敗與未報告的實驗

這一年期間,我曾短暫着迷過許多業餘的小項目,儘管它們都失敗了……接下來我會簡單來描述其中的幾個:

一、大數的素因數分解

素因數分解一貫都是個大難題。但即使是現在,咱們仍在不斷髮現有關素數分解的新問題。若是爲深度神經網絡提供足夠的實例,它能不能找出一些新東西?Mohammad和我嘗試過兩種方法。他修改了Google機器翻譯的seq2seq神經模型,該模型把一個半素大數的整數序列做爲輸入,並將其素因素預測爲輸出。我則使用一個較爲簡單的模型,它將定長整數做爲輸入,並用幾個全鏈接層來預測輸入的分類:素數或合數。這兩種方法都只學到了最爲明顯的規律(若是尾數爲0,那它就不是素數!),咱們只能拋棄這個想法。

二、Adversarial Dreaming

受Michael Gygli的項目啓發,我想探究一下鑑別器可否充當它本身的生成器。爲此,我構建出一個簡單的二元分類卷積神經網絡來判斷輸入的真假。爲了生成圖像,你須要給出噪點並讓它使用梯度來更新輸入(有時被稱爲deep dreaming),令該網絡把「真實」類別最大化。該模型經過交替生成「假」實例來進行訓練,然後跟典型的GAN鑑別器同樣,經過升級權重來區分真假實例。

個人想法是,鑑於更少的架構決策,該網絡相比通常的GAN可能更容易訓練。事實上,它用MNIST確實能夠工做。下圖中每一欄都在展現:不一樣的噪音圖像被逐漸推向紅色MNIST數值的情形。

但我無法讓它在CIFAR-10數據集上工做,而且它的實際意義也極爲有限。這遺憾了,我相信 "Adversarial Dreaming" 會是一個很酷的論文題目。

三、使用PixelCNN來訓練生成器

PixelCNN生成樣本的時間過長,這讓我很沮喪。因而,我就想試試能不能用一個預訓練的PixelCNN訓練出前饋式圖像對圖像卷積神經網絡(8x8至32x32尺寸的LSUN臥室圖片集)。我所設置的訓練方法是:在前饋式網絡的輸出上進行自動迴歸。在PixelCNN下更新權重以便將機率最大化。它用這樣的線條生成了很是奇怪的圖像:

對異步隨機梯度降低算法的修改探索

如前文所述,不少模型都不適用於異步隨機梯度降低算法。最近,一篇名爲DCASGD論文提出了一種解決過期梯度問題的可能方法:在機器開始步進去應用它們權重的前,在權空間(weight space)使用差分向量。這種方法可大大減小每個人的訓練時間。不幸的是,我沒能在TensorFlow上重複他們的結果,也沒法實現我所想出的幾個相似想法。這裏可能有Bug。(若是想獲取個人實現方法,請經過內部渠道聯繫我)

想法和總結

聊了這麼多的技術,我大體作些總結,也算是比較深的心得體會吧。

做爲軟件工程師,我在機器學習方面並無什麼經驗。但基於過去一年對深度學習的研究,我來分享一下在該領域的整體見解,及其同範圍更廣的軟件領域之間的關係。

我堅信,機器學習將改變全部行業,並最終改善每一個人的生活,許多行業都會因機器學習所提供的智能預測而受益。

對於我,我在這個項目中,最初的目標是,在不久的未來,全部人均可以看到查理·卓別林這類老電影的4K版。

不過,我確實發現,這一模型的構建、訓練和調試都至關困難。固然,大部分的困難是因爲我缺少經驗,這也代表有效訓練這些模型是須要至關豐富的經驗的。

個人工做集中在機器學習最爲容易的分支上:監督式學習。但即使有着完美的標註,模型開發仍十分困難。彷佛,預測的維度越大,構建模型所花的時間就越長(例如:花大把的時間進行編程、調試和訓練)。

所以,我推薦全部人在開始時都儘量簡化和限制你的預測

舉一個咱們在着色實驗中的例子:咱們在開始時試圖讓模型預測整個的RGB圖像,而非只預測顏色通道。咱們認爲,神經網絡很容易就能處理好灰度圖(intensity image)並輸出出來,由於咱們使用的是跳躍鏈接(skip connection)。只預測顏色通道依然能改進性能。

若是我以主觀、本能的方式使用「工做」來描述軟件:圖像分類工做起來彷佛很穩健。生成式模型幾乎不多能工做,人們也不太瞭解這種模型。GAN能輸出很好地圖像,可是構建起來幾乎是不可能的——個人經驗是,對架構做出任何小改動都有可能使它沒法工做。我據說強化學習更加困難。但因經驗不足,我對遞歸神經網絡不予置評。

可是,隨機梯度降低算法工做起來是太過於穩定,即便是嚴重的數學錯誤也不會讓它完全失敗,僅稍微有損於性能。

由於訓練模型常常須要花費數日,這是一個很是緩慢的 修改—運行 循環。

測試文化還沒有徹底興起。訓練模型時咱們須要更好的評斷方法,網絡的多個組成部分須要維持特定的均值和變量,不能過分擺動或者留在範圍內。機器學習漏洞使系統的heisenbugs能特別輕鬆地經過測試。

並行化能帶來的好處頗有限。增長計算機數後,大規模的超參數搜索會變得更加容易,可是理想狀況下,咱們會設計不用仔細調試也能正常工做的模型。(實際上,我懷疑超參數搜索能力有限的研究人員將不得不設計出更好的模型,所以他們設計出的模型更加穩定)。

不幸的是,對於不少模型而言,異步隨機梯度降低算法並無什麼用處——更加精確的梯度一般用處不大。這就是爲何 DCASGD 的研究方向很重要的緣由。

從軟件維護的角度看,關於如何組織機器學習項目你們都鮮有共識。

就像是Rail出現以前的網站:一羣隨機PHP腳本,商業邏輯和標記符號亂混一氣。在TensorFlow項目中,數據管道、數學和超參數/配置管理無組織地混爲一團。我認爲咱們還未發現精美的結構/組織。(或者說是還未從新發現,就像DHH從新發現並普及 MVC那樣。)個人項目結構一直在進步,可是我不會認爲它是精美的。

框架會繼續快速進化。我開始使用的是Caffe,不得不稱讚TensorFlow帶來的好處。如今,PyTorch 和 Chainer之類的項目使用動態計算圖形取悅客戶。漫長的修改—行循環是開發更好模型的主要阻礙——我懷疑能優先實現快速啓動和快速評估的框架最終會取得成功。儘管擁有TensorBoard和iPython之類的有用工具,可是檢查模型在訓練期間的活動仍然很難。

論文中的信噪比很低。可是須要改進的空間還很大。人們一般不會坦率認可他們模型的失敗之處,由於學術會議更看重的是準確度而不是透明度。我但願學術會議能接受提交博客文章,並要求開源實現)。Distill 在這方面的努力值得稱讚。

對機器學習而言,這是一個使人激動的時代。各個層面上有大量工做須要完成:從理論端到框架端,還有不少值得改進的空間。它幾乎和因特網的誕生同樣使人激動。加入這場技術革命吧!

這是你的機器學習系統嗎?

是啊!將數據倒到這一大堆線性代數中,而後在另一端收集答案。

若是答案是錯誤的呢?

只管攪動這堆線性代數,直到結果開始看起來正確爲止。

相關文章
相關標籤/搜索