標籤:

TensorFlow官方教程翻譯:導入數據

作者:馬小李23

原文鏈接:jianshu.com/p/c934a9679

查看更多的專業文章,請移步至「人工智慧LeadAI」公眾號,查看更多的課程信息及產品信息,請移步至全新打造的官網:www.leadai.org.

正文共19441個字,4張圖,預計閱讀時間49分鐘。

原文地址:tensorflow.org/programm

簡書地址:jianshu.com/p/c934a9679

需要注意的是,如下教程的tf.data的模塊需要將tensorflow升級到1.4的版本,才可以支持,低於1.4的版本的導入數據教程,見之前的翻譯教程,戳這裡(jianshu.com/p/64bd6a49a

Dataset的API讓你能從簡單,可重用的模塊中構建複雜的輸入管道。例如一個圖片模型的輸入管道,可能要從分散式的文件系統中獲得數據,對每張圖片做隨機擾動,以及將隨機選取的圖片合併到一個批次中用作訓練。文本模型的輸入管道可能涉及到從原始文本數據中提取符號,然後將其轉換到查找表中嵌入的標識符,以及將不同長度的序列組合成批次。Dataset的API使得處理大量的數據,不同的數據格式和複雜的轉換變得容易。

Dataset的API為TensorFlow中引入了兩個新的抽象概念:

1、tf.data.Dataset表示一個元素的序列,在這個序列中每個元素包含一個或多個Tensor對象。例如在一個圖片輸入管道中,一個元素可能是單個訓練樣本,這個元素包含一對Tensor分別表示圖片數據和一個標籤。有兩種不同的方式創建一個dataset:

創建一個source(例如Dataset.from_tensor_slices())從一個或多個tf.Tensor對象中構建一個dataset

應用一個transformation(例如Dataset.batch())從一個或多個tf.data.Dataset對象中構建一個dataset

2、tf.data.Iterator提供從一個dataset中提取元素的主要方式。Iterator.get_next()返回的操作在運行時會產生一個Dataset的下一個元素,它通常充當著輸入管道代碼和你的模型之間的介面。最簡單的迭代器是「一次性迭代器」,這種迭代器與特殊的Dataset聯繫並且只通過它迭代一次。對於更複雜的使用,Iterator.initializer操作能讓你使用不同的數據集重新初始化和配置迭代器。例如,你可以在同一個程序中多次迭代訓練和驗證數據。

01

Basic mechanics

這部分的指南介紹了創建不同類型的Dataset和Iterator對象的基礎,以及如何從它們中獲取數據。

為了開始一個輸入管道,你必須定義一個源。例如你可以使用tf.data.Dataset.from_tensors()或者tf.data.Dataset.from_tensor_slices()來使用在內存中的一些tensor構建一個Dataset。或者你的數據在硬碟里以推薦的TFRecord格式保存,那麼你可以創建一個tf.data.TFRecordDataset。

一旦你有了一個Dataset對象,你可以通過在tf.data.Dataset對象上鏈接方法調用來將其轉換成一個新的Dataset對象。比如你可以應用每個元素的轉換,如Dataset.map()(來對每個元素調用函數),以及多元素的轉換,如Dataset.batch()。有關轉換的完整列表,請參閱tf.data.Dataset的文檔。

最常見的從一個Dataset中消耗數值的方法就是創建一個迭代器對象,迭代器對象提供對於數據集中一個元素的一次訪問(例如通過調用Dataset.make_one_shot_iterator())。

tt.data.Iterator提供兩個操作:Iterator.initializer,讓你能(重新)初始化迭代器的狀態;Iterator.get_next()會返回對應符號的下一個元素的tf.Tensor對象。根據你的使用情況,你可以選擇不同類型的迭代器,下面概述了可選的迭代器。

02

Dataset structure

一個數據集包含的每個元素都有同樣的結構。一個元素包含一個或者多個tf.Tensor對象,這些對象被稱作部件。每個部件有一個tf.DType表示在tensor中元素的類型,和一個tf.TensorShape表示(可能是部分指定的)每個元素的靜態形狀。

Dataset.output_types和Dataset.output_shapes屬性使得你能檢查數據集元素的每個部件的推斷的類型和形狀。這些屬性的嵌套結構映射到一個元素的結構,該元素可能是單個張量,張量元組或張量的嵌套元組。例如:

dataset1 = tf.data.Dataset.from_tensor_slices(tf.random_uniform([4, 10]))print(dataset1.output_types) # ==> "tf.float32"print(dataset1.output_shapes) # ==> "(10,)"dataset2 = tf.data.Dataset.from_tensor_slices(n (tf.random_uniform([4]),n tf.random_uniform([4, 100], maxval=100, dtype=tf.int32)))print(dataset2.output_types) # ==> "(tf.float32, tf.int32)"print(dataset2.output_shapes) # ==> "((), (100,))"dataset3 = tf.data.Dataset.zip((dataset1, dataset2))print(dataset3.output_types) # ==> (tf.float32, (tf.float32, tf.int32))print(dataset3.output_shapes) # ==> "(10, ((), (100,)))"n

通常給一個元素的每個組件命名是比較方便的,例如如果它們表示一個訓練樣本的不同特徵。除了元組,你可以使用collections.namedtuple或者將字元串映射到張量的字典來表示Dataset中的單個元素。

dataset = tf.data.Dataset.from_tensor_slices(n {"a": tf.random_uniform([4]), "b": tf.random_uniform([4, 100], maxval=100, dtype=tf.int32)})print(dataset.output_types) # ==> "{a: tf.float32, b: tf.int32}"print(dataset.output_shapes) # ==> "{a: (), b: (100,)}"n

Dataset的轉換支持任何結構的數據集。當使用Dataset.map(),Dataset.flat_map()和Dataset.filter()轉換時——這些轉換會對每個元素應用一個函數,元素的結構決定調用函數的參數:

dataset1 = dataset1.map(lambda x: ...)nndataset2 = dataset2.flat_map(lambda x, y: ...)# Note: Argument destructuring is not available in Python 3.dataset3 = dataset3.filter(lambda x, (y, z): ...)n

03

Creating an iterator

一旦你創建了一個Dataset對象代表你的輸入數據,下一步就是創建一個Iterator來從數據集中獲取數據。

Dataset的API現在支持下列迭代器,它們的複雜程度順序遞增:

  • one-shot,
  • initializable,
  • reinitializable
  • feedable.

one-shot迭代器是最簡單的迭代器形式,它只支持迭代遍曆數據集一次,不需要顯式初始化。one-shot迭代器處理了現存的基於隊列輸入管道支持的幾乎所有的情況,但是它們不支持參數化配置。使用Dataset.range()例子:

dataset = tf.data.Dataset.range(100)niterator = dataset.make_one_shot_iterator()nnext_element = iterator.get_next()for i in range(100):nvalue = sess.run(next_element)assert i == valuen

注意:現在,one-shot迭代器是唯一的易於和Estimator使用的迭代器類型。

initializable迭代器要求你在使用它之前,顯式的調用iterator.initializer操作。這種不便換來的是它能讓你使用一個或多個tf.placeholder()張量來參數化定義數據集,這些張量能在你初始化迭代器的時候被提供。接著Dataset.range()的例子:

max_value = tf.placeholder(tf.int64, shape=[])ndataset = tf.data.Dataset.range(max_value)niterator = dataset.make_initializable_iterator()nnext_element = iterator.get_next()# Initialize an iterator over a dataset with 10 elements.sess.run(iterator.initializer, feed_dict={max_value: 10})for i in range(10):n value = sess.run(next_element) assert i == value# Initialize the same iterator over a dataset with 100 elements.sess.run(iterator.initializer, feed_dict={max_value: 100})for i in range(100):n value = sess.run(next_element) assert i == valuen

reinitializable迭代器能被多個不同的Dataset對象初始化。例如,你可能有一個訓練輸入管道,它會對輸入的圖片進行隨機擾動來提高其泛華能力,與此同時,有一個驗證輸入管道在不變的數據上評估預測。這些管道一般使用不同的Dataset對象,但這些對象有相同的結構(比如每個元素有相同的類型和兼容的形狀)。

# Define training and validation datasets with the same structure.training_dataset = tf.data.Dataset.range(100).map( lambda x: x + tf.random_uniform([], -10, 10, tf.int64))nvalidation_dataset = tf.data.Dataset.range(50)# A reinitializable iterator is defined by its structure. We could use the# `output_types` and `output_shapes` properties of either `training_dataset`# or `validation_dataset` here, because they are compatible.iterator = Iterator.from_structure(training_dataset.output_types,n training_dataset.output_shapes)nnext_element = iterator.get_next()nntraining_init_op = iterator.make_initializer(training_dataset)nvalidation_init_op = iterator.make_initializer(validation_dataset)# Run 20 epochs in which the training dataset is traversed, followed by the# validation dataset.for _ in range(20): # Initialize an iterator over the training dataset.n sess.run(training_init_op) for _ in range(100):n sess.run(next_element) # Initialize an iterator over the validation dataset.n sess.run(validation_init_op) for _ in range(50):n sess.run(next_element)n

feedable迭代器可以和tf.placeholder一起使用,通過熟悉的feed_dict機制在每次調用tf.Session.run的時候,選擇使用何種Iterator。它提供了與reinitializable迭代器相同的功能,但是在迭代器切換的時候,它不需要從數據集的開頭初始化迭代器。例如使用上述相同的訓練集和驗證集的例子,你可以使用tf.data.Iterator.from_string_handle來定義一個feedable迭代器,它可以讓你在兩個數據集之間切換:

# Define training and validation datasets with the same structure.training_dataset = tf.data.Dataset.range(100).map( lambda x: x + tf.random_uniform([], -10, 10, tf.int64)).repeat()nvalidation_dataset = tf.data.Dataset.range(50)# A feedable iterator is defined by a handle placeholder and its structure. We# could use the `output_types` and `output_shapes` properties of either# `training_dataset` or `validation_dataset` here, because they have# identical structure.handle = tf.placeholder(tf.string, shape=[])niterator = tf.data.Iterator.from_string_handle(n handle, training_dataset.output_types, training_dataset.output_shapes)nnext_element = iterator.get_next()# You can use feedable iterators with a variety of different kinds of iterator# (such as one-shot and initializable iterators).training_iterator = training_dataset.make_one_shot_iterator()nvalidation_iterator = validation_dataset.make_initializable_iterator()# The `Iterator.string_handle()` method returns a tensor that can be evaluated# and used to feed the `handle` placeholder.training_handle = sess.run(training_iterator.string_handle())nvalidation_handle = sess.run(validation_iterator.string_handle())# Loop forever, alternating between training and validation.while True: # Run 200 steps using the training dataset. Note that the training dataset isn # infinite, and we resume from where we left off in the previous `while` loopn # iteration.n for _ in range(200):n sess.run(next_element, feed_dict={handle: training_handle}) # Run one pass over the validation dataset.n sess.run(validation_iterator.initializer) for _ in range(50):n sess.run(next_element, feed_dict={handle: validation_handle})n

04

Consuming values from an iterator

Iterator.get_next()返回一個或者多個tf.Tensor對象,它們對應迭代器的迭代器下一個元素的象徵符號。每次這些張量被評估,它們獲取在隱藏的數據集中的下一個元素的數值。(注意:像其他在TensorFlow中的狀態對象,調用Iterator.get_next()不會馬上推動迭代器。相反你必須在TensorFlow表達式中使用返回的tf.Tensor對象,並且將這個表達式的結果傳給tf.Session.run()來獲取下一個元素和推動迭代器。)

如果迭代器達到數據集的末尾,運行Iterator.get_next()操作會拋出tf.errors.OutOfRangeError的錯誤。此時迭代器會處于禁用狀態,如果你想再次使用它,那麼你必須重新初始化它。

dataset = tf.data.Dataset.range(5)niterator = dataset.make_initializable_iterator()nnext_element = iterator.get_next()# Typically `result` will be the output of a model, or an optimizers# training operation.result = tf.add(next_element, next_element)nnsess.run(iterator.initializer)nprint(sess.run(result)) # ==> "0"print(sess.run(result)) # ==> "2"print(sess.run(result)) # ==> "4"print(sess.run(result)) # ==> "6"print(sess.run(result)) # ==> "8"try:n sess.run(result)except tf.errors.OutOfRangeError:n print("End of dataset") # ==> "End of dataset"n

一個常見的模式是將「訓練循環」封裝在try-except塊中:

sess.run(iterator.initializer)while True: try:n sess.run(result) except tf.errors.OutOfRangeError: breakn

如果數據集的每個元素是嵌套結構,那麼Iterator.get_next()返回值會是以同樣結構嵌套的一個或者多個tf.Tensor對象:

dataset1 = tf.data.Dataset.from_tensor_slices(tf.random_uniform([4, 10])) dataset2 = tf.data.Dataset.from_tensor_slices((tf.random_uniform([4]), tf.random_uniform([4, 100]))) dataset3 = tf.data.Dataset.zip((dataset1, dataset2)) iterator = dataset3.make_initializable_iterator() sess.run(iterator.initializer) next1, (next2, next3) = iterator.get_nextn

()

注意,評估next1,next2或者next3中任何一個,都會推動對於所有組件共用的迭代器。一個典型的迭代器消耗,是在單個表達式中包含其所有組件。

05

Reading input data

consuming numpy arrays

如果你的所有輸入數據能裝進內存中,用它們創建一個Dataset最簡單的方式就是將它們轉換成tf.Tensor對象,並用Dataset.from_tensor_slices()。

# Load the training data into two NumPy arrays, for example using `np.load()`.with np.load("/var/data/training_data.npy") as data: features = data["features"] labels = data["labels"]# Assume that each row of `features` corresponds to the same row as `labels`.assert features.shape[0] == labels.shape[0] dataset = tf.data.Dataset.from_tensor_slices((features, labels))n

注意上述代碼片段會將features和labels數組作為tf.constant()操作嵌入你的TensorFlow的圖中。這對於小的數據集而言運行良好,但是浪費內存——因為數組的內容會被拷貝兩次——並且會達到tf.GraphDef協議緩衝的2GB限制。

作為一種替代,你可以按照tf.placeholder()張量來定義Dataset,然後在初始化Iterator的時候供給Numpy數組給這個數據集。

# Load the training data into two NumPy arrays, for example using `np.load()`.with np.load("/var/data/training_data.npy") as data:n features = data["features"]n labels = data["labels"]# Assume that each row of `features` corresponds to the same row as `labels`.assert features.shape[0] == labels.shape[0]nnfeatures_placeholder = tf.placeholder(features.dtype, features.shape)nlabels_placeholder = tf.placeholder(labels.dtype, labels.shape)nndataset = tf.data.Dataset.from_tensor_slices((features_placeholder, labels_placeholder))# [Other transformations on `dataset`...]dataset = ...niterator = dataset.make_initializable_iterator()nnsess.run(iterator.initializer, feed_dict={features_placeholder: features,nlabels_placeholder: labels})n

consuming TFRecord data

Dataset的API支持各種文件格式,因而你可以處理那些不能裝進內存的大型數據集。例如,TFRecord文件格式是一種簡單的記錄式二進位格式,很多的TensorFlow應用將其格式用於訓練數據。tf.data.TFRecordDataset類可以讓你將一個或多個TFRecord文件的內容作為輸入管道的一部分進行流式處理。

# Creates a dataset that reads all of the examples from two files.filenames = ["/var/data/file1.tfrecord", "/var/data/file2.tfrecord"]ndataset = tf.data.TFRecordDataset(filenames)n

傳給TFRecordDataset初始化的filenames參數既可以是一個字元串,或者是一個字元串列表,或者是字元串的tf.Tensor。因此如果你有用於訓練和驗證兩個數據集,你可以使用tf.placeholder(tf.string)來當做filenames參數,然後用合適的filenames參數來初始化迭代器:

filenames = tf.placeholder(tf.string, shape=[None])ndataset = tf.data.TFRecordDataset(filenames)ndataset = dataset.map(...) # Parse the record into tensors.dataset = dataset.repeat() # Repeat the input indefinitely.dataset = dataset.batch(32)niterator = dataset.make_initializable_iterator()# You can feed the initializer with the appropriate filenames for the current# phase of execution, e.g. training vs. validation.# Initialize `iterator` with training data.training_filenames = ["/var/data/file1.tfrecord", "/var/data/file2.tfrecord"]nsess.run(iterator.initializer, feed_dict={filenames: training_filenames})# Initialize `iterator` with validation data.validation_filenames = ["/var/data/validation1.tfrecord", ...]nsess.run(iterator.initializer, feed_dict={filenames: validation_filenames})n

consuming text data

很多數據集分布在一個或多個文本文件中。

tf.data.TextLineDataset提供了從一個或多個文本文件中獲取每行數據的簡單方式。給定一個或多個文件名,TextLineDataset會為這些文件的每一行產生一個字元串-數值元素。與TFRecordDataset相同,TextLineDataset接收tf.Tensor類型的數據作為filenames參數,因此你可以通過傳一個tf.placeholder(tf.string)來參數化配置filenames這個參數。

filenames = ["/var/data/file1.txt", "/var/data/file2.txt"]ndataset = tf.data.TextLineDataset(filenames)n

默認情況下,TextLineDataset會遍歷文件的每一行,這樣可能是不必要的,比如文件如果開始有個標題行,或者包含評論。可以使用Dataset.skip()和Dataset.filter()轉換移除這些行。為了對每個文件分別應用這些轉換,我們使用Dataset.flat_map()為每個文件創建一個嵌套的Dataset。

filenames = ["/var/data/file1.txt", "/var/data/file2.txt"]nndataset = tf.data.Dataset.from_tensor_slices(filenames)# Use `Dataset.flat_map()` to transform each file as a separate nested dataset,# and then concatenate their contents sequentially into a single "flat" dataset.# * Skip the first line (header row).# * Filter out lines beginning with "#" (comments).dataset = dataset.flat_map( lambda filename: (n tf.data.TextLineDataset(filename)n .skip(1)n .filter(lambda line: tf.not_equal(tf.substr(line, 0, 1), "#"))))n

有關使用datasets解析CSV文件的完全例子,查看Regression Examples中的 imports85.py。

06

preprocessing data with dataset.map()

Dataset.map(f)轉換通過對輸入的數據集中每個元素應用給定的函數f,來產生一個新的數據集。這基於在函數式編程語言中經常應用於列表(和其他結構)的map()函數。函數f獲得在輸入中表示單個元素的tf.Tensor對象,然後返回其在新的數據集中代表的單個元素的tf.Tensor對象。這個實現使用了標準的TensorFlow的操作來將一個元素轉換成另一個。

這節包含了如何使用Dataset.map()的常用例子。

07

parsing tf.example protocol buffer messages

很多輸入管道從TFRecord格式的文件中提取tf.train.Example協議緩存消息(例如用tf.python_io.TFRecordWriter寫的)每個tf.train.Example記錄包含一個或多個「特徵」,一般輸入管道將這些特徵轉換成張量。

# Transforms a scalar string `example_proto` into a pair of a scalar string and# a scalar integer, representing an image and its label, respectively.def _parse_function(example_proto):n features = {"image": tf.FixedLenFeature((), tf.string, default_value=""), "label": tf.FixedLenFeature((), tf.int32, default_value=0)}n parsed_features = tf.parse_single_example(example_proto, features) return parsed_features["image"], parsed_features["label"]# Creates a dataset that reads all of the examples from two files, and extracts# the image and label features.filenames = ["/var/data/file1.tfrecord", "/var/data/file2.tfrecord"]ndataset = tf.data.TFRecordDataset(filenames)ndataset = dataset.map(_parse_function)n

08

Decoding image data and resizing it

當使用真實世界的圖片數據來訓練一個神經網路的時候,經常需要將不同大小的圖片轉換成一個統一的大小,這樣使它們能夠合批到一個固定的大小。

# Reads an image from a file, decodes it into a dense tensor, and resizes it# to a fixed shape.def _parse_function(filename, label):n image_string = tf.read_file(filename)n image_decoded = tf.image.decode_image(image_string)n image_resized = tf.image.resize_images(image_decoded, [28, 28]) return image_resized, label# A vector of filenames.filenames = tf.constant(["/var/data/image1.jpg", "/var/data/image2.jpg", ...])# `labels[i]` is the label for the image in `filenames[i].labels = tf.constant([0, 37, ...])nndataset = tf.data.Dataset.from_tensor_slices((filenames, labels))ndataset = dataset.map(_parse_function)n

09

Applyng arbitrary python logic with tf.py_func()

因為性能的原因,我們鼓勵你儘可能使用TensorFlow的操作來預處理你的數據。但是,當你解析你的輸入數據的時候,有時候需要調用額外的Python庫。為此,在Dataset.map()轉換中調用tf.py_func()。

import cv2# Use a custom OpenCV function to read the image, instead of the standard# TensorFlow `tf.read_file()` operation.def _read_py_function(filename, label):n image_decoded = cv2.imread(image_string, cv2.IMREAD_GRAYSCALE) return image_decoded, label# Use standard TensorFlow operations to resize the image to a fixed shape.def _resize_function(image_decoded, label):n image_decoded.set_shape([None, None, None])n image_resized = tf.image.resize_images(image_decoded, [28, 28]) return image_resized, labelnnfilenames = ["/var/data/image1.jpg", "/var/data/image2.jpg", ...]nlabels = [0, 37, 29, 1, ...]nndataset = tf.data.Dataset.from_tensor_slices((filenames, labels))ndataset = dataset.map( lambda filename, label: tuple(tf.py_func(n _read_py_function, [filename, label], [tf.uint8, label.dtype])))ndataset = dataset.map(_resize_function)n

10

Batch dataset elements

simple batching

最簡單的合批形式就是將一個數據集中的連續n個元素堆疊成一個元素。Dataset.batch()就是這麼坐的,它與tf.stack()操作有同樣的約束,被應用於每個元素的組件:就是說對於每個組件i,所有的元素必須是有確切形狀的張量。

inc_dataset = tf.data.Dataset.range(100)ndec_dataset = tf.data.Dataset.range(0, -100, -1)ndataset = tf.data.Dataset.zip((inc_dataset, dec_dataset))nbatched_dataset = dataset.batch(4)nniterator = batched_dataset.make_one_shot_iterator()nnext_element = iterator.get_next()print(sess.run(next_element)) # ==> ([0, 1, 2, 3], [ 0, -1, -2, -3])print(sess.run(next_element)) # ==> ([4, 5, 6, 7], [-4, -5, -6, -7])print(sess.run(next_element)) # ==> ([8, 9, 10, 11], [-8, -9, -10, -11])n

batching tensors with padding

上述辦法對於有一樣大小的張量有用。但是,很多模型(比如序列模型)處理的輸入數據會有不同的大小(比如不同長度的序列)。為了處理這種情況,Dataset.padded_batch()轉換能使你通過指定一個或多個維度來填充,從而合批不同形狀的張量。

dataset = tf.data.Dataset.range(100)ndataset = dataset.map(lambda x: tf.fill([tf.cast(x, tf.int32)], x))ndataset = dataset.padded_batch(4, padded_shapes=[None])nniterator = dataset.make_one_shot_iterator()nnext_element = iterator.get_next()nnprint(sess.run(next_element)) # ==> [[0, 0, 0], [1, 0, 0], [2, 2, 0], [3, 3, 3]]print(sess.run(next_element)) # ==> [[4, 4, 4, 4, 0, 0, 0],n # [5, 5, 5, 5, 5, 0, 0],n # [6, 6, 6, 6, 6, 6, 0],n # [7, 7, 7, 7, 7, 7, 7]]n

Dataset.padded_batch()轉換允許你對於每個組件的每個維度設置不同的填充,並且這些填充可以是變長度的(如上述例子中的用None指明)或者固定長度的。它也可以設置填充的數值,這個數值默認為0。

11

Trainin workflows

processing multiple epochs

Dataset的API主要提供兩種方式來處理同樣的數據多代使用的情況。

在一個數據集上迭代多代次的最簡單版本使用Dataset.repeat()轉換。例如創建一個數據集,重複輸入10代次:

filenames = ["/var/data/file1.tfrecord", "/var/data/file2.tfrecord"]ndataset = tf.data.TFRecordDataset(filenames)ndataset = dataset.map(...)ndataset = dataset.repeat(10)ndataset = dataset.batch(32)n

沒有參數的應用Dataset.repeat()將重複輸出無限次。Dataset.repeat()轉換連接其參數,不會在一代結束和下一代開始的時候發信號。

如果你想要在每代結束的時候接收信號,你可以編寫訓練循環來捕獲數據集末尾的tf.errors.OutOfRangeError。這時你可以為該代收集一些統計信息(比如驗證錯誤)。

filenames = ["/var/data/file1.tfrecord", "/var/data/file2.tfrecord"]ndataset = tf.data.TFRecordDataset(filenames)ndataset = dataset.map(...)ndataset = dataset.batch(32)niterator = dataset.make_initializable_iterator()nnext_element = iterator.get_next()# Compute for 100 epochs.for _ in range(100):n sess.run(iterator.initializer) while True: try:n sess.run(next_element) except tf.errors.OutOfRangeError: breaknn # [Perform end-of-epoch calculations here.]n

Randomly shuffling input data

Dataset.shuffle()轉換使用與tf.RandomShuffleQueue相似的演算法來隨機打亂輸入的數據集:它維護了一個固定大小的緩存,並等概率的隨機的從中選擇下一個元素。

filenames = ["/var/data/file1.tfrecord", "/var/data/file2.tfrecord"]ndataset = tf.data.TFRecordDataset(filenames)ndataset = dataset.map(...)ndataset = dataset.shuffle(buffer_size=10000)ndataset = dataset.batch(32)ndataset = dataset.repeat()n

12

Using high-level APIs

tf.train.MonitoredTrainingSession的API簡化了在分散式設置上運行TensorFlow的很多方面。MonitoredTraingSession拋出tf.errors.OutOfRangeError來通知訓練的完成,因此配合它使用Dataset的API,我們推薦使用Dataset.make_one_shot_iterator()。例如

filenames = ["/var/data/file1.tfrecord", "/var/data/file2.tfrecord"]ndataset = tf.data.TFRecordDataset(filenames)ndataset = dataset.map(...)ndataset = dataset.shuffle(buffer_size=10000)ndataset = dataset.batch(32)ndataset = dataset.repeat(num_epochs)niterator = dataset.make_one_shot_iterator()nnnext_example, next_label = iterator.get_next()nloss = model_function(next_example, next_label)nntraining_op = tf.train.AdagradOptimizer(...).minimize(loss)with tf.train.MonitoredTrainingSession(...) as sess: while not sess.should_stop():n sess.run(training_op)n

為了在tf.estimator.Estimator的input_fn中使用Dataset,我們也推薦使用Dataset.make_one_shot_iterator()。例如:

def dataset_input_fn():n filenames = ["/var/data/file1.tfrecord", "/var/data/file2.tfrecord"]n dataset = tf.data.TFRecordDataset(filenames) # Use `tf.parse_single_example()` to extract data from a `tf.Example`n # protocol buffer, and perform any additional per-record preprocessing.n def parser(record):n keys_to_features = { "image_data": tf.FixedLenFeature((), tf.string, default_value=""), "date_time": tf.FixedLenFeature((), tf.int64, default_value=""), "label": tf.FixedLenFeature((), tf.int64,n default_value=tf.zeros([], dtype=tf.int64)),n }n parsed = tf.parse_single_example(record, keys_to_features) # Perform additional preprocessing on the parsed data.n image = tf.decode_jpeg(parsed["image_data"])n image = tf.reshape(image, [299, 299, 1])n label = tf.cast(parsed["label"], tf.int32) return {"image_data": image, "date_time": parsed["date_time"]}, label # Use `Dataset.map()` to build a pair of a feature dictionary and a labeln # tensor for each example.n dataset = dataset.map(parser)n dataset = dataset.shuffle(buffer_size=10000)n dataset = dataset.batch(32)n dataset = dataset.repeat(num_epochs)n iterator = dataset.make_one_shot_iterator() # `features` is a dictionary in which each value is a batch of values forn # that feature; `labels` is a batch of labels.n features, labels = iterator.get_next() return features, labelsn

推薦閱讀:

譯文 | 與TensorFlow的第一次接觸 第六章:並發
TensorFlow與中文手寫漢字識別
怎麼理解tensorflow中tf.train.shuffle_batch()函數?
作為深度學習最強框架的TensorFlow如何進行時序預測!

TAG:TensorFlow |