? ? ?后面會在微信公眾號中推送后續的翻譯章節,與TensorFlow的第一次接觸系列已整理成pdf,關注公眾號后回復:tensorflow即可下載~~公眾號:源碼之心
?在前言中,已經提到經常使用深度學習的領域就是模式識別。編程初學者都是從打印“Hello World”開始,深度學習中我們則是從識別手寫數字開始。
? ? ? 本章中,我會講解如何在TensorFlow中一步步建立單層神經網絡,這個建立的神經網絡用來識別手寫數字,它是基于TensorFlow官方新手指南中的一個例子改變而來。
? ? ? 根據本書的風格,在本例子中會簡化一些概念與理論證明。
? ? ? 如果讀者在讀完本章后,有興趣研究例子中相關的理論概念,建議讀者去閱讀神經網絡與深度學習一書,該書同樣可在網上獲得,該書闡述了本例子中的一些深度理論概念。
The MNIST data-set
? ? ? ?MNIST data-set由一些黑白照片集合組成,每張照片包含手寫的數字。集合中60000張照片用來訓練模型,10000張照片用來測試模型。MNIST data-set可通過網絡在MNIST數據庫中獲得。
? ? ? ?對于剛開始基于真實樣例學習模式識別確沒有時間進行數據預處理或歸一化的同學,這個數據集十分理想,因為數據預處理與歸一化是非常重要且花時間的兩個步驟。
? ? ? ?這些黑白照片已經規則化成20*20像素,并保留了寬高比。對于本例子,我們發現由于歸一化算法(圖片的分辨率降為其中最低水平之一)中使用了抗鋸齒,圖片中包含了很多灰色像素。通過計算質心,并將照片移至28*28像素方框的正中間。照片如下圖所示:
? ? ? ?本例子中使用的學習算法同樣為監督學習,照片已經用它們代表的數據進行標注。這是一種非常常見機器學習算法。
? ? ? ?我們首先收集很大的包含數字的照片集合,每一張照片用它代表的數字進行標注。在訓練過程中,模型輸入一張照片,輸出得分數組,每一個得分代表了一個分類。我們希望想要的那個分類在所有分類中擁有最大的得分,但在訓練模型之前這是不太可能發生的。
? ? ? ?通過計算一個對象函數來度量錯誤值,這個錯誤值代表了輸出得分與目標模式得分的差別。模型會修改內部的可調參數(也叫權重)來降低這個錯誤值。在一個典型的深度學習系統中,可能會有成百上千的可調參數,成百上千的標注數據為訓練模型。我們會通過一個較小的例子來幫助講解這種類型的模型是如何工作的。
? ? ? ?為方便下載數據,你可以使用input_data.py腳本,該文件也已放在github上。當在TensorFlow中編程實現神經網絡時,可直接通過這個腳本下載數據到當前目錄下。在你的應用程序中,只需要導入并調用如下代碼:
? ? ? ?當執行完這兩行命令后,mnist.train會包含了全部的訓練數據,mnist.test包含了全部的測試數據集。正如我之前所說的,每一個元素都由一張照片組成,用”xs”來表示,它的標注用“ys”表示,這可以很方便的表示處理代碼。請記住,所有數據集,訓練集與測試集都包含了“xs”與“ys”;同時,mnist.train.images表示訓練照片,mnist.train.labels表示訓練標簽。
? ? ? ?正如之前所說,圖像被格式成28*28像素,并可表示成一個數值矩陣。例如,數字1的照片可表示為:
? ? ? ?每一個位置代表了每一個像素灰的程序,取值0到1。這個矩陣可表示為一個28*28=784的數組。實際上,照片已經變換成784維向量空間中一系列的點。需要說明的是,當我們將結構降到2維后,我們會失去部分信息,對于一些計算圖像算法,這會帶來不利影響,但在本例子中使用的算法來說,這沒有任何影響。
? ? ? ?總結一下,我們有了mnitst.train.images 2D tensor,當調用get_shape()時顯示的結果為:
TensorShape([Dimension(60000),Dimension(784)])
? ? ? ?第一維度索引了每一張照片,第二維索引了照片中每一像素。Tensor中每一元素是該像素強度值,該值介于0到1之間。
? ? ? ?標簽都是數字0到9的格式,表明圖片代表哪一個數字。本例子中,每個標簽表示為10個元素的向量,圖片代表的數字相應的位置為1,其余位置為0。所以mnist.train.labelses是一個shape為([Dimension(6000),Dimension(10)]的tensor。
人造神經元
? ? ? 雖然本書不會主要講神經網絡的理論概念,但是簡短直觀的介紹神經網絡如何學習訓練數據會幫助讀者理解神經網絡做了什么。已經非常了解神經網絡理論,只是如何學習使用TensorFlow的同學,可以跳過本小節。
? ? ? 我們可以看一個簡單但又很有代表性的例子來說明神經元如何學習。假設一個平面中有一個點的集合,分別被標記為“square”與“circle”。給一個新的點“X”,我們想知道這新點會被標記為哪個標簽:
? ? ? 一個通用的方法是畫一條直線作為分類器,將點分成兩組:
? ? ? 在這種情形下,輸入數據表示為shape為(x,y)的vectors,代表了2維空間中的坐標,我們的函數返回0或1(直線之上或之下)來代表將該點分類為“square”還是“circle”。通過線性回歸那一小節學到的,從數學上,這條直線(分類器)可表示為y=W*x+b。
? ? ? 一般來說,神經元一定要學到一個權重W(與輸入數據X有同樣的維度)與偏移b(神經網絡中叫bias)來學會將如何分類這些值。根據W和b,神經元會對輸入計算一個加權和,并加上偏移b;最后神經元會應用激活非線性函數來產生結果0或1。神經元的函數可形式化表示為:
? ? ? 為神經元定義了這個函數后,我們想了解神經元是如何通過這些標注數據(squares與circles)來學得參數W和b,并用來分類新點X。
? ? ? 第一個嘗試的方法類似之前提到的線性回歸,對神經元輸入已知的標注數據,并比較計算結果與真實結果。在迭代時,通過調整參數W和b來最小化錯誤值,正像第二章中線性回歸所做的那樣。
? ? ? 一旦有了參數W和b后,就可以計算加權和,現在我們需要一個函數來將結果轉化成0或1。有幾個激活函數可以做到這樣,在本例子中,我們使用一個很流行的函數叫sigmoid來返回一個0到1之間的真實值:
? ? ? 通過公式我們可以看到,它會返回一個非常接近0或1的值。如果輸入z是正值且足夠大,e的-z次冪為0,然后y為1。如果輸入z是負值且足夠大,e的-z次冪為無窮大,分母為無窮大,然后y為0。如果用圖表畫出該函數,大約如下圖所示:
? ? ? 到現在為止我們已經講解了如何描述一個神經元,但神經網絡是由很多神經元組成,神經元間以不同方式連接并使用不同的激活函數。本書范圍內不會討論神經網絡的很多擴展細節,但向你保證,神經網絡是非常有趣的。
? ? ? 需要提一下,現在有具體的神經網絡實現方式(第五章中會使用),神經元以層的方式來組織,輸入層接受輸入,最頂層(輸出層)產生響應結果。神經網絡可以有很多中間層,叫隱藏層。用圖畫出神經網絡如下所示:
? ? ? 神經網絡中,某一層的神經元與前一層的神經元通信來獲得該層的輸入信息,然后將結果輸出給下一層的神經元。
? ? ? 正如之前所說的,除了sigmoid之外,還有很多的激活函數,每個激活函數都有不同的屬性。例如,如果我們在輸出層想將數據分到多于2類中,需要使用softmax激活函數,是sigmoid函數的通用版。Softmax計算屬于每一個分類的概率,概率總和為1,最有可能的結果是概率最大的那一個。
簡單例子開始:Softmax
? ? ? 還記的我們的需要解決的問題是,輸入一張圖片,得到這張圖片屬于某一數字的概率。例如,我們的模型可以預測一張圖片為9的概率為80%,為8的概率為5%,同樣其它數字的概率也很低。識別手寫數字有一定的不確定性,我們做不到100%的正確性來識別數字。在本例子中,概率分布使得我們可以明白有多大的正確性來預測。
? ? ? 所以,我們會得到向量,它包含了不同輸出標簽的概率分布,它們之間互斥。也就是說,一個向量帶有10個概率值,每一個概率值對應了數字0到9,所有概率之和為1。
? ? ? 如之前所說,我們通過在輸出層使用softmax激活函數來達到這個目的。神經元中softmax的輸出結果依賴于本層中其它神經元的輸出,因為必須保證輸出結果之和為1。
? ? ? Softmax函數有兩個主要步驟:1.計算一張圖片屬于某一標簽的“證據”;2.將“證據”轉換成屬于每一個可能標簽的概率。
屬于某類的“證據”
? ? ? 如何度量一張圖片屬于某一分類/標簽的證據?一個常用的方法是計算像素強度的加權和。像素的權重為負說明像素有很高的強度表明不屬于該類,為正時表明屬于該類。
? ? ? 接下來看一個圖形例子:假如一個對于數字0學習完的模型(稍后我們會看到模型是如何得到的)。這次,我們將模型定義為包含一些信息來推斷一個數字是否屬于某一分類。在本例子中,我們選擇一個如下所示的模型,紅色(或b/n版本中的亮灰色)代表負樣本(這些像素不屬于0),藍色(或b/n版本中的深灰)代表了正樣本:
? ? ? 想像在28*28像素的一張白紙下畫一個0。一般來說,0會被畫在藍色區域(我們在20*20畫的區域周邊預留一些空間,用來將它居中)。
? ? ? 非常明顯當我們畫的穿過紅色區域時,很有可能我們畫的不是0。所以,穿過藍色區域對像素加權,紅色區域會像素懲罰的機制是合理的。
? ? ? 現在來看3:很明顯模型中對于0的紅色區域會懲罰它屬于0的概率。但是如果相關模型是哪下所示,一般生成3的像素會在藍色區域;同時畫0時也會進入到紅色區域。
? ? ? 希望讀者通過這兩個例子能理解這種方法是如何來預估哪個數字表示了這些圖。
? ? ? 下面的這些圖片顯示了從MNIST數據集中學到的10個不同標簽/分類。記住紅色(亮灰)代表負權重,藍色(暗灰)代表正權重:
? ? ? ?用公式表達的話,輸入X屬于類別i的證據可表示為:
? ? ? ?i代表分類(本例子中為0到9),j是輸入照片求和的索引,wi代表了前面描述的權重。
? ? ? 一般來說,模型中也會包含一個額外的參數,表示為bias,用來增加一些不確定性。本例子中,公式如下所示:
? ? ? 對于第一個i(0到9),我們有一個784元素的矩陣Wi,每一個元素j與輸入照片784元素中相應位置的元素相乘,然后加上bi。圖形化表示為:
屬于某類的概率
? ? ?之前提到第二步包含了計算概率。我們用softmax函數將“證據”求和轉變成可預測的概率,并用y來表示:
? ? ?輸出的向量一定是一個概率函數且和為1。為歸一化每一個元素,softmax函數對每一個輸入求指數,然后如下來歸一化:
? ? ?采用指數的效果是在權重上進行乘法的效果。當支持某一類的“證據”很小時,該類的支持會被之前的權重減掉一小部分。更進一步,softmax函數歸一化權重,并使得其和為1,同時創建一個概率分布。
? ? ?該函數比較有意思的一點是好的預測輸出結果中一個值接近1,其余的接近0;弱的預測中,一些標簽可能是相似的值。
TensorFlow中編程實現
? ? ?在簡要介紹了算法是如何識別數字后,我們可以在TensorFlow中實現它。先快速了解下tensor如何存儲我們的數據和模型參數。基于此,下面的范式描述了相關數據與它閃間的關系(幫助讀者容易回憶起問題中的每一個部分):
? ? ?首先創建兩個變量來保存權重W和bias b:
? ? ?這兩個變量通過調用tf.Variable來創建并初始化;本例子中,我們用常量0來初始化tensor。
? ? ?可以看到W的shape為【Dimension(784), Dimension(10)】,這是由它的參數常量tensor?tf.zeros[784,10]定義的。參數b也是類似,由它的參數指定形狀為[Dimension(10)]。
? ? ?矩陣W有這樣的大小是因為對于10個可能性中的任一個。它都要與圖片向量784個位置相乘,加上b之后生成一個“證據”tensor。
? ? ?本例子中使用了MNIST,同樣需要創建一個2維的tensor來保留這些點的信息,代碼如下:
? ? ?tensorx將用來存儲MNIST圖像向量中784個浮點值(None代表該維度可為任意大小,本例子中將會是學習過程中照片的數量)
? ? ?定義完tensor后,接下來就可以實現模型。TensorFlow提供了很多操作來實現之前描述的softmax函數,tf.nn.softmax(logits,name)只是眾多可用操作中的一個。參數必須是一個tensor,另外一個可選參數是name。函數返回一個同類型的tensor,其shape與參數一樣。
? ? ?在本例子中,我們將圖像向量x與權重矩陣W相乘再加上b之后的結果作為參數傳給softmax函數:
y=tf.nn.softmax(tf.matmul(x,W)+b)
? ? ?一旦確認了模型的實現,就可以通過一個迭代訓練算法來獲得權重W和bias b。在每次迭代中,訓練算法讀入訓練數據,應用神經網絡,比較輸出結果與預期結果。
? ? ?為了能夠判斷一個模型是足夠好還是足夠壞,我們需要定義足夠好的定義。如之前章節中看到的,通用的方法是定義相反面:使用cost function表示一個模型有多壞。這樣的話,目標就是找到參數W和b的值來最小化該函數。
? ? ?有多種不同機制來度量在訓練數據上輸出結果與期望結果的差異。一個通用的方法是平均方差或平方歐氏距離。即使如此,一些研究小組針對神經網絡提出了其它的機制,類似本例子中使用的交叉熵個代價函數。該算法計算公式如下:
? ? ?y是預測生成的概率分布,y`是訓練數據集中標注的真實分布。這里不會深入到交叉熵背后的數學細節以及它在神經網絡中的地位,因為這已經遠超過本書的討論范圍;我們需要知道的是當兩個分布完全一樣的時候,此時獲得最小值。再次說明,如果讀者希望學習該函數的內部細節,建議閱讀神經網絡與深度學習一書。
? ? ?為實現交叉熵,需要創建一個placeholder代表正確的標簽:
y_=tf.placeholder("float",[None,10])
? ? ?使用這個placeholder,可通過下面代碼實現交叉熵,用來代表cost function:
cross_entropy=-tf.reduce_sum(y_*tf.log(y))
? ? ?首先使用tensorflow中內置的tf.log()對每一個元素y求對數,然后再與每一個y_的元素相乘。最后使用tf.reduce_sum對tensor的所有元素求和(稍后我們會看到圖片是分批處理的,所以交叉熵的值是一批照片的,并不是一張照片的)。
? ? ?在迭代中,一旦對樣本定義了錯誤表示,就需要在下次迭代中修正模型(通過修改參數W和b)來減少計算結果與期望結果的差值。
? ? ?最后,只需要實現迭代最小化的處理過程。神經網絡中有一些算法來解決這個問題;我們使用反向傳播(backward propagation of errors)算法,正如它的名字所示,該算法會反向傳播輸出中的錯誤值,以用來重新計算權重W,該算法對多層神經網絡尤其重要。
? ? 反射傳播算法通常會與梯度下降算法一起使用,梯度下降算法中會使用交叉熵cost function,并使得我們在每次迭代中根據局部可用信息來計算需要多大程度修改參數來降低錯誤值。在本例子中,它會在每一次迭代中持續一點點修改權重W(這里的每一小步表示為學習速率參數,表示變化的速率)來降低錯誤值。
? ? ?由于本例子中我們使用的神經網絡只有一層,我們不會詳細分析反射傳播算法。只需要記住TensorFlow知道全部計算圖,并使用優化算法為cost function找到合適的梯度來訓練模型。
? ? ? 因為我們使用了MNIST數據集,下面的代碼顯示我們使用反向傳播算法與梯度下降算法來最小化交叉熵,同時學習速率為0.01。
train_step=tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)
? ? ? 到現在為止,我們已經實現了所有問題,可以通過創建tf.Session()開始在可用設備CPUS或GPUS上計算各操作:
sess=tf.Session()
? ? ? 接下來,通過一個操作來初始化所有變量:
sess.run(tf.initialize_all_variables())
? ? ? 從現在開始,我們可以訓練模型。執行后返回的train_step參數,會對相關參數應用梯度下降。所以訓練模型可以通過重復執行train_step來實現。假如我們想迭代1000次train_step;通過下面的代碼就能實現:
? ? ? 循環中的第一行表示,每次迭代中,從訓練數據集中隨機選取100張圖片作為一批。在每次迭代時,雖然我們可以使用全部訓練數據集,但為了使得本例子更精巧,我們每次選擇使用一小部分樣本。第二行表示之前獲得的輸入分別賦給相關的placeholders。
? ? ? 最后說明一點,基于梯度下降的機器學習算法可以充分利用TensorFlow自動對比差值的能力。TensorFlow的用戶只需要定義預測模型的計算結構,與目標函數相結合,然后只需要提供數據。
? ? ? TensorFlow同樣負責學習過程背后的導數計算。當minimize()被執行時,TensorFlow辨認出loss function依賴的變量集合,對集合中的每一個變量計算梯度。如果你有興趣了解對比是如何實現的,可以研究ops/gradients.py文件。
模型評估
? ? ? 訓練得到的模型必須被評估來看該模型是有多好(或多壞)。例如,我們可以計算在預測中正確與錯誤的比例,查看哪些樣本被正確的預測了。在之前的章節中,我們看到tf.argmax(y,1)函數會返回tensor中參數指定的維度中的最大值的索引。在效果上,tf.argmax(y,1)是我們模型中輸入數據的最大概率標簽,tf.argmax(y_,1)是實際的標簽。通過tf.equal方法可以比較預測結果與實際結果是否相等:
correct_prediction=tf.equal(tf.argmax(y,1),tf.argmax(y_,1))
? ? ? 這行代碼返回一個布爾列表。為得到哪些預測是正確的,我們可用如下代碼將布爾值轉換成浮點數:
accuracy=tf.reduce_mean(tf.cast(correct_prediction,"float"))
? ? ? 例如,[True, False, True, True]會轉換成[1,0,1,1],其平均值0.75代表了準確比例。現在我們可使用mnist.test數據集作為feed_dict參數來計算準確率:
printsess.run(accuracy,feed_dict={x:mnist.test.images,y_:mnist.test.labels})
? ? ? 我得到的精度是91%。這個精度好嗎?我認為非常好,因為讀者已經可以在TensorFlow中編程并執行他們的第一個神經網絡。
? ? ? 另外一個問題是其它模型可能提供更好的精度,下一章中的多層神經網絡會詳細講解。
? ? ? 讀者可在github上的RedNeuronalSimple.py文件中看到本章中所有代碼,全部代碼如下:
? ? ?下一章節中人分析構建多層神經網絡。