tensorflow數據的讀取
寫在前面的話,雖然目前tensorflow很流行,但是網上對於tensorflow數據讀取的文章比較少,官方給的比較全,但是大佬寫得比較飄,思維跳躍性比較強。網上各位大佬給出的參差不齊,所以小白整理整理了這些東西,希望能對大家有用。
1. 數據讀取方式
根據tensorflow的官方教程來看,tensorflow主要支持4中數據讀取的方式。
- Preloaded data: 預載入數據
- Feeding: 先產生一個個batch數據,然後在運行的時候依次餵給計算圖。
- Reading from file: 從文件中讀取,tensorflow主要支持兩種方法從文件中讀取數據餵給計算圖:一個是CSV,還有一個是TFRecords
- 多管線輸入
下面我們依次介紹這幾類方法。
2. 預載入數據
這個是最直觀的方法了,初次寫程序,或者寫小型程序的時候我們往往都是這樣操作的。直接把我們需要的數據在代碼中定義出來。下面是一個簡單的例子。
import tensorflow as tf# 構建一個Graphx1 = tf.constant([1, 2, 3])x2 = tf.constant([4, 5, 6])y = tf.add(x1, x2)# 喂數據 -> 啟動session,計算圖 with tf.Session() as sess: print sess.run(y)
這裡的數據X1,X2都是以常量寫出來的,這種方式就是預載入數據的方式。
3. Feeding
喂數據的方式也是tensorflow初學者比較常見的一種方法,這種方法就是在預載入數據的基礎上做了一個靈活性的改動,上面的例子(計算圖)中只需要一次數據的讀取,但是在深度學習中,我們往往都是需要一個batch一個batch的喂很多次數據來迭代計算出權重。這個時候怎麼做呢?
很直觀的方法,反正圖是一樣,數據也都長得一樣,只是值不同而已,搞個變數(不要像上面constant),搞個循環不就可以了么?
所以tensorflow提出一個placeholder(佔位符)的概念,在構建計算圖的時候,告訴編譯器,這個節點是一個變數,需要賦予不同的值來計算的,能提前定義大小就行。
3.1 簡單的例子
import tensorflow as tf# 構建Graphx1 = tf.placeholder(tf.int16)x2 = tf.placeholder(tf.int16)y = tf.add(x1, x2)# X_1,X_2是變數,可以賦予不同的值X_1 = [1, 2, 3]X_2 = [4, 5, 6]# 喂數據 -> 啟動session,計算圖 with tf.Session() as sess: print sess.run(y, feed_dict={x1: X_1, x2: X_2})
3.2 CNN的例子
例子來源於:https://github.com/hunkim/DeepLearningZeroToAll/blob/master/lab-11-3-mnist_cnn_class.py
# Lab 11 MNIST and Deep learning CNNimport tensorflow as tf# import matplotlib.pyplot as pltfrom tensorflow.examples.tutorials.mnist import input_datatf.set_random_seed(777) # reproducibilitymnist = input_data.read_data_sets("MNIST_data/", one_hot=True)# Check out https://www.tensorflow.org/get_started/mnist/beginners for# more information about the mnist dataset# hyper parameterslearning_rate = 0.001training_epochs = 15batch_size = 100class Model: def __init__(self, sess, name): self.sess = sess self.name = name self._build_net() def _build_net(self): with tf.variable_scope(self.name): # dropout (keep_prob) rate 0.7~0.5 on training, but should be 1 # for testing self.keep_prob = tf.placeholder(tf.float32) # input place holders self.X = tf.placeholder(tf.float32, [None, 784]) # img 28x28x1 (black/white) X_img = tf.reshape(self.X, [-1, 28, 28, 1]) self.Y = tf.placeholder(tf.float32, [None, 10]) # L1 ImgIn shape=(?, 28, 28, 1) W1 = tf.Variable(tf.random_normal([3, 3, 1, 32], stddev=0.01)) # Conv -> (?, 28, 28, 32) # Pool -> (?, 14, 14, 32) L1 = tf.nn.conv2d(X_img, W1, strides=[1, 1, 1, 1], padding=SAME) L1 = tf.nn.relu(L1) L1 = tf.nn.max_pool(L1, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding=SAME) L1 = tf.nn.dropout(L1, keep_prob=self.keep_prob) # L2 ImgIn shape=(?, 14, 14, 32) W2 = tf.Variable(tf.random_normal([3, 3, 32, 64], stddev=0.01)) # Conv ->(?, 14, 14, 64) # Pool ->(?, 7, 7, 64) L2 = tf.nn.conv2d(L1, W2, strides=[1, 1, 1, 1], padding=SAME) L2 = tf.nn.relu(L2) L2 = tf.nn.max_pool(L2, ksize=[1, 2, 2, 1], strides=[1, 2, 2, 1], padding=SAME) L2 = tf.nn.dropout(L2, keep_prob=self.keep_prob) # L3 ImgIn shape=(?, 7, 7, 64) W3 = tf.Variable(tf.random_normal([3, 3, 64, 128], stddev=0.01)) # Conv ->(?, 7, 7, 128) # Pool ->(?, 4, 4, 128) # Reshape ->(?, 4 * 4 * 128) # Flatten them for FC L3 = tf.nn.conv2d(L2, W3, strides=[1, 1, 1, 1], padding=SAME) L3 = tf.nn.relu(L3) L3 = tf.nn.max_pool(L3, ksize=[1, 2, 2, 1], strides=[ 1, 2, 2, 1], padding=SAME) L3 = tf.nn.dropout(L3, keep_prob=self.keep_prob) L3_flat = tf.reshape(L3, [-1, 128 * 4 * 4]) # L4 FC 4x4x128 inputs -> 625 outputs W4 = tf.get_variable("W4", shape=[128 * 4 * 4, 625], initializer=tf.contrib.layers.xavier_initializer()) b4 = tf.Variable(tf.random_normal([625])) L4 = tf.nn.relu(tf.matmul(L3_flat, W4) + b4) L4 = tf.nn.dropout(L4, keep_prob=self.keep_prob) # L5 Final FC 625 inputs -> 10 outputs W5 = tf.get_variable("W5", shape=[625, 10], initializer=tf.contrib.layers.xavier_initializer()) b5 = tf.Variable(tf.random_normal([10])) self.logits = tf.matmul(L4, W5) + b5 # define cost/loss & optimizer self.cost = tf.reduce_mean(tf.nn.softmax_cross_entropy_with_logits( logits=self.logits, labels=self.Y)) self.optimizer = tf.train.AdamOptimizer( learning_rate=learning_rate).minimize(self.cost) correct_prediction = tf.equal( tf.argmax(self.logits, 1), tf.argmax(self.Y, 1)) self.accuracy = tf.reduce_mean(tf.cast(correct_prediction, tf.float32)) def predict(self, x_test, keep_prop=1.0): return self.sess.run(self.logits, feed_dict={self.X: x_test, self.keep_prob: keep_prop}) def get_accuracy(self, x_test, y_test, keep_prop=1.0): return self.sess.run(self.accuracy, feed_dict={self.X: x_test, self.Y: y_test, self.keep_prob: keep_prop}) def train(self, x_data, y_data, keep_prop=0.7): return self.sess.run([self.cost, self.optimizer], feed_dict={ self.X: x_data, self.Y: y_data, self.keep_prob: keep_prop})# initializesess = tf.Session()m1 = Model(sess, "m1")sess.run(tf.global_variables_initializer())print(Learning Started!)# train my modelfor epoch in range(training_epochs): avg_cost = 0 total_batch = int(mnist.train.num_examples / batch_size) for i in range(total_batch): ########## 啟動session, 每次得到一個batch喂到網路 ########## batch_xs, batch_ys = mnist.train.next_batch(batch_size) c, _ = m1.train(batch_xs, batch_ys) avg_cost += c / total_batch print(Epoch:, %04d % (epoch + 1), cost =, {:.9f}.format(avg_cost))print(Learning Finished!)# Test model and check accuracyprint(Accuracy:, m1.get_accuracy(mnist.test.images, mnist.test.labels))
4. 從文件中讀取
上面的兩種方式都只是適合小的數據,但是遇到圖像集,比如PASCAL什麼的動不動10G+, 遇上視頻處理很可能500G+,或者上T。這個時候就完全不能用上面的兩種方式了。
為此tensorflow定義了一種從文件中讀取的方法,而數據保存的文件格式現在主要是支持兩種,第一種是CSV格式,另外一種就是TFRecords。下面我們將介紹介紹TFRecords。
4.1 工作機制
在學著操作之前,我個人還是覺得有必要看一下tensorflow所定義的這一套從文件中讀取數據的方法。
首先,我們先創建數據流圖,這個數據流圖由一些流水線的階段組成,階段間用隊列連接在一起。第一階段將生成文件名,我們讀取這些文件名並且把他們排到文件名隊列中。第二階段從文件中讀取數據(使用Reader),產生樣本,而且把樣本放在一個樣本隊列中。根據你的設置,實際上也可以拷貝第二階段的樣本,使得他們相互獨立,這樣就可以從多個文件中並行讀取。在第二階段的最後是一個排隊操作,就是入隊到隊列中去,在下一階段出隊。因為我們是要開始運行這些入隊操作的線程,所以我們的訓練循環會使得樣本隊列中的樣本不斷地出隊。
4.2 寫入TFRecords
tfrecord數據文件是一種將圖像數據和標籤統一存儲的二進位文件,能更好的利用內存,在tensorflow中快速的複製,移動,讀取,存儲等。那麼如何將我們的數據寫入TFRecords文件呢?
寫入TFRecords主要有三個步驟:
- 定義Example,數據格式定義。類似於caffe在caffe.prototxt中定義,然後將數據序列化至lmdb。tensorflow也是如此,tf.train.Example_protocol_buffer中進行聲明。
- 然後將數據序列化為string。example.SerializeToString
- 寫介面。tf.python_io.TFRecordWriter, 將序列化後的string寫入到TFRecords中。
4.2.1 tf.train.Example
這個函數有點類似於我們在數據結構中定義的一個結構體,我們定義我們想要的一條Example。比如最常見的MNIST數據集,一條Example至少需要原圖像和label。所以我們可以有如下定義。
example = tf.train.Example(features = tf.train.Features(feature={ length: _int64_feature(feature_length), label: _int64_feature(int(labels[index])), image_raw: _bytes_feature(image_raw)}))
4.2.2 example.SerializeToString
然後,我們將這條example序列化為string,這裡直接用tf.train.Example實例的成員函數。
example.SerializeToString()
4.2.3 writer
最後一步,將序列化的string寫入到TFRecords中,這一步與視頻寫入類似。首先需要初始化一個writer介面,然後調用成員函數write就可以了。
# Step1: 初始化writer介面 writer = tf.python_io.TFRecordWriter(filename) # Step2: 定義exampleexample = tf.train.Example(features = tf.train.Features(feature={ length: _int64_feature(feature_length), label: _int64_feature(int(labels[index])), image_raw: _bytes_feature(image_raw)})) # Step3:一般序列化後直接寫入writer.write(example.SerializeToString())
到此,寫入TFRecords就結束了。還是比較直觀明了的。
4.3 文件隊列
根據得到的TFRecords和一些網路訓練的設置參數,比如num_epochs等等,可以預先生成一個文件序列。
filename_queue = tf.train.string_input_producer( [./data/train.tfrecords], num_epochs=10)
4.4 讀取TFRecords文件
生成文件隊列後,可以生成相應的數據隊列。
def read_data(filename_queue): reader = tf.TFRecordReader() _, example = reader.read(filename_queue) # parse from records file and get a example of records. features = tf.parse_single_example( example, features={ image_raw: tf.FixedLenFeature([], tf.string), # tf.FixedLenFeature返回字典 label: tf.FixedLenFeature([], tf.int64) } ) images = tf.decode_raw(features[image_raw], tf.uint8) # 將byte轉換為各種類型 images = tf.cast(images, tf.float32) * (1./255.) labels = features[label] return images, labels
4.5 batch生成
上述讀取TFRecords返回後得到的Image和labels我想是一個句柄,並不是讀入內存。對於網路一般都是以batch為單位訓練,所以這一步是根據上述兩個句柄生成一系列batch。
這個一般叫做 : 批生成器(batcher)
tf.train.shuffle_batch()Args: - tensorflow: 向量隊列 - batch_size: - capacity: 整型,生成的batch的容量 - num_threads: 線性個數
4.6 訓練
img, label = read_and_decode("train.tfrecords")#使用shuffle_batch可以隨機打亂輸入img_batch, label_batch = tf.train.shuffle_batch([img, label], batch_size=30, capacity=2000, min_after_dequeue=1000)init = tf.initialize_all_variables()with tf.Session() as sess: sess.run(init) threads = tf.train.start_queue_runners(sess=sess) for i in range(3): val, l= sess.run([img_batch, label_batch]) #我們也可以根據需要對val, l進行處理 #l = to_categorical(l, 12) print(val.shape, l)
參考文獻
[1]TensorFlow高效讀取數據的方法
[2] http://honggang.io/2016/08/19/tensorflow-data-reading/[3] https://saicoco.github.io/tf3/<個人網頁blog已經上線,一大波乾貨即將來襲:https://faiculty.com/>
版權聲明:公開學習資源,只供線上學習,不可轉載,如需轉載請聯繫本人 .QQ交流群:451429116
推薦閱讀:
※機器學習導論——Day2、3
※激活函數的實現與梯度檢查<五>
※有關NLP的比賽
※【翻譯】Brian2高級指導_狀態更新
※Learning Explanatory Rules from Noisy Data 閱讀筆記2
TAG:機器學習 |