天天看點

來自中科院計算所博士師兄的建議

聲明:本文引用自畢業于中國科學院計算技術研究所的劉昕博士 

程式設計語言與DL架構的選擇

當然,作為開發者,想要去實作一個模型,繞不開的問題便是:

應該選擇什麼語言?應該選擇什麼架構?

對于開發人員而言,語言的選擇其實不是問題。但作為入門,最為理所當然的建議則是Python,原因也非常簡單:Python最好學。

對于機器學習的學習,使用Python就意味着你不必分心去學習那些複雜的資料類型限制以及轉化、指針、記憶體管理或垃圾收集之類的“進階”(一般同時也代表着複雜)的特性,将精力集中在自己的目标上。當然,一些Python特有的方法(如lambda、yield或reduce)以及工具(如NumPy、pandas),還是需要多多使用,盡快熟練。

而架構方面,從使用者的次元去劃分,目前數量非常之多的機器學習架構,則可大體上分為兩大陣營。

學術友好型: Theano、Torch與Caffe

學術研究時,弄出來一個新模型、新算法、新函數是常有的事,做出新的突破也是學術研究最基本的要求。是以,這些架構通常都便于定制模型,也可深入修改内部實作。很多新成果都會在發表論文的同時,提供這些架構上的實作代碼以供參考。它們在性能方面也比較出色。

其代價就是,要麼是使用了困難(Caffe:C++)或小衆(Torch:Lua)的開發語言,要麼是有一些古怪的缺點(Theano:編譯超級慢)。

而且,這些架構似乎都沒怎麼考慮過“怎麼提供服務”的問題。想要部署到伺服器上?Caffe已算是最簡單的了,但仍要經曆漫長而痛苦的摸索曆程。

工業友好型: Tensorflow、MXNet與Caffe

工業上往往更注重“把一個東西做出來,并且讓它運作得良好”。是以這些架構首先就需要支援并行訓練。其中Tensorflow和MXNet支援多機多卡、單機多卡、多機單卡并行,Caffe則支援單機多卡,雖然性能還不是特别理想。

在我們的測試中,Tensorflow的雙卡并行隻能達到單卡的1.5倍左右性能,卡越多,這個比例越低。Caffe要好一些,但參數同步和梯度計算無論如何也都需要時間,是以沒有哪個架構能在沒有性能損失的情況下實作擴充。而多機情況下,性能損失更大,很多時候都讓人感到無法接受。

相對來說,隻有Tensorflow提供了比較好的部署機制(Serving),并且有直接部署到移動端的方案。而MXNet和Caffe則是直接編譯的方式,雖然也能實作,但是說實話,依然很麻煩。

至于缺點,除Caffe之外,其他兩種架構對于學術界動态的跟蹤都不太緊,Tensorflow到現在都沒有PReLU的官方實作,前不久才剛推出一系列檢測(Detection)的模型。MXNet這一點上要積極些,可是受限于較小的開發者社群,很多成果都隻能等待大神們的contribution,或是自行實作。

這樣看來,難道最好的架構是Caffe?既能兼顧學術和實作,又能兼備靈活性和性能兼備……說實話,我的确是這麼認為的。但前提是你懂C++,如果出身不是C++開發人員,相信我,這門語言也不比機器學習容易多少。

是以,對于大多數有志于投身于機器學習開發(而非研究)的同學們來說,我推薦首選Tensorflow作為你的第一個開發架構。除了上述的優點之外,最主要的因素是它人氣高。遇到任何問題,你都可以找到一群志同道合的夥伴們去咨詢,或是一起研究。對于初學者而言,其重要程度不言而喻。

實戰上手的資料

上過課程、學好語言、裝好架構之後,自然就要通過親手程式設計,來把自己的模型實作出來。

但在深度學習領域,沒有資料的模型就是無源之水,毫無價值。而目前流行的監督學習,要求必須有足夠的帶标注資料來作為訓練資料。那麼,從哪裡能得到這樣的資料以進行學習呢?答案就是公開資料集。

例如,在學習論文時,如果它提出了一個性能優異的模型或者方法,通常會附有在幾個公開的标準資料集上的成績,這些标準資料集就是可以去下載下傳來學習和使用的資源。另外,諸如Kaggle和天池之類的機器學習競賽,其比賽項目中也會提供很多資料集供學習和測試。這些就是學習階段的主要資料來源。

以CV領域為例,常見的公開資料集就包括以下這些。

MNIST

不論選擇哪本教材、哪個架構,在剛剛接觸機器學習的時候,一定會接觸到MNIST。它是由Yann LeCun所建立的手寫數字庫,每條資料是固定的784個位元組,由28x28個灰階像素組成,大概長成這樣:

目标是對輸入進行10-分類,進而輸出每個手寫數字所表示的真實數字。

因為它體積小(10M左右)、資料多(6萬張訓練圖檔)、适用範圍廣(NN/CNN/SVM/KNN都可以拿來跑跑)而聞名天下,其地位相當于機器學習界的Hello World。在LeCun的MNIST官方網站上(yann.lecun.com/exdb/mnist/),還貼有各種模型跑這個資料集的最好成績,目前的最好得分是CNN的,約為99.7%。

由于該資料集非常之小,是以即便是在CPU上,也可以幾秒鐘就跑完NN的訓練,或是幾分鐘跑完一個簡單的CNN模型。

CIFAR

而打算從圖像方面入手的同學,CIFAR資料庫(官網:www.cs.toronto.edu/~kriz/cifar.html)則是一個更好的入門選項。

該資料庫分為2個版本,CIFAR-10和CIFAR-100。顧名思義,CIFAR-10有10個分類,每個分類有5000張訓練圖檔和1000張測試圖檔,每張圖檔是32x32像素的3通道位圖,如圖2所示。

 而CIFAR-100則有100個分類,每個分類變成500張訓練圖檔與100張測試圖檔,但圖檔的大小并沒有什麼變化。

之是以它比MNIST更适合作為圖檔處理的入門,是因為它盡管分辨率較低,但卻是三通道、真實拍攝的照片。其中有些圖檔的背景還略微複雜,更貼近我們真實的圖檔處理場景。相對而言,MNIST的灰階輸入和幹淨背景就顯得過于簡單,況且99.7%的準确率也确實難有提升的空間。

 ImageNet和MS COCO

至于ImageNet(www.image-net.org/)和COCO(http://mscoco.org/),則是兩個工業級别的圖像資料集。通常提到它們時,ImageNet指的是ILSVRC2012的訓練集,而COCO則是COCO-2014訓練集。

ImageNet有大量的圖檔(一百多萬張,分成1000個分類)和标注。

 COCO雖然圖檔數量少一些(8萬多張,80個分類),但每張圖檔都有輪廓标記,并且附帶分類标注和5句描述話語(英文)。其圖檔大緻如圖4。

是以當我們進入實際工作的階段,就要根據具體的需要從中選擇适合自己的資料集,以作為benchmark或是pretrain資料集。

實戰階段的學習用機配置

接下來,我們就需要一台機器來把架構搭建起來,以編寫和運作我們的helloAI。然而,我在很多地方都看到小夥伴們在問 

(1)我需要什麼樣的配置能學機器學習?

(2)我需要買塊GTX1080/TITAN/Tesla嗎?

(3)我應該裝幾塊顯示卡?一塊?兩塊?還是四塊?

而答案也往往傾向于:

“必須得有GPU啊,至少1080,沒有四路Titan你都不好意思跟人打招呼!”

其實,并不完全是這樣。

如果僅僅是入門和學習,CPU或GPU完全不影響你對代碼和架構的學習。運作MNIST或CIFAR之類的玩具資料集,它們的差距并不大。以我的機器為例,運作自帶的CIFAR demo,i7 CPU和GTX 1080 Ti的速度分别是770 pics/s和2200 pics/s。GPU大概有不到三倍的性能優勢。是以,差距其實也沒多大。

這裡還有一個小竅門,就是想用CPU版本的Tensorflow,最好不要用pip下載下傳的方式,而是自行編譯。因為在開發機上編譯時,它會自動打開所有支援的加速指令集(SSE4.1/SSE4.2/AVX/AVX2/FMA),進而使CPU的運算大大加快。根據我們的測試,在打開全部加速指令集的情況下,訓練速度大概會有30%的提升,而預測的速度大概能提升一倍。

當然,如果真想用一個複雜模型去處理實際的生産問題,模型的複雜度和資料量都不是CIFAR這樣的玩具資料集可以比拟的。如果用我們的一個生産模型來運作CIFAR資料集,其他參數和條件完全相同,它在i5/i7/960/GTX1080/GTX1080Ti下的速度分别是:19/25/140/460/620(機關pics/s,越大越好)。這裡就能看出差距了,1080Ti大概是i7 CPU的25倍。而在模型上線使用(inference)時,GPU也會有10-20倍的性能優勢。模型越複雜,GPU的優勢越明顯。

綜合來看,如果僅僅是入門時期的學習,我建議先不用專門購買帶GPU的機器;而是先用你現有的機器,使用CPU版本,去學習架構和一些基礎。等到你對基礎已經掌握得比較紮實,那麼自然就會形成跑一些更複雜的模型和更“真實”的資料的想法,這時候再考慮買一塊GPU,以縮短訓練時間。

在選GPU時,我聽過一些朋友們推薦GTX1070×2這樣的選擇。理論上講,1070的性能大概能達到1080的75%,而價格隻有1080的一半,從各個方面看,似乎都是雙1070更有優勢。然而不要忘記,雙卡的性能是不可能達到單卡的2倍的,在目前的Tensorflow上,大概隻能達到1.5倍上下,算下來其實和1080單卡差不多。而雙顯示卡的主機闆、電源與機箱散熱都需要做更多的考慮,從成本效益上來看,未必真的劃算。

不過,如果顯示卡預算剛好卡在5000-6000的檔位,雙1070也有它的優勢。比如,可以學習使用多顯示卡并行計算的用法,在不着急的時候可以用兩塊顯示卡同時跑兩個不同的任務,合并起來就相當于有了16G的顯存等等。考慮到這些因素,雙1070的确是最适合入門學習的選擇——如果買不起雙1080/雙TITAN的話(笑)。

如果你有打算用筆記本來作為主力學習用機,我的建議是:最好不要,除非你使用Linux的經驗很豐富,或是不打算用GPU加速。很多筆記本在安裝Liunx後會出現驅動方面的問題,而且使用GPU加速時的高熱量也會非常影響系統的穩定性。如果沒有很豐富的經驗,經常會在一個小問題上卡掉幾個小時寶貴的學習時間。

深度學習高手該怎樣煉成?

深度學習本質上是深層的人工神經網絡,它不是一項孤立的技術,而是數學、統計機器學習、計算機科學和人工神經網絡等多個領域的綜合。深度學習的了解,離不開大學數學中最為基礎的數學分析(高等數學)、線性代數、機率論和凸優化;深度學習技術的掌握,更離不開以程式設計為核心的動手實踐。沒有紮實的數學和計算機基礎做支撐,深度學習的技術突破隻能是空中樓閣。

是以,想在深度學習技術上有所成就的初學者,就有必要了解這些基礎知識之于深度學習的意義。除此之外,我們的專業路徑還會從結構與優化的理論次元來介紹深度學習的上手,并基于深度學習架構的實踐淺析一下進階路徑。

最後,本文還将分享深度學習的實踐經驗和擷取深度學習前沿資訊的經驗。

數學基礎

如果你能夠順暢地讀懂深度學習論文中的數學公式,可以獨立地推導新方法,則表明你已經具備了必要的數學基礎。

掌握數學分析、線性代數、機率論和凸優化四門數學課程包含的數學知識,熟知機器學習的基本理論和方法,是入門深度學習技術的前提。因為無論是了解深度網絡中各個層的運算和梯度推導,還是進行問題的形式化或是推導損失函數,都離不開紮實的數學與機器學習基礎。

(1)數學分析:在工科專業所開設的高等數學課程中,主要學習的内容為微積分。對于一般的深度學習研究和應用來說,需要重點溫習函數與極限、導數(特别是複合函數求導)、微分、積分、幂級數展開、微分方程等基礎知識。在深度學習的優化過程中,求解函數的一階導數是最為基礎的工作。當提到微分中值定理、Taylor公式和拉格朗日乘子的時候,你不應該隻是感到與它們似曾相識。這裡推薦同濟大學第五版的《高等數學》教材。

(2)線性代數:深度學習中的運算常常被表示成向量和矩陣運算。線性代數正是這樣一門以向量和矩陣作為研究對象的數學分支。需要重點溫習的包括向量、線性空間、線性方程組、矩陣、矩陣運算及其性質、向量微積分。當提到Jacobian矩陣和Hessian矩陣的時候,你需要知道确切的數學形式;當給出一個矩陣形式的損失函數時,你可以很輕松的求解梯度。這裡推薦同濟大學第六版的《線性代數》教材。

(3)機率論:機率論是研究随機現象數量規律的數學分支,随機變量在深度學習中有很多應用,無論是随機梯度下降、參數初始化方法(如Xavier),還是Dropout正則化算法,都離不開機率論的理論支撐。除了掌握随機現象的基本概念(如随機試驗、樣本空間、機率、條件機率等)、随機變量及其分布之外,還需要對大數定律及中心極限定理、參數估計、假設檢驗等内容有所了解,進一步還可以深入學習一點随機過程、馬爾可夫随機鍊的内容。這裡推薦浙江大學版的《機率論與數理統計》。

(4)凸優化:結合以上三門基礎的數學課程,凸優化可以說是一門應用課程。但對于深度學習而言,由于常用的深度學習優化方法往往隻利用了一階的梯度資訊進行随機梯度下降,因而從業者事實上并不需要多少“高深”的凸優化知識。了解凸集、凸函數、凸優化的基本概念,掌握對偶問題的一般概念,掌握常見的無限制優化方法如梯度下降方法、随機梯度下降方法、Newton方法,了解一點等式限制優化和不等式限制優化方法,即可滿足了解深度學習中優化方法的理論要求。這裡推薦一本教材,Stephen Boyd的《Convex Optimization》。

(5)機器學習:歸根結底,深度學習隻是機器學習方法的一種,而統計機器學習則是機器學習領域事實上的方法論。以監督學習為例,需要你掌握線性模型的回歸與分類、支援向量機與核方法、随機森林方法等具有代表性的機器學習技術,并了解模型選擇與模型推理、模型正則化技術、模型內建、Bootstrap方法、機率圖模型等。深入一步的話,還需要了解半監督學習、無監督學習和強化學習等專門技術。這裡推薦一本經典教材《The elements of Statistical Learning》

計算機基礎

深度學習要在實戰中論英雄,是以具備GPU伺服器的硬體選型知識,熟練操作Linux系統和進行Shell程式設計,熟悉C++和Python語言,是成長為深度學習實戰高手的必備條件。目前有一種提法叫“全棧深度學習工程師”,這也反映出了深度學習對于從業者實戰能力的要求程度:既需要具備較強的數學與機器學習理論基礎,又需要精通計算機程式設計與必要的體系結構知識。

(1)程式設計語言:在深度學習中,使用最多的兩門程式設計語言分别是C++和Python。迄今為止,C++語言依舊是實作高性能系統的首選,目前使用最廣泛的幾個深度學習架構,包括Tensorflow、Caffe、MXNet,其底層均無一例外地使用C++編寫。而上層的腳本語言一般為Python,用于資料預處理、定義網絡模型、執行訓練過程、資料可視化等。目前,也有Lua、R、Scala、Julia等語言的擴充包出現于MXNet社群,呈現百花齊放的趨勢。這裡推薦兩本教材,一本是《C++ Primer第五版》,另外一本是《Python核心程式設計第二版》。()(2)Linux作業系統:深度學習系統通常運作在開源的Linux系統上,目前深度學習社群較為常用的Linux發行版主要是Ubuntu。對于Linux作業系統,主要需要掌握的是Linux檔案系統、基本指令行操作和Shell程式設計,同時還需熟練掌握一種文本編輯器,比如VIM。基本操作務必要做到熟練,當需要批量替換一個檔案中的某個字元串,或者在兩台機器之間用SCP指令拷貝檔案時,你不需要急急忙忙去打開搜尋引擎。這裡推薦一本工具書《鳥哥的Linux私房菜》。

(3)CUDA程式設計:深度學習離不開GPU并行計算,而CUDA是一個很重要的工具。CUDA開發套件是NVidia提供的一套GPU程式設計套件,實踐當中應用的比較多的是CUDA-BLAS庫。這裡推薦NVidia的官方線上文檔http://docs.nvidia.com/cuda/。

(4)其他計算機基礎知識:掌握深度學習技術不能隻滿足于使用Python調用幾個主流深度學習架構,從源碼着手去了解深度學習算法的底層實作是進階的必由之路。這個時候,掌握資料結構與算法(尤其是圖算法)知識、分布式計算(了解常用的分布式計算模型),和必要的GPU和伺服器的硬體知識(比如當我說起CPU的PCI-E通道數和GPU之間的資料交換瓶頸時,你能心領神會),你一定能如虎添翼。

深度學習入門

接下來分别從理論和實踐兩個角度來介紹一下深度學習的入門。

(1)深度學習理論入門:我們可以用一張圖(圖1)來回顧深度學習中的關鍵理論和方法。從MCP神經元模型開始,首先需要掌握卷積層、Pooling層等基礎結構單元,Sigmoid等激活函數,Softmax等損失函數,以及感覺機、MLP等經典網絡結構。接下來,掌握網絡訓練方法,包括BP、Mini-batch SGD和LR Policy。最後還需要了解深度網絡訓練中的兩個至關重要的理論問題:梯度消失和梯度溢出。

以卷積神經網絡為例,我們用圖2來展示入門需要掌握的知識。起點是Hubel和Wiesel的對貓的視覺皮層的研究,再到日本學者福島邦彥神經認知機模型(已經出現了卷積結構),但是第一個CNN模型誕生于1989年,1998年誕生了後來被大家熟知的LeNet。随着ReLU和Dropout的提出,以及GPU和大資料所帶來的曆史機遇,CNN在2012年迎來了曆史性的突破——誕生了AlexNet網絡結構。2012年之後,CNN的演化路徑可以總結為四條:1. 更深的網絡;2. 增強卷積模的功能以及上訴兩種思路的融合ResNet和各種變種;3. 從分類到檢測,最新的進展為ICCV 2017的Best Paper Mask R-CNN;4. 增加新的功能子產品。

(2)深度學習實踐入門:掌握一個開源深度學習架構的使用,并進一步的研讀代碼,是實際掌握深度學習技術的必經之路。目前使用最為廣泛的深度學習架構包括Tensorflow、Caffe、MXNet和PyTorch等。架構的學習沒有捷徑,按照官網的文檔step by step配置及操作,參與GitHub社群的讨論,遇到不能解答的問題及時Google是快速實踐入門的好方法。

初步掌握架構之後,進一步的提升需要依靠于具體的研究問題,一個短平快的政策是先刷所在領域權威的Benchmark。例如人臉識别領域的LFW和MegaFace,圖像識别領域與物體檢測領域的ImageNet、Microsoft COCO,圖像分割領域的Pascal VOC等。通過複現或改進别人的方法,親手操練資料的準備、模型的訓練以及調參,能在所在領域的Benchmark上達到目前最好的結果,實踐入門的環節就算初步完成了。

後續的進階,就需要在實戰中不斷地去探索和提升了。例如:熟練的處理大規模的訓練資料,精通精度和速度的平衡,掌握調參技巧、快速複現或改進他人的工作,能夠實作新的方法等等。

深度學習實戰經驗

在這裡,分享四個方面的深度學習實戰經驗。

1. 充足的資料。大量且有标注的資料,依舊在本質上主宰着深度學習模型的精度,每一個深度學習從業者都需要認識到資料極端重要。擷取資料的方式主要有三種:開放資料(以學術界開放為主,如ImageNet和LFW)、第三方資料公司的付費資料和結合自身業務産生的資料。

2. 熟練的程式設計實作能力。深度學習算法的實作離不開熟練的程式設計能力,熟練使用Python進行程式設計是基礎。如果進一步的修改底層實作或增加新的算法,則可能需要修改底層代碼,此時熟練的C++程式設計能力就變得不可或缺。一個明顯的現象是,曾經隻需要掌握Matlab就可以笑傲江湖的計算機視覺研究者,如今也紛紛需要開始補課學習Python和C++了。

3. 充裕的GPU資源。深度學習的模型訓練依賴于充裕的GPU資源,通過多機多卡的模型并行,可以有效的提高模型收斂速度,進而更快的完成算法驗證和調參。一個專業從事深度學習的公司或實驗室,擁有數十塊到數百塊的GPU資源已經是普遍現象。

4. 創新的方法。以深度學習領域權威的ImageNet競賽為例,從2012年深度學習技術在競賽中奪魁到最後一屆2017競賽,方法創新始終是深度學習進步的核心動力。如果隻是滿足于多增加一點資料,把網絡加深或調幾個SGD的參數,是難以做出真正一流的成果的。

根據筆者的切身經曆,方法創新确實能帶來難以置信的結果。一次參加阿裡巴巴組織的天池圖像檢索比賽,筆者提出的一點創新——使用标簽有噪聲資料的新型損失函數,結果竟極大地提高了深度模型的精度,還拿到了當年的冠軍。

深度學習前沿

前沿資訊的來源

實戰中的技術進階,必需要了解深度學習的最新進展。換句話說,就是刷論文:除了定期刷Arxiv,刷代表性工作的Google Scholar的引用,關注ICCV、CVPR和ECCV等***會議之外,知乎的深度學習專欄和Reddit上時不時會有最新論文的讨論(或者精彩的吐槽)。

一些高品質的公衆号(深度學習大講堂),同時,關注學術界大佬LeCun和Bengio等人的Facebook/Quora首頁,關注微網誌大号“愛可可愛生活”等人,也常有驚喜的發現。

建議關注的重點

(1)新的網絡結構。在以SGD為代表的深度學習優化方法沒有根本性突破的情況下,修改網絡結構是可以較快提升網絡模型精度的方法。2015年以來,以ResNet的各種改進為代表的各類新型網絡結構如雨後春筍般湧現,其中代表性的有DenseNet、SENet、ShuffuleNet等。

(2)新的優化方法。縱觀從1943年MCP模型到2017年間的人工神經網絡發展史,優化方法始終是進步的靈魂。以誤差反向傳導(BP)和随機梯度下降(SGD)為代表的優化技術的突破,或是Sigmoid/ReLU之後全新一代激活函數的提出,都非常值得期待。筆者認為,近期的工作如《Learning gradient descent by gradient descent》以及SWISH激活函數,都很值得關注。但能否取得根本性的突破,也即完全替代目前的優化方法或ReLU激活函數,尚不可預測。

(3)新的學習技術。深度強化學習和生成對抗網絡(GAN)。最近幾周刷屏的Alpha Zero再一次展示了深度強化學習的強大威力,完全不依賴于人類經驗,在圍棋項目上通過深度強化學習“左右互搏”所練就的棋力,已經遠超過上一代秒殺一衆人類高手的AlghaGo Master。同樣的,生成對抗網絡及其各類變種也在不停地預告一個學習算法自我生成資料的時代的序幕。筆者所在的公司也正嘗試将深度強化學習和GAN相結合,用于跨模态的訓練資料的增廣。

(4)新的資料集。資料集是深度學習算法的練兵場,是以資料集的演化是深度學習技術進步的縮影。以人臉識别為例,後LFW時代,MegaFace和Microsoft Celeb-1M資料集已接棒大規模人臉識别和資料标簽噪聲條件下的人臉識别。後ImageNet時代,Visual Genome正試圖建立一個包含了對象、屬性、關系描述、問答對在内的視覺基因組。

最後,也是最初

在目前這個階段,業内還處于算法紅利期,新的算法、新的模型層出不窮,僅僅在CV領域,每天就有二三十篇paper被釋出到arXiv上,每年的頂會頂刊收錄的成果都在大幅度重新整理上一年甚至上一個月的記錄。

打好基礎之後,跟蹤論文并複現、學習和思考,這樣的任務将成為你現階段的一項日常作業,如果你已經進入或是決定進入這個行業的話。因為稍有懈怠,便要面臨着被時代抛棄、跟不上節奏的情況。是以,到這一步,對于有些人來說是一個結束,而對另一些人來說,則才剛剛是開始。

這個時候,我們可以回過頭來重新問問自己前面那幾個問題:

(1)“我真的已經想清楚,要踏足這個行業嗎?”

(2)“我能夠付出比其他人更多的辛苦汗水,在這條路上堅定地走下去嗎?”

(3)“在遭受了痛苦甚至打擊之後,我對機器學習的熱愛,仍然能夠維持我繼續前進嗎?”

這條路,我在走,很多人在走,那麼,你來嗎?