我是一個很懶的人璧疗,我想試試
希望我能堅持到最后姨裸,把tensorflow的官方教程全部翻譯出來
提高自己秧倾,也幫助他人
我的博客:終身學(xué)習(xí)者
TensorFlow Mechanics 101
代碼:tensorflow/examples/tutorials/mnist/
本教程的目標是向大家展示在(經(jīng)典)的 MNIST 數(shù)據(jù)集下如何使用 TensorFlow 訓(xùn)練和評估一個用于識別手寫數(shù)字的簡單的前饋神經(jīng)網(wǎng)絡(luò)(feed-forward neural network)。本教程的目標讀者是有興趣使用 TensorFlow 的有經(jīng)驗的機器學(xué)習(xí)使用者傀缩。
這些教程不適用于機器學(xué)習(xí)初學(xué)者教學(xué)那先。
請確保你已經(jīng)按照說明安裝 TensorFlow。
Tutorial Files
本教程引用了以下文件:
文件 | 目的 |
---|---|
mnist.py |
構(gòu)建一個全連接 MNIST 模型代碼 |
fully_connected_feed.py |
主要代碼是利用 feed dictionary 對構(gòu)建的 MNIST 模型使用下載數(shù)據(jù)集進行訓(xùn)練 |
直接運行 fully_connected_feed.py
文件開始訓(xùn)練:
python fully_connected_feed.py
Prepare the Data
在機器學(xué)習(xí)中 MNIST 是一個經(jīng)典問題——通過觀察一個28x28像素的灰度手寫數(shù)字圖像來確定圖上的數(shù)字表示幾赡艰,其中所有的數(shù)字都是從0到9.
更多信息售淡,請參考 Yann LeCun's MNIST page 或 Chris Olah's visualizations of MNIST。
Download
在 run_training()
方法之前慷垮,input_data.read_data_sets()
函數(shù)確保了正確的數(shù)據(jù)集被下載到你的本地的訓(xùn)練目錄揖闸,然后解壓并返回DataSet
實例的字典。
data_sets = input_data.read_data_sets(FLAGS.train_dir, FLAGS.fake_data)
注意: fake_data
標志是用于單元測試的料身,讀者可以忽略楔壤。
數(shù)據(jù)集 | 目的 |
---|---|
data_sets.train |
55000 個圖像和標志,用于訓(xùn)練 |
data_sets.validation |
5000 個圖像和標志惯驼,迭代驗證訓(xùn)練準確度 |
data_sets.test |
10000 圖像和標志蹲嚣,用于最終測試訓(xùn)練準確度 |
Inputs and Placeholders
placeholder_inputs()
函數(shù)創(chuàng)建兩個 tf.placeholder
操作,定義了輸入的形狀祟牲,包括 batch_size
隙畜,到圖的其余部分,并將實際訓(xùn)練樣本輸入到其中说贝。
images_placeholder = tf.placeholder(tf.float32, shape=(batch_size,
mnist.IMAGE_PIXELS))
labels_placeholder = tf.placeholder(tf.int32, shape=(batch_size))
再往下议惰,在訓(xùn)練循環(huán)的每一步中,完整的圖像和標簽數(shù)據(jù)集被分割成符合batch_size
的大小乡恕,并與占位符操作相匹配言询。然后使用feed_dict
參數(shù)將數(shù)據(jù)傳入sess.run()
函數(shù)。
Build the Graph
為數(shù)據(jù)創(chuàng)建占位符后傲宜,從mnist.py
文件中根據(jù)三個階段模型:inference()
运杭,loss()
,和 training()
就可以構(gòu)建圖了函卒。
-
inference()
- 根據(jù)需求構(gòu)建圖辆憔,以便向前運行網(wǎng)絡(luò)進行預(yù)測。 -
loss()
- 在 inference 圖中添加產(chǎn)生損失(loss)所需的操作(ops)。 -
training()
- 在 loss 圖中添加計算和應(yīng)用梯度(gradients)的操作虱咧。
Inference
根據(jù)需要 inference()
函數(shù)構(gòu)建好圖并返回包含預(yù)測結(jié)果(output predictions)的張量(tensor)熊榛。
它將圖像占位符作為輸入,并在其上構(gòu)建一對全連接層腕巡,其中有一個 ReLU 激活函數(shù)玄坦,其后接著是十個指定輸出logits的線性層節(jié)點。
每一層都在唯一的 tf.name_scope
之下創(chuàng)建绘沉,它充當在該范圍內(nèi)創(chuàng)建的項目的前綴营搅。
with tf.name_scope('hidden1'):
在定義的范圍內(nèi)闹究,每個層所使用的權(quán)重和偏置都在 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
范圍內(nèi)創(chuàng)建叼风,賦予權(quán)重變量唯一的名稱就是 "hidden1/weights
"帖世。
每個變量作為他們構(gòu)造的一部分都會被賦予初始化操作休蟹。
在這種最常見的情況下,通過tf.truncated_normal
來初始化權(quán)重日矫,并給予他們2維形狀的張量赂弓,其中第一維表示該層中權(quán)重連接的單元數(shù)量,而其中第二維表示該層權(quán)重連接到的單元數(shù)量哪轿。對于名為 hidden1
的第一層盈魁,維度為 [IMAGE_PIXELS, hidden1_units]
,因為權(quán)重連接輸入圖像到 hidden1 層窃诉。根據(jù)給定的均值和標準差 tf.truncated_normal
初始化生成一個隨機分布杨耙。
然后通過 tf.zeros
初始化偏置,以確保他們使用全為零的值開始飘痛,而它們的形狀就是該層連接的所有單元數(shù)量珊膜。
圖的三個主要操作——兩個 tf.nn.relu
操作,在隱藏層中包含了 tf.matmul
宣脉。一個 logits 所需的額外的tf.matmul
操作车柠。然后依次創(chuàng)建,而每個單獨的 tf.Variable
實例連接到每個輸入占位符或前一層的輸出張量塑猖。
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
loss()
函數(shù)通過添加所需的損失操作來進一步構(gòu)建圖羊苟。
首先塑陵,來自labels_placeholder
的值被轉(zhuǎn)化為64位整數(shù)。然后增加一個 tf.nn.sparse_softmax_cross_entropy_with_logits
操作到labels_placeholder
自動產(chǎn)生的1-hot 標簽践险,并比較從 inference()
函數(shù)中的輸出 logits 與這些1-hot 標簽猿妈。
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')
然后返回包含損失值的張量彭则。
注意: 交叉熵是信息論的一個概念,它允許我們基于實際是真的占遥,描述相信神經(jīng)網(wǎng)絡(luò)是有多糟俯抖。欲了解更多信息,請閱讀視覺信息理論博客 (http://colah.github.io/posts/2015-09-Visual-Information/)
Training
training()
函數(shù)添加通過 Gradient Descent 最小化損失的操作瓦胎。
首先芬萍,從loss()
函數(shù)中獲取損失張量,并傳遞給 tf.summary.scalar
搔啊,然后再使用 tf.summary.FileWriter
(見下文)柬祠,向事件文件(events file)生成匯總值(summary values)。在這里负芋,每次寫入?yún)R總值時漫蛔,它都會發(fā)出當前的損失值(snapshot value)。
tf.summary.scalar('loss', loss)
接下來旧蛾,我們實例化一個 tf.train.GradientDescentOptimizer
莽龟,負責(zé)按照我們要求的學(xué)習(xí)率(learning rate),應(yīng)用梯度下降(gradients)锨天。
optimizer = tf.train.GradientDescentOptimizer(learning_rate)
再然后毯盈,我們生成一個變量來保存全局訓(xùn)練步驟的數(shù)值(global training step),并使用tf.train.Optimizer.minimize
操作來更新系統(tǒng)的訓(xùn)練權(quán)重和增加全局訓(xùn)練步驟病袄。按照慣例搂赋,這個操作被稱為 train_op
,是 TensorFlow 會話執(zhí)行一整個訓(xùn)練步驟(見下文)必須執(zhí)行的操作益缠。
global_step = tf.Variable(0, name='global_step', trainable=False)
train_op = optimizer.minimize(loss, global_step=global_step)
Train the Model
一旦圖構(gòu)建完成厂镇,就可以通過 fully_connected_feed.py
文件中用戶代碼進行循環(huán)迭代訓(xùn)練和評估控制。
The Graph
在 run_training()
函數(shù)之前是一個 python 的 with
命令左刽,它表明所有的構(gòu)建操作都與默認的全局tf.Graph
實例關(guān)聯(lián)起來捺信。
with tf.Graph().as_default():
tf.Graph
是一個操作集合,將作為一個組(group)一起被執(zhí)行欠痴。大多數(shù)的 TensorFlow 使用都只需要依賴于一個默認的圖的實例即可迄靠。
使用多個圖實現(xiàn)更復(fù)雜的情況是可能的,但是這超出了本篇教程的范圍喇辽。
The Session
一旦所有的構(gòu)建準備都完成掌挚,并且生成了所有的必須的操作,就可以創(chuàng)建 tf.Session
來執(zhí)行圖菩咨。
sess = tf.Session()
另外吠式,也可以在 with
塊中生成 Session
來限制作用域:
with tf.Session() as sess:
無參 session 函數(shù)表明這段代碼將連接(或者如果沒有創(chuàng)建那就創(chuàng)建)默認的本地 session陡厘。
在創(chuàng)建 session 后立即在它們的初始化操作中調(diào)用tf.Session.run
來初始化所有的tf.Variable
實例。
init = tf.global_variables_initializer()
sess.run(init)
tf.Session.run
方法將運行與作為參數(shù)傳遞的操作(op)對應(yīng)的完整子圖特占。在首次調(diào)用時糙置, init
操作是一個只包含變量初始化的tf.group
。圖的其他部分不會在這里執(zhí)行是目,而只會在下面的循環(huán)訓(xùn)練里執(zhí)行谤饭。
Train Loop
在 session 中初始化了所有的變量后,訓(xùn)練就可以開始了懊纳。
訓(xùn)練中的每一步都是由用戶代碼控制著揉抵,而有效訓(xùn)練的最簡單循環(huán)如下:
for step in xrange(FLAGS.max_steps):
sess.run(train_op)
然而,本教程會稍微復(fù)雜一點點嗤疯,因為它必須在每個循環(huán)中將輸入數(shù)據(jù)切片以匹配先前生成的占位符冤今。
Feed the Graph
對于每一步,代碼將生成一個 反饋字典(feed dictionary)茂缚,其中包含該步驟訓(xùn)練的樣本辟汰,例子的鍵(key)就是它們代表的占位符操作。
在fill_feed_dict()
函數(shù)中阱佛,查詢給定的DataSet
的下一批batch_size
的圖像和標簽帖汞,與占位符相匹配的張量包含了下一批的圖像和標簽。
images_feed, labels_feed = data_set.next_batch(FLAGS.batch_size,
FLAGS.fake_data)
生成一個 python 字典對象凑术,其中占位符為 鍵(key)翩蘸,代表的反饋張量(feed tensor)為值(value)。
feed_dict = {
images_placeholder: images_feed,
labels_placeholder: labels_feed,
}
這個字典對象將傳遞給 sess.run()
函數(shù)的feed_dict
參數(shù)淮逊,為這一步的訓(xùn)練提供輸入樣本催首。
Check the Status
該代碼指定了兩個要在其運行調(diào)用中獲取的值: [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
對應(yīng)著返回元組中的一個 numpy 數(shù)組(array),而該數(shù)組包含了這一步訓(xùn)練所需要的張量的值备籽。由于train_op
是一個沒有輸出值的 Operation
舶治,返回的元組中對應(yīng)的元素是 None
,因此 train_op 會被丟棄车猬。然后如果在訓(xùn)練期間模型發(fā)散導(dǎo)致loss
張量的值可能編程 NaN霉猛,因此我們要獲取這個值并記錄下來。
假設(shè)訓(xùn)練運行的很好珠闰,沒有產(chǎn)生 NaN值惜浅,訓(xùn)練循環(huán)也將每 100 次打印一個簡單的狀態(tài)來讓我們知道訓(xùn)練的狀態(tài)。
if step % 100 == 0:
print('Step %d: loss = %.2f (%.3f sec)' % (step, loss_value, duration))
Visualize the Status
為了發(fā)布由 [TensorBoard 使用的事件文件伏嗜,在圖的構(gòu)建階段坛悉,所有的總結(jié)信息(summary)(在這里只有一個)被收集進一個張量里伐厌。
summary = tf.summary.merge_all()
在創(chuàng)建好會話(session)之后,實例化一個 tf.summary.FileWriter
來寫事件文件裸影,其中包含了圖本身和總結(jié)信息的值挣轨。
summary_writer = tf.summary.FileWriter(FLAGS.train_dir, sess.graph)
最后,每次summary
評估的新的總結(jié)信息值都將更新事件文件空民,并輸出到事件文件讀寫器(writer)的 add_summary()
函數(shù)中刃唐。
summary_str = sess.run(summary, feed_dict=feed_dict)
summary_writer.add_summary(summary_str, step)
當事件文件被寫入時羞迷,在訓(xùn)練文件夾內(nèi) TensorBoard 將會運行來顯示匯總信息的值界轩。
注意:欲了解更多如何構(gòu)建和運行 Tensorboard,請參考隨后的 Tensorboard: Visualizing Learning 教程衔瓮。
Save a Checkpoint
為了后續(xù)恢復(fù)模型以便將來能進一步的訓(xùn)練或評估而發(fā)布一個檢查點文件(checkpoint file)浊猾,我們實例化 tf.train.Saver
。
saver = tf.train.Saver()
在循環(huán)訓(xùn)練中热鞍,周期性的調(diào)用 tf.train.Saver.save
方法寫入檢查點文件到訓(xùn)練目錄下葫慎,其中包含了所有可訓(xùn)練變量的當前值。
saver.save(sess, FLAGS.train_dir, global_step=step)
在未來的某個時候薇宠,可以通過使用 tf.train.Saver.restore
方法來重新載入模型參數(shù)以恢復(fù)訓(xùn)練偷办。
saver.restore(sess, FLAGS.train_dir)
Evaluate the Model
每循環(huán)一千次,代碼將嘗試使用訓(xùn)練數(shù)據(jù)和測試數(shù)據(jù)來評估模型澄港。 do_eval()
方法將被調(diào)用三次椒涯,分別使用訓(xùn)練數(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)
注意更復(fù)雜的用法是隔離
data_sets.test
废岂,直到大量的超參數(shù)(hyperparameter )調(diào)整之后才被檢查。但對于一個簡單的 MNIST 問題狱意,這里我們一次性評估了所有的數(shù)據(jù)湖苞。
Build the Eval Graph
在進入循環(huán)訓(xùn)練之前,通過從mnist.py
文件中調(diào)用evaluation()
函數(shù)來構(gòu)建評估操作详囤,其中使用了和loss()
函數(shù)相同的 logist/labels 參數(shù)财骨。
eval_correct = mnist.evaluation(logits, labels_placeholder)
evaluation()
函數(shù)會簡單的生成一個 tf.nn.in_top_k
操作,如果在 K 個最可能的預(yù)測中發(fā)現(xiàn)了真的標簽藏姐,那么它將自動給每個模型輸出標記為正確蚓再。在這里我們將設(shè)置 K 為1,因為我們只考慮只有在標簽為真的時候的預(yù)測才為正確包各。
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
操作中被認為是正確的所有預(yù)測的簡單疊加娃属,這樣六荒,精度的計算可以是簡單地將所有正確的預(yù)測的樣本總數(shù)除以所有的樣本的總數(shù)得到。
precision = true_count / num_examples
print(' Num examples: %d Num correct: %d Precision @ 1: %0.04f' %
(num_examples, true_count, precision))