1. 程式人生 > >tensorflow識別MNIST資料集

tensorflow識別MNIST資料集

目錄

資料準備

1、引入MNIST資料集

2、儲存前30條資料的原始圖片

 一、softmax實現單神經元模型

1、初始化變數

2、向前傳播以及損失函式

3、向後傳播以及優化引數

4、開始訓練

5、評估模型

補充

二、兩層卷積網路分類

1、初始化變數

2、預定義函式

3、卷積層

4、全連線層

5、定義交叉熵損失以及測試的準確率

6、開始訓練

總結


資料準備

簡單的說,MNIST就是一組最基礎的資料集,M代表Modified,NIST代表國家標準和技術研究所,包括從0~9的訓練數字的圖片,這個分類問題是機器學習最簡單和最廣泛使用的測試之一。

1、引入MNIST資料集

from tensorflow.examples.tutorials.mnist import input_data
# 從MNIST_data/中讀取MNIST資料。這條語句在資料不存在時,會自動執行下載
mnist = input_data.read_data_sets("MNIST_data/", one_hot=True)

# 檢視訓練資料的大小
print(mnist.train.images.shape)  # (55000, 784)
print(mnist.train.labels.shape)  # (55000, 10)

# 檢視驗證資料的大小
print(mnist.validation.images.shape)  # (5000, 784)
print(mnist.validation.labels.shape)  # (5000, 10)

# 檢視測試資料的大小
print(mnist.test.images.shape)  # (10000, 784)
print(mnist.test.labels.shape)  # (10000, 10)

MNIST官網下載的四個資料包放在MNIST_data中。不需要解壓,不需要解壓,不需要解壓。

若沒有資料包,Tensorflow會檢測到並且會自動下載到MNIST_data資料夾中。

2、儲存前30條資料的原始圖片

import scipy.misc
import os

# 我們把原始圖片儲存在MNIST_data/raw/資料夾下
# 如果沒有這個資料夾會自動建立
save_dir = 'MNIST_data/raw/'
if os.path.exists(save_dir) is False:
    os.makedirs(save_dir)

# 儲存前30張圖片
for i in range(30):
    # 請注意,mnist.train.images[i, :]就表示第i張圖片(序號從0開始)
    image_array = mnist.train.images[i, :]
    # TensorFlow中的MNIST圖片是一個784維的向量,我們重新把它還原為28x28維的影象。
    image_array = image_array.reshape(28, 28)
    # 儲存檔案的格式為 mnist_train_0.jpg, mnist_train_1.jpg, ... ,mnist_train_19.jpg
    filename = save_dir + 'mnist_train_%d.jpg' % i
    # 將image_array儲存為圖片
    # 先用scipy.misc.toimage轉換為影象,再呼叫save直接儲存。
    scipy.misc.toimage(image_array, cmin=0.0, cmax=1.0).save(filename)

print('Please check: %s ' % save_dir)

 一、softmax實現單神經元模型

1、初始化變數

import tensorflow as tf
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_ = tf.placeholder(tf.float32,[None,10]) 

因為圖片是28x28畫素的,所以1張圖片,即x中的一張圖片轉化成(1,784)的向量,它的便籤值y_也轉化為向量(1,10)。

因為不確定樣本的數量,所以用“佔位符(placeholder)”佔據一定形式的記憶體空間,等待使用者傳值來決定具體的樣本數量。我理解成一個有784個小格子高度的容器,由使用者來決定有多少個這樣的容器。

w,b為“變數”,規定了維度具體大小,即規定了有784個10個格子高度的容器,並把格子中裝的值初始化為0。

因為x的值是固定的,所以預測值y的值主要由w,b來決定。

思考:

a、佔位符和變數的區別是什麼?

b、什麼是softmax?為什麼使用softmax?

 

2、向前傳播以及損失函式

為了確定預測的y與標籤值y_的差距,需要定義cost function去評估預測的準確性,即演算法的優良性。

cross_entropy =  tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y)))

思考:

a、該損失函式的具體原理是什麼?

 

3、向後傳播以及優化引數

為了最小化損失函式,需要向後傳播計算出dw以及db,即w和b對損失函式的影響程度,然後通過w-學習率*dw、b-學習率*db更新w和b的值。當然,Tensorflow將這兩步通過一行程式碼同時實現了:

train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy)

 程式碼中學習率為0.01

 

4、開始訓練

首先初始化所有變數並申請記憶體空間:

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

 

 之後,梯度下降1000步:

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

 執行完後,模型便已被訓練完成了,即引數w,b已經被訓練好,儘可能的使y(預測值)接近y_(標籤紙),在損失函式的影象上,使值儘可能的接近最凹的點,即最優的點。

 

5、評估模型

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

輸出: 

0.9168

思考:

a、為什麼使用tf.argmax來進行評估?

 

補充

1、佔位符和變數的區別是什麼?

佔位符和變數都屬於Tensor(張量:一個數組中的元素分佈在若干維的規則網格中,則稱之為張量)。

佔位符不依賴於其他Tensor,具體的值由使用者傳入,一般用來儲存樣本資料和標籤值。

變數是計算過程中可以改變的值,每次計算後變數的值都會被儲存下來,一般用來儲存模型的引數。

2、什麼是softmax?為什麼使用softmax?

softmax函式是用於區分多個類別的函式,例如,對(a,b,c)三個類別進行softmax後,每個類別的概率為(\LARGE \frac{e^{a}}{e^{a}+e^{b}+e^{c}},\LARGE \frac{e^{b}}{e^{a}+e^{b}+e^{c}},\LARGE \frac{e^{c}}{e^{a}+e^{b}+e^{c}}),每個數值都在0-1,並且和為1。

相比於“hardmax”只將值表示為0或者1,softmax更詳細的輸出了每個類別的概率並且能夠進行多個類別的判斷,所以這裡使用它。

3、 tf.reduce_mean(-tf.reduce_sum(y_*tf.log(y))) 損失函式的具體原理是什麼?

只從程式碼來看錶示將 y_-{}\times (-\ln y)  公式的矩陣中所有值求和最後再求平均值。因為y的值肯定在0-1之間,為了保證損失值為正,新增符號取負。

若要損失函式的值最小:

當y_向量中某元素為0時,具體含義表示該圖片不是某一張圖,該項的損失函式值也為0,即相當於最後將10個類別的損失值求和的時候不考慮。

當y_向量中某元素為1時,只有當y的對應元素的值儘可能的接近1時,y_-{}\times (-\ln y)才儘可能最小,即儘可能接近0。所有讓損失值最小的過程就是讓預測值y的值無限接近真實值的情況。

4、為什麼使用tf.argmax(y,1)來進行評估?

該函式表示取得最大值的下標,而值最大的元素的下標值就表示圖片中真實數字的值。所以tf.argmax(y_,1)取得的下標值為真實圖片的數字值,例如[0,2,7,1];tf.argmax(y,1)取得y向量中,對每個類別的預測值裡最大值的下標值,即預測的圖片的數字值,例如[8,2,7,5]。最後tf.equal進行比較,得到類似[0,1,1,0]的陣列,通過tf.reduce_mean得到平均值0.5,表示預測準確率。

 

二、兩層卷積網路分類

 採用單神經元進行預測,最後的準確率為大約為91.6%,採用卷積網路進行圖片識別可將準確率提高到99%

1、初始化變數

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data

#讀入資料
mnist = input_data.read_data_sets("MNIST_data/",one_hot=True)

#建立佔位符
x = tf.placeholder(tf.float32,[None,784])
y_ = tf.placeholder(tf.float32,[None,10])

#將向量還原,-1表示第一維度由x的具體資料確定,即由x的矩陣中樣本個數來確定
x_image = tf.reshape(x,[-1,28,28,1])

2、預定義函式

def weight_variable(shape):
    inital = tf.truncated_normal(shape)
    return tf.Variable(inital)

def bias_variable(shape):
    inital =tf.constant(0.1,shape=shape)
    return tf.Variable(inital)

def conv2d(x,W):
    return tf.nn.conv2d(x,W,strides=[1,1,1,1],padding='SAME')

def max_pool_2x2(x):
    return tf.nn.max_pool(x, ksize=[1,2,2,1],strides=[1,2,2,1], padding='SAME')

分別表示得到一定維度的引數,指定值的偏執項,卷積函式,2x2最大池化函式。

這裡池化函式的過濾器為2x2,步長為2x2,當為此情況時,輸出圖片的維度是輸入圖片維度的一半

3、卷積層

#第一卷積層
w_conv1 = weight_variable([5, 5, 1, 32])
b_conv1 = bias_variable([32])
h_conv1 = tf.nn.relu(conv2d(x_image, w_conv1) + b_conv1)
h_pool1 = max_pool_2x2(h_conv1)

#第二卷積層
w_conv2 = weight_variable([5, 5, 32, 64])
b_conv2 = bias_variable([64])
h_conv2 = tf.nn.relu(conv2d(h_pool1, w_conv2) + b_conv2)
h_pool2 = max_pool_2x2(h_conv2)

第一卷積層:

32個5x5的卷積核進行卷積,padding為same,所以h_conv1的維度為(-1,28,28,32),-1表示該維度由具體樣本數量決定;最後經過2x2最大池化卷積,得到h_pool,維度為(-1,14,14,32)

第二卷積層:

進行立體卷積,立體卷積時要保證卷積核的通道數與將要處理圖片的通道數相同,所以卷積核維度為(5,5,32),有64個卷積核。h_conv2的維度為(-1,14,14,64),經過2x2池化層後,h_pool2的維度為(-1,7,7,64)

 

4、全連線層

#全連線層
w_fc1 = weight_variable([7*7*64,1024])
b_fc1 = bias_variable([1024])
h_pool2_flat = tf.reshape(h_pool2, [-1, 7*7*64])
h_fc1 = tf.nn.relu(tf.matmul(h_pool2_flat, w_fc1)+ b_fc1)

#使用dropout
keep_prob = tf.placeholder(tf.float32)
h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob)

#最後一層全連線層
w_fc2 = weight_variable([1024, 10])
b_fc2 = bias_variable([10])
y_conv = tf.matmul(h_fc1_drop,w_fc2)+b_fc2

第一層全連線層:

將h_pool2後三維轉化成一維向量,輸出1024維的向量;使用dropout,每一步訓練時,一定概率的去掉全連線層中某些連線,防止過度擬合。

第二層全連線層:

將1024維度h_fc1_drop轉化為10個類別的打分。

 

5、定義交叉熵損失以及測試的準確率

y_conv相當於softmax的logit(即wx+b),所以當然可以用softmax定義將其轉換為10個類別的概率,再定義交叉熵損失。但是tensorflow有打包好的函式,直接對logit定義交叉熵損失: 

cross_entropy =  tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits_v2(labels=y_,logits=y_conv))

 取預測後結果的平均值得到準確率:

correct_prediction = tf.equal(tf.argmax(y_conv,1),tf.argmax(y_,1))
accuracy = tf.reduce_mean(tf.cast(correct_prediction,tf.float32))

 

6、開始訓練

#建立Session,對變數初始化
sess = tf.InteractiveSession()
sess.run(tf.global_variables_initializer())

# 訓練20000步
for i in range(20000):
    batch = mnist.train.next_batch(50)
    # 每100步報告一次在驗證集上的準確度
    if i % 100 == 0:
        train_accuracy = accuracy.eval(feed_dict={x: batch[0], y_: batch[1], keep_prob: 1.0})
        print("step %d, training accuracy %g" % (i, train_accuracy))
    train_step.run(feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})


# 訓練結束後報告在測試集上的準確度
print("test accuracy %g" % accuracy.eval(feed_dict={x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}))

 

總結

主要完成了Tesorflow建立Softmax迴歸模型以及兩層卷積的神經網路,瞭解如何讀入資料集以及Tensorflow建立模型的基本流程:

  1. 建立還沒有執行的tensor(以及自定義輔助函式)
  2. 給tensor間書寫邏輯
  3. 初始化各個tensor
  4. 建立以及執行會話