2.1 TensorFlow實踐-入門與數字識別示例解析(1)

本章節中準備寫一些TensorFlow的入門示例,但是這並不是意味著第一章寫完了,第一章會一直寫下去,因為我一直認為數學基礎是應該貫穿整個學習過程的,但是願意看的人很少。很多人都以為神經網路只要會用一些框架並搭建現有網路解決問題就夠了,但抱著這種思想其實也不能說是錯,但是其實以這種思想的話其他一些比如貝葉斯演算法、ID3、EM等一些簡單的演算法也可以完成任務,未來的神經網路應用範圍可能沒有想像的那麼廣,或者說只有擁有大量數據的公司才搞得起來,但是補足基礎,過渡到其他簡單的數據挖掘演算法就足以應付中小公司的數據處理工作了。

本章中我們需要構建一個TensorFlow的基礎,所謂基礎就是我們可以搭建簡單的神經網路,保存模型、並驗證模型。

基礎部分第一章已經說過了,這裡我們在重複一下,下面是TensorFlow官方手寫識別版本的簡化,並修改了一些函數,為了入門講解更加方便修改了一些函數。

#example 2.1n#by cangyen#引入庫nfrom tensorflow.examples.tutorials.mnist import input_datanimport tensorflow as tfn#獲取數據nmnist = input_data.read_data_sets("MNIST_data/", one_hot=True)n#構建網路模型n#x,label分別為圖形數據和標籤數據nx = tf.placeholder(tf.float32, [None, 784])nlabel = tf.placeholder(tf.float32, [None, 10])n#構建單層網路中的權值和偏置nW = tf.Variable(tf.zeros([784, 10]))nb = tf.Variable(tf.zeros([10]))n#本例中無非線性激活函數ny = tf.matmul(x, W) + bn#定義損失函數為歐氏距離nloss = tf.reduce_mean(tf.square(y-label))n#用梯度迭代演算法ntrain_step = tf.train.GradientDescentOptimizer(0.005).minimize(loss)n#用於驗證ncorrect_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(label, 1))naccuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32))n#定義會話nsess = tf.Session()n#初始化所有變數nsess.run(tf.global_variables_initializer())n#迭代過程nfor itr in range(3000):n batch_xs, batch_ys = mnist.train.next_batch(100)n sess.run(train_step, feed_dict={x: batch_xs, label: batch_ys})n if itr % 10 == 0:n print("step:%6d accuracy:"%itr, sess.run(accuracy, feed_dict={x: mnist.test.images,n label: mnist.test.labels}))n

首先來看下搭建的網路模型:

當然我一直以為用數學手段描述更為簡單:

y_{[batchsize,10]} = x_{[batch-size,784]}cdot w_{[784,10]}+b_{[10]}

下面來一步一步的講解,

from tensorflow.examples.tutorials.mnist import input_datanimport tensorflow as tfn

首先是import兩個python庫,其中tensorflow.examples.tutorials.mnist的目的在於產生數據,也就是手寫識別的圖片和標籤。其中標籤數字為一個長度為10的向量,加入數字為7則向量的第七個數字為1其餘數字為0。圖片是一個28*28的圖片而存儲方式為一個長度為784的一維數組如下:

為了方便理解,將繪圖過程的程序寫到下面:

import matplotlib.pyplot as pltnimport numpy as npn#獲取數據nmnist = input_data.read_data_sets("MNIST_data/", one_hot=True)n#分別讀取數據中的圖片數據和標籤數據nbatch_xs, batch_ys = mnist.train.next_batch(100)n#繪圖過程nfig = plt.figure()nax = fig.add_subplot(221)nax.matshow(np.reshape(batch_xs[1],[28,28]), cmap=plt.get_cmap("Purples"))nax = fig.add_subplot(222)nax.matshow(np.reshape(batch_xs[2],[28,28]), cmap=plt.get_cmap("Purples"))nax = fig.add_subplot(223)nax.matshow(np.reshape(batch_xs[3],[28,28]), cmap=plt.get_cmap("Purples"))nax = fig.add_subplot(224)nax.matshow(np.reshape(batch_xs[4],[28,28]), cmap=plt.get_cmap("Purples"))nplt.show()n

之後進行的操作為定義向量,第一步中定義的向量為:

#x,label分別為圖形數據和標籤數據nx = tf.placeholder(tf.float32, [None, 784])nlabel = tf.placeholder(tf.float32, [None, 10])n

這裡的向量是一個placeholder,因為x和label是在訓練過程中需要不斷的進行更改填入神經網路之中的。由於TensorFlow是無法接利用python的列表(list),或者numpy的array的,而在訓練的過程中需要不斷的改變x和y的值,這就需要一個placeholder,用以不斷的接受list或array。對於x的參數[None, 784],代表placeholder的shape,其中第一個為None代表每次輸入的訓練數據的個數是不確定的。也就是可以為任意多個數字。而每次輸入訓練數據的個數稱之為batch_size,這是一個非常重要的概念,數學章節我們可以看到,訓練過程是以梯度迭代的方式進行的,但是梯度取決於我們的輸入數據,由於數據具有一定的隨機性,那麼梯度也必然帶有一定的隨機性,所以在訓練的每一次迭代過程中我們可以一次輸入多個樣本,通過多個樣本的估計可以更好的約束梯度迭代的方向,使得梯度迭代過程減少一定的隨機性,這個過程稱之為批量學習,而數據的量的大小稱之為批尺寸(batch_size)。相應的我們在數學章節中的學習過程稱之為在線學習也就是每次輸入一個樣本進行學習

可以看下單層神經網路的公式

#構建單層網路中的權值和偏置nW = tf.Variable(tf.zeros([784, 10]))nb = tf.Variable(tf.zeros([10]))n#本例中無非線性激活函數ny = tf.matmul(x, W) + bn

這個部分就是我們構建單層神經網路的過程,其中常說的神經網路權值就是一個二維矩陣W,偏置b,這兩個量實際上就是我們整個神經網路中需要確定的東西。對於這種需要確定的量,用Variable來表示。tf.Variable(tf.zeros([784, 10]))返回的量就是TensorFlow中的Tensor可以將其當做矩陣,其實也就是矩陣。

定義兩個矩陣的乘法tf.matmul(x, W),y就是輸出的預測結果。

由於還沒有具體的講信息熵的概念,二者接近程度用歐氏距離來表示:

#定義損失函數為歐氏距離nloss = tf.reduce_mean(tf.square(y-label))n

其中label就是我們已知結果,y是神經網路預測結果,我們的期望是二者越接近越好。這就需要定義迭代過程:

#用梯度迭代演算法ntrain_step = tf.train.GradientDescentOptimizer(0.005).minimize(loss)n

這裡需要用到的演算法就是梯度迭代演算法,其中迭代步長為0.005(這並不是最好的步長),這個步長的選取是十分重要的呃,過大的步長會使得梯度迭代發散,也就是loss函數不僅沒有減少反而一直增大,但是大步長會使得迭代速度加快。而過小的迭代會使得收斂速度緩慢。如何平衡是一個不斷試驗的過程。而迭代優化器的目標在於求解最優的W和b。

實際上到此為止計算過程都沒有執行,我們只是在「描述」這個計算過程,TensorFlow中稱之為計算圖。TensorFlow的優點就在於此,其並沒有直接利用python語言去執行計算,因為python是計算速度很慢的語言,而是用python去描述計算圖,而具體的執行則需要放到c++的框架之中。因此需要一個回話來執行所有描述的過程:

#定義會話nsess = tf.Session()n#初始化所有變數nsess.run(tf.global_variables_initializer())n

同樣的,我們在描述計算過程的過程中,甚至於都沒有為運算過程的向量分配內存空間,所以在整個程序運行過程中需要進行變數的初始化工作。在用會話(session)來執行這個過程,再次提醒,我們提到的絕大部分操作都需要利用會話去執行,否則只是描述了需要進行相應的計算而已。

最後來看一下迭代過程:

#迭代過程nfor itr in range(3000):n batch_xs, batch_ys = mnist.train.next_batch(100)n sess.run(train_step, feed_dict={x: batch_xs, label: batch_ys})n if itr % 10 == 0:n print("step:%6d accuracy:"%itr, sess.run(accuracy, feed_dict={x: mnist.test.images,n label: mnist.test.labels}))n

可以看到我們執行的每個過程都需要sess.run函數去運行。TensorFlow採取feed機制,也就是執行過程中不斷的輸入相應訓練數據,此時placeholder的作用就體現了出來,它用來接收我們傳入的量,這個量可以是numpy的array或者是python的list。這裡feed的量用字典來表示feed_dict={x: batch_xs, label: batch_ys}。

可以看到在迭代500次後準確率達到了80%,當然繼續迭代準確率還會更高,準確率有極限:

如果想要看權值W一些數值,我們需要獲取w的值

W.value()n

但是前面說到,到此只是描述了計算,並沒有執行,因此需要會話來進行操作:

W_value = sess.run(W.value())n

將標籤0-3的權值繪製一下:

可以大致看到權值代表什麼


推薦閱讀:

MobileNet教程(2):用TensorFlow做一個安卓圖像分類App
TensorFlow 聊天機器人開源項目評測第一期:DeepQA
cs20si: tensorflow for research 學習筆記1
Quo Vadis, Action Recognition? A New Model and the Kinetics
五分鐘喝不完一杯咖啡,但五分鐘可以帶你入門TensorFlow

TAG:TensorFlow | 深度学习DeepLearning | 神经网络 |