人人都可以做深度學習應用:入門篇

徐漢彬發表於2017-03-14

一、人工智慧和新科技革命

2017年圍棋界發生了一件比較重要事,Master(Alphago)以60連勝橫掃天下,擊敗各路世界冠軍,人工智慧以氣勢如虹的姿態出現在我們人類的面前。圍棋曾經一度被稱為“人類智慧的堡壘”,如今,這座堡壘也隨之成為過去。從2016年三月份AlphaGo擊敗李世石開始,AI全面進入我們大眾的視野,對於它的討論變得更為火熱起來,整個業界普遍認為,它很可能帶來下一次科技革命,並且,在未來可預見的10多年裡,深刻得改變我們的生活。

人人都可以做深度學習應用:入門篇

其實,AI除了可以做我們熟知的人臉、語音等識別之外,它可以做蠻多有趣的事情。

例如,讓AI學習大量古詩之後寫古詩,並且可以寫出質量非常不錯的古詩。

人人都可以做深度學習應用:入門篇

又或者,將兩部設計造型不同的汽車進行融合,形成全新一種設計風格的新汽車造型。

人人都可以做深度學習應用:入門篇

還有,之前大家在朋友圈裡可能看過的,將相片轉換成對應的藝術風格的畫作。

人人都可以做深度學習應用:入門篇

當前,人工智慧已經在影象、語音等多個領域的技術上,取得了全面的突破。與此同時,另外一個問題隨之而來,如果這一輪的AI浪潮真的將會掀起新的科技革命,那麼在可預見的未來,我們整個網際網路都將發生翻天覆地的變化,深刻影響我們的生活。那麼作為工程師的我,又應該以何種態度和方式應對這場時代洪流的衝擊呢?

在回答這個問題之前,我們先一起看看上一輪由計算機資訊科技引領的科技革命中,過去30多年中國程式設計師的角色變化:

人人都可以做深度學習應用:入門篇

通過上圖可以簡總結:程式設計技術在不斷地發展並且走向普及,從最開始掌握在科學家和專家學者手中的技能,逐漸發展為一門大眾技能。換而言之,我們公司內很多資深的工程師,如果帶著今天對程式設計和計算機的理解和理念回到1980年,那麼他無疑就是那個時代的計算機專家。

如果這一輪AI浪潮真的會帶來新的一輪科技革命,那麼我們相信,它也會遵循類似的發展軌跡,逐步發展和走向普及。如果基於這個理解,或許,我們可以通過積極學習,爭取成為第一代AI工程師。

二、深度學習技術

這一輪AI的技術突破,主要源於深度學習技術,而關於AI和深度學習的發展歷史我們這裡不重複講述,可自行查閱。我用了一個多月的業務時間,去了解和學習了深度學習技術,在這裡,我嘗試以一名工程師的視角,以儘量容易讓大家理解的方式一起探討下深度學習的原理,儘管,受限於我個人的技術水平和掌握程度,未必完全準確。

1. 人的智慧和神經元

人類智慧最重要的部分是大腦,大腦雖然複雜,它的組成單元卻是相對簡單的,大腦皮層以及整個神經系統,是由神經元細胞組成的。而一個神經元細胞,由樹突和軸突組成,它們分別代表輸入和輸出。連在細胞膜上的分叉結構叫樹突,是輸入,那根長長的“尾巴”叫軸突,是輸出。神經元輸出的有電訊號和化學訊號,最主要的是沿著軸突細胞膜表面傳播的一個電脈衝。忽略掉各種細節,神經元,就是一個積累了足夠的輸入,就產生一次輸出(興奮)的相對簡單的裝置。

人人都可以做深度學習應用:入門篇

樹突和軸突都有大量的分支,軸突的末端通常連線到其他細胞的樹突上,連線點上是一個叫“突觸”的結構。一個神經元的輸出通過突觸傳遞給成千上萬個下游的神經元,神經元可以調整突觸的結合強度,並且,有的突觸是促進下游細胞的興奮,有的是則是抑制。一個神經元有成千上萬個上游神經元,積累它們的輸入,產生輸出。

人人都可以做深度學習應用:入門篇

人腦有1000億個神經元,1000萬億個突觸,它們組成人腦中龐大的神經網路,最終產生的結果即是人的智慧。

2. 人工神經元和神經網路

一個神經元的結構相對來說是比較簡單的,於是,科學家們就思考,我們的AI是否可以從中獲得借鑑?神經元接受激勵,輸出一個響應的方式,同計算機中的輸入輸出非常類似,看起來簡直就是量身定做的,剛好可以用一個函式來模擬。

人人都可以做深度學習應用:入門篇

通過借鑑和參考神經元的機制,科學家們模擬出了人工神經元和人工神經網路。當然,通過上述這個抽象的描述和圖,比較難讓大家理解它的機制和原理。我們以“房屋價格測算”作為例子,一起來看看:

一套房子的價格,會受到很多因素的影響,例如地段、朝向、房齡、面積、銀行利率等等,這些因素如果細分,可能會有幾十個。一般在深度學習模型裡,這些影響結果的因素我們稱之為特徵。我們先假設一種極端的場景,例如影響價格的特徵只有一種,就是房子面積。於是我們收集一批相關的資料,例如,50平米50萬、93平米95萬等一系列樣本資料,如果將這些樣本資料放到而為座標裡看,則如下圖:

人人都可以做深度學習應用:入門篇

然後,正如我們前面所說的,我們嘗試用一個“函式”去擬合這個輸入(面積x)和輸出(價格y),簡而言之,我們就是要通過一條直線或者曲線將這些點“擬合”起來。

假設情況也比較極端,這些點剛好可以用一條“直線”擬合(真實情況通常不會是直線),如下圖:

人人都可以做深度學習應用:入門篇

那麼我們的函式是一個一次元方程f(x) = ax +b,當然,如果是曲線的話,我們得到的將是多次元方程。我們獲得這個f(x) = ax +b的函式之後,接下來就可以做房價“預測”,例如,我們可以計算一個我們從未看見的面積案例81.5平方米,它究竟是多少錢?

這個新的樣本案例,可以通過直線找到對應的點(黃色的點),如圖下:

人人都可以做深度學習應用:入門篇

粗略的理解,上面就是AI的概括性的運作方式。這一切似乎顯得過於簡單了?當然不會,因為,我們前面提到,影響房價其實遠不止一個特徵,而是有幾十個,這樣問題就比較複雜了,接下來,這裡則要繼續介紹深度學習模型的訓練方式。這部分內容相對複雜一點,我儘量以業務工程師的視角來做一個粗略而簡單的闡述。

3. 深度學習模型的訓練方式

當有好幾十個特徵共同影響價格的時候,自然就會涉及權重分配的問題,例如有一些對房價是主要正權重的,例如地段、面積等,也有一些是負權重的,例如房齡等。

(1)初始化權重計算

那麼,第一個步其實是給這些特徵加一個權重值,但是,最開始我們根本不知道這些權重值是多少?怎麼辦呢?不管那麼多了,先給它們隨機賦值吧。隨機賦值,最終計算出來的估算房價肯定是不準確的,例如,它可能將價值100萬的房子,計算成了10萬。

(2)損失函式

因為現在模型的估值和實際估值差距比較大,於是,我們需要引入一個評估“不準確”程度的衡量角色,也就是損失(loss)函式,它是衡量模型估算值和真實值差距的標準,損失函式越小,則模型的估算值和真實值的察覺越小,而我們的根本目的,就是降低這個損失函式。讓剛剛的房子特徵的模型估算值,逼近100萬的估算結果。

(3)模型調整

通過梯度下降和反向傳播,計算出朝著降低損失函式的方向調整權重引數。舉一個不恰當的比喻,我們給面積增加一些權重,然後給房子朝向減少一些權重(實際計算方式,並非針對單個個例特徵的調整),然後損失函式就變小了。

(4)迴圈迭代

調整了模型的權重之後,就可以又重新取一批新的樣本資料,重複前面的步驟,經過幾十萬次甚至更多的訓練次數,最終估算模型的估算值逼近了真實值結果,這個模型的則是我們要的“函式”。

人人都可以做深度學習應用:入門篇

為了讓大家更容易理解和直觀,採用的例子比較粗略,並且講述深度學習模型的訓練過程,中間省略了比較多的細節。講完了原理,那麼我們就開始講講如何學習和搭建demo。

三、深度學習環境搭建

在2個月前(2016年11月),人工智慧對我來說,只是一個高大上的概念。但是,經過一個多月的業餘時間的認真學習,我發現還是能夠學到一些東西,並且跑一些demo和應用出來的。

1. 學習的提前準備

(1)部分數學內容的複習,高中數學、概率、線性代數等部分內容。(累計花費了10個小時,,挑了關鍵的點看了下,其實還是不太夠,只能讓自己看公式的時候,相對沒有那麼懵)

(2)Python基礎語法學習。(花費了3個小時左右,我以前從未寫過Python,因為後面Google的TensorFlow框架的使用是基於Python的)

(3)Google的TensorFlow深度學習開源框架。(花費了10多個小時去看)

數學基礎好或者前期先不關注原理的同學,數學部分不看也可以開始做,全憑個人選擇。

2. Google的TensorFlow開源深度學習框架

深度學習框架,我們可以粗略的理解為是一個“數學函式”集合和AI訓練學習的執行框架。通過它,我們能夠更好的將AI的模型執行和維護起來。

深度學習的框架有各種各樣的版本(CaffeTorchTheano等等),我只接觸了Google的TensorFlow,因此,後面的內容都是基於TensorFlow展開的,它的詳細介紹這裡不展開講述,建議直接進入官網檢視。非常令人慶幸的是TensorFlow比較早就有中文社群了,儘管裡面的內容有一點老,搭建環境方面有一些坑,但是已經屬於為數不多的中文文件了,大家且看且珍惜。

TensorFlow的中文社群:

TensorFlow中文社群-首頁

TensorFlow的英文社群:

tensorflow.org/

3. TensorFlow環境搭建

環境搭建本身並不複雜,主要解決相關的依賴。但是,基礎庫的依賴可以帶來很多問題,因此,建議儘量一步到位,會簡單很多。

(1)作業系統

我搭建環境使用的機器是騰訊雲上的機器,軟體環境如下:

作業系統:CentOS 7.2 64位(GCC 4.8.5)

因為這個框架依賴於python2.7和glibc 2.17。比較舊的版本的CentOS一般都是python2.6以及版本比較低的glibc,會產生比較的多基礎庫依賴問題。而且,glibc作為Linux的底層庫,牽一髮動全身,直接對它升級是比較複雜,很可能會帶來更多的環境異常問題。

(2)軟體環境

我目前安裝的Python版本是python-2.7.5,建議可以採用yum install python的方式安裝相關的原來軟體。然後,再安裝 python內的元件包管理器pip,安裝好pip之後,接下來的其他軟體的安裝就相對比較簡單了。

例如安裝TensorFlow,可通過如下一句命令完成(它會自動幫忙解決一些庫依賴問題):

pip install -U tensorflow

這裡需要特別注意的是,不要按照TensorFlow的中文社群的指引去安裝,因為它會安裝一個非常老的版本(0.5.0),用這個版本跑很多demo都會遇到問題的。而實際上,目前通過上述提供的命令安裝,是tensorflow (1.0.0)的版本了。

人人都可以做深度學習應用:入門篇

Python(2.7.5)下的其他需要安裝的關鍵元件:

tensorflow (0.12.1),深度學習的核心框架

image (1.5.5),影象處理相關,部分例子會用到

PIL (1.1.7),影象處理相關,部分例子會用到

除此之後,當然還有另外的一些依賴元件,通過pip list命令可以檢視我們安裝的python元件:

按照上述提供的來搭建系統,可以規避不少的環境問題。

搭建環境的過程中,我遇到不少問題。例如:在跑官方的例子時的某個報,AttributeError: ‘module’ object has no attribute ‘gfile’,就是因為安裝的TensorFlow的版本比較老,缺少gfile模組導致的。而且,還有各種各樣的。

更詳細的安裝說明:

tensorflow.org/install/

(3)TensorFlow環境測試執行

測試是否安裝成功,可以採用官方的提供的一個短小的例子,demo生成了一些三維資料, 然後用一個平面擬合它們(官網的例子採用的初始化變數的函式是initialize_all_variables,該函式在新版本里已經被廢棄了):

執行的結果類似如下:

人人都可以做深度學習應用:入門篇

經過200次的訓練,模型的引數逐漸逼近最佳擬合的結果(W: [[0.100 0.200]], b: [0.300]),另外,我們也可以從程式碼的“風格”中,瞭解到框架樣本訓練的基本執行方式。雖然,官方的教程後續會涉及越來越多更復雜的例子,但從整體上看,也是類似的模式。

人人都可以做深度學習應用:入門篇

步驟劃分:

  1. 準備資料:獲得有標籤的樣本資料(帶標籤的訓練資料稱為有監督學習);
  2. 設定模型:先構建好需要使用的訓練模型,可供選擇的機器學習方法其實也挺多的,換而言之就是一堆數學函式的集合;
  3. 損失函式和優化方式:衡量模型計算結果和真實標籤值的差距;
  4. 真實訓練運算:訓練之前構造好的模型,讓程式通過迴圈訓練和學習,獲得最終我們需要的結果“引數”;
  5. 驗證結果:採用之前模型沒有訓練過的測試集資料,去驗證模型的準確率。

其中,TensorFlow為了基於python實現高效的數學計算,通常會使用到一些基礎的函式庫,例如Numpy(採用外部底層語言實現),但是,從外部計算切回到python也是存在開銷的,尤其是在幾萬幾十萬次的訓練過程。因此,Tensorflow不單獨地執行單一的函式計算,而是先用圖描述一系列可互動的計算操作流程,然後全部一次性提交到外部執行(在其他機器學習的庫裡,也是類似的實現)。所以,上述流程圖中,藍色部分都只是設定了“計算操作流程”,而綠色部分開始才是真正的提交資料給到底層庫進行實際運算,而且,每次訓練一般是批量執行一批資料的。

四、經典入門demo:識別手寫數字(MNIST)

常規的程式設計入門有“Hello world”程式,而深度學習的入門程式則是MNIST,一個識別28*28畫素的圖片中的手寫數字的程式。

人人都可以做深度學習應用:入門篇

MNIST的資料和官網:

MNIST handwritten digit database, Yann LeCun, Corinna Cortes and Chris Burges

深度學習的內容,其背後會涉及比較多的數學原理,作為一個初學者,受限於我個人的數學和技術水平,也許並不足以準確講述相關的數學原理,因此,本文會更多的關注“應用層面”,不對背後的數學原理進行展開,感謝諒解。

1. 載入資料

程式執行的第一步當然是載入資料,根據我們之前獲得的資料集主要包括兩部分:60000的訓練資料集(mnist.train)和10000的測試資料集(mnist.test)。裡面每一行,是一個28*28=784的陣列,陣列的本質就是將28*28畫素的圖片,轉化成對應的畫素點陣。

例如手寫字1的圖片轉換出來的對應矩陣表示如下:

人人都可以做深度學習應用:入門篇

之前我們經常聽說,圖片方面的深度學習需要大量的計算能力,甚至需要採用昂貴、專業的GPU(Nvidia的GPU),從上述轉化的案例我們就已經可以獲得一些答案了。一張784畫素的圖片,對學習模型來說,就有784個特徵,而我們實際的相片和圖片動輒幾十萬、百萬級別,則對應的基礎特徵數也是這個數量級,基於這樣數量級的陣列進行大規模運算,沒有強大的計算能力支援,確實寸步難行。當然,這個入門的MNIST的demo還是可以比較快速的跑完。

Demo中的關鍵程式碼(讀取並且載入資料到陣列物件中,方便後面使用):

人人都可以做深度學習應用:入門篇

2. 構建模型

MNIST的每一張圖片都表示一個數字,從0到9。而模型最終期望獲得的是:給定一張圖片,獲得代表每個數字的概率。比如說,模型可能推測一張數字9的圖片代表數字9的概率是80%但是判斷它是8的概率是5%(因為8和9都有上半部分的小圓),然後給予它代表其他數字的概率更小的值。

人人都可以做深度學習應用:入門篇

MNIST的入門例子,採用的是softmax迴歸(softmax regression),softmax模型可以用來給不同的物件分配概率。

為了得到一張給定圖片屬於某個特定數字類的證據(evidence),我們對圖片的784個特徵(點陣裡的各個畫素值)進行加權求和。如果某個特徵(畫素值)具有很強的證據說明這張圖片不屬於該類,那麼相應的權重值為負數,相反如果某個特徵(畫素值)擁有有利的證據支援這張圖片屬於這個類,那麼權重值是正數。類似前面提到的房價估算例子,對每一個畫素點作出了一個權重分配。

假設我們獲得一張圖片,需要計算它是8的概率,轉化成數學公式則如下:

人人都可以做深度學習應用:入門篇

公式中的i代表需要預測的數字(8),人人都可以做深度學習應用:入門篇 代表預測數字為8的情況下,784個特徵的不同權重值,人人都可以做深度學習應用:入門篇代表8的偏置量(bias),X則是該圖片784個特徵的值。通過上述計算,我們則可以獲得證明該圖片是8的證據(evidence)的總和,softmax函式可以把這些證據轉換成概率 y。(softmax的數學原理,辛苦各位查詢相關資料哈)

將前面的過程概括成一張圖(來自官方)則如下:

人人都可以做深度學習應用:入門篇

不同的特徵x和對應不同數字的權重進行相乘和求和,則獲得在各個數字的分佈概率,取概率最大的值,則認為是我們的圖片預測結果。

將上述過程寫成一個等式,則如下:

人人都可以做深度學習應用:入門篇

該等式在矩陣乘法裡可以非常簡單地表示,則等價為:

人人都可以做深度學習應用:入門篇

不展開裡面的具體數值,則可以簡化為:

人人都可以做深度學習應用:入門篇

如果我們對線性代數中矩陣相關內容有適當學習,其實,就會明白矩陣表達在一些問題上,更易於理解。如果對矩陣內容不太記得了,也沒有關係,後面我會附加上線性代數的視訊。

雖然前面講述了這麼多,其實關鍵程式碼就四行:

人人都可以做深度學習應用:入門篇

上述程式碼都是類似變數佔位符,先設定好模型計算方式,在真實訓練流程中,需要批量讀取源資料,不斷給它們填充資料,模型計算才會真實跑起來。tf.zeros則表示,先給它們統一賦值為0佔位。X資料是從資料檔案中讀取的,而w、b是在訓練過程中不斷變化和更新的,y則是基於前面的資料進行計算得到。

3. 損失函式和優化設定

為了訓練我們的模型,我們首先需要定義一個指標來衡量這個模型是好還是壞。這個指標稱為成本(cost)或損失(loss),然後儘量最小化這個指標。簡單的說,就是我們需要最小化loss的值,loss的值越小,則我們的模型越逼近標籤的真實結果。

Demo中使用的損失函式是“交叉熵”(cross-entropy),它的公式如下:

人人都可以做深度學習應用:入門篇

y 是我們預測的概率分佈, y’ 是實際的分佈(我們輸入的),交叉熵是用來衡量我們的預測結果的不準確性。TensorFlow擁有一張描述各個計算單元的圖,也就是整個模型的計算流程,它可以自動地使用反向傳播演算法(backpropagation algorithm),來確定我們的權重等變數是如何影響我們想要最小化的那個loss值的。然後,TensorFlow會用我們設定好的優化演算法來不斷修改變數以降低loss值。

其中,demo採用梯度下降演算法(gradient descent algorithm)以0.01的學習速率最小化交叉熵。梯度下降演算法是一個簡單的學習過程,TensorFlow只需將每個變數一點點地往使loss值不斷降低的方向更新。

對應的關鍵程式碼如下:

人人都可以做深度學習應用:入門篇

備註內容:

交叉熵:Visual Information Theory

反向傳播:Calculus on Computational Graphs: Backpropagation

在程式碼中會看見one-hot vector的概念和變數名,其實這個是個非常簡單的東西,就是設定一個10個元素的陣列,其中只有一個是1,其他都是0,以此表示數字的標籤結果。

例如表示數字3的標籤值:

[0,0,0,1,0,0,0,0,0,0]

4. 訓練運算和模型準確度測試

通過前面的實現,我們已經設定好了整個模型的計算“流程圖”,它們都成為TensorFlow框架的一部分。於是,我們就可以啟動我們的訓練程式,下面的程式碼的含義是,迴圈訓練我們的模型500次,每次批量取50個訓練樣本。

人人都可以做深度學習應用:入門篇

其訓練過程,其實就是TensorFlow框架的啟動訓練過程,在這個過程中,python批量地將資料交給底層庫進行處理。

我在官方的demo裡追加了兩行程式碼,每隔50次則額外計算一次當前模型的識別準確率。它並非必要的程式碼,僅僅用於方便觀察整個模型的識別準確率逐步變化的過程。

人人都可以做深度學習應用:入門篇

當然,裡面涉及的accuracy(預測準確率)等變數,需要在前面的地方定義佔位:

人人都可以做深度學習應用:入門篇

當我們訓練完畢,則到了驗證我們的模型準確率的時候,和前面相同:

人人都可以做深度學習應用:入門篇

我的demo跑出來的結果如下(softmax迴歸的例子執行速度還是比較快的),當前的準確率是0.9252:

人人都可以做深度學習應用:入門篇

5. 實時檢視引數的數值的方法

剛開始跑官方的demo的時候,我們總想將相關變數的值列印出來看看,是怎樣一種格式和狀態。從demo的程式碼中,我們可以看見很多的Tensor變數物件,而實際上這些變數物件都是無法直接輸出檢視,粗略地理解,有些只是佔位符,直接輸出的話,會獲得類似如下的一個物件:

既然它是佔位符,那麼我們就必須喂一些資料給它,它才能將真實內容展示出來。因此,正確的方法是,在列印時通常需要加上當前的輸入資料給它。

例如,檢視y的概率資料:

部分非佔位符的變數還可以這樣輸出來:

總的來說,92%的識別準確率是比較令人失望,因此,官方的MNIST其實也有多種模型的不同版本,其中比較適合圖片處理的CNN(卷積神經網路)的版本,可以獲得99%以上的準確率,當然,它的執行耗時也是比較長的。

(備註:cnn_mnist.py就是卷積神經網路版本的,後面有附帶微雲網盤的下載url)

前饋神經網路(feed-forward neural network)版本的MNIST,可達到97%:

人人都可以做深度學習應用:入門篇

分享在微雲上的資料和原始碼:

微雲檔案

(備註:國外網站下載都比較慢,我這份下載相對會快一些,在環境已經搭建完畢的情況下,執行裡面的run.py即可)

五、和業務場景結合的demo:預測使用者是否是超級會員身份

根據前面的內容,我們對上述基於softmax只是三層(輸入、處理、輸出)的神經網路模型已經比較熟悉,那麼,這個模型是否可以應用到我們具體的業務場景中,其中的難度大嗎?為了驗證這一點,我拿了一些現網的資料來做了這個試驗。

1. 資料準備

人人都可以做深度學習應用:入門篇

我將一個現網的電影票活動的使用者參與資料,包括點選過哪些按鈕、手機平臺、IP地址、參與時間等資訊抓取了出來。其實這些資料當中是隱含了使用者的身份資訊的,例如,某些禮包的必須是超級會員身份才能領取,如果這個按鈕使用者點選領取成功,則可以證明該使用者的身份肯定是超級會員身份。當然,我只是將這些不知道相不相關的資料特徵直觀的整理出來,作為我們的樣本資料,然後對應的標籤為超級會員身份。

用於訓練的樣本資料格式如下:

人人都可以做深度學習應用:入門篇

第一列是QQ號碼,只做認知標識的,第二列表示是否超級會員身份,作為訓練的標籤值,後面的就是IP地址,平臺標誌位以及參與活動的參與記錄(0是未成功參與,1表示成功參與)。則獲得一個擁有11個特徵的陣列(經過一些轉化和對映,將特別大的數變小):

對應的是否是超級資料格式如下,作為監督學習的標籤:

超級會員:[0, 1]

非超級會員:[1, 0]

這裡需要專門解釋下,在實際應用中需要做資料轉換的原因。一方面,將這些資料做一個對映轉化,有助於簡化資料模型。另一方面,是為了規避NaN的問題,當數值過大,在一些數學指數和除法的浮點數運算中,有可能得到一個無窮大的數值,或者其他溢位的情形,在Python裡會變為NaN型別,這個型別會破壞掉後續全部計算結果,導致計算異常。

例如下圖,就是特徵數值過大,在訓練過程中,導致中間某些引數累計越來越大,最終導致產生NaN值,後續的計算結果全部被破壞掉:

人人都可以做深度學習應用:入門篇

而導致NaN的原因在複雜的數學計算裡,會產生無窮大或者無窮小。例如,在我們的這個demo中,產生NaN的原因,主要是因為softmax的計算導致。

人人都可以做深度學習應用:入門篇

剛開始做實際的業務應用,就發現經常跑出極奇怪異的結果(遇到NaN問題,我發現程式也能繼續走下去),幾經排查才發現是NAN值問題,是非常令人沮喪的。當然,經過仔細分析問題,發現也並非沒有排查的方式。因為,NaN值是個奇特的型別,可以採用下述編碼方式NaN != NaN來檢測自己的訓練過程中,是否出現的NaN。

關鍵程式程式碼如下:

人人都可以做深度學習應用:入門篇

我採用上述方法,非常順利地找到自己的深度學習程式,在學習到哪一批資料時產生的NaN。因此,很多原始資料我們都會做一個除以某個值,讓數值變小的操作。例如官方的MNIST也是這樣做的,將256的畫素顏色的數值統一除以255,讓它們都變成一個小於1的浮點數。

MNIST在處理原始圖片畫素特徵資料時,也對特徵資料進行了變小處理:

人人都可以做深度學習應用:入門篇

處理NaN問題更專業的方法,就是對輸入資料進行歸一化處理(min-max標準化或Z-score標準化方法),將值控制在一個可控的範圍內。NaN值問題曾一度深深地困擾著我,特別放到這裡,避免入門的同學踩坑。

2. 執行結果

我準備的訓練集(6700)和測試集(1000)資料並不多,不過,超級會員身份的預測準確率最終可以達到87%。雖然,預測準確率是不高,這個可能和我的訓練集資料比較少有關係,不過,整個模型也沒有花費多少時間,從整理資料、編碼、訓練到最終跑出結果,只用了2個晚上的時間。

人人都可以做深度學習應用:入門篇

下圖是兩個實際的測試例子,例如,該模型預測第一個QQ使用者有82%的概率是非超級會員使用者,17.9%的概率為超級會員使用者(該預測是準確的)。

人人都可以做深度學習應用:入門篇

通過上面的這個例子,我們會發覺其實對於某些比較簡單的場景下應用,我們是可以比較容易就實現的。

六、其他模型

1. CIFAR-10識別圖片分類的demo(官方)

CIFAR-10資料集的分類是機器學習中一個公開的基準測試問題,它任務是對一組32x32RGB的影象進行分類,這些影象涵蓋了10個類別:飛機, 汽車, 鳥, 貓, 鹿, 狗, 青蛙, 馬, 船和卡車。

這也是官方的重要demo之一。

人人都可以做深度學習應用:入門篇

更詳細的介紹內容:

CIFAR-10 and CIFAR-100 datasets

TensorFlow 官方文件中文版

該例子執行的過程比較長,需要耐心等待。

我在機器上的執行過程和結果:

cifar10_train.py用於訓練:

人人都可以做深度學習應用:入門篇

cifar10_eval.py用於檢驗結果:

人人都可以做深度學習應用:入門篇

識別率不高是因為該官方模型的識別率本來就不高:

人人都可以做深度學習應用:入門篇

另外,官方的例子我首次在1月5日跑的時候,還是有一些小問題的,無法跑起來(最新的官方可能已經修正),建議可以直接使用我放到微雲上的版本(程式碼裡面的log和讀取檔案的路徑,需要調整一下)。

原始碼下載:微雲檔案

微雲盤裡,不含訓練集和測試集的圖片資料,但是,程式如果檢測到這些圖片不存在,會自行下載:

人人都可以做深度學習應用:入門篇

2. 是否大於5歲的測試demo

為了檢驗softma迴歸模型是否能夠學習到一些我自己設定好的規則,我做了一個小demo來測試。我通過隨機數生成的方式構造了一系列的資料,讓前面的softmax迴歸模型去學習,最終看看模型能否通過訓練集的學習,最終100%預測這個樣本資料是否大於5歲。

模型和資料本身都比較簡單,構造的資料的方式:

我隨機構造一個只有2個特徵緯度的樣本資料,[year, 1],其中year隨機取值0-10,數字1是放進去作為干擾。

如果year大於5歲,則標籤設定為:[0, 0, 1];

否則,標籤設定為:[0, 1, 0]。

生成了6000條假訓練集去訓練該模型,最終它能做到100%成功預測準確:

人人都可以做深度學習應用:入門篇

微雲下載(原始碼下載):

微雲檔案

3. 基於RNN的古詩學習

最開頭的AI寫古詩,非常令人感到驚豔,那個demo是美國的一個研究者做出來的,能夠根據主題生成不能的古詩,而且古詩的質量還比較高。於是,我也嘗試在自己的機器上也跑一個能夠寫古詩的模型,後來我找到的是一個基於RNN的模型。RNN迴圈神經網路(Recurrent Neural Networks),是非常常用的深度學習模型之一。我基於一個外部的demo,進行一些調整後跑起一個能夠學習古詩和寫古詩的比較簡單的程式。

我的程式預設配置是讀取三萬首詩(做了一些過濾,將格式有誤的或者非五言、七言的過濾掉),執行寫詩(讓它寫了十首):

畫枕江天月似霜,竹房春雪夜中春。今人已向陵邊寺,夜客閒行入畫舟。雲上古來煙雪晚,月寒溪水夜無窮。何因便是鱸根侶,又是離觴酒到年。
酒渴清秋未可還,年華偏見酒壺錢。無因不自全為叟,自覺平陽似我同。
棋中春草下春城,更被霜衣獨入門。若教未開應要老,無妨歸夢不離身。青苔白首無山藥,落雪飛來夜夜長。何時未過無惆悵,滿溪紅土綠荷寒。
不辭宮樹與仙郎,曾與青春得斷魂。為向前溪猶繞藥,可因心苦雪時春。不須愛盡春來老,自有文師說了何。不必便從歸上信,也為言在此花來。
初時一點錦蓮紅,曾對仙輿在上河。萬卷有時人未見,五金終處更難過。山橫海渚人來起,天柳蕭森舊殿寒。唯見長州知己所,更從平地作風光。
去事相來別恨情,年邊未是我家貧。花聲未覺春多病,白雪無多到日寒。三畝有愁多不定,數千終去故心忙。莫將何用知兄用,猶待青林又不迷。
子有心才非病拙,一杯曾有白流愁。三朝獨到南山晚,白鶴爭生未見山。多在玉壺人愛靜,只能安穩更堪憐。只慚舊筆同才力,猶恐長心是主機。
塵末高臺入碧霄,故王門戶盡知無。黃華只擬相依鎖,三落青花亦有時。不見一家相似恨,白衣無限夢長安。
莫惜花聲酒醒杯,未央山冷一枝香。花垂未入東窗曉,雨冷山寒白鶴飛。長是玉山心寂漫,何曾便在舊樓間。時聞此夕來還坐,笑作青苔寄舊遊。
夾江城暖望潾山,山水清深獨倚樓。白雲半向三山客,萬頃東樓日滿林。白日夜聲多遠浪,綠花猶向夢來遲。明年不覺長相見,欲別寒泉又夜流。

 

另外,我抽取其中一些個人認為寫得比較好的詩句(以前跑出來的,不在上圖中):

人人都可以做深度學習應用:入門篇

該模型比較簡單,寫詩的水平不如最前面我介紹的美國研究者demo,但是,所採用的基本方法應該是類似的,只是他做的更為複雜。

另外,這是一個通用模型,可以學習不同的內容(古詩、現代詩、宋詞或者英文詩等),就可以生成對應的結果。

七、深度學習的入門學習體會

1. 人工智慧和深度學習技術並不神祕,更像是一個新型的工具,通過喂資料給它,然後,它能發現這些資料背後的規律,併為我們所用。

2. 數學基礎比較重要,這樣有助於理解模型背後的數學原理,不過,從純應用角度來說,並不一定需要完全掌握數學,也可以提前開始做一些嘗試和學習。

3. 我深深地感到計算資源非常缺乏,每次調整程式的引數或訓練資料後,跑完一次訓練集經常要很多個小時,部分場景不跑多一些訓練集資料,看不出差別,例如寫詩的案例。個人感覺,這個是制約AI發展的重要問題,它直接讓程式的“除錯”效率非常低下。

4. 中文文件比較少,英文文件也不多,開源社群一直在快速更新,文件的內容過時也比較快。因此,入門學習時遇到的問題會比較多,並且缺乏成型的文件。

八、小結

我們不知道人工智慧的時代是否真的會來臨,也不知道它將要走向何方,但是,毫無疑問,它是一種全新的技術思維模式。更好的探索和學習這種新技術,然後在業務應用場景尋求結合點,最終達到幫助我們的業務獲得更好的成果,一直以來,就是我們工程師的不懈追求。另一方面,對發展有重大推動作用的新技術,通常會快速的發展並且走向普及,就如同我們的程式設計一樣,因此,人人都可以做深度學習應用,並非只是一句噱頭。

參考文件:

TensorFlow中文社群-首頁

tensorflow.org/

部分數學相關的內容:

高中和大學數學部分內容

微雲檔案

線性代數視訊:

麻省理工公開課:線性代數_全35集_網易公開課

相關文章