W3Cschool
恭喜您成為首批注冊(cè)用戶(hù)
獲得88經(jīng)驗(yàn)值獎(jiǎng)勵(lì)
注意:將數(shù)據(jù)導(dǎo)入到 TensorFlow 程序的首選方法是使用數(shù)據(jù)集 API。
另外還有三種方法可以將數(shù)據(jù)導(dǎo)入到 TensorFlow 程序中:
TensorFlow 的 feed 機(jī)制允許您在計(jì)算圖中向任何張量注入數(shù)據(jù)。因此,python 計(jì)算可以直接將數(shù)據(jù)導(dǎo)入到圖中。
通過(guò) feed_dict 參數(shù)向啟動(dòng)計(jì)算的 run() 或 eval () 調(diào)用提供 feed 數(shù)據(jù)。
注意:“Feeding” 是將數(shù)據(jù)傳送到 TensorFlow 程序的最有效的方式,只能用于小型實(shí)驗(yàn)和調(diào)試。
with tf.Session():
input = tf.placeholder(tf.float32)
classifier = ...
print(classifier.eval(feed_dict={input: my_python_preprocessing_fn()}))
雖然可以使用 Feed 數(shù)據(jù)(包括變量和常量)替換任何 Tensor,但最佳做法是使用 tf.placeholder 節(jié)點(diǎn)。placeholder(占位符)只是作為 feed 的目標(biāo)存在。它未初始化,不包含任何數(shù)據(jù)如果占位符在沒(méi)有 Feed 的情況下執(zhí)行,則會(huì)產(chǎn)生錯(cuò)誤,因此您不會(huì)忘記將其遺忘。
在 tensorflow/examples/tutorials/mnist/fully_connected_feed.py 中可以找到在 MNIST 數(shù)據(jù)上使用占位符和 Feeding 訓(xùn)練的示例,并在 MNIST 教程中進(jìn)行了說(shuō)明。
從文件導(dǎo)入記錄的典型管道有以下幾個(gè)階段:
注意:本節(jié)討論使用基于隊(duì)列的API實(shí)現(xiàn)輸入管道,該 API 可以被 ${$datasets$Dataset API} 完整地替換。
對(duì)于文件名列表,請(qǐng)使用常量字符串張量(如["file0", "file1"]或[("file%d" % i) for i in range(2)])或函數(shù):tf.train.match_filenames_once。
將文件名列表傳遞給 tf.train.string_input_producer 函數(shù)。string_input_producer 創(chuàng)建一個(gè) FIFO 隊(duì)列,用于保存文件名,直到讀取器需要它們?yōu)橹埂?/p>
string_input_producer 有選擇的 shuffling 和設(shè)置一個(gè)最大的 epoch 數(shù)。隊(duì)列運(yùn)行程序?yàn)槊總€(gè) epoch 將文件名的整個(gè)列表添加到隊(duì)列中一次,如果洗牌 = True,則在一個(gè) epoch 中重新排列文件名。此過(guò)程提供了一個(gè)統(tǒng)一的文件取樣,以便相對(duì)于彼此不會(huì)對(duì)示例進(jìn)行低估或過(guò)度采樣。
隊(duì)列運(yùn)行程序在與從隊(duì)列中抽取文件名的讀取器分開(kāi)的線(xiàn)程中工作,因此,shuffling 和 enqueuing 進(jìn)程不會(huì)阻止讀取器。
選擇與您的輸入文件格式相匹配的讀取器,并將文件名隊(duì)列傳遞給讀取器的讀取方法。read 方法輸出一個(gè)標(biāo)識(shí)文件和記錄的密鑰 (如果有一些奇怪的記錄,則對(duì)調(diào)試有用) 和一個(gè)標(biāo)量字符串值,使用一個(gè) (或多個(gè)) 解碼器和轉(zhuǎn)換 ops 將此字符串解碼為構(gòu)成示例的張量。
若要以逗號(hào)分隔值 (CSV) 格式讀取文本文件,請(qǐng)使用 tf.TextLineReader 與 tf.decode_csv 操作。例如:
filename_queue = tf.train.string_input_producer(["file0.csv", "file1.csv"])
reader = tf.TextLineReader()
key, value = reader.read(filename_queue)
# Default values, in case of empty columns. Also specifies the type of the
# decoded result.
record_defaults = [[1], [1], [1], [1], [1]]
col1, col2, col3, col4, col5 = tf.decode_csv(
value, record_defaults=record_defaults)
features = tf.stack([col1, col2, col3, col4])
with tf.Session() as sess:
# Start populating the filename queue.
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(coord=coord)
for i in range(1200):
# Retrieve a single instance:
example, label = sess.run([features, col5])
coord.request_stop()
coord.join(threads)
每次讀取的執(zhí)行都從文件中讀取一行。然后,decode_csv 操作將結(jié)果解析為張量列表。該 record_defaults 參數(shù)確定生成的張量的類(lèi)型,并設(shè)置在輸入字符串中缺少值時(shí)要使用的默認(rèn)值。
在調(diào)用 run 或 eval 執(zhí)行讀取之前,必須調(diào)用 tf.train.start_queue_runners 來(lái)填充隊(duì)列。否則,讀取將在等待隊(duì)列中的文件名時(shí)阻止。
要讀取每條記錄是固定字節(jié)數(shù)的二進(jìn)制文件,請(qǐng)使用 tf.FixedLengthRecordReader 與 tf. decode_raw 操作.decode_raw 操作從一個(gè)字符串轉(zhuǎn)換為 uint8 張量。
例如,CIFAR-10 數(shù)據(jù)集使用一種文件格式,其中每個(gè)記錄使用固定的字節(jié)數(shù)表示:1 字節(jié)的標(biāo)簽,后跟3072字節(jié)的圖像數(shù)據(jù)。一旦你有一個(gè) uint8 張量,標(biāo)準(zhǔn)操作可以分割出每一塊和并根據(jù)需要重新格式化。對(duì)于 CIFAR-10,您可以在 tensorflow_models/tutorials/image/cifar10/cifar10_input.py 中了解如何進(jìn)行閱讀和解碼,并在本教程中介紹。
另一種方法是將您擁有的任何數(shù)據(jù)轉(zhuǎn)換為受支持的格式。這種方法使混合和匹配數(shù)據(jù)集和網(wǎng)絡(luò)體系結(jié)構(gòu)變得更加容易。TensorFlow 的推薦格式是包含 tf.train.Example 協(xié)議緩沖區(qū) (包含作為字段的功能) 的 TFRecords 文件。您編寫(xiě)了一個(gè)小程序來(lái)獲取您的數(shù)據(jù),將它放在一個(gè)示例協(xié)議緩沖區(qū)中,將協(xié)議緩沖區(qū)序列化為一個(gè)字符串,然后使用 tf. python_io. TFRecordWriter 將該字符串寫(xiě)入 TFRecords 文件。例如,tensorflow/examples/how_tos/reading_data/convert_to_records.py 將 MNIST 數(shù)據(jù)轉(zhuǎn)換為此格式。
要讀取 TFRecords 的文件,請(qǐng)使用 tf.TFRecordReader 與 tf. parse_single_example 解碼器.parse_single_example 操作將示例協(xié)議緩沖區(qū)解碼為張量。使用 convert_to_records 生成的數(shù)據(jù)的 MNIST 示例可以在 tensorflow/examples/how_tos/reading_data/fully_connected_reader.py 中找到。您可以與 fully_connected_feed 版本進(jìn)行比較。
然后,您可以對(duì)所需的這些示例進(jìn)行任何預(yù)處理。這將是任何不依賴(lài)于訓(xùn)練參數(shù)的處理.示例包括數(shù)據(jù)正常化、選擇隨機(jī)切片、增加噪聲或失真等。有關(guān)示例,請(qǐng)參見(jiàn) tensorflow_models/tutorials/image/cifar10/cifar10_input.py。
在管道的最后,我們使用另一個(gè)隊(duì)列來(lái)為訓(xùn)練,評(píng)估或推斷一起批處理示例。為此,我們使用一個(gè)隨機(jī)化的示例順序的隊(duì)列:tf.train.shuffle_batch。
例:
def read_my_file_format(filename_queue):
reader = tf.SomeReader()
key, record_string = reader.read(filename_queue)
example, label = tf.some_decoder(record_string)
processed_example = some_processing(example)
return processed_example, label
def input_pipeline(filenames, batch_size, num_epochs=None):
filename_queue = tf.train.string_input_producer(
filenames, num_epochs=num_epochs, shuffle=True)
example, label = read_my_file_format(filename_queue)
# min_after_dequeue defines how big a buffer we will randomly sample
# from -- bigger means better shuffling but slower start up and more
# memory used.
# capacity must be larger than min_after_dequeue and the amount larger
# determines the maximum we will prefetch. Recommendation:
# min_after_dequeue + (num_threads + a small safety margin) * batch_size
min_after_dequeue = 10000
capacity = min_after_dequeue + 3 * batch_size
example_batch, label_batch = tf.train.shuffle_batch(
[example, label], batch_size=batch_size, capacity=capacity,
min_after_dequeue=min_after_dequeue)
return example_batch, label_batch
如果您需要在文件之間進(jìn)行更多的并行性或示例的 shuffling,請(qǐng)使用多個(gè)讀取器實(shí)例 tf.train.shuffle_batch_join。例如:
def read_my_file_format(filename_queue):
# Same as above
def input_pipeline(filenames, batch_size, read_threads, num_epochs=None):
filename_queue = tf.train.string_input_producer(
filenames, num_epochs=num_epochs, shuffle=True)
example_list = [read_my_file_format(filename_queue)
for _ in range(read_threads)]
min_after_dequeue = 10000
capacity = min_after_dequeue + 3 * batch_size
example_batch, label_batch = tf.train.shuffle_batch_join(
example_list, batch_size=batch_size, capacity=capacity,
min_after_dequeue=min_after_dequeue)
return example_batch, label_batch
您仍然只能使用由所有讀取器共享的單個(gè)文件名隊(duì)列.這樣,我們確保不同的讀取器使用不同的文件從同一個(gè) epoch,直到所有的 epoch 文件已經(jīng)開(kāi)始。(通常只需一個(gè)線(xiàn)程填充文件名隊(duì)列即可。)
另一種方法是使用 num_threads 大于1的 tf.train.shuffle_batch 的單一讀取器。這將使它同時(shí)從單個(gè)文件中讀取 (但速度比使用1線(xiàn)程快),而不是同時(shí)讀 N 個(gè)文件.這可能很重要:
您需要多少個(gè)線(xiàn)程?tf.train.shuffle_batch* 函數(shù)向關(guān)系圖中添加一個(gè)摘要,以指示示例隊(duì)列的完整程度。如果有足夠的讀取線(xiàn)程,該摘要將保持在零以上。您可以使用TensorBoard 查看您的摘要作為培訓(xùn)進(jìn)度。
簡(jiǎn)短的版本:tf. train 上面列出的許多函數(shù)將 tf.train.QueueRunner 對(duì)象添加到圖形中。這些要求您在運(yùn)行任何培訓(xùn)或推理步驟之前調(diào)用 tf.train.start_queue_runners,否則它將永遠(yuǎn)掛起.這將啟動(dòng)運(yùn)行輸入管道的線(xiàn)程,填充示例隊(duì)列,以使得出列獲得示例的成功。這與 tf.train.Coordinator 很好的結(jié)合,可以在發(fā)生錯(cuò)誤的時(shí)候,快捷地關(guān)閉這些線(xiàn)程時(shí)。如果您對(duì) epoch 的數(shù)量設(shè)置了限制,那么將使用需要初始化的 epoch 計(jì)數(shù)器。建議的代碼模式組合如下:
# Create the graph, etc.
init_op = tf.global_variables_initializer()
# Create a session for running operations in the Graph.
sess = tf.Session()
# Initialize the variables (like the epoch counter).
sess.run(init_op)
# Start input enqueue threads.
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
try:
while not coord.should_stop():
# Run training steps or whatever
sess.run(train_op)
except tf.errors.OutOfRangeError:
print('Done training -- epoch limit reached')
finally:
# When done, ask the threads to stop.
coord.request_stop()
# Wait for threads to finish.
coord.join(threads)
sess.close()
首先,我們創(chuàng)建圖形。它將有幾個(gè)通過(guò)隊(duì)列連接的管道階段.第一階段將生成文件名,以便在文件名隊(duì)列中讀取和排隊(duì)它們。第二階段使用文件名 (讀取器),生成示例,并將其排入示例隊(duì)列。根據(jù)您設(shè)置內(nèi)容的方式,您可能實(shí)際上擁有第二個(gè)階段的一些獨(dú)立副本,以便可以并行讀取多個(gè)文件。在這些階段的結(jié)束時(shí),是一個(gè)排隊(duì)操作,排入隊(duì)列,下一個(gè)隊(duì)列出隊(duì)。我們要啟動(dòng)運(yùn)行這些入隊(duì)操作的線(xiàn)程,以便我們的訓(xùn)練循環(huán)可以從示例隊(duì)列中出示示例。
在 tf. train 中創(chuàng)建這些隊(duì)列和入隊(duì)操作的幫助器使用 tf.train.add_queue_runner 函數(shù)向圖形添加 tf.train.QueueRunner。每個(gè) QueueRunner 負(fù)責(zé)一個(gè)階段,并保存需要在線(xiàn)程中運(yùn)行的入隊(duì)操作的列表。一旦構(gòu)造了圖形,tf.train.start_queue_runners 函數(shù)就會(huì)要求圖中的每個(gè) QueueRunner 開(kāi)始運(yùn)行進(jìn)行操作的線(xiàn)程。
如果一切順利,您現(xiàn)在可以運(yùn)行您的培訓(xùn)步驟,并且隊(duì)列將由后臺(tái)線(xiàn)程填充。如果你已經(jīng)設(shè)置了一個(gè) epoch 的限制,在某些時(shí)候試圖出示的例子將得到一個(gè) tf.errors.OutOfRangeError。這是 TensorFlow 相當(dāng)于 "文件結(jié)束" (EOF)——這意味著已經(jīng)達(dá)到了 epoch 限制,沒(méi)有更多的示例可用。
最后是 tf.train.Coordinator。這是負(fù)責(zé)讓所有線(xiàn)程知道有沒(méi)有發(fā)出關(guān)閉信號(hào)。最常見(jiàn)的情況是,這是因?yàn)橐l(fā)了一個(gè)異常,例如,其中一個(gè)線(xiàn)程在運(yùn)行某項(xiàng)操作 (或一個(gè)普通的 Python 異常) 時(shí)發(fā)生了錯(cuò)誤。
有關(guān)線(xiàn)程,隊(duì)列,QueueRunners 和 Coordinators 的更多信息,請(qǐng)參見(jiàn)此處。
想象一下,你有一個(gè)模型,它對(duì)訓(xùn)練的 epoch 數(shù)設(shè)定了限制。這意味著生成文件名的線(xiàn)程只會(huì)在生成 OutOfRange 錯(cuò)誤之前運(yùn)行多次。QueueRunner 將捕獲該錯(cuò)誤,關(guān)閉文件名隊(duì)列,然后退出該線(xiàn)程.關(guān)閉隊(duì)列有兩點(diǎn)注意項(xiàng):
關(guān)鍵是,當(dāng)文件名隊(duì)列關(guān)閉時(shí),該隊(duì)列中可能仍有許多文件名,因此,管道的下一階段 (讀取器和其他預(yù)處理) 可能會(huì)繼續(xù)運(yùn)行一段時(shí)間。不過(guò),一旦文件名隊(duì)列被耗盡,下一次嘗試將一個(gè)文件名排隊(duì) (例如,從已完成文件的讀取器讀取) 將觸發(fā) OutOfRange 錯(cuò)誤。但是,在這種情況下,您可能有多個(gè)與單個(gè) QueueRunner 關(guān)聯(lián)的線(xiàn)程。如果這不是 QueueRunner 中的最后一個(gè)線(xiàn)程,則 OutOfRange 錯(cuò)誤只會(huì)導(dǎo)致一個(gè)線(xiàn)程退出。這允許其他線(xiàn)程,它們?nèi)匀煌瓿伤麄兊淖詈笠粋€(gè)文件,繼續(xù)前進(jìn),直到他們也完成。(假設(shè)您正在使用的是 tf.train.Coordinator,其他類(lèi)型的錯(cuò)誤將導(dǎo)致所有線(xiàn)程停止。一旦所有讀取器線(xiàn)程都命中了 OutOfRange 錯(cuò)誤,則只有下一個(gè)隊(duì)列 (即示例隊(duì)列) 才會(huì)關(guān)閉。
同樣,示例隊(duì)列將有一些元素排隊(duì),因此訓(xùn)練將繼續(xù)進(jìn)行,直到耗盡為止。如果示例隊(duì)列是 tf.RandomShuffleQueue,因?yàn)槟闶褂?shuffle_batch 或 shuffle_batch_join,它通常會(huì)避免比其 min_after_dequeue 緩沖的 attr 元素少。但是,一旦隊(duì)列關(guān)閉,將取消限制,并且隊(duì)列最終將為空。在這一點(diǎn)上,實(shí)際的訓(xùn)練線(xiàn)程,當(dāng)他們嘗試從示例隊(duì)列中出隊(duì)時(shí),將開(kāi)始獲得 OutOfRange 錯(cuò)誤并且退出。一旦所有的訓(xùn)練線(xiàn)程完成,tf.train.Coordinator.join 將返回,你可以徹底退出。
與形狀 [x、y、z] 的示例相反,您將生成一批具有形狀 [batch、x、y、z] 的示例。如果要將此記錄過(guò)濾(也許它在保留集合中),則批量大小可以為0;如果您每個(gè)記錄生成多個(gè)示例,則大于1。然后在調(diào)用一個(gè)批處理函數(shù) (如 shuffle_batch 或 shuffle_batch_join) 時(shí),簡(jiǎn)單地設(shè)置 enqueue_many = True。
SparseTensors(稀疏傳感器)不能很好地排隊(duì)。如果您使用 SparseTensors,則必須在批處理后使用 tf parse_example 對(duì)字符串記錄進(jìn)行解碼 (而不是在批處理之前使用 tf. parse_single_example).
這僅用于可以完全加載到內(nèi)存中的小型數(shù)據(jù)集.有兩種方法:
使用常數(shù)有點(diǎn)簡(jiǎn)單,但是會(huì)使用更多的內(nèi)存(因?yàn)槌A吭趫D形數(shù)據(jù)結(jié)構(gòu)中是內(nèi)聯(lián)存儲(chǔ)的,這可能會(huì)重復(fù)幾次)。
training_data = ...
training_labels = ...
with tf.Session():
input_data = tf.constant(training_data)
input_labels = tf.constant(training_labels)
...
要使用變量,您還需要在構(gòu)建圖形之后對(duì)其進(jìn)行初始化。
training_data = ...
training_labels = ...
with tf.Session() as sess:
data_initializer = tf.placeholder(dtype=training_data.dtype,
shape=training_data.shape)
label_initializer = tf.placeholder(dtype=training_labels.dtype,
shape=training_labels.shape)
input_data = tf.Variable(data_initializer, trainable=False, collections=[])
input_labels = tf.Variable(label_initializer, trainable=False, collections=[])
...
sess.run(input_data.initializer,
feed_dict={data_initializer: training_data})
sess.run(input_labels.initializer,
feed_dict={label_initializer: training_labels})
設(shè)置 trainable = False 將變量從圖中的 GraphKeys TRAINABLE_VARIABLES 集合中保留出來(lái),這樣我們就不會(huì)在訓(xùn)練時(shí)嘗試更新它.設(shè)置 collections = [] 將變量保留在用于保存和還原檢查點(diǎn)的 GraphKeys. GLOBAL_VARIABLES 集合中。
無(wú)論哪種方式,tf.train.slice_input_producer 都可以用于一次生成 slice。這個(gè) shuffles 的例子可以在整個(gè) epoch 中使用,所以進(jìn)一步 shuffling 時(shí),batching 是不可取的。因此,我們不使用 shuffle_batch 函數(shù),而是使用普通的 tf.train.batch 函數(shù).要使用多個(gè)預(yù)處理線(xiàn)程,請(qǐng)將 num_threads 參數(shù)設(shè)置為大于1的數(shù)字。
用于預(yù)先加載使用常量數(shù)據(jù)的 MNIST 例子可以在 tensorflow/examples/how_tos/reading_data/fully_connected_preloaded.py 找到,而一個(gè)用于預(yù)先加載使用變量的數(shù)據(jù)的 MNIST 例子可以在 tensorflow/examples/how_tos/reading_data/fully_connected_preloaded_var.py 找到,您可以將這些與上面的 fully_connected_feed 和 fully_connected_reader 版本進(jìn)行比較。
通常,您將希望在一個(gè)數(shù)據(jù)集上進(jìn)行訓(xùn)練,并對(duì)另一個(gè)數(shù)據(jù)集進(jìn)行評(píng)估 (或 "eval")。實(shí)現(xiàn)這一目標(biāo)的一個(gè)方法是實(shí)際上有兩個(gè)不同的圖形和會(huì)話(huà),可能在不同的進(jìn)程中:
這是在 CIFAR-10 示例中完成的估計(jì)和手動(dòng)操作.這有幾個(gè)好處:
您可以在同一進(jìn)程中的同一圖形中進(jìn)行訓(xùn)練和評(píng)估(eval),并共享他們訓(xùn)練的變量或?qū)?請(qǐng)參閱共享變量教程。
為了支持 single-graph(單圖) 方法,數(shù)據(jù)集還提供了高級(jí)迭代器類(lèi)型,允許用戶(hù)在不重建圖或會(huì)話(huà)的情況下更改輸入管道。
您可以在同一個(gè)過(guò)程中的同一個(gè)圖表中列出列車(chē)和eval,并分享訓(xùn)練有素的變量或?qū)?請(qǐng)參閱共享變量教程。
為了支持單圖方法,Datasets還提供了高級(jí)迭代器類(lèi)型,允許用戶(hù)在不重建圖形或會(huì)話(huà)的情況下更改輸入管道。
注意:無(wú)論執(zhí)行情況如何,許多操作(如$ {tf.layers.batch_normalization}和 tf.layers.dropout)都需要知道他們是否處于訓(xùn)練或評(píng)估模式,如果更改數(shù)據(jù)源,則必須小心設(shè)置。
Copyright©2021 w3cschool編程獅|閩ICP備15016281號(hào)-3|閩公網(wǎng)安備35020302033924號(hào)
違法和不良信息舉報(bào)電話(huà):173-0602-2364|舉報(bào)郵箱:jubao@eeedong.com
掃描二維碼
下載編程獅App
編程獅公眾號(hào)
聯(lián)系方式:
更多建議: