首頁 > 技術(shù)資料 > 技術(shù)資料

TensorFlow運作方式入門

代碼:tensorflow/g3doc/tutorials/mnist/

本篇教程的目的,是向大家展示如何利用TensorFlow使用(經(jīng)典)MNIST數(shù)據(jù)集訓練并評估一個用于識別手寫數(shù)字的簡易前饋神經(jīng)網(wǎng)絡(luò)(feed-forward neural network)。我們的目標讀者,是有興趣使用TensorFlow的資深機器學習人士。

因此,撰寫該系列教程并不是為了教大家機器學習領(lǐng)域的基礎(chǔ)知識。

在學習本教程之前,請確保您已按照安裝TensorFlow教程中的要求,完成了安裝。

教程使用的文件

本教程引用如下文件:

文件目的
mnist.py構(gòu)建一個完全連接(fully connected)的MINST模型所需的代碼。
fully_connected_feed.py利用下載的數(shù)據(jù)集訓練構(gòu)建好的MNIST模型的主要代碼,以數(shù)據(jù)反饋字典(feed dictionary)的形式作為輸入模型。

只需要直接運行fully_connected_feed.py文件,就可以開始訓練:

python fully_connected_feed.py

準備數(shù)據(jù)

MNIST是機器學習領(lǐng)域的一個經(jīng)典問題,指的是讓機器查看一系列大小為28x28像素的手寫數(shù)字灰度圖像,并判斷這些圖像代表0-9中的哪一個數(shù)字。

TensorFlow運作方式入門(圖1)

更多相關(guān)信息,請查閱Yann LeCun網(wǎng)站中關(guān)于MNIST的介紹 或者Chris Olah對MNIST的可視化探索。

下載

run_training()方法的一開始,input_data.read_data_sets()函數(shù)會確保你的本地訓練文件夾中,已經(jīng)下載了正確的數(shù)據(jù),然后將這些數(shù)據(jù)解壓并返回一個含有DataSet實例的字典。

data_sets = input_data.read_data_sets(FLAGS.train_dir, FLAGS.fake_data)

注意fake_data標記是用于單元測試的,讀者可以不必理會。

數(shù)據(jù)集目的
data_sets.train55000個圖像和標簽(labels),作為主要訓練集。
data_sets.validation5000個圖像和標簽,用于迭代驗證訓練準確度。
data_sets.test10000個圖像和標簽,用于最終測試訓練準確度(trained accuracy)。

了解更多數(shù)據(jù)有關(guān)信息,請查閱此系列教程的數(shù)據(jù)下載 部分.

輸入與占位符(Inputs and Placeholders)

placeholder_inputs()函數(shù)將生成兩個tf.placeholder操作,定義傳入圖表中的shape參數(shù),shape參數(shù)中包括batch_size值,后續(xù)還會將實際的訓練用例傳入圖表。

images_placeholder = tf.placeholder(tf.float32, shape=(batch_size,
 IMAGE_PIXELS))
labels_placeholder = tf.placeholder(tf.int32, shape=(batch_size))

在訓練循環(huán)(training loop)的后續(xù)步驟中,傳入的整個圖像和標簽數(shù)據(jù)集會被切片,以符合每一個操作所設(shè)置的batch_size值,占位符操作將會填補以符合這個batch_size值。然后使用feed_dict參數(shù),將數(shù)據(jù)傳入sess.run()函數(shù)。

構(gòu)建圖表 (Build the Graph)

在為數(shù)據(jù)創(chuàng)建占位符之后,就可以運行mnist.py文件,經(jīng)過三階段的模式函數(shù)操作:inference(), loss(),和training()。圖表就構(gòu)建完成了。

1.inference() —— 盡可能地構(gòu)建好圖表,滿足促使神經(jīng)網(wǎng)絡(luò)向前反饋并做出預測的要求。

2.loss() —— 往inference圖表中添加生成損失(loss)所需要的操作(ops)。

3.training() —— 往損失圖表中添加計算并應用梯度(gradients)所需的操作。

TensorFlow運作方式入門(圖2)

推理(Inference)

inference()函數(shù)會盡可能地構(gòu)建圖表,做到返回包含了預測結(jié)果(output prediction)的Tensor。

它接受圖像占位符為輸入,在此基礎(chǔ)上借助ReLu(Rectified Linear Units)激活函數(shù),構(gòu)建一對完全連接層(layers),以及一個有著十個節(jié)點(node)、指明了輸出logtis模型的線性層。

每一層都創(chuàng)建于一個唯一的tf.name_scope之下,創(chuàng)建于該作用域之下的所有元素都將帶有其前綴。

with tf.name_scope('hidden1') as scope:

在定義的作用域中,每一層所使用的權(quán)重和偏差都在tf.Variable實例中生成,并且包含了各自期望的shape。

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作用域下生成時,賦予權(quán)重變量的獨特名稱將會是"hidden1/weights"。

每個變量在構(gòu)建時,都會獲得初始化操作(initializer ops)。

在這種最常見的情況下,通過tf.truncated_normal函數(shù)初始化權(quán)重變量,給賦予的shape則是一個二維tensor,其中第一個維度代表該層中權(quán)重變量所連接(connect from)的單元數(shù)量,第二個維度代表該層中權(quán)重變量所連接到的(connect to)單元數(shù)量。對于名叫hidden1的第一層,相應的維度則是[IMAGE_PIXELS, hidden1_units],因為權(quán)重變量將圖像輸入連接到了hidden1層。tf.truncated_normal初始函數(shù)將根據(jù)所得到的均值和標準差,生成一個隨機分布。

然后,通過tf.zeros函數(shù)初始化偏差變量(biases),確保所有偏差的起始值都是0,而它們的shape則是其在該層中所接到的(connect to)單元數(shù)量。

圖表的三個主要操作,分別是兩個tf.nn.relu操作,它們中嵌入了隱藏層所需的tf.matmul;以及l(fā)ogits模型所需的另外一個tf.matmul。三者依次生成,各自的tf.Variable實例則與輸入占位符或下一層的輸出tensor所連接。

hidden1 = tf.nn.relu(tf.matmul(images, weights) + biases)
hidden2 = tf.nn.relu(tf.matmul(hidden1, weights) + biases)
logits = tf.matmul(hidden2, weights) + biases

最后,程序會返回包含了輸出結(jié)果的logitsTensor。

損失(Loss)

loss()函數(shù)通過添加所需的損失操作,進一步構(gòu)建圖表。

首先,labels_placeholer中的值,將被編碼為一個含有1-hot values的Tensor。例如,如果類標識符為“3”,那么該值就會被轉(zhuǎn)換為:
[0, 0, 0, 1, 0, 0, 0, 0, 0, 0]

batch_size = tf.size(labels)
labels = tf.expand_dims(labels, 1)
indices = tf.expand_dims(tf.range(0, batch_size, 1), 1)
concated = tf.concat(1, [indices, labels])
onehot_labels = tf.sparse_to_dense(
concated, tf.pack([batch_size, NUM_CLASSES]), 1.0, 0.0)

之后,又添加一個tf.nn.softmax_cross_entropy_with_logits操作,用來比較inference()函數(shù)與1-hot標簽所輸出的logits Tensor。

cross_entropy = tf.nn.softmax_cross_entropy_with_logits(logits,
onehot_labels,
name='xentropy')

然后,使用tf.reduce_mean函數(shù),計算batch維度(第一維度)下交叉熵(cross entropy)的平均值,將將該值作為總損失。

loss = tf.reduce_mean(cross_entropy, name='xentropy_mean')

最后,程序會返回包含了損失值的Tensor。

注意:交叉熵是信息理論中的概念,可以讓我們描述如果基于已有事實,相信神經(jīng)網(wǎng)絡(luò)所做的推測最壞會導致什么結(jié)果。更多詳情,請查閱博文《可視化信息理論》(http://colah.github.io/posts/2015-09-Visual-Information/)

訓練

training()函數(shù)添加了通過梯度下降(gradient descent)將損失最小化所需的操作。

首先,該函數(shù)從loss()函數(shù)中獲取損失Tensor,將其交給tf.scalar_summary,后者在與SummaryWriter(見下文)配合使用時,可以向事件文件(events file)中生成匯總值(summary values)。在本篇教程中,每次寫入?yún)R總值時,它都會釋放損失Tensor的當前值(snapshot value)。

tf.scalar_summary(loss.op.name, loss)

接下來,我們實例化一個tf.train.GradientDescentOptimizer,負責按照所要求的學習效率(learning rate)應用梯度下降法(gradients)。

optimizer = tf.train.GradientDescentOptimizer(FLAGS.learning_rate)

之后,我們生成一個變量用于保存全局訓練步驟(global training step)的數(shù)值,并使用minimize()函數(shù)更新系統(tǒng)中的三角權(quán)重(triangle weights)、增加全局步驟的操作。根據(jù)慣例,這個操作被稱為 train_op,是TensorFlow會話(session)誘發(fā)一個完整訓練步驟所必須運行的操作(見下文)。

global_step = tf.Variable(0, name='global_step', trainable=False)
train_op = optimizer.minimize(loss, global_step=global_step)

最后,程序返回包含了訓練操作(training op)輸出結(jié)果的Tensor。

訓練模型

一旦圖表構(gòu)建完畢,就通過fully_connected_feed.py文件中的用戶代碼進行循環(huán)地迭代式訓練和評估。

圖表

run_training()這個函數(shù)的一開始,是一個Python語言中的with命令,這個命令表明所有已經(jīng)構(gòu)建的操作都要與默認的tf.Graph全局實例關(guān)聯(lián)起來。

with tf.Graph().as_default():

tf.Graph實例是一系列可以作為整體執(zhí)行的操作。TensorFlow的大部分場景只需要依賴默認圖表一個實例即可。

利用多個圖表的更加復雜的使用場景也是可能的,但是超出了本教程的范圍。

會話

完成全部的構(gòu)建準備、生成全部所需的操作之后,我們就可以創(chuàng)建一個tf.Session,用于運行圖表。

sess = tf.Session()

另外,也可以利用with代碼塊生成Session,限制作用域:

with tf.Session() as sess:

Session函數(shù)中沒有傳入?yún)?shù),表明該代碼將會依附于(如果還沒有創(chuàng)建會話,則會創(chuàng)建新的會話)默認的本地會話。

生成會話之后,所有tf.Variable實例都會立即通過調(diào)用各自初始化操作中的sess.run()函數(shù)進行初始化。

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

sess.run()方法將會運行圖表中與作為參數(shù)傳入的操作相對應的完整子集。在初次調(diào)用時,init操作只包含了變量初始化程序tf.group。圖表的其他部分不會在這里,而是在下面的訓練循環(huán)運行。

訓練循環(huán)

完成會話中變量的初始化之后,就可以開始訓練了。

訓練的每一步都是通過用戶代碼控制,而能實現(xiàn)有效訓練的最簡單循環(huán)就是:

for step in xrange(max_steps):
sess.run(train_op)

但是,本教程中的例子要更為復雜一點,原因是我們必須把輸入的數(shù)據(jù)根據(jù)每一步的情況進行切分,以匹配之前生成的占位符。

向圖表提供反饋

執(zhí)行每一步時,我們的代碼會生成一個反饋字典(feed dictionary),其中包含對應步驟中訓練所要使用的例子,這些例子的哈希鍵就是其所代表的占位符操作。

fill_feed_dict函數(shù)會查詢給定的DataSet,索要下一批次batch_size的圖像和標簽,與占位符相匹配的Tensor則會包含下一批次的圖像和標簽。

images_feed, labels_feed = data_set.next_batch(FLAGS.batch_size)

然后,以占位符為哈希鍵,創(chuàng)建一個Python字典對象,鍵值則是其代表的反饋Tensor。

feed_dict = {
images_placeholder: images_feed,
labels_placeholder: labels_feed,
}

這個字典隨后作為feed_dict參數(shù),傳入sess.run()函數(shù)中,為這一步的訓練提供輸入樣例。

檢查狀態(tài)

在運行sess.run函數(shù)時,要在代碼中明確其需要獲取的兩個值:[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數(shù)組,而這些數(shù)組中包含了當前這步訓練中對應Tensor的值。由于train_op并不會產(chǎn)生輸出,其在返回的元祖中的對應元素就是None,所以會被拋棄。但是,如果模型在訓練中出現(xiàn)偏差,loss Tensor的值可能會變成NaN,所以我們要獲取它的值,并記錄下來。

假設(shè)訓練一切正常,沒有出現(xiàn)NaN,訓練循環(huán)會每隔100個訓練步驟,就打印一行簡單的狀態(tài)文本,告知用戶當前的訓練狀態(tài)。

if step % 100 == 0:print 'Step %d: loss = %.2f (%.3f sec)' % (step, loss_value, duration)

狀態(tài)可視化

為了釋放TensorBoard所使用的事件文件(events file),所有的即時數(shù)據(jù)(在這里只有一個)都要在圖表構(gòu)建階段合并至一個操作(op)中。

summary_op = tf.merge_all_summaries()

在創(chuàng)建好會話(session)之后,可以實例化一個tf.train.SummaryWriter,用于寫入包含了圖表本身和即時數(shù)據(jù)具體值的事件文件。

summary_writer = tf.train.SummaryWriter(FLAGS.train_dir,
graph_def=sess.graph_def)

最后,每次運行summary_op時,都會往事件文件中寫入最新的即時數(shù)據(jù),函數(shù)的輸出會傳入事件文件讀寫器(writer)的add_summary()函數(shù)。。

summary_str = sess.run(summary_op, feed_dict=feed_dict)
summary_writer.add_summary(summary_str, step)

事件文件寫入完畢之后,可以就訓練文件夾打開一個TensorBoard,查看即時數(shù)據(jù)的情況。

TensorFlow運作方式入門(圖3)

注意:了解更多如何構(gòu)建并運行TensorBoard的信息,請查看相關(guān)教程Tensorboard:訓練過程可視化。

保存檢查點(checkpoint)

為了得到可以用來后續(xù)恢復模型以進一步訓練或評估的檢查點文件(checkpoint file),我們實例化一個tf.train.Saver。

saver = tf.train.Saver()

在訓練循環(huán)中,將定期調(diào)用saver.save()方法,向訓練文件夾中寫入包含了當前所有可訓練變量值得檢查點文件。

saver.save(sess, FLAGS.train_dir, global_step=step)

這樣,我們以后就可以使用saver.restore()方法,重載模型的參數(shù),繼續(xù)訓練。

saver.restore(sess, FLAGS.train_dir)

評估模型

每隔一千個訓練步驟,我們的代碼會嘗試使用訓練數(shù)據(jù)集與測試數(shù)據(jù)集,對模型進行評估。do_eval函數(shù)會被調(diào)用三次,分別使用訓練數(shù)據(jù)集、驗證數(shù)據(jù)集合測試數(shù)據(jù)集。

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測試數(shù)據(jù)集,只有在大量的超參數(shù)優(yōu)化調(diào)整(hyperparameter tuning)之后才進行檢查。但是,由于MNIST問題比較簡單,我們在這里一次性評估所有的數(shù)據(jù)。

構(gòu)建評估圖表(Eval Graph)

在打開默認圖表(Graph)之前,我們應該先調(diào)用get_data(train=False)函數(shù),抓取測試數(shù)據(jù)集。

test_all_images, test_all_labels = get_data(train=False)

在進入訓練循環(huán)之前,我們應該先調(diào)用mnist.py文件中的evaluation函數(shù),傳入的logits和標簽參數(shù)要與loss函數(shù)的一致。這樣做事為了先構(gòu)建Eval操作。

eval_correct = mnist.evaluation(logits, labels_placeholder)

evaluation函數(shù)會生成tf.nn.in_top_k 操作,如果在K個最有可能的預測中可以發(fā)現(xiàn)真的標簽,那么這個操作就會將模型輸出標記為正確。在本文中,我們把K的值設(shè)置為1,也就是只有在預測是真的標簽時,才判定它是正確的。

eval_correct = tf.nn.in_top_k(logits, labels, 1)

評估圖表的輸出(Eval Output)

之后,我們可以創(chuàng)建一個循環(huán),往其中添加feed_dict,并在調(diào)用sess.run()函數(shù)時傳入eval_correct操作,目的就是用給定的數(shù)據(jù)集評估模型。

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操作判定為正確的預測之和。接下來,只需要將正確測試的總數(shù),除以例子總數(shù),就可以得出準確率了。

precision = float(true_count) / float(num_examples)print 'Num examples: %dNum correct: %dPrecision @ 1: %0.02f' % (
num_examples, true_count, precision)

原文:TensorFlow Mechanics 101 翻譯:bingjin 校對:LichAmnesia


?
電話:13070863493
郵箱:13070863493@163.com
地址:青島市市北區(qū)臺柳路223號新都朗悅2號樓
解決方案
人工智能
高性能計算
儲存
云計算
技術(shù)資料
技術(shù)資料
技術(shù)方案
行業(yè)動態(tài)
公司
關(guān)于我們
聯(lián)系我們
互動平臺

Copyright ? 2019-2024 青島希諾智能科技有限公司版權(quán)所有 備案號:魯ICP備19042003號-1

技術(shù)支持:微動力網(wǎng)絡(luò)

首頁 解決方案 一鍵撥打