3. 計算圖(Computation Graph)
有了張量和基于張量的各種操作之后,下一步就是將各種操作整合起來,輸出我們需要的結(jié)果。
但不幸的是,隨著操作種類和數(shù)量的增多,有可能引發(fā)各種意想不到的問題,包括多個操作之間應(yīng)該并行還是順次執(zhí)行,如何協(xié)同各種不同的底層設(shè)備,以及如何避免各種類型的冗余操作等等。這些問題有可能拉低整個深度學(xué)習(xí)網(wǎng)絡(luò)的運行效率或者引入不必要的Bug,而計算圖正是為解決這一問題產(chǎn)生的。
據(jù)雷鋒網(wǎng)了解,計算圖首次被引入人工智能領(lǐng)域是在2009年的論文《Learning Deep Architectures for AI》。當(dāng)時的圖片如下所示,作者用不同的占位符(*,+,sin)構(gòu)成操作結(jié)點,以字母x、a、b構(gòu)成變量結(jié)點,再以有向線段將這些結(jié)點連接起來,組成一個表征運算邏輯關(guān)系的清晰明了的“圖”型數(shù)據(jù)結(jié)構(gòu),這就是最初的計算圖。
后來隨著技術(shù)的不斷演進,加上腳本語言和低級語言各自不同的特點(概括地說,腳本語言建模方便但執(zhí)行緩慢,低級語言則正好相反),因此業(yè)界逐漸形成了這樣的一種開發(fā)框架:前端用Python等腳本語言建模,后端用C++等低級語言執(zhí)行(這里低級是就應(yīng)用層而言),以此綜合了兩者的優(yōu)點??梢钥吹?,這種開發(fā)框架大大降低了傳統(tǒng)框架做跨設(shè)備計算時的代碼耦合度,也避免了每次后端變動都需要修改前端的維護開銷。而這里,在前端和后端之間起到關(guān)鍵耦合作用的就是計算圖。
將計算圖作為前后端之間的中間表示(Intermediate Representations)可以帶來良好的交互性,開發(fā)者可以將Tensor對象作為數(shù)據(jù)結(jié)構(gòu),函數(shù)/方法作為操作類型,將特定的操作類型應(yīng)用于特定的數(shù)據(jù)結(jié)構(gòu),從而定義出類似MATLAB的強大建模語言。
需要注意的是,通常情況下開發(fā)者不會將用于中間表示得到的計算圖直接用于模型構(gòu)造,因為這樣的計算圖通常包含了大量的冗余求解目標(biāo),也沒有提取共享變量,因而通常都會經(jīng)過依賴性剪枝、符號融合、內(nèi)存共享等方法對計算圖進行優(yōu)化。
目前,各個框架對于計算圖的實現(xiàn)機制和側(cè)重點各不相同。例如Theano和MXNet都是以隱式處理的方式在編譯中由表達式向計算圖過渡。而Caffe則比較直接,可以創(chuàng)建一個Graph對象,然后以類似Graph.Operator(xxx)的方式顯示調(diào)用。
因為計算圖的引入,開發(fā)者得以從宏觀上俯瞰整個神經(jīng)網(wǎng)絡(luò)的內(nèi)部結(jié)構(gòu),就好像編譯器可以從整個代碼的角度決定如何分配寄存器那樣,計算圖也可以從宏觀上決定代碼運行時的GPU內(nèi)存分配,以及分布式環(huán)境中不同底層設(shè)備間的相互協(xié)作方式。除此之外,現(xiàn)在也有許多深度學(xué)習(xí)框架將計算圖應(yīng)用于模型調(diào)試,可以實時輸出當(dāng)前某一操作類型的文本描述。
4. 自動微分(Automatic Differentiation)工具
計算圖帶來的另一個好處是讓模型訓(xùn)練階段的梯度計算變得模塊化且更為便捷,也就是自動微分法。
正如前面提到的,因為我們可以將神經(jīng)網(wǎng)絡(luò)視為由許多非線性過程組成的一個復(fù)雜的函數(shù)體,而計算圖則以模塊化的方式完整表征了這一函數(shù)體的內(nèi)部邏輯關(guān)系,因此微分這一復(fù)雜函數(shù)體,即求取模型梯度的方法就變成了在計算圖中簡單地從輸入到輸出進行一次完整遍歷的過程。與自動微分對應(yīng),業(yè)內(nèi)更傳統(tǒng)的做法是符號微分。
符號微分即常見的求導(dǎo)分析。針對一些非線性過程(如修正線性單元ReLU)或者大規(guī)模的問題,使用符號微分法的成本往往非常高昂,有時甚至不可行(即不可微)。因此,以上述迭代式的自動微分法求解模型梯度已經(jīng)被廣泛采用。并且由于自動微分可以成功應(yīng)對一些符號微分不適用的場景,目前許多計算圖程序包(例如Computation Graph Toolkit)都已經(jīng)預(yù)先實現(xiàn)了自動微分。
另外,由于每個節(jié)點處的導(dǎo)數(shù)只能相對于其相鄰節(jié)點計算,因此實現(xiàn)了自動微分的模塊一般都可以直接加入任意的操作類中,當(dāng)然也可以被上層的微分大模塊直接調(diào)用。
5. BLAS、cuBLAS、cuDNN等拓展包
現(xiàn)在,通過上述所有模塊,我們已經(jīng)可以搭建一個全功能的深度學(xué)習(xí)框架:將待處理數(shù)據(jù)轉(zhuǎn)換為張量,針對張量施加各種需要的操作,通過自動微分對模型展開訓(xùn)練,然后得到輸出結(jié)果開始測試。這時還缺什么呢?答案是運算效率。