彩雲ICLR 2018頂會論文帶你進入「組合式神經編程」的世界
GIF
大家好,年前彩雲科技就爆出重磅消息,肖達、廖若雨和袁行遠的論文《Improving the Universality and Learnability of Neural Programmer-Interpreters with Combinator Abstraction》被國際頂級學術會議ICLR2018接受。小編苦苦研讀了一個春節假期終於搞明白這篇論文原來是將神經網路的泛化能力與經典AI的組合、推理能力結合到了一起,可以用於解決自然語言處理領域的一系列問題,並有望在攻克圖靈測試的道路上邁進一步。於是,小編趕緊從肖老師那裡淘來了關於論文構思的第一手材料,以及肖達老師親自撰寫的科普解讀,以及對他的獨家專訪,今天一併奉獻給大家。
前言
什麼是神經編程
神經編程(Neural Programming,簡稱NP),顧名思義,就是利用神經網路來寫程序。我們都知道,神經網路擅長的是模式識別和預測,並不擅長寫程序這樣的邏輯性很強的任務。所以,由此可知這個任務的難度非同小可。我們需要將神經網路的泛化能力優勢與傳統AI的邏輯推理能力巧妙地結合起來才能實現我們的預期。但是,一旦我們造出靠譜的神經編程機器,它就有可能兼具形象思維和高級的邏輯推理能力,這有助於我們解決自然語言處理中的一系列高難度任務,如閱讀理解、機器翻譯、人機對話等,甚至有可能突破圖靈測試難題。
什麼是組合子
組合子(combinator),也就是函數的函數。我們都寫過計算機程序,函數或者子過程可以封裝一部分功能。那麼函數的函數就是將函數的指針作為參數傳給另一個函數實現的。例如,y=x^2是一個函數,求導Derivative就是一個函數的函數,我們將y=x^2這個函數的指針傳遞給Derivative,就可以得到這個函數的導數2x了。將這種組合子作為我們操作的基本單元,就可以實現功能強大的計算。
關於ICLR
ICLR,全稱為「International Conference on Learning Representations」(國際學習表徵會議),2013 年才由Yoshua Bengio和Yann LeCun牽頭創辦。這個一年一度的會議雖然今年才辦到第五屆,但已經被學術研究者們廣泛認可,被認為「深度學習的頂級會議」。ICLR 不同於其它國際會議,它推行了 Open Review 評審制度,論文質量普遍很高,錄用率僅30%多,被稱為深度學習界的無冕之王。
論文介紹
「組合式神經編程解釋器」簡介
為什麼神經編程近年來會成為學界研究的一個熱點呢?其實研究神經編程的最大意義並不是真的搞出個AI programmer代替人類程序員。我們知道,現在的深度神經網路在視覺識別、語音識別等低級感知任務上的已經超過人類,但在邏輯推理、規劃、搜索、語言理解等需要「高級認知」能力的任務上的表現卻遠沒有令人滿意。而我們所能想到的最全面和集中的體現這種高級認知能力的活動,可能非編程莫屬了。程序設計不僅僅是我們熟悉的寫一段代碼解決一個演算法題(例如排序),其實很多困難AI問題歸根結底都要用程序求解。所以,讓神經網路學習構造和解釋執行程序來解決問題,是提升其高級認知能力的可行手段。從更技術的層面說,高級認知能力的一個核心,是抽象和組合能力。我們想讓機器具有抽象思考和舉一反三的泛化能力,就要把合適的抽象機制引入模型中。這些抽象機制哪裡來呢?計算機科學的先輩們已經給我們準備好了一個大寶藏,就是程序設計語言的各種抽象機制及其在編譯器/解釋器中的實現方式。這裡的程序設計語言不僅限於大家熟悉的命令式編程語言(如C/C++,Java),還包括函數式編程語言(如Lisp、Haskell)和聲明式編程語言(如Prolog)。
言歸正傳,下面介紹我們的這篇論文。
戲說版
時空輪轉,一個叫Agent的同學,來到了一個需要不斷打怪升級的陌生世界。純小白的他要從頭開始學習各種戰鬥技能。好在A同學有學霸潛質,善於學習和思考,有悟性。身無分文的A同學,唯一的初始裝備是一個空的技能卡槽。卡槽背面寫著簡單的行動規則:每get到一個新技能,就把寫有技能名稱和描述(例如,一技能:[舉盾、前沖、砍一劍])的技能卡放到技能卡槽里,以備需要時取出施展。每次行動前,先根據當前情況,從卡槽里取出一張技能卡。每做完一個動作,就根據血量、技能恢復進度等自身狀態,周圍的敵我情況和當時手裡拿的技能卡,決定下一個動作,並更新自身狀態。下一個動作做完後,再根據新的周圍情況和狀態,重複這個過程,直到把當前技能打完。怎麼get新技能呢?有兩種方式:足夠幸運的話,會遇到一個老師手把手一個動作一個動作的教各個技能,否則,就只能直接上戰場,在要麼成功殺敵要麼不幸陣亡的不斷錘鍊中學習成長(好在可以無限復活)。
A同學一開始的學習進度很慢,學到的也都是些基礎技能,練了很久還在青銅級徘徊,經常被虐,只能打打小怪。直到有一天,他猛然醒悟:原來一個技能里的下一個動作,除了砍一劍這種具體動作,還可以是一個已經學到的技能!如果是後者,就把已學技能的卡片從卡槽里取出,用同樣的套路開始打,打完後再返回之前的技能接著打,perfect。這樣,A同學就能把技能組合起來變成威力倍增的組合技,技能卡槽里多了像[一技能、二技能、大招]這種新開發的組合技連招後,功力突飛猛進,大殺四方,很快升級為黃金英雄。
然而A同學並未就此滿足,為了避免單一英雄被克制,他開始嘗試變身成各種英雄,學習他們的技能和打法。隨著要掌握的普通技能和組合技能越來越多,技能卡槽越插越滿,A同學對學習新的組合技漸感力不從心,也經常狗熊掰苞米似的學了新的忘了舊的。升級進入瓶頸期。直到有一天,也許是他的不斷努力探索得到了上天的眷顧,A同學再次頓悟:看似五花八門的各種組合技,如果忽略被組合的具體技能,組合的方法本身不也是一種技能嗎?!而且組合技雖多,其背後的組合方法好像就只有那麼幾種!頓悟後,A同學學習效率大增,例如,從英雄甲的「一二大」三連和英雄乙的「二三大」三連總結出「三連」這個「元技能」後,他瞬間學會了其他英雄的各種三連。僅僅掌握了幾種元技能後,A同學就輕鬆精熟了各路英雄的打法,終於成為無敵寂寞的王者。
術語對照表:動作 = primitive action,技能 = policy / program /procedure,組合技 = compound procedure,技能名稱 = program key,技能描述 = program embedding,技能卡槽 = program memory,自身狀態 = hidden state,周圍情況 = environment input,手把手教 = supervised learning,戰鬥中學習 = reinforcement learning,青銅英雄 = plain RL agent,黃金英雄 = hierarchical RL agent / NPI,王者英雄 = CNPI,元技能 = combinator
正經版
本文工作的基礎是神經編程解釋器(NPI,Neural Programming Interpretor,即A同學的第一次頓悟),相比之前的神經編程模型,NPI的最大亮點是有個program memory來存儲已經學到的子過程,解釋執行程序時可以調用program memory中的子過程,因此NPI可以在已學到子過程的基礎上學習新程序,而不必從頭學起,從而使得用一個核心控制器(core controller)持續不斷的學習從簡單到複雜的程序成為可能。實際上,NPI引入了程序設計中一種非常基本和常用的抽象和組合機制——定義子過程並用子過程的嵌套調用實現複雜功能,即過程抽象。
但NPI也存在一些重要缺陷。首先,由於NPI依賴一個單獨的核心控制器去學習解釋執行所有的程序,隨著program memory中學到的子過程越來越多,學習新程序的難度也越來越大。其次,很多程序雖然表面不同,但其實有相似或相同的結構(見下圖右半部分十進位加法和冒泡排序程序),而NPI把它們都當成完全不同的程序花同樣的力氣去學,沒有利用它們的相似性提高學習效率。這些問題導致NPI雖然目標是模擬通用圖靈機,但無論在理論上還是實驗中都無法達到真正的universal——即能夠正確解釋執行任何程序;並且只能以有監督的方式訓練,用程序執行的trace作為訓練樣本(即手把手教)。
造成這些問題的根本原因是,NPI雖然利用過程抽象對程序進行分解降低了每個子過程的複雜度,但由於抽象層次不夠高,分解得並不徹底。
為了解決NPI的這些問題,我們在這篇論文提出組合式NPI(CNPI,Combinatory Neural Programmer-Interpreter即A同學的第二次頓悟),引入程序設計中另一個非常重要的抽象機制,即函數式編程中的高階函數,也叫組合子(combinator)。顧名思義,高階函數就是函數的函數,一般是通過把函數作為參數傳給另一個函數實現的。CNPI中的組合子(combinator)是種特殊的有參過程,它只能調用作為參數傳給它的子過程,組合子的作用就是把這些子過程組合成一個新的過程。特別要注意的是:因為子過程是通過參數傳給組合子的,所以每個組合子實現的用形參表示的子過程的組合方式和被組合的實際子過程(實參)無關。換句話說,組合子表達的是一個抽象的關於「如何組合」的概念,就像「三連」元技能一樣。
和普通過程不同,由於組合子的高度抽象性和由此帶來的可復用性,它們的數量並不需要很多。這篇論文的討論限定在演算法任務。那麼我們要問,到底需要幾個組合子,才能搞定所有的演算法任務呢?論文提出:四個就夠了。這四個組合子分別表達四種最普遍的程序結構,它們是:
seq(順序,表達順序執行)、
cond(條件,表達if-then-else等分支結構)、
linrec(線性遞歸,表達for循環、while循環等循環結構)
treerec(樹遞歸),表達多次遞歸調用,例如在快速排序和圖的深度優先遍歷中。
前三個組合子的偽代碼見下圖。樹遞歸組合子treerec比較複雜,這裡就不介紹了。
除了子過程參數,組合子還會接收一個檢測子(detector)參數。如果說子過程是主動技能,那檢測子可以看成被動技能。它們並不會被顯式調用執行動作,而是持續的提取環境中的某種信息,提供給組合子用於條件判定(例如分支條件或循環的終止條件)。檢測子是NPI中encoder的精簡版。注意組合子linrec和treerec遞歸調用自身(self),以實現某種循環結構。
僅有這四個組合子還不夠,因為單靠它們無法構成完整的程序,也就只能把原始動作做一次最淺層組合。我們還要引入另一種特殊過程——應用子(applier)。應用子調用一個組合子並給它提供參數,把有參的組合子封裝成跟無參的原始動作一樣的東西。應用子就像粘結劑把多個組合子連接起來構成完整程序,允許把組合出的子過程再做組合,通過任意多層的組合實現任意複雜的程序。於是一個程序的完整執行過程可能是這樣子:應用子A調用組合子b,組合子b又調用應用子C,應用子c又調用組合子D,……直到應用子X或組合子y調用原始動作Z。這個組合子和應用子的循環調用是個非常基本的計算結構,實際上,它正是函數式編程語言解釋器的核心eval-apply循環。《計算機程序的構造和解釋》(即傳說中的神書SICP)第4章對此作了很好的講解。下圖給出了冒泡排序的一趟冒泡過程的子過程BSTEP的正常版本和組合式版本以及執行trace。
我們把這樣構造出的程序,叫組合式程序(combinatory program)。可是這種構造方法有什麼特別的好處呢?這也是理解為什麼CNPI能universal,即本論文主旨的關鍵。我們回頭再來看一下構成組合式程序的四種特殊的基本子過程:
1)組合子:總個數固定(本文中為4),且每個組合子能調用的子過程的個數有限(=組合子參數的個數,本文中也為4);
2)應用子:總個數無限制,執行一次調用即返回,沒有任何分支循環等控制結構,相當於一個只有一行的宏定義;
3)檢測子:每個檢測子可以單獨訓練一個神經網路來實現,存儲在detector memory中;
4)原始動作:解釋執行由每個具體領域提供,不需要學習。
一方面,我們看到,四種子過程都是高度受限的,所以它們的解釋執行很容易被學習。而且由於應用子和檢測子這兩種子過程的特殊性,CNPI的架構可以保證即使不斷學習新的子過程添加到program memory,後添加的子過程也不會對已有子過程的正確解釋執行造成干擾(見論文第4節定理1)。另一方面,通過這四種極其簡單的子過程的相互調用,卻可以表達任意複雜的程序(實際上我們認為組合式程序是圖靈完備的,但論文中沒有證明,只給出把普通程序轉化為組合式程序的一個一般演算法,見附錄B的演算法2)。正是這兩點保證了CNPI是universal的。
至此我們已經搞出一種可以被分解得非常徹底的組合式程序,可離大功告成還差重要一步:要讓NPI通過訓練能正確解釋執行它,為此我們還要對NPI架構和解釋執行過程做了幾個重要擴展,以讓新的CNPI架構和這種新程序「兼容」:
1)增加了detector memory來保存檢測子,它和program memory一樣也是一個key-value存儲結構。
2)增加了個parser專門用來解釋執行應用子。
3)為了能給組合子傳遞參數,應用子調用組合子時,要構造一個幀結構(frame),並在裡面填好組合子需要的子過程參數和檢測子參數的key。幀可以看成是一個動態創建的局部program memory,為每個組合子的調用提供一個執行環境。解釋執行子過程時,由原來每步用輸出的key直接到program memory里找下一步調用子過程的向量,變成每步先從當前幀里找到下一步調用子過程的key,再拿這個key到program memory里找程序向量。這種間接定址使每步決定下一步調用子過程的搜索範圍由program memory里存儲的所有子過程(個數可以不斷增長)縮減為一個幀里的固定4個子過程參數,大大降低了組合子的學習難度。
論文的訓練方法、分析和實驗等部分不再詳細介紹,只列出幾個重要結果:
結語和展望
CNPI的原理就介紹到這裡。你可能會問,搞了一堆這麼複雜的東西除了浪費腦細胞還有什麼實際用途呢?確實,離實際應用尚有距離或者說缺乏殺手級應用,可以說是目前幾乎所有神經編程工作(包括本論文)的一個通病。而我們認為CNPI的最大價值,正在於它的思想和基本框架有應用到演算法編程以外領域的潛力(戲說里的例子也多少體現出這點)。其實自然語言可以看成一種程序,而所謂自然語言理解,就是人腦對這種程序的解釋執行。當我們分析自然語言程序時,會發現它之所以有極強的表達能力,使你在讀完這篇文字後能理解CNPI這麼複雜的東西,正是因為也包含函數抽象、高階函數等抽象和組合機制。這裡不再詳述,感興趣的同學可以去看Montague語法等自然語言語義學研究的相關書籍和論文。CNPI的特性使它有可能發展成自然語言解釋器的內核,進而構建能更好的理解和執行人類語言和指令的且能終身學習的agent。當然,本論文的工作只是我們在通用人工智慧的探索之路上邁出的一小步,就像A同學一樣,前方還有更多的未知在等待著我們。
完整版
北京海淀區學院路甲5號768創業園C座04號。
作者介紹
肖達博士畢業於清華大學計算機科學與技術系,現為北京郵電大學網路空間安全學院講師,彩雲科技首席科學家,集智俱樂部核心成員,集智科學家。目前研究興趣包括深度學習、人工智慧、認知科學。曾在集智俱樂部發起並主持「腦與deep learning讀書會」、「高級認知deep learning讀書會」等線下活動。
採訪肖達老師
Q:請問您是什麼時候開始創業的,為什麼想到做彩雲天氣?
A:2010年左右,我的研究興趣從雲安全轉到人工智慧,一開始的目標很「宏大」,試圖用神經生物學、統計物理等理論方法弄清人腦認知的基本原理,揭開智能的本質。2012年底在集智俱樂部的讀書會了解到行遠的用雷達圖做短臨降雨預報的想法,覺得很酷就加入一起做了,當時對天氣是純小白,在過程中工作重心逐漸轉到更加具體的深度學習研究及其在天氣上的應用。發現與理論研究相比,這種扎進一個完全陌生的領域,以解決實際問題為出發點,死磕並最終搞定,用技術創新給數以百萬的用戶提供更好的服務,是一種全新的體驗,很有成就感。幾年做下來,公司依賴技術優勢逐漸發展壯大,自己的提升也非常大。
Q:你的論文研究的方向是神經編程,您是如何想起來做這個方面的研究?這個研究以後會不會用於商業用途?
A:在彩雲做產品相關的演算法研發的同時,我一直在思考怎樣給擅長基於模式匹配的感知的深度神經網路加入人的高階認知,即抽象思維能力,以實現更像人類的通用智能。我認為神經編程是達到這個目標的一條有前景的路,所以一直在關注這個方向,尤其是2016年NPI的工作出來後。但NPI有一些在我看來很嚴重的缺陷,2017年我接觸到函數式編程和解釋器領域,發現可以借鑒一些思想和方法解決NPI的問題,就寫了這篇CNPI的論文。這篇論文只是個開頭,神經編程真正的價值不在編程而在其他領域,例如我們目前正在做的將CNPI框架應用於自然語言理解,這是塊難啃的硬骨頭,但最終會落地為產品帶來商業價值。
Q:很多學者在面臨商業和科研的時候都覺得很矛盾,無法權衡,您是如何考慮應對商業壓力和科研興趣?
A:就公司理念來說,我認為商業壓力和科研興趣並沒有本質矛盾。我們會追求商業利益,但根本目的是兩個:一是做好的產品用技術服務大眾,踐行人工智慧讓生活更美好;二是通過產品和商業上的成績獲得更多的社會資源投入,支持我們在通用人工智慧上持續的科學研究。後者是我們創立彩雲的初心,也是一直沒變的終極目標。當然,從實操角度講,作為一個創業公司,平衡商業與科研是個挑戰,尤其在我們科研的方向和公司主營業務關係並不緊密的情況下。但通過我們的不斷嘗試我認為並不是不可能。如果放棄「跑偏」的科學探索,「專心」做一個純粹追求商業價值最大化的公司,也許「成功」的概率更大。但為了有機會成為我們自己心目中真正理想的公司,我們還是要不忘初心。


TAG:集智俱樂部 |