從鍋爐工到AI專家(5)

圖像識別基本原理

從上一篇開始,咱們終於進入到了TensorFlow機器學習的世界。採用第一個分類算法進行手寫數字識別獲得了一個91%左右的識別率結果,進展可喜,但成績尚不能使人滿意。
結果不滿意的緣由,固然仍是算法太簡單了。儘管咱們都已經接受了「全部問題均可以用數學公式來描述」這個觀點,但直接把一幅圖片展開的784個數字做爲方程式參數進行一個線性運算+非線性分類器就叫作「人工智能」怎麼都感受那麼不靠譜...至於能獲得91%不高的識別率,從這個意義上說,彷佛都使人有點不太相信。這個不相信不是指91%過低了,而是這種玩笑通常的計算就有91%的準確率有點奇幻啊。
其實數學的魅力就是這樣,看起來公式簡單,但上一節就說了,你別忘了是784維啊,手工計算確定會瘋掉的。
若是利用上一篇介紹的小程序,把咱們圖像識別程序學習過程完成後所計算的權重矩陣W的10個維度都轉換成28x28分辨率的圖片(還記得吧,咱們的權重矩陣W是784x10,其中784就是28x28得來的),而後作一些着色渲染,看到的會是這個樣子:

其中紅色的部分表明權重是負值,藍色的部分表明權重是正值。
以字符0爲例,圖中紅色的部分表明,若是要識別的圖片,上面這個位置有手寫痕跡的話,那這幅圖片更趨向於不太多是字符0。而藍色的部分,則表明若是一樣位置有手寫痕跡的話,那圖片更趨向於多是字符0。這樣所有28x28=784個數據都用這種方式計算,最後的結果,固然就表明更接近字符0的可能性。這就是這個程序圖像識別的基本原理。
咱們在這裏把這個權重圖給出來的緣由,就是雖然這個算法簡單,但能更清晰的表現「機器學習」的數學含義。接下來的「神經網絡算法」及其它算法,由於複雜度高,單純結果的權重每每已經不能用這種直觀的方式表達出來了。html

神經網絡

在官方MNIST的案例中,神經網絡的部分是直接跳過了的。由於隨着技術的發展,在圖像識別這個問題上已經有了更好的算法,就是「卷積神經網絡」,這個實現咱們下一篇再講。
實際上我以爲,「神經網絡」這個概念不管如何是跨不過去的,否則後期的不少概念都沒法講下去或者講了也沒法讓人理解。科學老是這樣,大多時候即使沒有巔峯突破,普通的工做也並不是能夠省略,否則就成爲了空中樓閣。
「神經網絡」的誕生是天然選擇的結果,人腦就是由無數個神經元組成的,有資料說大概接近900億個,是天文數字的級別。這些神經網絡的傳導和反射支撐着現代人類全部的智力和行爲。

在人工智能尚未足夠現代理論支撐的年代,仿照人腦「神經網絡」的工做模式,創建「人工神經網絡」進行機器學習是很天然的事情。而且在實踐中的結果也很是使人興奮,因此從並不很長的AI歷史上,「人工神經網絡」算統治了至關不短的時間。以致於對於不少非專業人士來說,「神經網絡」已經成了AI標誌性的概念。

模仿人腦神經元細胞的基本工做方式,下圖示意了一個「人工神經網絡」基本單元的工做方式:

每個這樣的計算節點,都有n維的輸入,在其中完成一個相似上一個源碼樣例中的線性計算,而後彙總輸出,這個輸出會再鏈接到下一級的計算節點。不少個這樣的計算節點彙總完成一組計算,這樣成爲一「層」。上一層的輸出,成爲下一層的輸入,多個層次累計起來,完成最終的機器學習過程。
在這些多層的計算中,第一層承擔了全部原始數據的輸入,所以叫作「輸入層」;最後一層完成結果的輸出,叫作「輸出層」;中間的部分承擔上一層的結果,通過計算完成下一層的輸入,但對用戶來說實際是不可見的,叫作「隱藏層」。這幾個概念之後你在看各類資料的時候會常常看到,你須要知道這些概念指的是什麼。

上圖示意了神經網絡的多種變形和組合後的網絡模式。這種「仿生學」通常的組合模式取得了使人驚喜的效果。從數學的計算結構上很是的清晰,但內部多節點組合以後的數學機理實際上至今也沒有哪篇論文描述的很是清楚。你能夠理解爲:經過增長計算節點、更多的體現和保持每一個數據和其它數據之間的微小關係甚至多層互動以後的關係,從而更準確的完成對結果的計算。python

反向傳播

有了已經內置的神經網絡算法實現以後,普通用戶對於算法的內部數學實現確定關心的更少了,這裏也只說一個重點。
線性迴歸方程中,咱們使用梯度降低法解方程,每一次計算均可以經過代價函數的表現決定咱們下一個計算的走向。
在多層神經網絡中,這種解方程方式顯然不靈了。由於最終的結果,跟最初的輸入,中間隔了多個隱藏層。
所以「人工神經網絡」的求解主要依賴「反向傳播」的方式來進行求解,大意是指最後一層得出結果後,經過這一層的代價函數修正本層的權重W和偏移b,並把信號反向傳遞到上一層,從而讓上一層也能夠調整本身層的W/b,逐次反向傳播,一直到輸入層。算法

激活函數

前面一個獨立神經節點的示意圖中,你可能注意到了除了咱們上一個例子中熟悉過的線性公式。
其後部還有一個「Threshold unit」,也就是「閥值單元」。在真實的世界中,咱們的大腦不太可能對於任何須要處理的問題,都動用所有的大腦。
而根據上面那副「人工神經網絡」示意圖能夠看出,全部的節點,雖然有層的劃分,其實是全鏈接的。
全鏈接的意思也就是對於任何一個輸入,事實上全部的單元都會參與計算,這顯然也是不合常理的。
那每一個節點最後的閥值單元,就是用來決定對於某個任務,本節點是否參與以及以何種方法參與到最終的計算中。這個動做,在機器學習中也稱爲「激活函數」。
經常使用的激活函數有好多種,好比咱們前面提過的sigmoid函數,上一次提到它是由於這個函數能夠用於作0、1分類。這個函數的輸入值若是小於0.5,則輸出爲0;輸入大於0.5,則輸入爲1。
還有tanh激活函數,輸入小於0則輸出0,輸入大於0,則輸出1。
最後則是本次咱們會採用的激活函數ReLu,它的輸入若是小於0,則輸出0,輸入若是大於0,則原樣輸出。
這些數學特徵,決定了所採用的神經元單元以何種方式參與到總體的計算。具體如何選擇,依賴於咱們要解決的問題。若是問題比較複雜,沒法一下想清楚如何取捨怎麼辦?那,這麼易用的工具和框架,這麼小的代碼量,都試一遍又何妨?小程序

神經網絡圖像識別源碼

#!/usr/bin/env python
# -*- coding=UTF-8 -*-

import input_data
mnist = input_data.read_data_sets('MNIST_data', one_hot=True)

import tensorflow as tf
sess = tf.InteractiveSession()

#對W/b作初始化有利於防止算法陷入局部最優解,
#文檔上講是爲了打破對稱性和防止0梯度及神經元節點恆爲0等問題,數學原理是相似問題
#這兩個初始化單獨定義成子程序是由於多層神經網絡會有屢次調用
def weight_variable(shape):
    #填充「權重」矩陣,其中的元素符合截斷正態分佈
    #能夠有參數mean表示指定均值及stddev指定標準差
  initial = tf.truncated_normal(shape, stddev=0.1)
  return tf.Variable(initial)
def bias_variable(shape):
    #用0.1常量填充「偏移量」矩陣
  initial = tf.constant(0.1, shape=shape)
  return tf.Variable(initial)


#定義佔位符,至關於tensorFlow的運行參數,
#x是輸入的圖片矩陣,y_是給定的標註標籤,有標註必定是監督學習
x = tf.placeholder("float", shape=[None, 784])
y_ = tf.placeholder("float", shape=[None, 10])

#定義輸入層神經網絡,有784個節點,1024個輸出,
#輸出的數量是本身定義的,要跟第二層節點的數量吻合
W1 = weight_variable([784, 1024])
b1 = bias_variable([1024])
#使用relu算法的激活函數,後面的公式跟前一個例子相同
h1 = tf.nn.relu(tf.matmul(x, W1) + b1)

#定義第二層(隱藏層)網絡,1024輸入,512輸出
W2 = weight_variable([1024, 512])
b2 = bias_variable([512])
h2 = tf.nn.relu(tf.matmul(h1, W2) + b2)

#定義第三層(輸出層),512輸入,10輸出,10也是咱們但願的分類數量
W3 = weight_variable([512, 10])
b3 = bias_variable([10])
#最後一層的輸出一樣用softmax分類(也算是激活函數吧)
y3=tf.nn.softmax(tf.matmul(h2, W3) + b3)

#交叉熵代價函數
cross_entropy = -tf.reduce_sum(y_*tf.log(y3))
#這裏使用了更加複雜的ADAM優化器來作"梯度最速降低",
#前一個例子中咱們使用的是:GradientDescentOptimizer
train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)
#計算正確率以評估效果
correct_prediction = tf.equal(tf.argmax(y3,1), tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))
#tf初始化及全部變量初始化
sess.run(tf.global_variables_initializer())
#進行20000步的訓練
for i in range(20000):
    #每批數據50組
  batch = mnist.train.next_batch(50)
  #每100步進行一次正確率計算並顯示中間結果
  if i%100 == 0:
    train_accuracy = accuracy.eval(feed_dict={
        x:batch[0], y_: batch[1]})
    print "step %d, training accuracy %g"%(i, train_accuracy)
    #使用數據集進行訓練
  train_step.run(feed_dict={x: batch[0], y_: batch[1]})

#完成模型訓練給出最終的評估結果
print "test accuracy %g"%accuracy.eval(feed_dict={
    x: mnist.test.images, y_: mnist.test.labels})

這個程序中使用了3層的神經網絡,通過20000*50個數據的訓練,最終正確率能夠達到96%以上,比上一個例子有了明顯的進步。
實際上一個例子和本例,最終咱們都使用的tf.nn.softmax()函數。看到其中的「nn」沒有,這是「Neural Networks」的縮寫,也就是說,不只本例是神經網絡算法,其實上一個例子,一樣也使用了神經網絡算法。
若是是之前沒有TensorFlow的年代,這種特色咱們能在算法源碼中看的一清二楚,而如今,很容易就會忽略掉。
那麼上一例中,咱們實際上使用的是隻有「一層」的神經網絡算法,數學公式簡化後,也就是普通的線性算法,而後通過非線性的softmax分類。
本例則毫無疑問是一個經典的神經網絡算法,3層分別是784個輸入->(輸入層)1024個節點->(隱藏層)512節點->(輸出層)10節點輸出。
神經網絡每一層之間是如何鏈接起來的呢?很簡單,就如同程序中所示,每一層在公式那一行,其中計算時所引用的變量,是上一層輸出的變量,就等於將各層進行了連接。TensorFlow會自動在這個計算圖中上一層以後,添加上這一層的節點。
爲了獲得更好的識別結果,咱們還採用了AdamOptimizer優化器進行「梯度最速降低」。TensorFlow中內置了好幾種算法,數學實現能夠參考最下面的參考連接。
那麼神經網絡的設計,究竟應當採用多少層網絡?每層多少個節點?
這個目前沒統一的標準,通常而言,層數越多、節點越多,就能夠獲得更好的識別率,但同時這個模型的工做速度也會越慢。還可能會有更大的「過擬合」風險。過擬合咱們後面再介紹。
並且識別率的一點點增長,每每會須要更多的計算節點,成本不必定划算。
並不像增長一整層那樣劇烈的資源消耗增長,在一個層中適當增長節點數一般是比較划算的方法,具體狀況,也是要靠實驗測試和科學評估的來決定。
多層的神經網絡,由於網絡深度的增長,也被稱爲「深度神經網絡」(Deep Neural Networks / DNN),這個簡寫常常會跟CNN(卷積神經網絡)、RNN(循環神經網絡)一塊兒出現。網絡

小說明

最近爲了寫這個系列,在網上翻找參考資料,另外也試圖尋找一些現成的圖片幫助概念的解釋行文。結果在不少介紹機器學習的文章中,發現大量的謬誤,讀之冷汗不絕啊。
這也提醒我,一方面我盡力的校對並再次釐清概念,防止本文出現相似的低級錯誤。固然水平所限,不免仍然有一些錯誤沒法發現或者認知自己就有誤,歡迎各界高手指正也讓我不斷進步。
另一方面整體感受,多是發展「大躍進」的緣由,並且畢竟國內的基礎水平進展偏慢、偏晚,不少譯文及「教程」是概念錯誤的重災區。
本來由於我主要面對身邊及國內的讀者,但願儘量引用的參考資料都來自中文資料,但到了今天決定完全放棄這個想法。能有質量至關的中文資料更好,若是沒有,也只好引用一些國外的資料,畢竟不只僅水平上,只說認真程度上就徹底無法比。
我想這可能也是當前國內技術界廣泛應當重視的問題。水平是一方面,態度則是更重要的一方面。今天在這裏寫出來,但願跟你們共勉。app

此外是關於本文的結構,看上去每一篇的篇幅差異比較大。這一點主要是爲了知識點的連貫性。好比第四篇,不少概念不連續介紹下來,恐怕在閱讀源碼階段會碰到不少困難,只好放的比較長。在閱讀的時候能夠根據本身的狀況作一些取捨及控制一下進度。框架

(待續...)機器學習

引文及參考

TensorFlow中文社區
Tensorflow 搭建本身的神經網絡 (莫煩 Python 教程視頻)
Overview of Artificial Neural Networks and its Applications
基於神經網絡的激活函數和相應的數學介紹
An overview of gradient descent optimization algorithmside

相關文章
相關標籤/搜索