13 Tensorflow機制(翻譯)

    代碼: 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 MNISTpost

 

    數據下載單元測試

    在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()。

  1. inference() - 運行網絡來進行預測。
  2. loss() - 用來計算損失值。
  3. 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')

    而後返回包含損失值的張量。

 
    注意:交叉熵是信息論中的一個想法,它使咱們可以描述神經網絡的預測有多糟糕。有關更多信息,請閱讀博客文章Visual Information Theory(http://colah.github.io/posts/2015-09-Visual-Information/)
 
    訓練
    training()函數經過梯度降低法計算最小損失。
    首先,它從loss()函數中獲取損失張量,並將其傳遞給tf.summary.scalar,該函數用於在與tf.summary.FileWriter一塊兒使用時將事件生成摘要。
   
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

相關文章
相關標籤/搜索