TensorFlow 实战 MINST
工作中需要實現(xiàn) CNN、RNN 模型,于是開始學習 TensorFlow。這是第一篇,MNIST的實戰(zhàn)。官方文檔講的很詳細,這里我不過是用我的思路整理一遍,方便日后的查閱。
TensorFlow 介紹
綜述
TensorFlow 是一個編程系統(tǒng), 使用圖來表示計算任務. 圖中的節(jié)點被稱之為 op (operation 的縮寫). 一個 op 獲得 0 個或多個 Tensor, 執(zhí)行計算, 產生 0 個或多個 Tensor. 每個 Tensor 是一個類型化的多維數(shù)組. 例如, 你可以將一小組圖像集表示為一個四維浮點數(shù)數(shù)組, 這四個維度分別是 [batch, height, width, channels].
一個 TensorFlow 圖描述了計算的過程. 為了進行計算, 圖必須在 會話 里被啟動. 會話 將圖的 op 分發(fā)到諸如 CPU 或 GPU 之類的 設備 上, 同時提供執(zhí)行 op 的方法. 這些方法執(zhí)行后, 將產生的 tensor 返回. 在 Python 語言中, 返回的 tensor 是 numpy ndarray 對象; 在 C 和 C++ 語言中, 返回的 tensor 是 tensorflow::Tensor 實例.
下載安裝
| 1 | sudo pip install —upgrade https://storage.googleapis.com/tensorflow/mac/tensorflow-0.8.0-py2-none-any.whl |
初步使用
- 使用圖 (graph) 來表示計算任務.
- 在被稱之為 會話 (Session) 的上下文 (context) 中執(zhí)行圖.
- 使用 tensor 表示數(shù)據(jù).
- 通過 變量 (Variable) 維護狀態(tài).
- 使用 feed 和 fetch 可以為任意的操作(arbitrary operation) 賦值或者從其中獲取數(shù)據(jù).
| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849 | # 常量a = tf.constant([3.0, 3.0])# 變量,變量要進行初始化x = tf.Variable([1.0, 2.0])# 變量初始化init_op = tf.initialize_all_variables()# 矩陣乘法product = tf.matmul(matrix1, matrix2)# 減法sub = tf.sub(x, a)# 加法new_value = tf.add(state, one)# Fetch# 啟動默認圖sess = tf.Session()# 執(zhí)行矩陣乘法。函數(shù)調用 'run(product)' 觸發(fā)了圖中三個 op (兩個常量 op 和一個矩陣乘法 op) 的執(zhí)行result = sess.run(product)# 任務完成, 關閉會話.sess.close()# Session 對象在使用完后需要關閉以釋放資源. 除了顯式調用 close 外, 也可以使用 "with" 代碼塊 來自動完成關閉動作.with tf.Session() as sess:result = sess.run([product])print result# 取回多個 tensor:input1 = tf.constant(3.0)input2 = tf.constant(2.0)input3 = tf.constant(5.0)intermed = tf.add(input2, input3)mul = tf.mul(input1, intermed)with tf.Session() as sess:result = sess.run([mul, intermed])print result# Feed#feed 使用一個 tensor 值臨時替換一個操作的輸出結果. 你可以提供 feed 數(shù)據(jù)作為 run() 調用的參數(shù). feed 只在調用它的方法內有效, 方法結束, feed 就會消失. 最常見的用例是將某些特殊的操作指定為 "feed" 操作, 標記的方法是使用 tf.placeholder() 為這些操作創(chuàng)建占位符.input1 = tf.placeholder(tf.float32)input2 = tf.placeholder(tf.float32)output = tf.mul(input1, input2)with tf.Session() as sess:print sess.run([output], feed_dict={input1:[7.], input2:[2.]}) |
單層 SoftMax 神經網絡模型
加載 MNIST 數(shù)據(jù)
60000行的訓練數(shù)據(jù)集(mnist.train)和10000行的測試數(shù)據(jù)集(mnist.test)。
每一個MNIST數(shù)據(jù)單元有兩部分組成:一張包含手寫數(shù)字的圖片和一個對應的標簽。圖片設為“xs”,標簽設為“ys”。訓練數(shù)據(jù)集和測試數(shù)據(jù)集都包含xs和ys,比如訓練數(shù)據(jù)集的圖片是 mnist.train.images ,訓練數(shù)據(jù)集的標簽是 mnist.train.labels。
每一張圖片包含28X28個像素點。我們把這個數(shù)組展開成一個向量,長度是 28x28 = 784。
在 MNIST 訓練數(shù)據(jù)集中,mnist.train.images 是一個形狀為 [60000, 784] 的張量,第一個維度數(shù)字用來索引圖片,第二個維度數(shù)字用來索引每張圖片中的像素點。在此張量里的每一個元素,都表示某張圖片里的某個像素的強度值,值介于0和1之間。
相對應的 MNIST 數(shù)據(jù)集的標簽是介于0到9的數(shù)字,用來描述給定圖片里表示的數(shù)字。為了用于這個教程,我們使標簽數(shù)據(jù)是”one-hot vectors”。 一個one-hot向量除了某一位的數(shù)字是1以外其余各維度數(shù)字都是0。所以在此教程中,數(shù)字n將表示成一個只有在第n維度(從0開始)數(shù)字為1的10維向量。比如,標簽0將表示成([1,0,0,0,0,0,0,0,0,0,0])。因此, mnist.train.labels 是一個 [60000, 10] 的數(shù)字矩陣。
| 12 | import tensorflow.examples.tutorials.mnist.input_data as input_datamnist = input_data.read_data_sets("MNIST_data/", one_hot=True) |
運行 TensorFlow 的 InteractiveSession
Tensorflow 依賴于一個高效的C++后端來進行計算。與后端的這個連接叫做session。一般而言,使用TensorFlow程序的流程是先創(chuàng)建一個圖,然后在session中啟動它。這里,我們使用更加方便的InteractiveSession類。通過它,你可以更加靈活地構建你的代碼。它能讓你在運行圖的時候,插入一些計算圖,這些計算圖是由某些操作(operations)構成的。這對于工作在交互式環(huán)境中的人們來說非常便利,比如使用IPython。如果你沒有使用InteractiveSession,那么你需要在啟動session之前構建整個計算圖,然后啟動該計算圖。
| 12 | import tensorflow as tfsess = tf.InteractiveSession() |
構建 Softmax 回歸模型
y = softmax(Wx + b)
| 1234567891011 | # x 是一個占位符placeholder,在TensorFlow運行計算時輸入這個值。我們希望能夠輸入任意數(shù)量的MNIST圖像,每一張圖展平成784維的向量。我們用2維的浮點數(shù)張量來表示這些圖,這個張量的形狀是[None,784 ]。(這里的None表示此張量的第一個維度可以是任何長度的。)x = tf.placeholder(tf.float32, [None, 784])# 權重值W = tf.Variable(tf.zeros([784,10]))# 偏離值b = tf.Variable(tf.zeros([10]))# 類別預測 - softmax 模型。(激活函數(shù),線性輸出->概率分布)y = tf.nn.softmax(tf.matmul(x,W) + b) |
我們在調用tf.Variable的時候傳入初始值。在這個例子里,我們把 W 和 b 都初始化為零向量。W 是一個784x10的矩陣(因為我們有784個特征和10個輸出值)。b 是一個10維的向量(因為我們有10個分類)。
構建代價函數(shù)
指標
交叉熵
代碼
| 12345 | # 正確值y_ = tf.placeholder("float", [None,10])# 損失函數(shù)cross_entropy = -tf.reduce_sum(y_*tf.log(y)) |
注意,tf.reduce_sum把minibatch里的每張圖片的交叉熵值都加起來了。我們計算的交叉熵是指整個minibatch的。
訓練模型
| 1 | train_step = tf.train.GradientDescentOptimizer(0.01).minimize(cross_entropy) |
TensorFlow用梯度下降算法(gradient descent algorithm)以0.01的學習速率最小化交叉熵。梯度下降算法(gradient descent algorithm)是一個簡單的學習過程,TensorFlow只需將每個變量一點點地往使成本不斷降低的方向移動。
TensorFlow在這里實際上所做的是,它會在后臺給計算圖增加一系列新的計算操作單元用于實現(xiàn)反向傳播算法和梯度下降算法。然后,它返回給你的只是一個單一的操作,當運行這個操作時,它用梯度下降算法訓練你的模型,微調你的變量,不斷減少成本。
返回的train_step操作對象,在運行時會使用梯度下降來更新參數(shù)。因此,整個模型的訓練可以通過反復地運行train_step來完成。
訓練
| 1234567891011 | # 初始化變量init = tf.initialize_all_variables()# 在session里啟動模型sess = tf.Session()sess.run(init)# 開始訓練模型,這里我們讓模型循環(huán)訓練1000次!for i in range(1000):batch = mnist.train.next_batch(50)sess.run(train_step,feed_dict={x: batch[0], y_: batch[1]}) |
每一步迭代,我們都會隨機加載50個訓練樣本,然后執(zhí)行一次train_step,并通過feeddict將x 和 y張量占位符用訓練訓練數(shù)據(jù)替代。
使用一小部分的隨機數(shù)據(jù)來進行訓練被稱為隨機訓練(stochastic training)- 在這里更確切的說是隨機梯度下降訓練。在理想情況下,我們希望用我們所有的數(shù)據(jù)來進行每一步的訓練,因為這能給我們更好的訓練結果,但顯然這需要很大的計算開銷。所以,每一次訓練我們可以使用不同的數(shù)據(jù)子集,這樣做既可以減少計算開銷,又可以最大化地學習到數(shù)據(jù)集的總體特性。
評估模型
找出預測正確的標簽
tf.argmax 給出某個tensor對象在某一維上的其數(shù)據(jù)最大值所在的索引值。由于標簽向量是由0,1組成,因此最大值1所在的索引位置就是類別標簽。tf.argmax(y,1)返回的是模型對于任一輸入x預測到的標簽值
tf.argmax(y_,1) 代表正確的標簽
tf.equal 來檢測我們的預測是否真實標簽匹配(索引位置一樣表示匹配)
| 1 | correct_prediction = tf.equal(tf.argmax(y,1), tf.argmax(y_,1)) |
這里返回一個布爾數(shù)組。為了計算我們分類的準確率,我們將布爾值轉換為浮點數(shù)來代表對、錯,然后取平均值。例如:[True, False, True, True]變?yōu)閇1,0,1,1],計算出平均值為0.75。
| 1 | accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float")) |
最后,我們可以計算出在測試數(shù)據(jù)上的準確率,大概是90.92%。
| 1 | print sess.run(accuracy,feed_dict={x: mnist.test.images, y_: mnist.test.labels}) |
多層卷積網絡模型
CNN 對模式分類非常適合,最初是為識別二維形狀而特殊設計的,這種二維形狀對平移、比例縮放、傾斜或其他形式對變形有高度不變性。詳見?卷積神經網絡 CNN 筆記
TensorFlow 實現(xiàn)
初始化權重和偏置項
為了創(chuàng)建這個模型,我們需要創(chuàng)建大量的權重和偏置項。這個模型中的權重在初始化時應該加入少量的噪聲來打破對稱性以及避免 0 梯度。由于我們使用的是 ReLU 神經元,因此比較好的做法是用一個較小的正數(shù)來初始化偏置項,以避免神經元節(jié)點輸出恒為 0 的問題(dead neurons)。為了不在建立模型的時候反復做初始化操作,我們定義兩個函數(shù)用于初始化。
| 1234567 | def weight_variable(shape):initial = tf.truncated_normal(shape, stddev=0.1)return tf.Variable(initial)def bias_variable(shape):initial = tf.constant(0.1, shape=shape)return tf.Variable(initial) |
卷積和池化
我們的卷積使用 1 步長(stride size),0 邊距(padding size)的模板,保證輸出和輸入是同一個大小。
我們的池化用簡單傳統(tǒng)的 2x2 大小的模板做 max pooling。為了代碼更簡潔,我們把這部分抽象成一個函數(shù)。
| 12345678 | # 卷積函數(shù)def conv2d(x, W):return tf.nn.conv2d(x, W, strides=[1, 1, 1, 1], padding='SAME')# 池化函數(shù)def max_pool_2x2(x):return tf.nn.max_pool(x, ksize=[1, 2, 2, 1],strides=[1, 2, 2, 1], padding='SAME') |
第一層卷積
第一層卷積由一個卷積接一個 max pooling 完成。卷積在每個 5x5 的 patch 中算出 32 個特征。卷積的權重張量形狀是[5, 5, 1, 32],前兩個維度是 patch 的大小,接著是輸入的通道數(shù)目,最后是輸出的通道數(shù)目。 而對于每一個輸出通道都有一個對應的偏置量。
| 123456789 | W_conv1 = weight_variable([5, 5, 1, 32])b_conv1 = bias_variable([32])# 把 x 變成一個4d向量,其第2、第3維對應圖片的寬、高,最后一維代表圖片的顏色通道數(shù)(因為是灰度圖所以這里的通道數(shù)為1,如果是 rgb 彩色圖,則為3)。x_image = tf.reshape(x, [-1,28,28,1])# 把 x_image 和權值向量進行卷積,加上偏置項,然后應用 ReLU 激活函數(shù),最后進行 max pooling。h_conv1 = tf.nn.relu(conv2d(x_image, W_conv1) + b_conv1)h_pool1 = max_pool_2x2(h_conv1) |
第二層卷積
為了構建一個更深的網絡,我們會把幾個類似的層堆疊起來。第二層中,每個 5x5 的 patch 會得到64個特征。
| 12345 | 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) |
密集連接層(全連接層)
經過第一次池化,圖片尺寸減小到 14*14,經過第二次池化,圖片尺寸減小到 7x7。我們加入一個有 1024 個神經元的全連接層,用于處理整個圖片。我們把池化層輸出的張量reshape成一些向量,乘上權重矩陣,加上偏置,然后對其使用ReLU。
| 12345 | 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
為了減少過擬合,我們在輸出層之前加入 dropout。我們用一個 placeholder 來代表一個神經元的輸出在dropout中保持不變的概率。這樣我們可以在訓練過程中啟用 dropout,在測試過程中關閉 dropout。 TensorFlow的tf.nn.dropout 操作除了可以屏蔽神經元的輸出外,還會自動處理神經元輸出值的scale。所以用dropout的時候可以不用考慮scale。
| 12 | keep_prob = tf.placeholder("float")h_fc1_drop = tf.nn.dropout(h_fc1, keep_prob) |
輸出層
最后,我們添加一個softmax層,就像前面的單層softmax regression一樣。
| 1234 | W_fc2 = weight_variable([1024, 10])b_fc2 = bias_variable([10])y_conv=tf.nn.softmax(tf.matmul(h_fc1_drop, W_fc2) + b_fc2) |
訓練和評估模型
使用與之前簡單的單層SoftMax神經網絡模型幾乎相同的一套代碼,只是我們會用更加復雜的ADAM優(yōu)化器來做梯度最速下降,在feed_dict中加入額外的參數(shù)keep_prob來控制dropout比例。然后每100次迭代輸出一次日志。最后的準確率是 99.2%
| 12345678910111213141516 | cross_entropy = -tf.reduce_sum(y_*tf.log(y_conv))train_step = tf.train.AdamOptimizer(1e-4).minimize(cross_entropy)correct_prediction = tf.equal(tf.argmax(y_conv,1), tf.argmax(y_,1))accuracy = tf.reduce_mean(tf.cast(correct_prediction, "float"))sess.run(tf.initialize_all_variables())for i in range(20000):batch = mnist.train.next_batch(50)if i % 100 == 0:train_accuracy = sess.run(accuracy, feed_dict={x: batch[0], y_: batch[1], keep_prob: 1.0})print "step %d, training accuracy %g" % (i, train_accuracy)sess.run(train_step, feed_dict={x: batch[0], y_: batch[1], keep_prob: 0.5})print "test accuracy %g" % sess.run(accuracy, feed_dict={x: mnist.test.images, y_: mnist.test.labels, keep_prob: 1.0}) |
代碼
參考鏈接:
中文文檔
github 項目地址
http://blog.csdn.net/zouxy09/article/details/8781543
http://blog.csdn.net/celerychen2009/article/details/8973218
卷積神經網絡(CNN)學習筆記 - LeNet5網絡詳解
原文地址: http://www.shuang0420.com/2016/06/20/TensorFlow%E5%AE%9E%E6%88%98-MNIST/
總結
以上是生活随笔為你收集整理的TensorFlow 实战 MINST的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 爬虫总结(五)-- 其他技巧
- 下一篇: Distributed Systems笔