代碼: tensorflow/examples/tutorials/mnist/python
本文的目的是來展現如何使用Tensorflow訓練和評估手寫數字識別問題。本文的觀衆是那些對使用Tensorflow進行機器學習感興趣的人。git
本文的目的並非講解機器學習。github
請確認您已經安裝了Tensorflow。算法
教程文件數組
文件 | 做用 |
mnist.py |
用來建立一個徹底鏈接的MNIST模型。 |
fully_connected_feed.py |
使用下載的數據集訓練模型。 |
運行fully_connected_feed.py文件開始訓練。網絡
python fully_connected_feed.py
準備數據機器學習
MNIST是機器學習的一個經典問題。這個問題是識別28*28像素圖片上的數字,從0到9。函數
更多信息,請參考Yann LeCun's MNIST page 或者 Chris Olah's visualizations of MNIST。post
數據下載單元測試
在run_training()方法以前,input_data.read_data_sets()方法可讓數據下載到本機訓練文件夾,解壓數據並返回一個DataSet實例。
data_sets = input_data.read_data_sets(FLAGS.train_dir, FLAGS.fake_data)
注意:fake_data是用來進行單元測試的,讀者能夠忽略。
數據集 | 做用 |
data_sets.train | 55000圖片和標籤,用來訓練。 |
data_sets.validation | 5000圖片和標籤,用來在迭代中校驗模型準確度。 |
data_sets.test | 10000圖片和標籤,用來測試訓練模型準確度。 |
輸入和佔位符
placeholder_inputs()函數建立兩個tf.placeholder,用來定義輸入的形狀,包括fetch_size。
images_placeholder = tf.placeholder(tf.float32, shape=(batch_size, mnist.IMAGE_PIXELS))
labels_placeholder = tf.placeholder(tf.int32, shape=(batch_size))
在訓練循環中,圖片和標籤數據集會被切分紅batch_size大小,跟佔位符匹配,而後經過feed_dict參數傳遞到sess.run()方法中。
建立圖
建立佔位符後,mnist.py文件中會經過三個步驟來建立圖:inference(), loss()
, 和training()。
loss()
- 用來計算損失值。training()
- 計算梯度。
inference層
inference()函數建立圖,返回預測結果。
它把圖片佔位符看成輸入,並在上面構建一對徹底鏈接的層,使用ReLU激活後,鏈接一個10個節點的線性層。
每一層都位於tf.name_scope
聲明的命名空間中。
with tf.name_scope('hidden1'):
在該命名空間中,權重和偏置會產生tf.Variable實例,並具備所需的形狀。
weights = tf.Variable(tf.truncated_normal([IMAGE_PIXELS, hidden1_units], stddev=1.0 / math.sqrt(float(IMAGE_PIXELS))), name='weights') biases = tf.Variable(tf.zeros([hidden1_units]), name='biases')
例如,這些會在hidden1命名空間中建立,那麼權重的惟一名稱爲「hidden1/weights」。
每一個變量使用初始化器做爲構造函數。
一般,權重會使用tf.truncated_normal(截尾正態分佈)
做爲初始化器,它是一個2D張量,第一個參數表示該層中的神經元數,第二個表示它鏈接的層中的神經元數。再第一層hidden1中,權限矩陣的大小是[圖片像素, hidden1神經元數],由於該權重鏈接圖片輸入。tf.truncated_normal初始化器會根據平均值和標準差產生一些隨機數。
而後,偏置會使用tf.zeros
做爲初始化器,保證開始時全部數都是0。它們的形狀跟它們鏈接的層的神經元同樣。
該圖的三個主要運算:兩個tf.nn.relu操做
(包括隱層中的一個tf.matmul操做
)和一個額外的tf.matmul操做。而後依次建立,鏈接到輸入佔位符或上一層的輸出張量上。
hidden1 = tf.nn.relu(tf.matmul(images, weights) + biases)
hidden2 = tf.nn.relu(tf.matmul(hidden1, weights) + biases)
logits = tf.matmul(hidden2, weights) + biases
最後,logits張量包含輸出結果。
損失
loss()函數經過添加所需的損失操做來進一步構建圖形。
首先,將labels_placeholder的值轉換爲64位整數。 而後,添加tf.nn.sparse_softmax_cross_entropy_with_logits操做,以自動從labels_placeholder產生標籤,並將inference()函數的輸出與這些標籤進行比較。
labels = tf.to_int64(labels) cross_entropy = tf.nn.sparse_softmax_cross_entropy_with_logits(labels=labels, logits=logits, name='xentropy')
而後使用tf.reduce_mean將batch維度(第一維)的交叉熵的平均數做爲總損耗。
loss = tf.reduce_mean(cross_entropy, name='xentropy_mean')
而後返回包含損失值的張量。
tf.summary.scalar('loss', loss)
接下來,咱們實例化一個tf.train.GradientDescentOptimizer,進行梯度降低算法。
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
而後,咱們定義一個變量,用來做爲全局訓練步驟的計數器,而且tf.train.Optimizer.minimize op用於更新系統中的可訓練權重,並增長全局步長。 一般,這個操做被稱爲train_op. 它是由TensorFlow會話運行的,以便引導一個完整的訓練步驟。
global_step = tf.Variable(0, name='global_step', trainable=False) train_op = optimizer.minimize(loss, global_step=global_step)
訓練模型
構建圖形後,能夠在full_connected_feed.py中由用戶代碼控制的循環中進行迭代訓練和評估。
圖
在run_training()函數的頂部,其中的命令指示全部構建的操做都與默認的全局tf.Graph實例相關聯。
with tf.Graph().as_default():
tf.Graph是能夠做爲一組一塊兒執行的操做的集合。 大多數TensorFlow用戶只須要依賴於單個默認圖形。
更復雜的使用多個圖形是可能的,但超出了這個簡單教程的範圍。
會話
一旦全部的構建準備工做已經完成而且生成了全部必要的操做,就會建立一個tf.Session來運行圖形。
sess = tf.Session()
或者,能夠將會話生成到某個做用域中:
with tf.Session() as sess:
會話的空參數表示此代碼將附加到默認本地會話(或建立還沒有建立)。
在建立會話以後,全部的tf.Variable實例都經過在初始化操做中調用tf.Session.run來初始化。
init = tf.global_variables_initializer()
sess.run(init)
tf.Session.run方法將進行參數傳遞操做。在這個調用中,只進行變量的初始值。 圖的其他部分都不在這裏運行; 這在下面的訓練循環中運行。
訓練循環
在會話初始化變量後,能夠開始訓練。
用戶代碼控制每一步的訓練,最簡單的循環能夠是:
for step in xrange(FLAGS.max_steps): sess.run(train_op)
可是,本教程稍微複雜一些,由於它還必須分割每一個步驟的輸入數據,以匹配先前生成的佔位符。
數據輸入到圖
對於每一個步驟,代碼將生成一個Feed字典,其中包含一組數據,用於訓練,由其所對應的佔位符操做輸入。
在fill_feed_dict()函數中,查詢給定的DataSet用於其下一個batch_size圖像和標籤集,填充與佔位符匹配的張量,其中包含下一個圖像和標籤。
images_feed, labels_feed = data_set.next_batch(FLAGS.batch_size, FLAGS.fake_data)
而後生成一個python字典對象,其中佔位符做爲鍵,表明性的Feed張量做爲值。
feed_dict = {
images_placeholder: images_feed,
labels_placeholder: labels_feed,
}
這將被傳遞給sess.run()函數的feed_dict參數,以供該訓練循環使用。
檢查狀態
該代碼指定在運行調用中獲取的兩個值:[train_op,loss]。
for step in xrange(FLAGS.max_steps): feed_dict = fill_feed_dict(data_sets.train, images_placeholder, labels_placeholder) _, loss_value = sess.run([train_op, loss], feed_dict=feed_dict)
由於要獲取兩個值,因此sess.run()返回一個包含兩個項的元組。 要提取的值列表中的每一個Tensor對應於返回的元組中的numpy數組,在該訓練步驟中填充該張量的值。 因爲train_op是沒有輸出值的操做,返回的元組中的相應元素爲None,所以被丟棄。 然而,若是模型在訓練過程當中發生分歧,則損失張量的值可能變爲NaN,所以咱們捕獲該值用於記錄。
假設沒有NaN,訓練運行良好,訓練循環還會每100個步驟打印一個簡單的狀態文本,讓用戶知道訓練狀態。
if step % 100 == 0: print('Step %d: loss = %.2f (%.3f sec)' % (step, loss_value, duration))
狀態可視化
爲了輸出TensorBoard使用的事件文件,在圖形構建階段,全部的摘要(在這種狀況下只有一個)被收集到一個Tensor中。
summary = tf.summary.merge_all()
而後在建立會話以後,能夠將tf.summary.FileWriter實例化爲寫入事件文件,其中包含圖形自己和摘要的值。
summary_writer = tf.summary.FileWriter(FLAGS.train_dir, sess.graph)
最後,每次評估摘要並將輸出傳遞給add_summary()函數時,事件文件將被更新爲新的摘要值。
summary_str = sess.run(summary, feed_dict=feed_dict)
summary_writer.add_summary(summary_str, step)
當寫入事件文件時,能夠針對訓練文件夾運行TensorBoard,以顯示摘要中的值。
注意:有關如何構建和運行Tensorboard的更多信息,請參閱隨附的教程Tensorboard:可視化學習。
保存檢查點
爲了輸出一個檢查點文件,能夠用於稍後恢復模型進行進一步的訓練或評估,咱們實例化一個tf.train.Saver。
saver = tf.train.Saver()
在訓練循環中,將按期調用tf.train.Saver.save方法,將訓練中各變量的值寫入檢查點文件。
saver.save(sess, FLAGS.train_dir, global_step=step)
在稍後的某些時候,可使用tf.train.Saver.restore方法來從新加載模型參數來恢復訓練。
saver.restore(sess, FLAGS.train_dir)
評估模型
每一步,代碼將嘗試針對訓練和測試數據集來評估模型。 do_eval()函數被執行三次,用於訓練,驗證和測試數據集。
print('Training Data Eval:') do_eval(sess, eval_correct, images_placeholder, labels_placeholder, data_sets.train) print('Validation Data Eval:') do_eval(sess, eval_correct, images_placeholder, labels_placeholder, data_sets.validation) print('Test Data Eval:') do_eval(sess, eval_correct, images_placeholder, labels_placeholder, data_sets.test)
請注意,更復雜的使用一般會將data_sets.test隔離,以便在大量超參數調整後才能進行檢查。 然而,爲了簡單的小MNIST問題,咱們對全部數據進行評估。
構建評估圖
在進入訓練循環以前,評估操做應該是經過調用mnist.py中的evaluate()函數,使用與loss()函數相同的參數構建的。
eval_correct = mnist.evaluation(logits, labels_placeholder)
評估函數簡單地生成一個tf.nn.in_top_k操做,若是真正的標籤能夠在K個最可能的預測中找到,那麼能夠自動對每一個模型輸出進行評分。 在這種狀況下,咱們將K的值設置爲1,以便僅對真實標籤考慮預測是否正確。
eval_correct = tf.nn.in_top_k(logits, labels, 1)
評估輸出
而後能夠建立一個填充feed_dict的循環,並針對eval_correct op調用sess.run()來評估給定數據集上的模型。
for step in xrange(steps_per_epoch): feed_dict = fill_feed_dict(data_set, images_placeholder, labels_placeholder) true_count += sess.run(eval_correct, feed_dict=feed_dict)
true_count變量簡單地累加了in_top_k op已經肯定爲正確的全部預測。 從那裏能夠從簡單地除以實例的總數來計算精度。
precision = true_count / num_examples print(' Num examples: %d Num correct: %d Precision @ 1: %0.04f' % (num_examples, true_count, precision))
原文:《TensorFlow Mechanics 101》:https://www.tensorflow.org/get_started/mnist/mechanics