王秉睿,蘭慧盈,陳云霽
1. 中國(guó)科學(xué)技術(shù)大學(xué),安徽 合肥 230026;2. 中國(guó)科學(xué)院計(jì)算技術(shù)研究所,北京 100190;3. 中國(guó)科學(xué)院大學(xué),北京 100049
機(jī)器學(xué)習(xí)是一類(lèi)研究通過(guò)計(jì)算機(jī)模擬人類(lèi)學(xué)習(xí)行為,從而解決實(shí)際問(wèn)題的學(xué)科。機(jī)器學(xué)習(xí)算法涉及多學(xué)科,如概率論、統(tǒng)計(jì)學(xué)、逼近論、凸分析等。傳統(tǒng)的機(jī)器學(xué)習(xí)算法包括k近鄰(k-nearest neighbor,k-NN)分類(lèi)、k均值(k-means)聚類(lèi)算法、支持向量機(jī)(support vector machine,SVM)、決策樹(shù)(decision tree)等。最近,機(jī)器學(xué)習(xí)中的一個(gè)子類(lèi)——深度學(xué)習(xí),在圖像處理、語(yǔ)音處理等多個(gè)領(lǐng)域上都取得了長(zhǎng)足的進(jìn)步。深度學(xué)習(xí)的快速發(fā)展得益于兩點(diǎn),首先是硬件計(jì)算設(shè)備性能的提升,比如圖形處理器(graphics processing unit,GPU)的廣泛應(yīng)用,其次是大規(guī)模數(shù)據(jù)集的構(gòu)建,大量的訓(xùn)練數(shù)據(jù)減輕了過(guò)擬合的問(wèn)題,使得訓(xùn)練復(fù)雜的模型成為可能。深度學(xué)習(xí)算法的結(jié)構(gòu)通常非常復(fù)雜,包含上百兆的可訓(xùn)練參數(shù)。比如2016年由He K等人[1]提出的ResNet網(wǎng)絡(luò),最大的一種模型包含了上千層。
由于算法的復(fù)雜性,構(gòu)建算法的計(jì)算過(guò)程需要耗費(fèi)大量的時(shí)間。值得慶幸的是,深度學(xué)習(xí)算法的復(fù)雜網(wǎng)絡(luò)結(jié)構(gòu)是由有限的基本算子通過(guò)各種復(fù)雜連接關(guān)系搭建起來(lái)的,常用的算子包括卷積、池化、全連接等。因此,可以提取出機(jī)器學(xué)習(xí)算法中共性的部分,將其抽象出來(lái),便于反復(fù)調(diào)用。用于機(jī)器學(xué)習(xí)算法的編程庫(kù)層出不窮,各有特色。比如,Google公司提出的Tensorflow[2],是一款基于數(shù)據(jù)流圖的深度學(xué)習(xí)庫(kù),支持多種計(jì)算設(shè)備(CPU、GPU、張量處理單元(tensor processing unit,TPU)[3]),同時(shí)還可以直接運(yùn)行在包含多種計(jì)算設(shè)備的分布式結(jié)構(gòu)上。除了深度學(xué)習(xí)算法庫(kù),還有針對(duì)傳統(tǒng)機(jī)器學(xué)習(xí)算法的庫(kù)。比如,Scikit-Learn用Python語(yǔ)言作為接口,提供大量的機(jī)器學(xué)習(xí)算法,包括有監(jiān)督學(xué)習(xí)算法、無(wú)監(jiān)督學(xué)習(xí)算法、數(shù)據(jù)降維算法、圖像預(yù)處理算法等。
現(xiàn)有的深度學(xué)習(xí)庫(kù)主要面臨兩個(gè)方面的挑戰(zhàn)。一是對(duì)更多的計(jì)算設(shè)備的支持,尤其是對(duì)機(jī)器學(xué)習(xí)加速器的支持。目前,多數(shù)深度學(xué)習(xí)庫(kù)支持的設(shè)備是CPU和GPU(如MXNet、Caffe),一些深度學(xué)習(xí)庫(kù)僅支持CPU(如Scikit-Learn),只有很少的一部分深度學(xué)習(xí)庫(kù)可以支持深度學(xué)習(xí)加速器,如TensorFlow可以支持TPU。但是,這種支持還是有局限性的,其他的加速器要集成到TensorFlow中會(huì)非常困難,同時(shí),TPU也無(wú)法被其他編程庫(kù)利用。另一個(gè)挑戰(zhàn)是機(jī)器學(xué)習(xí)庫(kù)的模塊化?,F(xiàn)在的機(jī)器學(xué)習(xí)庫(kù)所有模塊之間耦合緊密,不利于代碼的重用。開(kāi)發(fā)者如果想構(gòu)建一個(gè)新的機(jī)器學(xué)習(xí)庫(kù),很難利用現(xiàn)有庫(kù)的模塊進(jìn)行開(kāi)發(fā)。
經(jīng)典機(jī)器學(xué)習(xí)算法指主要依賴(lài)統(tǒng)計(jì)方法的機(jī)器學(xué)習(xí)算法。和深度學(xué)習(xí)算法相比,這類(lèi)機(jī)器學(xué)習(xí)算法的模型較為簡(jiǎn)單,在小數(shù)據(jù)集上可以達(dá)到很好的預(yù)測(cè)效果,但是對(duì)于大數(shù)據(jù)集,如ImageNet,預(yù)測(cè)能力不足。表1列舉了常見(jiàn)的經(jīng)典機(jī)器學(xué)習(xí)算法以及它們可以完成的機(jī)器學(xué)習(xí)任務(wù)。
深度學(xué)習(xí)算法是機(jī)器學(xué)習(xí)算法中的一類(lèi),近年來(lái),隨著計(jì)算設(shè)備的計(jì)算能力的增強(qiáng)以及大規(guī)模數(shù)據(jù)集的建立,神經(jīng)網(wǎng)絡(luò)算法開(kāi)始從單層逐漸發(fā)展到多層,到現(xiàn)在,一個(gè)神經(jīng)網(wǎng)絡(luò)可能包含上百層以及上百兆的可訓(xùn)練參數(shù)。深度神經(jīng)網(wǎng)絡(luò)模型主要有:卷積神經(jīng)網(wǎng)絡(luò)[8]以及遞歸神經(jīng)網(wǎng)絡(luò)。卷積神經(jīng)網(wǎng)絡(luò)[8]是近年來(lái)迅速發(fā)展起來(lái),并獲得了廣泛關(guān)注的一種前饋人工神經(jīng)網(wǎng)絡(luò)算法。它在大規(guī)模的圖像識(shí)別任務(wù)上取得了出色的識(shí)別率。2012年提出的AlexNet[9]取得了ImageNet2012圖像分類(lèi)任務(wù)比賽的第一名,Top 5的識(shí)別錯(cuò)誤率低至15.3%。之后的幾年,這一錯(cuò)誤率不斷被新提出的CNN刷新,2014年提出的VGGNet[10]取得了89.3%的平均正確率,2016年He K等人[1]提出的ResNet,又將分類(lèi)錯(cuò)誤率降低到3.57%。通常,卷積神經(jīng)網(wǎng)絡(luò)是由很多層構(gòu)成的,常見(jiàn)的層包括卷積層、池化層、激活層、全連接層。卷積神經(jīng)網(wǎng)絡(luò)非常善于處理圖像數(shù)據(jù),通過(guò)卷積層,可以提取出各種圖像特征,經(jīng)過(guò)多次卷積處理后,可以提取出比較抽象的圖像特征,這些高級(jí)的抽象特征則作為分類(lèi)器(全連接層)的輸入,用于圖像的分類(lèi)。遞歸神經(jīng)網(wǎng)絡(luò)是一類(lèi)用于處理序列數(shù)據(jù)的神經(jīng)網(wǎng)絡(luò),可以展現(xiàn)輸入數(shù)據(jù)在時(shí)序上的行為。不同于前饋神經(jīng)網(wǎng)絡(luò)的是,RNN可以利用其內(nèi)部的記憶來(lái)處理任意時(shí)序的輸入序列,更容易處理輸入數(shù)據(jù)長(zhǎng)度不定的情況,比如手寫(xiě)識(shí)別、語(yǔ)音識(shí)別等。
表1 常見(jiàn)的機(jī)器學(xué)習(xí)算法
為了幫助深度學(xué)習(xí)開(kāi)發(fā)者更加快速、方便地開(kāi)發(fā)深度學(xué)習(xí)算法,各種針對(duì)深度學(xué)習(xí)算法開(kāi)發(fā)的編程庫(kù)被提出。圖1展示了一般的深度學(xué)習(xí)編程庫(kù)的層次。最上層是編程庫(kù)提供的編程接口,程序員通過(guò)調(diào)用編程接口來(lái)描述算法的計(jì)算過(guò)程。對(duì)于開(kāi)發(fā)者來(lái)說(shuō),編程接口的易用性以及接口的表達(dá)能力非常重要,對(duì)算法的描述會(huì)映射到計(jì)算圖上,對(duì)計(jì)算圖進(jìn)行優(yōu)化和調(diào)度后,圖中的每一個(gè)算子會(huì)調(diào)用硬件的編程接口,如Nvidia廠商發(fā)布的、在其GPU設(shè)備上處理深度學(xué)習(xí)算法的高性能庫(kù)——cuDNN。最后,這些硬件調(diào)用接口(高性能庫(kù))再進(jìn)一步生成硬件指令,以在硬件設(shè)備上運(yùn)行。比如,在TensorFlow和MXNet中,它們的編程接口是基于圖的,源文件是一個(gè)Python文件。而Caffe基于層的框架采用了自定義的prototxt文件構(gòu)建神經(jīng)網(wǎng)絡(luò)。
深度學(xué)習(xí)庫(kù)的編程接口主要可以分為3類(lèi):一類(lèi)是基于數(shù)據(jù)流圖的編程接口,流行的基于數(shù)據(jù)流圖的機(jī)器學(xué)習(xí)編程框架包括Tensorflow[2]、MXNet[11]、Theano[12]、Torch7[13]等;另一類(lèi)是基于層的編程接口,如Caffe[14];還有一類(lèi)是基于算法的編程接口,主要用于傳統(tǒng)機(jī)器學(xué)習(xí)算法的實(shí)現(xiàn),如Scikit-Learn。
基于數(shù)據(jù)流圖(data flow graph)[2]的機(jī)器學(xué)習(xí)編程框架利用節(jié)點(diǎn)(node)和邊(edge)構(gòu)造的有向圖來(lái)描述計(jì)算過(guò)程。節(jié)點(diǎn)可以表示一個(gè)運(yùn)算操作,或者表示一塊數(shù)據(jù)的輸入起點(diǎn)或者輸出終點(diǎn),邊則表示節(jié)點(diǎn)之間的輸入/輸出關(guān)系。數(shù)據(jù)被表示為多維數(shù)組(張量)的形式,可以在這些邊上進(jìn)行傳輸。通過(guò)一個(gè)節(jié)點(diǎn)時(shí),數(shù)據(jù)就會(huì)作為該節(jié)點(diǎn)運(yùn)算操作的輸入被計(jì)算,計(jì)算的結(jié)果則順著該節(jié)點(diǎn)的輸出邊流向后面的節(jié)點(diǎn)。一旦輸入端的所有數(shù)據(jù)準(zhǔn)備好,節(jié)點(diǎn)將被分配到各種計(jì)算設(shè)備,完成異步并行的執(zhí)行運(yùn)算。下面介紹4種流行的基于數(shù)據(jù)流圖的機(jī)器學(xué)習(xí)庫(kù)。
Theano[12]是一個(gè)用Python語(yǔ)言寫(xiě)成的基于圖的機(jī)器學(xué)習(xí)庫(kù)。用戶可以定義、優(yōu)化和評(píng)估數(shù)學(xué)表達(dá)式,尤其是包含多維數(shù)組的表達(dá)式,多維數(shù)組是機(jī)器學(xué)習(xí)算法中最常用的一種數(shù)據(jù)結(jié)構(gòu)。當(dāng)數(shù)據(jù)量很大的時(shí)候,使用Theano可以獲得與手工優(yōu)化的C代碼相媲美的運(yùn)行速度。Theano也支持跨平臺(tái)執(zhí)行,在GPU上,可以獲得超過(guò)CPU幾個(gè)數(shù)量級(jí)的運(yùn)行速度。Theano將計(jì)算機(jī)代數(shù)系統(tǒng)(computer algebra system,CAS)的各個(gè)方面與優(yōu)化編譯器的各個(gè)方面結(jié)合起來(lái)。它還可以為許多數(shù)學(xué)運(yùn)算生成定制的C代碼。CAS與優(yōu)化編譯的結(jié)合,對(duì)于復(fù)雜的數(shù)學(xué)表達(dá)式被反復(fù)計(jì)算且計(jì)算速度很關(guān)鍵的任務(wù)來(lái)說(shuō)特別有用。
Tensorflow[2]是Google公司開(kāi)發(fā)的一種基于數(shù)據(jù)流圖的機(jī)器學(xué)習(xí)編程框架。它具有編程靈活、支持跨平臺(tái)運(yùn)行的特點(diǎn)。程序員只需要修改很少量的代碼,就可以將在CPU上執(zhí)行的Tensorflow移植到GPU平臺(tái)上進(jìn)行運(yùn)算。同時(shí),Tensorflow還可以支持自動(dòng)異構(gòu)分布式計(jì)算,它的模型能夠運(yùn)行在不同的分布式系統(tǒng)上,系統(tǒng)可以包括多個(gè)GPU、CPU、手機(jī)節(jié)點(diǎn)等。
圖1 深度學(xué)習(xí)編程框架結(jié)構(gòu)抽象層次
MXNet[11]也是一個(gè)基于計(jì)算圖模型的機(jī)器學(xué)習(xí)編程庫(kù),類(lèi)似Theano和TensorFlow。它同樣可以支持多GPU配置。MXNet包含了類(lèi)似Lasagne 和Blocks更高級(jí)別的模型構(gòu)建塊,并且可以在常見(jiàn)的硬件設(shè)備上運(yùn)行(包括手機(jī)、服務(wù)器等)。除了支持Python的編程接口外,MXNet還提供了對(duì) R、Julia、C++、Scala、Matlab和JavaScript 的編程接口。
Torch7[13]是一款用于科學(xué)計(jì)算的編程框架,為機(jī)器學(xué)習(xí)算法提供了充分的支持。Torch7采用數(shù)據(jù)流圖的編程方法,便于構(gòu)建計(jì)算模型。它采用Lua語(yǔ)言作為接口,主要原因是Lua和C/C++語(yǔ)言之間的調(diào)用接口友好,開(kāi)銷(xiāo)小,可以更好地支持內(nèi)嵌CUDA-C優(yōu)化代碼。
基于層的編程框架為用戶提供一組表示各種層(比如卷積層、池化層、全連接層等)的函數(shù)作為接口。用戶通過(guò)反復(fù)調(diào)用這些層的函數(shù)接口構(gòu)成網(wǎng)絡(luò)。通過(guò)將計(jì)算單位限制到層上,庫(kù)的開(kāi)發(fā)者們可以對(duì)各種層進(jìn)行充分的性能優(yōu)化,因此可以提供更好的運(yùn)行效率。Caffe[14]是一種常用的卷積神經(jīng)網(wǎng)絡(luò)框架,它采用層的調(diào)用方式,用一個(gè)prototxt文件對(duì)每一個(gè)層進(jìn)行定義和配置,之后程序分析這個(gè)文件,獲得這個(gè)網(wǎng)絡(luò)結(jié)構(gòu)的信息。
基于算法的編程庫(kù)提供了大量的機(jī)器學(xué)習(xí)算法,涵蓋各種任務(wù)和算法。和前兩種框架不同,基于算法的編程庫(kù)不需要構(gòu)建復(fù)雜的網(wǎng)絡(luò)結(jié)構(gòu),只需要通過(guò)設(shè)置庫(kù)里面提供的算法函數(shù)接口中的參數(shù)即可完成任務(wù)。比如Scikit-Learn機(jī)器學(xué)習(xí)庫(kù),它是一種基于Python語(yǔ)言的機(jī)器學(xué)習(xí)庫(kù),提供了數(shù)據(jù)分析和數(shù)據(jù)挖掘中針對(duì)各種任務(wù)(包括分類(lèi)、聚類(lèi)、數(shù)據(jù)降維、模型選擇、預(yù)處理等)的算法,提供了各種不同類(lèi)別(如k-NN、k-means)的決策樹(shù)(如C4.5、ID3等)的算法接口,開(kāi)發(fā)者只需要設(shè)置接口中的參數(shù),并且將數(shù)據(jù)傳入,就可以得到訓(xùn)練和預(yù)測(cè)的結(jié)果。
本節(jié)將針對(duì)3個(gè)深度學(xué)習(xí)編程框架中的問(wèn)題進(jìn)行分析。
(1)添加新算子
深度學(xué)習(xí)算法是由不同的算子構(gòu)成的,在實(shí)現(xiàn)一個(gè)新算法的時(shí)候,有兩種實(shí)現(xiàn)方式。首先可以利用深度學(xué)習(xí)框架中已經(jīng)有的基本算子(如矩陣計(jì)算(矩陣乘法、矩陣轉(zhuǎn)置等)、代數(shù)計(jì)算(包括標(biāo)量數(shù)據(jù)的加減乘除))實(shí)現(xiàn)一個(gè)新算子。這種處理方法的劣勢(shì)在于,由于一個(gè)算法中包含的算子非常多,算子的調(diào)度開(kāi)銷(xiāo)會(huì)增大。同時(shí)每一個(gè)算子都需要調(diào)用一次硬件設(shè)備,而調(diào)用硬件設(shè)備需要一定的啟動(dòng)開(kāi)銷(xiāo),算子越多,整體啟動(dòng)開(kāi)銷(xiāo)越大,導(dǎo)致運(yùn)行效率低下。因此,通常采用另一種更加高效的實(shí)現(xiàn)方式,即添加一個(gè)新的算子,算子內(nèi)部是通過(guò)直接調(diào)用下一層的硬件調(diào)用接口實(shí)現(xiàn)的,以此節(jié)省算子的調(diào)度開(kāi)銷(xiāo)。深度學(xué)習(xí)算法的發(fā)展非常迅速,這使得添加新算子成為一種常見(jiàn)任務(wù)。如何方便地添加新算子成為深度學(xué)習(xí)框架需要研究的一個(gè)重要問(wèn)題。
(2)資源映射策略
神經(jīng)網(wǎng)絡(luò)中很多算子的計(jì)算規(guī)模很大,需要較多的計(jì)算資源和內(nèi)存資源。這可能超過(guò)了硬件能夠提供的資源,因此需要深度學(xué)習(xí)框架對(duì)硬件上的計(jì)算資源和內(nèi)存資源進(jìn)行調(diào)配,通過(guò)將一個(gè)操作拆分成更小的子操作,使得硬件的資源可以支持該操作。此外,不同的算子對(duì)資源的需求也是不平衡的。這種不平衡使資源的映射和分配變得更加困難。
(3)分布式執(zhí)行
現(xiàn)在神經(jīng)網(wǎng)絡(luò)結(jié)構(gòu)規(guī)模越來(lái)越大,一些研究人員開(kāi)始使用包含多種計(jì)算設(shè)備的集群(cluster)來(lái)執(zhí)行。分布式執(zhí)行面臨的多種困難(如不同算子之間的同步、算子和設(shè)備之間的映射、算子到設(shè)備上的分配等)也是深度學(xué)習(xí)架構(gòu)需要解決的,尤其是針對(duì)訓(xùn)練算法的分布式計(jì)算。
本文對(duì)現(xiàn)有的常用機(jī)器學(xué)習(xí)庫(kù)進(jìn)行了介紹和分析。隨著機(jī)器學(xué)習(xí)領(lǐng)域的發(fā)展,新的需求逐漸被提出,現(xiàn)有的機(jī)器學(xué)習(xí)庫(kù)要兼容這些新的需求,需要進(jìn)行進(jìn)一步的改善。未來(lái),對(duì)機(jī)器學(xué)習(xí)庫(kù)的研究可從以下發(fā)展方向展開(kāi)。
機(jī)器學(xué)習(xí)算法的發(fā)展越來(lái)越快,尤其是在各種實(shí)際情景中,機(jī)器學(xué)習(xí)的應(yīng)用場(chǎng)景日益增多。人們逐漸發(fā)現(xiàn),傳統(tǒng)的計(jì)算設(shè)備已經(jīng)無(wú)法支持機(jī)器學(xué)習(xí)的計(jì)算需求。比如,在手機(jī)上,許多應(yīng)用都需要用到人臉識(shí)別技術(shù)、語(yǔ)音識(shí)別技術(shù)。然而,雖然使用深度學(xué)習(xí)算法進(jìn)行人臉識(shí)別、語(yǔ)音識(shí)別任務(wù)效果較好,但是計(jì)算量巨大,手機(jī)的計(jì)算資源有限,無(wú)法支持這樣大規(guī)模的計(jì)算任務(wù)。在這樣的情況下,研究人員提出了專(zhuān)門(mén)針對(duì)機(jī)器學(xué)習(xí)算法的加速器,利用機(jī)器學(xué)習(xí)算法中大量的數(shù)據(jù)重用,有效降低了功耗,提高了計(jì)算性能[15-20]。機(jī)器學(xué)習(xí)加速器雖然有巨大的計(jì)算潛力,但是由于缺乏合適的編程框架,機(jī)器學(xué)習(xí)開(kāi)發(fā)者實(shí)際上很難在機(jī)器學(xué)習(xí)加速器上進(jìn)行開(kāi)發(fā)。因此,機(jī)器學(xué)習(xí)庫(kù)除了需要支持CPU、GPU之外,還需要進(jìn)一步支持機(jī)器學(xué)習(xí)加速器,尤其是對(duì)跨平臺(tái)(多加速器)的支持?,F(xiàn)在,雖然有一些加速器可以被集成到框架中,如TensorFlow可以支持同是Google公司研發(fā)的TPU[3],但是,其他加速器要想集成到TensorFlow中則非常困難。
模塊化是機(jī)器學(xué)習(xí)庫(kù)發(fā)展的另一個(gè)方向。一個(gè)機(jī)器學(xué)習(xí)庫(kù)一般由幾個(gè)層次構(gòu)成,各層次都是非模塊化的,與自己的系統(tǒng)是緊耦合的,開(kāi)發(fā)者如果想要定制自己的機(jī)器學(xué)習(xí)系統(tǒng),很難復(fù)用現(xiàn)有庫(kù)中的模塊,這導(dǎo)致本來(lái)可以重用的模塊還需要重新實(shí)現(xiàn)一次。現(xiàn)在,已經(jīng)有一些開(kāi)發(fā)者提出針對(duì)機(jī)器學(xué)習(xí)算法的中間語(yǔ)言(intermediate representation,IR)[21-22]以及相應(yīng)的編譯器,如由Chen T等人[22]提出的TVM,是一個(gè)針對(duì)深度學(xué)習(xí)的編譯軟件棧,其中用到的NNVM,就是一個(gè)開(kāi)放的模塊化的計(jì)算圖的中間語(yǔ)言。
機(jī)器學(xué)習(xí)算法已經(jīng)被學(xué)術(shù)界和工業(yè)界廣泛接受,成為一種實(shí)用有效的算法,應(yīng)用在了很多任務(wù)上,如圖像識(shí)別、圖像分類(lèi)等。本文首先介紹了常用的機(jī)器學(xué)習(xí)算法,包括經(jīng)典的基于統(tǒng)計(jì)學(xué)的機(jī)器學(xué)習(xí)算法以及深度學(xué)習(xí)算法(如CNN、RNN/LSTM)。由于機(jī)器學(xué)習(xí)算法編程的復(fù)雜性,人們提出了各種深度學(xué)習(xí)編程框架,從而為深度學(xué)習(xí)算法的開(kāi)發(fā)提供便利。本文主要介紹了3類(lèi)深度學(xué)習(xí)開(kāi)發(fā)庫(kù):基于數(shù)據(jù)流圖的編程庫(kù)、基于層的編程庫(kù)以及基于算法的編程庫(kù)。