1. 程式人生 > >TensorFlow初學者入門(二)——MNIST機器學習入門

TensorFlow初學者入門(二)——MNIST機器學習入門

本人學習TensorFlow中的一些學習筆記和感悟,僅供學習參考,有疑問的地方可以一起交流討論,持續更新中。

本文學習地址為:TensorFlow官方文件,在此基礎上加入了自己的學習筆記和理解。

文章是建立在有一定的深度學習基礎之上的,建議有一定理論基礎之後再同步學習。

1.準備MNIST資料集

1.1 資料集下載及匯入

MNIST是一個入門級的計算機視覺資料集,它包含各種手寫數字圖片:

它也包含每一張圖片對應的標籤,告訴我們這個是數字幾。比如,上面這四張圖片的標籤分別是5,0,4,1。 

MNIST資料集在官方文件中提供了一個指令碼檔案下載,但是我個人用這個檔案無法下載資料集,所以建議直接去

MNIST資料集官網下載,下載下面四個檔案並將其放在MNIST_data資料夾中。

然後在python檔案中只要加入以下程式碼,MNIST資料集就存在mnist這個變數中了。

import input_data

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

在上式中,one-hot=True表示label向量中除了對應位置的數字是1以外其餘各維度數字都是0,即label式一個10維的向量,例如數字3的標籤為[0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]。如果沒有one-hot則label直接儲存數字的標籤,例如數字3的標籤為3

1.2 MNIST資料格式

我們可以利用下列指令檢視mnist資料集大小和標籤

print('train_size:', mnist.train.images.shape)
print('train_label_size:', mnist.train.labels.shape)
print('val_size:', mnist.validation.images.shape)
print('val_label_size:', mnist.validation.labels.shape)
print('test_size:', mnist.test.images.shape)
print('test_label_size:', mnist.test.labels.shape)

輸出結果為:

train_size: (55000, 784)
train_label_size: (55000, 10)
val_size: (5000, 784)
val_label_size: (5000, 10)
test_size: (10000, 784)
test_label_size: (10000, 10)

(55000, 784)代表的含義是:訓練集中共有55000張圖片,一行資料就代表了一張圖片。每張圖片28*28的大小被reshape為1*784。(55000, 10)代表共55000張圖片被分為10類(0~9),每一個行向量代表對應圖片的標籤,例如某行向量為[0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]則代表該圖片對應的數字為3。

1.3 MNIST影象展示

瞭解過MNIST的資料格式之後將其用影象展示出來,利用下列程式碼:

def data_trainsform(a):  
    b = np.zeros([28, 28])  
    for i in range(0, 27):
        for j in range(0, 27):
            b[i][j] = a[28 * i + j]
    return b


tile = data_trainsform(mnist.train.images[1])
print(mnist.train.labels[1])
plt.figure()
plt.imshow(tile, 'bone')
plt.show()

可以展示訓練集中的第二張圖片,如下所示。以及其對應的label向量[0. 0. 0. 1. 0. 0. 0. 0. 0. 0.]。

至此,對於mnist資料格式以及儲存方式有了一個大致的瞭解,我們繼續往下學習。

2.MNIST機器學習入門

2.1 模型構造

匯入MNIST和TensorFlow:

import tensorflow as tf
import input_data

mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)#這裡MNIST_data/是存MNIST的路徑,自己修改

我們現在要做的就是實現機器學習中最基礎的迴歸模型——線性迴歸y=wx+b。先對這幾個引數做出定義:

x = tf.placeholder(tf.float32, [None, 784])  #placeholder 產生一個佔位符
W = tf.Variable(tf.zeros([784, 10]))         #Variable 定義一個變數
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(x, W) + b)       #matmul(A,B) 表示矩陣乘法A*B
y_hat = tf.placeholder('float', [None, 10])

結合MNIST資料格式,上述程式碼並不難理解。placeholder相當於定義了變數x,只不過這時候x是沒有具體值的,x只有第二維度的值被固定為784,因為輸入的MNIST圖片大小是固定的。但是因為輸入數量無法確定,所以x的第一維度是None,能隨著輸入的改變而改變。W初始賦值為784*10的零矩陣。其他語句基本類似,不再贅述。y表示預測值,也表示我們要用的模型是線性迴歸。y_hat是真實標籤。

2.2 訓練模型

定義完各個變數後和模型之後開始訓練這個模型。為了訓練我們的模型,我們首先需要定義一個指標來評估這個模型是好的。其實,在機器學習,我們通常定義指標來表示一個模型是壞的,這個指標稱為成本(cost)或損失(loss),然後儘量最小化這個指標。但是,這兩種方式是相同的。

一個非常常見的,非常漂亮的成本函式是“交叉熵”(cross-entropy)。交叉熵產生於資訊理論裡面的資訊壓縮編碼技術,但是它後來演變成為從博弈論到機器學習等其他領域裡的重要技術手段。它的定義如下:

y 是我們預測的概率分佈, y' 是實際的分佈,即為上述變數y_hat。比較粗糙的理解是,交叉熵是用來衡量我們的預測用於描述真相的低效性。

交叉熵的實現

cross_entropy = -tf.reduce_sum(y_hat*tf.log(y))

評估指標現在也有了,那麼我們就可以開始訓練這個模型了。一句話就是利用梯度下降演算法使cross_entropy最小,此時的模型引數W,b就是我們想要的模型引數。整個訓練過程如下所示:

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy) #用梯度下降演算法以0.01的學習速率最小化交叉熵
sess = tf.Session()    #Session是執行TensorFlow操作的類
sess.run(tf.initialize_all_variables())   #初始化所有引數,這一步是必須的
for i in range(1000):
    batch_xs, batch_ys = mnist.train.next_batch(100)    
    sess.run(train_step, feed_dict={x: batch_xs, y_hat: batch_ys})

Session的作用就是來執行TensorFlow的各種操作的,例如我們現在執行下列兩個命令:

print('print b get:', b)
print('print sess.run(b) get:', sess.run(b))

可以得到下列結果:

print b get: <tensorflow.python.ops.variables.Variable object at 0x10efa0eb8>
print sess.run(b) get: [0. 0. 0. 0. 0. 0. 0. 0. 0. 0.]

如果不放在Session裡面run是沒法直接得到各個變數或者操作的值的。

2.3 評估模型

模型已經訓練好了,接下來需要做的就是去用測試集測試評估這個模型。

correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_hat, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, 'float')) #tf.cast 型別轉換函式
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_hat: mnist.test.labels}))

tf.argmax 是一個非常有用的函式,它能給出某個tensor物件在某一維上的其資料最大值所在的索引值。由於標籤向量是由0,1組成,因此最大值1所在的索引位置就是類別標籤,比如tf.argmax(y,1)返回的是模型對於任一輸入x預測到的標籤值,而 tf.argmax(y_,1) 代表正確的標籤,我們可以用 tf.equal 來檢測我們的預測是否真實標籤匹配(索引位置一樣表示匹配)。

最終結果大約91%左右。

3.完整程式碼

放上完整程式碼,歡迎交流討論

import tensorflow as tf
import input_data
import matplotlib.pyplot as plt
import numpy as np


def data_trainsform(a):
    b = np.zeros([28, 28])
    for i in range(0, 27):
        for j in range(0, 27):
            b[i][j] = a[28 * i + j]
    return b


mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

print('train_size:', mnist.train.images.shape)
print('train_label_size:', mnist.train.labels.shape)
print('val_size:', mnist.validation.images.shape)
print('val_label_size:', mnist.validation.labels.shape)
print('test_size:', mnist.test.images.shape)
print('test_label_size:', mnist.test.labels.shape)

tile = data_trainsform(mnist.train.images[1])
print(mnist.train.labels[1])
plt.figure()
plt.imshow(tile, 'bone')
plt.show()

x = tf.placeholder(tf.float32, [None, 784])
W = tf.Variable(tf.zeros([784, 10]))
b = tf.Variable(tf.zeros([10]))
y = tf.nn.softmax(tf.matmul(x, W) + b)
y_hat = tf.placeholder('float', [None, 10])

cross_entropy = -tf.reduce_sum(y_hat * tf.log(y))
train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

init = tf.initialize_all_variables()
sess = tf.Session()
sess.run(init)

print('print b get:', b)
print('print sess.run(b) get:', sess.run(b))

for i in range(1000):
    batch_xs, batch_ys = mnist.train.next_batch(100)
    sess.run(train_step, feed_dict={x: batch_xs, y_hat: batch_ys})

correct_prediction = tf.equal(tf.argmax(y, 1), tf.argmax(y_hat, 1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction, 'float'))
print(sess.run(accuracy, feed_dict={x: mnist.test.images, y_hat: mnist.test.labels}))