我發(fā)現(xiàn),有時候人們會把神經(jīng)網(wǎng)絡(luò)當(dāng)作“不過是機(jī)器學(xué)習(xí)工具箱中的工具之一而已”。它有優(yōu)點(diǎn)也有缺點(diǎn),在某些領(lǐng)域有用,并且可以幫助你打贏 Kaggle 比賽。很不幸,這種觀點(diǎn)完全是只見樹木,不見森林。神經(jīng)網(wǎng)絡(luò)可不只是又一種分類器而已,它代表著一種根本轉(zhuǎn)變的開始,這種轉(zhuǎn)變與我們?nèi)绾伍_發(fā)軟件有關(guān)。它就是軟件2.0。
我們對軟件1.0已經(jīng)比較熟悉 — 它們由計(jì)算機(jī)語言(如 Python、C++ 等)所開發(fā)?! ∮沙绦騿T顯式指定計(jì)算機(jī)指令。隨著編寫一行行代碼,程序員在整個程序空間中可以確定一個符合期待行為的點(diǎn)與之對比的,軟件2.0由更抽象、人類更難理解的語言(比如說,神經(jīng)網(wǎng)絡(luò)中的權(quán)重)開發(fā)。沒人可以直接參與這種代碼的編寫,因?yàn)樗婕暗酱罅康臋?quán)重(往往上百萬數(shù)量級),并且(我試過)直接編寫權(quán)重某種意義上是很困難的。
取而代之的是,我們?yōu)槌绦虻男袨橹付繕?biāo)(比如,“符合數(shù)據(jù)集中樣本的輸入輸出對”,又或者“贏得圍棋比賽”),并寫好程序的骨架(比如神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)),這樣就在整個程序空間中確定了一個可以用于搜索的子集,然后就可以使用我們所有的計(jì)算資源在這個空間中搜索可用的程序。
對于神經(jīng)網(wǎng)絡(luò)而言,我們將搜索限制在程序空間的一個連續(xù)的子集上,并且,使用反向傳播和 SGD 方法進(jìn)行搜索,(出人意料地)這種搜索方式挺有效。
更具體地對比,軟件1.0是將人工設(shè)計(jì)的源碼(比如 .cpp 文件)編譯為可以有效工作的二進(jìn)制文件。而軟件2.0的源碼通常由兩部分組成:1)定義了目標(biāo)行為的數(shù)據(jù)集 2)給定代碼大致結(jié)構(gòu),但是需要填充細(xì)節(jié)的神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)。訓(xùn)練神經(jīng)網(wǎng)絡(luò)的過程,就是將數(shù)據(jù)集編譯成二進(jìn)制文件的過程 — 得到最終的神經(jīng)網(wǎng)絡(luò)。時至今日,大多數(shù)實(shí)際應(yīng)用中,神經(jīng)網(wǎng)絡(luò)的結(jié)構(gòu)及訓(xùn)練系統(tǒng)已經(jīng)日益標(biāo)準(zhǔn)化為一種商品,所以,大部分活躍的“軟件開發(fā)”工作某種形式上變成了組織、增加、調(diào)整和清理帶標(biāo)簽的數(shù)據(jù)集。這從根本上改變了我們迭代軟件的編程范式,將開發(fā)團(tuán)隊(duì)分成了兩撥:軟件2.0的程序員(數(shù)據(jù)標(biāo)記員)負(fù)責(zé)編輯和擴(kuò)大數(shù)據(jù)集,而另一小撮人,維護(hù)著與訓(xùn)練有關(guān)的基礎(chǔ)設(shè)施以及分析、可視化和標(biāo)注等接口。
事實(shí)證明,對于真實(shí)世界中的很多問題,采集數(shù)據(jù)(更泛化地說,確定期待的行為)比顯式地寫程序要容易得多。
由于以上以及以下我將要介紹的軟件2.0的諸多好處,我們正在見證工業(yè)界大量代碼從軟件1.0遷移至軟件2.0的重大轉(zhuǎn)變。軟件1.0吞噬著整個世界,軟件2.0(AI)在吞噬軟件1.0。
1.轉(zhuǎn)變進(jìn)行時
讓我們來看看這場轉(zhuǎn)變中的具體領(lǐng)域的例子。我們會發(fā)現(xiàn),在過去幾年,對于這些領(lǐng)域,我們放棄了嘗試通過顯式寫代碼的方式去解決復(fù)雜問題,取而代之的,是轉(zhuǎn)向了軟件2.0。
圖像識別:圖像識別之前常常是由特征工程組成的,只是在最后加入一點(diǎn)點(diǎn)機(jī)器學(xué)習(xí)(比如:SVM)。
之后,通過使用更大的數(shù)據(jù)集(比如 ImageNet)和在卷積神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)空間中進(jìn)行搜索,我們發(fā)現(xiàn)了更強(qiáng)大的視覺特征。最近,我們甚至不再相信自己手寫的網(wǎng)絡(luò)結(jié)構(gòu),而開始用類似的方法搜索(最優(yōu)網(wǎng)絡(luò)結(jié)構(gòu))。
語音識別:以前的語音識別工作,涉及到大量的預(yù)處理工作、高斯混合模型和隱式馬爾科夫模型,但是現(xiàn)在,幾乎只需要神經(jīng)網(wǎng)絡(luò)。還有一句與之非常相關(guān)的搞笑名言,是 1985 年 Fred Jelinek 所說:“每當(dāng)我開除一個語言學(xué)家,我的語音識別系統(tǒng)的性能就會提高一點(diǎn)”。
語音合成:歷史上,語音合成一直采用各種拼接技術(shù),但是現(xiàn)在,SOTA(State Of The Art) 類型的大型卷積網(wǎng)絡(luò)(比如 WaveNet)可以直接產(chǎn)生原始音頻信號輸出。
機(jī)器翻譯:機(jī)器翻譯的實(shí)現(xiàn)之前常常采用基于短語的統(tǒng)計(jì)方法,但是神經(jīng)網(wǎng)絡(luò)正迅速占領(lǐng)了統(tǒng)治地位。我最喜歡的網(wǎng)絡(luò)結(jié)構(gòu)就與多語言訓(xùn)練有關(guān):一個模型就可以把任意源語言翻譯成任意目標(biāo)語言,并且是無監(jiān)督學(xué)習(xí)的(或者只需要很弱的監(jiān)督)。
游戲:很長一段時間里,人們通過手寫圍棋程序來進(jìn)行游戲?qū)?zhàn),但如今,AlphaGo Zero(一種觀察棋盤原始狀態(tài)并對戰(zhàn)的卷積網(wǎng)絡(luò))成為了圍棋領(lǐng)域最強(qiáng)玩家。我預(yù)測在其它領(lǐng)域,如 DOTA 2、星際爭霸,也會有類似的結(jié)果。
數(shù)據(jù)庫:更多的本處于 AI 領(lǐng)域之外的傳統(tǒng)系統(tǒng),也顯露出向軟件2.0轉(zhuǎn)變的早期跡象。比如,“索引結(jié)構(gòu)學(xué)習(xí)案例”里,使用神經(jīng)網(wǎng)絡(luò)替代了原有的數(shù)據(jù)管理核心組件,其速度最高比做了緩存優(yōu)化的 B樹快70%,同時還省了一個數(shù)量級的內(nèi)存。
你可能注意到了上面很多鏈接的工作是 Google 做的。這是因?yàn)槟壳?Google 就是將大量自己的代碼轉(zhuǎn)變?yōu)檐浖?.0的排頭兵?!耙粋€萬能的模型”所描繪的草圖是:將原本散落在各個領(lǐng)域的基于統(tǒng)計(jì)的效果,融合成一個整體來理解世界。
2.軟件2.0的好處
為什么我們更傾向于把復(fù)雜程序移植到軟件2.0?顯然,一個簡單的答案是實(shí)踐證明它的效果更好。然而,還有很多其它的理由值得我們選擇軟件2.0。讓我們看看軟件2.0(卷積神經(jīng)網(wǎng)絡(luò)為代表)與軟件1.0(生產(chǎn)級別的C++代碼庫為代表)相比的好處,對于軟件2.0:
同質(zhì)化計(jì)算:一個典型的神經(jīng)網(wǎng)絡(luò)僅有兩種操作組合而成:矩陣乘法和激活函數(shù)(ReLu)。傳統(tǒng)軟件里的指令與之相比,明顯會更加復(fù)雜和異構(gòu)。由于只要用軟件1.0的方法實(shí)現(xiàn)非常少部分的核心代碼(比如矩陣乘法),正確性/性能驗(yàn)證都會容易很多。
對芯片更友好:因?yàn)樯窠?jīng)網(wǎng)絡(luò)所需要的指令集相對更小,作為推論,在芯片上實(shí)現(xiàn)它們將會更容易,比如,使用自定義 ASIC 芯片、neuromorphic chips 等等。當(dāng)?shù)湍芎牡闹悄茉O(shè)備充斥在我們周圍時,這個世界也將為此改變。比如,把預(yù)訓(xùn)練卷積網(wǎng)絡(luò)、語音識別、WaveNet 語音合成網(wǎng)絡(luò)裝載到便宜又小巧的設(shè)備中,這樣你可以用它連接其它東西。
常量級的運(yùn)行時間:一個典型的神經(jīng)網(wǎng)絡(luò)的每次前向迭代,需要的計(jì)算量(FLOPs)是高度一致的。在你手寫的復(fù)雜 C++ 代碼中會出現(xiàn)的各種執(zhí)行分支,在軟件 2.0 中是不存在的。當(dāng)然,你也許會有動態(tài)圖的需求,但是執(zhí)行流通常也是被嚴(yán)格限制了。即使在這種情況下,我們幾乎也能保證,不會陷入未預(yù)料的無限循環(huán)之中。
常量級的內(nèi)存消耗:和上面一點(diǎn)相關(guān),因?yàn)闆]有動態(tài)分配內(nèi)存的需要,所以幾乎沒有可能需要與硬盤進(jìn)行 swap,代碼中也沒內(nèi)存泄漏的可能。
高度可移植:同傳統(tǒng)的二進(jìn)制文件或腳本相比,一連串的矩陣乘法操作要更容易運(yùn)行在各種計(jì)算機(jī)環(huán)境下。
敏捷開發(fā):如果你在寫 C++,并且有人希望你開發(fā)速度提高2倍(可以犧牲性能的前提下),那么為適配新要求而調(diào)整系統(tǒng)可不是一件小事。然而,在軟件2.0中,我們只需要移除掉(計(jì)算圖中)一半的路徑,然后重新訓(xùn)練,就能得到精確度差一點(diǎn)點(diǎn),但訓(xùn)練快兩倍的結(jié)果。這很神奇。反過來說,只要你得到了更多的數(shù)據(jù)和算力,你可以馬上通過擴(kuò)大計(jì)算圖和重訓(xùn)練的方法,得到更好的實(shí)際效果。
融合模塊以求最優(yōu):普通軟件通常被分解成多個模塊,各個模塊中間通過共有函數(shù)、API 或者端到端的方式通信。然而,對于軟件2.0,如果一開始2個相交互的模塊是獨(dú)立訓(xùn)練的,我們之后也很容易在整個系統(tǒng)中進(jìn)行反向傳播。想想看,如果你的瀏覽器可以自動設(shè)計(jì)底層指令,從而提高加載頁面的速度;或者說你導(dǎo)入的計(jì)算機(jī)視覺庫(比如 OpenCV)可以根據(jù)你的特定數(shù)據(jù),自動調(diào)整行為;這將多么美妙。在軟件2.0中,這些都是基本操作。
比你更優(yōu)秀:最后,也是最重要的一點(diǎn),在很多垂直領(lǐng)域中,神經(jīng)網(wǎng)絡(luò)產(chǎn)生的代碼要比你或者我寫的代碼好。就目前而言,起碼在圖像、視頻、語音這些領(lǐng)域中是這樣的。
3.軟件2.0的缺點(diǎn)
軟件2.0也有一些缺點(diǎn)。當(dāng)優(yōu)化完成后,我們可以得到實(shí)踐中很有效的巨大網(wǎng)絡(luò),但是很難解釋它為什么有效。在許多領(lǐng)域,我們可以選擇比較好理解但是只有90%精度的模型;或者選擇不理解,但是有99%精度的模型。
軟件2.0會出現(xiàn)不直觀的、尷尬的錯誤,甚至更糟糕的,還可能“默默出錯”。比如,如果在訓(xùn)練時默默地采納了具有偏差的數(shù)據(jù),當(dāng)數(shù)據(jù)數(shù)量大到百萬級別時,再想分析和檢查原因,就變得非常困難了。
最后,軟件2.0的奇怪特性也在不斷出現(xiàn)。比如,對抗樣本和攻擊樣本的存在,使得軟件2.0的不可解釋性問題變得更加突出。
4.軟件2.0編程
軟件1.0的代碼,是我們手寫的代碼。軟件2.0的代碼,是基于評估準(zhǔn)則(比如“把訓(xùn)練數(shù)據(jù)正確分類”)優(yōu)化得來的。對于那些原理不明顯,但是可以反復(fù)評估表現(xiàn)的程序,都適用于這種轉(zhuǎn)變,因?yàn)榕c人寫的代碼相比,優(yōu)化方法找到的代碼要好得多。
眼光很重要。當(dāng)你意識到神經(jīng)網(wǎng)絡(luò)不僅僅是機(jī)器學(xué)習(xí)工具集中一種好用的分類器,而把軟件2.0當(dāng)作嶄露頭角的全新編程范式時,可以外推的事情就變得顯而易見了,還有大量的工作可以去做。
具體而言,我們已經(jīng)發(fā)明了大量輔助程序員做軟件1.0開發(fā)的工具,比如強(qiáng)大的 IDE,它可以具備很多功能,像語法高亮、調(diào)試器、profiler、符號跳轉(zhuǎn)、集成 git 等等。軟件2.0中,編程工作變成了積累、調(diào)整、清理數(shù)據(jù)集。比如,當(dāng)某些極端情況下,神經(jīng)網(wǎng)絡(luò)失效了,我們并不會去通過寫代碼來修復(fù)問題,而是導(dǎo)入更多這種情況下的數(shù)據(jù)就可以了。
誰將開發(fā)第一款軟件2.0的 IDE?它應(yīng)該可以在數(shù)據(jù)集相關(guān)的所有工作流中都發(fā)揮作用,包括積累數(shù)據(jù)、可視化、清洗數(shù)據(jù)、標(biāo)記數(shù)據(jù)、生產(chǎn)數(shù)據(jù)。也許這種 IDE,會根據(jù)每個樣本的 loss,把網(wǎng)絡(luò)懷疑被錯誤標(biāo)注的圖像給拎出來,或者通過預(yù)測提示應(yīng)該選用的標(biāo)簽的方式輔助標(biāo)注數(shù)據(jù),再或者依據(jù)網(wǎng)絡(luò)預(yù)測的不確定性,推薦適合標(biāo)注的樣本。
類似的,Github 是軟件1.0時代非常成功的網(wǎng)站。是否有可能出現(xiàn)軟件2.0時代的 Github?軟件2.0時代,倉庫將是數(shù)據(jù)集,而 commit 是由增加和編輯數(shù)據(jù)標(biāo)簽組成的。
傳統(tǒng)的包管理工具和部署手段,比如 pip、conda、docker 等幫助我們更輕松地部署和安裝軟件。在軟件2.0時代,如何更有效地部署、分享、導(dǎo)入和運(yùn)行軟件呢?在神經(jīng)網(wǎng)絡(luò)中,與 conda 對等的東西又會是什么呢?
簡而言之,在可以低成本反復(fù)評估、并且算法難以顯式設(shè)計(jì)的領(lǐng)域,軟件2.0都將日益流行起來。當(dāng)我們考慮整個開發(fā)生態(tài)以及如何適配這種新的編程范式時,會發(fā)現(xiàn)很多令人興奮的機(jī)會。長遠(yuǎn)來看,這種編程范式擁有光明的未來,因?yàn)樵絹碓酱_認(rèn)的是:當(dāng)我們某天要開發(fā)通用人工智能時,一定是使用軟件2.0。