當前位置:
首頁 > 最新 > 深度學習第8期:深度學習的常見框架

深度學習第8期:深度學習的常見框架

在之前的系列科普文中,我們介紹了許多深度學習的模型。但是,如果我們想要真正體會深度學習的威力的話,光有理論顯然是不夠的。我們必須要編程搭建網路,才能真正實現深度學習的威力。

如果要從底層開始搭建一個網路,並且從底層開始寫訓練網路的方法,無疑要花費大量的時間與精力。目前,有許多流行的深度學習框架,它們都對深度學習中常見的類與方法進行了定義。利用這些框架,就可以避免重複造輪子,較快設計出想要的網路。而每個框架都提供了各種不同語言的介面,這也使得我們更加容易上手。

下面,我們來介紹常見的深度學習框架。

常見的深度學習框架

深度學習框架也可以就其抽象的程度分為抽象程度較高的「前端框架」與抽象程度較低的「後端框架」。

前端框架主要有Keras與Gluon,它們的主要特點是容易上手。如果你想快一些在一些數據集上使用深度學習的模型,看看其威力的話,先學會一個「前端框架」是不錯的選擇。學會了前端框架之後,你往往可以只用四五行的代碼就寫出一個神經網路,然後,就可以將其用在你的數據集上了。

以下為Keras的標誌:

受到 Torch 啟發,Keras 提供了簡單易用的 API 介面,特別適合初學者入門。其後端採用 TensorFlow, CNTK,以及Theano。另外,Deeplearning4j的 Python 也是基於 Keras 實現的。Keras 幾乎已經成了 Python 神經網路的介面標準。如果熟悉sklearn的同學學習了Keras,他可能會發現使用Keras會和使用sklearn差不多——當你用幾行代碼定義了網路的結構之後,就可以讓它如同sklearn模型一般地fit與predict。

以下為Gluon的標誌:

Gluon是亞馬遜 (Amazon) 和 微軟 (Microsoft) 於 2017 年 10 月聯合推出的深度學習 API。Gluon 類似Keras,提供了簡單易用的 API 介面。和Keras不一樣,Gluon 支持動態計算圖(這對自然語言處理特別有用)。Gluon後端目前採用MXNet,未來還將支持微軟的CNTK。

學習「前端框架」所需要的時間比較短,所以同時學習這兩個框架不需要太長的時間。但如果非要分個先後的話,可以先試試Gluon,畢竟開發者是中國人,有官方出品的中文教程帶你入門。

「前端框架」的好處是簡單、容易上手,但是「前端框架」也有不好的地方。正是由於其抽象程度高,沒有較底層、較基本的語言,所以其缺乏靈活性。使用者無法完全根據自己的需求設計網路的結構。如果需要設計與傳統網路有明顯區別的新的網路結構,那麼「前端框架」顯然是不夠用的。這時,必須使用「後端框架」,從底層開始一步步地實現自己的網路才行。而主流的深度學習框架,也即「後端框架」有Theano、TensorFlow、Torch、Caffe、MXNet、Neon 和 CNTK這七種。

以下為TensorFlow的標誌:

TensorFlow是谷歌出品的,追隨者眾多。相比其它框架,TensorFlow 速度較慢,但它功能齊全且強大,並且提供的 TensorBoard 可視化工具還是很不錯的。

以下為MXNet的標誌:

MXNet已被亞馬遜選為 AWS 上的深度學習框架,支持動態圖計算。MXNet 有許多中國開發者,因而有非常良好的中文文檔支持。Gluon 介面使得 MXNet 像 Keras 一樣簡單易用,也是不錯的一個選擇。

以下是PyTorch的標誌:

PyTorch由Facebook支持,支持動態計算圖,可以提供很好的靈活性,適合研究。其最早的版本Torch由於只適合Lua這種小眾語言,所以使用者較少。但是隨著PyTorch推出了Python的介面,其迅速成長為最主流的語言之一。

以下是Caffe的標誌:

這些「後端框架」相對比較複雜,需要較長的時間才能學習掌握,所以要同時掌握多種框架無疑會花費大量時間。一般而言是沒有必要的。接下來,我們介紹各個框架的性能對比,以幫助讀者選擇合適的框架:

深度學習框架的性能對比

以下,我們將通過圖表來說明各個框架的區別:

上圖從介面語言、文檔豐富度、CNN、RNN、速度、對於並行的支持度等各個方面對比了各個框架的不同。首先,最好選擇一種具有自己熟悉的語言介面的框架,否則要為此專門學習一門語言是十分費力的。其次,要根據其各項性能的優劣做出選擇。從上面的表格中可以看出,如果沒有極其特殊的需要,一般最好從TensorFlow、PyTorch以及MXNet三者之中做出選擇。因為其它的框架與這三大主流的框架相比,各項性能上總是有一定的差距。

另外,Theano在性能上也是不錯的。但是,Yoshua Bengio 於 2017 年 9 月宣布不再維護 Theano,所以這個框架事實上已經宣告走向沒落。其它基於 Theano 的庫,如 Lasagne 和 Blocks,也基本不再可能有上升的空間。此外,我們可以看到CNTK對於RNN有較好的支持。如果需要設計有關RNN的項目,可以深入了解。不過,CNTK並不提供Python的介面。

對於使用者而言,主要考慮TensorFlow、PyTorch與MXNet三大框架即可。論性能而言,TensorFlow或許略勝一籌。並且,TensorFlow可以定義為「最流行」、「最被認可」的開源深度學習框架。其在GitHub上無論是Star數、Fork數,或是檢索基於TensorFlow的項目數,都大大超過其它框架,甚至超越其它框架資源的總和。但是,新崛起的PyTorch由於其動態圖、靈活易調試的特點,又簡單易上手,也是一個不錯的選擇。對於沒有深度學習編程經驗的同學來說,PyTorch是更加值得推薦的框架。目前,已經有不少深度學習的入門者將PyTorch作為自己的首選。此外,MXNet由於其適合併行、分散式等特點,在業界相對用處更加廣泛一些。不過其在學界的地位相對不如TensorFlow等,所以相對不適合作為入門的語言。

TensorFlow是最流行、最被認可的框架,並且,其python介面也是被使用最廣泛的介面,所以,有很多熟悉python的同學會嘗試學習TensorFlow。但是,TensorFlow的編程的思路與一般的python程序設計有著較大的不同。我們常說,python是一門動態語言。但是由於TensorFlow雖然提供了python的介面,其底層卻是用C語言實現的,因此我們無法使用python這種動態的特性。這一點與PyTorch有較大的不同。

在深度學習的主流框架中,PyTorch可以視作是動態計算的典型代表,而TensorFlow可以視作是靜態計算的典型代表。正是由於這個原因,使得精通python的同學會認為PyTorch較容易上手,而TensorFlow難於上手,這使得他們在初學的時候總是有種「摸不著頭腦」的感覺。所以在下面,我們專門介紹一下TensorFlow的主要編程思路,以便於只熟悉python的同學更好地入門。

靜態語言和動態語言

Python之所以被稱為動態語言,其動態之處在於其可以隨時增加、刪除變數,也可以修改變數的類型。例如,我們設定 a = 5 之後,我們可以重新令a = 8.8(浮點數)、a=「abc」(字元串)或者令a等於某個複雜的對象。而與之相比,C語言在一開始指定了一個變數的類型之後,就無法對該變數的類型進行改動。例如在C語言中,如果我們指定了 int a = 5,那麼我們或許可以為a重新賦值為別的整數,比如 a = 8。但我們不能再在接下來的程序中讓a等於非整數的其它類型。

兩種語言之所以有這麼大的不同,是因為其底層的實現有所不同。在C語言中,當我們指定 int a = 5,在編譯的時候系統會專門指定一塊內存的區域,用來代表a這個變數。我們可以讓a通過計算變成其它的整數,這就相當於讓a對應的那一塊內存中的存儲的數發生改變。但是,由於劃給a的那塊內存大小已經給定了,其大小隻適合裝一個整數,不能裝下一個浮點數,故而在指定a為int之後再修改a的類型是不允許的。但是在python中,有一個專門的環境去維護變數a與指針的對應關係。當我們指定a=5時,其會讓a對應的指針指向一塊儲存為5的內存。之後我們指定 a=「abc」的時候,它可以安排a對應的指針變化,重新指向另一塊地方。

C語言的交互性與python也有著較大的差別。我們知道,C是一門編譯語言,我們寫完代碼之後要將其編譯為一個可執行程序。當我們運行這個程序,其所有語句會依次執行,然後彈出,銷毀所有內存中的變數。這也就意味著我們不能在任何一個階段停下來,查詢當前各個變數的值是多少、並且根據查詢結果來調試程序(當然,我們可以在代碼中插入一些語句,將我們需要查詢的內容列印到標準輸出,但是這樣必須重新編譯,消耗大量時間)。而python是一門解釋語言,所有的語句解釋執行。系統維護了一個動態的環境,即變數名與指針的關係,所有語句也是基於這個環境才得以解釋執行的。這就方便於我們隨時地進行查詢,並且動態地修改。

在C中其實是沒有真正的「變數」這樣的概念的。在程序被編譯完成之後,運行的過程就相當於只是按照指定的順序在內存上的指定位置進行各種指定的運算。「變數」這個概念只是在編程的過程中便於我們去理解、去想像應該如何編程的。編譯完成後,「變數」等概念會完全被對於指定的內存位置定址取址等過程替代;而在Python中,「變數」的概念卻是真實存在的。在任何時候,系統維護的動態環境都清晰地指明了當前有哪些變數、變數是什麼。我們查詢、修改變數的語句,都會根據當前環境來解釋執行。也正是由於這個環境的存在,我們才得以在IPython控制台中調試程序,比如隨時查看當前變數的值,查看當前函數的效果。

事實上,這種動態、交互的特性無疑可以更加方便我們調試程序。但是與靜態語言相比,其運算會比較慢。因為在語句解釋執行的過程中會涉及到大量對環境的查詢。而在靜態語言中,所有運算的類型與內容都是預先規定好的。在程序運行的時候,其可以「輕車熟路」地在指定的位置按照指定的方式執行。目前,大多數的語言都嘗試盡量同時包含動態與靜態的特性,吸收二者各自的優點。這正是由於編程、調試程序等耗費的時間與程序運行的時間是同樣值得考慮的成本,而靈活性與效率也同樣都是有價值的。

在深度學習的框架中,PyTorch是比較偏向於python本身動態的特性的,這也使得其更加容易上手。而TensorFlow則更加具有靜態語言的特性。當然,由於它實現了python的介面,所以它也與完全的靜態語言有所區別。在下面,我們會介紹TensorFlow編程的主要思想。

TensorFlow的設計思想?

TensorFlow的整體思路是要先搭建好計算圖,然後才能開始進行計算。這就好像是先把水渠給搭建好,然後再讓水流進來,或者像是先把立交橋建好,再宣佈道路開放,讓汽車進來。這就與一般python中,一邊建橋一邊開車,車開到哪裡橋建到哪裡的思路有所不同。

我們之前說過,機器學習就相當於要根據一系列(X,y)的數據集去擬合一個函數f(X,w),使得f(X,w)與y盡量接近。其中w為函數的參數。在訓練的過程中,我們相當於是要優化loss=(y?f(X,w))2的函數。我們有固定的(X,y),故而可以把(X,y)視為loss函數的參數,而把w視為loss函數的自變數,要優化loss函數;而在預測的過程中,我們相當於把已經擬合好的w視為函數f(X,w)的參數,而把X視為函數的自變數。由此我們可見,X、y與w的地位是不同的,它們可以算是構成一個深度學習計算任務的兩種主要的數據。

在TensorFlow中,有兩種基本的元素,與上述的兩種數據相對應。一種是佔位符,即PlaceHolder,而另一種則是變數,即Variable。變數對應的是神經網路的各種參數,它從初始化之後就有了具體的值,然後就一直保存在神經網路中,被我們通過訓練不斷修改,直到訓練完成,它依然保存在神經網路中,可以讓我們進行預測任務。而佔位符對應的就是X、y,它並不是神經網路的一部分,而是需要從外界「喂」進來。

在TensorFlow中,我們常常要專門定義這些PlaceHolder與Variable,而不是立即對其進行賦值。在python中,我們一般直接通過賦值來定義變數,例如解釋執行語句a=5時,解釋器創建了變數,並且將其賦值為5,修改了環境。而在C語言中,我們可以只指定變數的類型,而沒有馬上賦值,例如我們可以先寫一句int a,過一陣再來指定a的值。從這一點來看,TensorFlow中定義PlaceHolder與Variable的過程是與C語言比較像的:

事實上,當我們寫C語言的程序時,無論語句中有沒有立即對a進行賦值,C語言編譯過程中都會根據變數的定義找出一個專屬的內存地址。編譯器可以縱覽整個程序中有哪些變數,根據這些變數之間的關係更加合理地為其安排地址,並且為待會即將要進行的計算安排一下秩序。等到程序運行的時候,才會修改該內存區域的值,正式開始計算。這種預先對於全局的安排無疑能夠讓計算的效率更高。而在python中,解釋器一般是一邊安排,一邊計算。這雖然使得python具有易於調試的特點,但這也使得其計算效率較低。TensorFlow的計算圖無疑是藉助了C的思路。

TensorFlow中,我們要定義計算圖,也就是定義網路各個部分如何計算。TensorFlow中有許多內置的函數,例如計算四則運算、矩陣乘法、卷積、激活函數等等。在TensorFlow中,我們也可以找到第三方的包,它可以將較多的基本運算封裝在一起。利用這些函數,我們可以定義出神經網路的各個部分:

總的來說,x1,x2,x3,x4都是神經網路的隱藏層的各個部分。它們實際上都是一開始我們定義的PlaceHolder與Variable通過我們指定的運算得到的組合。我們必須將計算圖定義完全之後,程序才能正式開始計算。這也就是說,程序必須先完全弄清楚網路中間各個部分,x1,x2,x3,x4等等與PlaceHolder與Variable是什麼關係,它們都是如何通過PlaceHolder與Variable的運算得到的,然後才能開始進行計算。

假定我們還定義了一個loss函數,比如loss=(y?pred)2,那麼我們的計算圖就定義完畢,可以正式開始跑程序了。要注意的是,時至此刻,我們網路只有計算圖,只有各個部分與定義的PlaceHolder與Variable的關係,卻沒有任何一處有一個具體的值。這就好像是水渠已經建立好了,水應該從哪裡流入哪裡流出已經完全設計好了,但是水卻沒有流進來;也像是立交橋已經完成了,哪個入口通道哪個出口我們都了如指掌了,但是汽車還沒有開進來。下面,我們要正式地「讓汽車開進來」。

tf.Session是一個類,它的方法run就是專門用來跑程序的。在sess.run裡面,你可以寫兩類的東西。第一類對神經網路的某些部分進行求值,第二類是對神經網路里的Variable進行修改的operation。在所有操作中,一般最先執行的就是Variable的初始化,它屬於第二類,即一種operation。Variable從初始化之後,就正式地擁有了數值。直到sess被關閉,Variable的數值就一直儲存在網路中。

我們寫如下的語句讓程序正式地開始跑:

初始化後Variable就有了數值,而PlaceHolder則是需要用feed_dict喂進來的。可以想像,當我們用一個feed_dict指定了我們定義的PlaceHolder的具體數值時,由於PlaceHolder與Variable都有具體數值,而神經網路的每一部分與PlaceHolder及Variable又有清晰的關係,則神經網路每一部分的值都可以求出來。

此外,TensorFlow具有自動求導的功能。自動求導是一種符號導數。所以當我們建立了計算圖,我們事實上就有了神經網路任何一部分相對於另一部分的符號導數,它也是通過Variable與PlaceHolder進行一些運算混合得到的。當我們有了Variable與PlaceHolder具體數值,sess就可以將各個部分的導數的數值求出來。 Sess可以跑的第二類內容是修改變數的operation。由於Variable的初始化是隨機的,我們必須不斷將其修改才能將其變得較好。在這些operation中,最常用的是優化。其原理是求出loss函數對於各個Variable的導數數值,然後用這些導數與四則運算對Variable進行修改。這個過程由於需要求梯度,所以要feed_dict指定輸入的訓練集數據才能得以進行。

在一些特殊情況下,例如強化學習的DQN演算法中,我們要定義target net與eval net,其中eval net是用優化的演算法更新的,而target net是通過將參數替換為eval net去更新的。直接將一些變數的數值替換為另一些變數的數值,這也算是一種operation。不過這種operation甚至是不需要feed_dict就可以直接進行的。(在下一篇關於強化學習的科普文中,我們會詳細介紹DQN演算法中替換參數的意義)。一些其他的operation,例如我們之前提到的對Variable進行初始化的operation,或者是將我們保存在一個文件中的Variable的值直接拿來開始使用,這樣的操作也是不需要用到PlaceHolder的值的,故而在用sess來運行它的時候也不必專門指定feed_dict。

總的來說,我們用TensorFlow寫一個神經網路可以概括為如下過程:

1、定義PlaceHolder與Variable的規格。

2、定義神經網路計算圖,即各個由PlaceHolder與Variable混合計算得到的部分。這其中應包含loss函數,它也是由PlaceHolder與Variable混合計算得到的。完成計算圖的定義時,神經網路的各個部分定義清晰、關係明確,但卻沒有任何一個部分具有具體數值。

3、使用Sess開始跑程序。首先應初始化各個Variable,使其獲得數值。

4、通過feed_dict=為PlaceHolder傳遞數值。藉此可以計算神經網路各個部分的具體數值,也可以不斷修改Variable使其變得更好。

5、訓練完畢後,通過feed_dict=為PlaceHolder傳遞數值。藉此可以計算神經網路在測試集上的各種表現。

6、有必要的話,存儲下Variable的數值,做為已經訓練好的網路以備後續使用。關閉Sess。至此,神經網路任何部分不再有具體數值,回到計算圖的狀態。

總結

對於初學者而言,可以考慮先學習一個輕量級的「前端框架」,其中Keras與Gluon都是不錯的選擇。由於其簡單、易學、易上手的特點,不妨將二者同時學會。這種前端框架的特點是很好寫,能夠快速方便地寫出一個網路投入具體問題使用。缺點是不夠靈活,不能從底層一步步地設計自己的網路。如果只是想在一些常見的場景中使用一下深度學習模型,感受一下深度學習的威力,事實上只需要學會一個輕量級前端框架就夠了。

不過對於深度學習工程師,或是科研工作者而言,為了要更加靈活地設計符合自己要求的網路,還是有必要學習一個完整的深度學習框架。目前真正主流的取捨存在於PyTorch與TensorFlow當中。總的來說,從計算效率、受歡迎程度、社區完善程度等各個方面,TensorFlow都還要略勝一籌。但是PyTorch在諸多的方面也不落下風。而二者最大的區別在於,PyTorch是動態的,而TensorFlow具有強大的靜態的屬性,這也導致了TensorFlow的上手難度比起PyTorch要大很多。

2018全國百所院校大數據公益巡講活動

為普及大數據知識、宣傳大數據文化,同時進一步推動數據科學的發展和大數據教學資源共享平台建設,北京大數據研究院博雅大數據學院特發起「2018全國百所院校大數據公益巡講活動」。歡迎全國院校積極申報!

喜歡這篇文章嗎?立刻分享出去讓更多人知道吧!

本站內容充實豐富,博大精深,小編精選每日熱門資訊,隨時更新,點擊「搶先收到最新資訊」瀏覽吧!


請您繼續閱讀更多來自 全球大搜羅 的精彩文章:

張繼科:英雄不遲暮,藏獒心依舊
我為什麼做無國界藝術?

TAG:全球大搜羅 |