1. 程式人生 > >TensorFlow載入資料的方式

TensorFlow載入資料的方式

tensorflow作為符號程式設計框架,需要先構建資料流圖,再讀取資料,然後再進行訓練。tensorflow提供了以下三種方式來載入資料:

  • 預載入資料(preloaded data):在tensorflow圖中定義常量或變數來儲存所有資料
  • 填充資料(feeding):Python產生資料,再把資料填充到後端
  • 從檔案中讀取資料(reading from file):通過佇列管理器從檔案中讀取資料

下面將詳細介紹這三種載入資料的方法以及它們之間的優缺點

一、預載入資料

下面是一個使用TensorFlow來預載入資料進行手寫數字的識別

1、以constant的方式進行預載入

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
from tensorflow.examples.tutorials.mnist import mnist
import time


class Config(object):
    #設定訓練集存放的路徑
    train_dir = "data/MNIST_data"
    #是否是fake_data進行單元測試
    fake_data = False
    #設定batch_size的大小
    batch_size = 100
    #設定學習率的大小
    learning_rate = 0.01
    #設定迭代的輪數
    num_epochs = 2
    #第一層隱藏層的層數
    hidden1 = 128
    #第二層隱藏層的層數
    hidden2 = 128
    #設定每多少次迭代輸出一次結果
    print_step = 100
    #多少次儲存一次模型
    save_checkpoint_step = 1000
    #設定模型的儲存路徑
    save_model_path = "model/"
    #設定tensorboard的儲存目錄
    save_tensorboard_path = "log/"

#神經網路的配置設定
config = Config()
'''
訓練模型
'''
def run_training():
    #獲取資料
    data_set = input_data.read_data_sets(config.train_dir)
    #設定預設的圖
    with tf.Graph().as_default():
        with tf.name_scope("input"):
            #使用cpu載入資料
            input_images = tf.constant(data_set.train.images)
            input_labels = tf.constant(data_set.train.labels)
        image,label = tf.train.slice_input_producer([input_images,input_labels],
                                                    num_epochs=config.num_epochs)
        #轉換標籤的型別
        label = tf.cast(label,tf.int32)
        #獲取一個批量資料
        images,labels = tf.train.batch([image,label],batch_size=config.batch_size)
        #構建一個計算圖建立預測模型
        logits = mnist.inference(images,config.hidden1,config.hidden2)
        #計算損失值
        loss = mnist.loss(logits,labels)
        #開始訓練,使用梯度下降演算法
        train_op = mnist.training(loss,config.learning_rate)
        #計算預測的準確率
        eval_correct = mnist.evaluation(logits,labels)
        #構建tensorboard
        summary_op = tf.summary.merge_all()
        #儲存模型
        saver = tf.train.Saver()
        init_op = tf.group(tf.global_variables_initializer(),
                           tf.local_variables_initializer())
        #建立會話
        sess = tf.Session()
        #初始化變數
        sess.run(init_op)
        #儲存計算圖
        summary_writer = tf.summary.FileWriter(config.save_tensorboard_path,sess.graph)

        #開啟入隊執行緒
        coord = tf.train.Coordinator()
        threads = tf.train.start_queue_runners(sess=sess,coord=coord)

        #開始訓練
        try:
            step = 0
            #檢查是否關閉執行緒
            while not coord.should_stop():
                #記錄開始時間
                start_time = time.time()
                #獲取該次迭代的損失值
                _,loss_value = sess.run([train_op,loss])
                #計算本次迭代所耗費時間
                duration = time.time() - start_time
                if step % config.print_step == 0:
                    print("step:%d,loss:%.3f,consum time:%.3f sec"%(step,loss_value,duration))
                    summary_str = sess.run(summary_op)
                    summary_writer.add_summary(summary_str,step)
                #儲存模型
                if(step+1)%config.save_checkpoint_step == 0:
                    saver.save(sess,config.save_model_path,global_step=step)
                step += 1
        except tf.errors.OutOfRangeError:
            saver.save(sess,config.save_model_path,global_step=step)
        finally:
            #停止執行緒
            coord.request_stop()
        #等待執行緒結束
        coord.join(threads)
        sess.close()

if __name__ == "__main__":
    run_training()

2、以variable的方式載入資料

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import input_data
from tensorflow.examples.tutorials.mnist import mnist
import time

'''
網路引數設定
'''
class Config(object):
    #設定訓練集存放的路徑
    train_dir = "data/MNIST_data"
    #是否是fake_data進行單元測試
    fake_data = False
    #設定batch_size的大小
    batch_size = 100
    #設定學習率的大小
    learning_rate = 0.01
    #設定迭代的輪數
    num_epochs = 2
    #第一層隱藏層的層數
    hidden1 = 128
    #第二層隱藏層的層數
    hidden2 = 128
    #設定每多少次迭代輸出一次結果
    print_step = 100
    #多少次儲存一次模型
    save_checkpoint_step = 1000
    #設定模型的儲存路徑
    save_model_path = "model/"
    #設定tensorboard的儲存目錄
    save_tensorboard_path = "log/"

#神經網路的配置設定
config = Config()


def run_training():
    #載入資料集
    data_sets = input_data.read_data_sets(config.train_dir,config.fake_data)
    #設定預設計算圖
    with tf.Graph().as_default():
        with tf.name_scope("input"):
            images_initializer = tf.placeholder(dtype=data_sets.train.images.dtype,
                                                shape=data_sets.train.images.shape)
            labels_initializer = tf.placeholder(dtype=data_sets.train.labels.dtype,
                                                shape=data_sets.train.labels.shape)
            input_images = tf.Variable(images_initializer,trainable=False,collections=[])
            input_labels = tf.Variable(labels_initializer,trainable=False,collections=[])
            image,label = tf.train.slice_input_producer([input_images,input_labels],num_epochs=config.num_epochs)
            label = tf.cast(label,tf.int32)
            images,labels = tf.train.batch([image,label],batch_size=config.batch_size)
        #構建訓練網路
        logits = mnist.inference(images,config.hidden1,config.hidden2)
        #計算損失值
        loss = mnist.loss(logits,labels)
        #使用優化演算法最小化損失函式
        train_op = mnist.training(loss,config.learning_rate)
        #計算準確率
        eval_correct = mnist.evaluation(logits,labels)
        #儲存tensorboard
        summary_op = tf.summary.merge_all()
        #儲存模型
        saver = tf.train.Saver()
        init_op = tf.group(tf.global_variables_initializer(),
                           tf.local_variables_initializer())
        #建立會話
        sess = tf.Session()
        #初始化變數
        sess.run(init_op)
        sess.run(input_images.initializer,feed_dict={images_initializer:data_sets.train.images})
        sess.run(input_labels.initializer,feed_dict={labels_initializer:data_sets.train.labels})
        #儲存tensorboard
        summary_writer = tf.summary.FileWriter(config.save_tensorboard_path,sess.graph)
        #啟動入隊執行緒
        coord = tf.train.Coordinator()
        threads = tf.train.start_queue_runners(sess=sess,coord=coord)
        #開始訓練
        try:
            step = 0
            while not coord.should_stop():
                start_time = time.time()
                _,loss_value = sess.run([train_op,loss])
                #計算時間間隔
                duration = time.time() - start_time
                if step % config.print_step == 0:
                    print("step:%s,loss:%.3f,consume time:%.3f sec"%(step,loss_value,duration))
                    #寫入tensorboard中
                    summary_str = sess.run(summary_op)
                    summary_writer.add_summary(summary_str,step)

                #儲存模型
                if (step+1)%config.save_checkpoint_step == 0:
                    saver.save(sess,config.save_model_path,global_step=step)
                step += 1
        except tf.errors.OutOfRangeError:
            saver.save(sess,config.train_dir,global_step=step)
        finally:
            #通知執行緒退出
            coord.request_stop()
        #等待執行緒關閉
        coord.join(threads)
        sess.close()

if __name__ == "__main__":
    run_training()

通過預載入的方式載入資料的缺點在於,將資料直接嵌入到資料流圖中,當訓練資料較大時,很消耗記憶體

二、填充資料

填充資料是使用sess.run()中的feed_dict引數,將Python產生的資料填充給後端。

import tensorflow as tf

if __name__ == "__main__":
    #定義輸入資料
    a = tf.placeholder(tf.float32)
    b = tf.placeholder(tf.float32)
    #定義操作
    c = tf.add(a,b)
    #python產生資料
    x1 = [1.0,2.0,3.0]
    x2 = [5.0,6.0,7.0]
    #建立會話
    with tf.Session() as sess:
        print(sess.run(c,feed_dict={a:x1,b:x2}))

填充資料也存在資料量大、消耗記憶體等缺點,並資料型別轉換等中間環節也增加了不少的記憶體開銷。這時候最好採用最後一種載入資料的方式,先在圖中定義好檔案讀取的方法,通過TensorFlow從檔案中讀取資料,再解碼成為訓練資料。

三、從檔案讀取資料

從檔案中讀取資料,主要分為兩個步驟:

1、將樣本寫入到TFRecords二進位制檔案中

import tensorflow as tf
from tensorflow.contrib.learn.python.learn.datasets import mnist
import os

#設定TFRecords檔案儲存路徑目錄
TFRecords_dir = "tfRecords/"
#設定data的存放目錄
data_dir = "data/MNIST_data"

def _int64_feature(value):
    return tf.train.Feature(int64_list=tf.train.Int64List(value=[value]))

def _bytes_feature(value):
    return tf.train.Feature(bytes_list=tf.train.BytesList(value=[value]))

'''
將資料轉換為TFRecords檔案
'''
def convert_to(data_sets,name):
    images = data_sets.images
    labels = data_sets.labels
    num_examples = data_sets.num_examples
    if images.shape[0] != num_examples:
        return ValueError("images size %d does not match label size %d."
                          %(images.shape[0],num_examples))
    #獲取圖片的高
    rows = images.shape[1]
    #獲取圖片的寬
    cols = images.shape[2]
    #獲取圖片的深度
    depth = images.shape[3]
    #獲取TFRecords檔案的儲存路徑
    save_TFRecords_path = os.path.join(TFRecords_dir,name+".tfrecords")
    #將資料儲存成tfrecords檔案
    with tf.python_io.TFRecordWriter(save_TFRecords_path) as writer:
        for index in range(num_examples):
            #將圖片資料轉換為字串
            image_raw = images[index].tostring()
            #將資料寫入協議緩衝區中,將圖片的寬、高、通道數、標籤編碼成為int64
            #將圖片資料編碼成為二進位制
            example = tf.train.Example(
                features=tf.train.Features(
                    feature={
                    "height":_int64_feature(rows),
                    "width":_int64_feature(cols),
                    "depth":_int64_feature(depth),
                    "label":_int64_feature(int(labels[index])),
                    "image_raw":_bytes_feature(image_raw)
                }))
            #將協議緩衝區資料轉為字串寫入檔案
            writer.write(example.SerializeToString())

if __name__ == "__main__":
    #獲取資料
    data_sets = mnist.read_data_sets(data_dir,dtype=tf.uint8,reshape=False,validation_size=5000)
    #將訓練集轉換成為tfrecords檔案
    convert_to(data_sets.train,"train")
    #將驗證集儲存為tfrecords檔案
    convert_to(data_sets.validation,"validation")
    #將測試集儲存為tfrecords檔案
    convert_to(data_sets.test,"test")

2、再從佇列中讀取解碼成為可以進行訓練的資料

import tensorflow as tf
from tensorflow.examples.tutorials.mnist import mnist
import os,time

#設定TFRecords檔案的存放路徑
train_tfrecords_path = "tfRecords/train.tfrecords"
test_tfrecords_path = "tfRecords/test.tfrecords"
validation_tfrecords_path = "tfRecords/validation.tfrecords"

'''
讀取TFRecords檔案並解碼
'''
def decode(serialized_example):
  features = tf.parse_single_example(
      serialized_example,
      features={
          'image_raw': tf.FixedLenFeature([], tf.string),
          'label': tf.FixedLenFeature([], tf.int64),
      })
  image = tf.decode_raw(features['image_raw'], tf.uint8)
  image.set_shape((mnist.IMAGE_PIXELS))
  label = tf.cast(features['label'], tf.int32)
  return image, label

def augment(image, label):
    return image, label

'''
歸一化圖片的畫素
'''
def normalize(image, label):
    #將圖片畫素值從[0,255]轉換成為[-0.5,0.5]
    image = tf.cast(image, tf.float32) * (1. / 255) - 0.5
    return image, label

'''
讀取資料
'''
def inputs(tfrecords_path,batch_size,num_epochs):
    if not num_epochs:
        num_epochs = None
    with tf.name_scope("input"):
        #讀取tfrecords檔案
        dataset = tf.data.TFRecordDataset(tfrecords_path)
        #tfrecords資料解碼
        dataset = dataset.map(decode)
        dataset = dataset.map(augment)
        dataset = dataset.map(normalize)
        #打亂資料的順序
        dataset = dataset.shuffle(1000 + 3 * batch_size)
        dataset = dataset.repeat(num_epochs)
        dataset = dataset.batch(batch_size)
        iterator = dataset.make_one_shot_iterator()
    return iterator.get_next()

'''
網路引數設定
'''
class Config(object):
    #設定訓練集存放的路徑
    train_dir = "data/MNIST_data"
    #是否是fake_data進行單元測試
    fake_data = False
    #設定batch_size的大小
    batch_size = 100
    #設定學習率的大小
    learning_rate = 0.01
    #設定迭代的輪數
    num_epochs = 2
    #第一層隱藏層的層數
    hidden1 = 128
    #第二層隱藏層的層數
    hidden2 = 128
    #設定每多少次迭代輸出一次結果
    print_step = 100
    #多少次儲存一次模型
    save_checkpoint_step = 1000
    #設定模型的儲存路徑
    save_model_path = "model/"
    #設定tensorboard的儲存目錄
    save_tensorboard_path = "log/"

#神經網路的配置設定
config = Config()

def run_training():
    with tf.Graph().as_default():
        image_batch,label_batch = inputs(train_tfrecords_path,batch_size=config.batch_size,num_epochs=config.num_epochs)
        logits = mnist.inference(image_batch,config.hidden1,config.hidden2)
        loss = mnist.loss(logits,label_batch)
        train_op = mnist.training(loss,config.learning_rate)
        init_op = tf.group(tf.global_variables_initializer(),
                           tf.local_variables_initializer())
        with tf.Session() as sess:
            sess.run(init_op)
            try:
                step = 0
                while True:
                    start_time = time.time()
                    _,loss_value = sess.run([train_op,loss])
                    duration_time = time.time() - start_time
                    if step % config.print_step == 0:
                        print("step:%s,loss:%.3f,consume time:%.3f sec"%(step,loss_value,duration_time))
                    step += 1
            except tf.errors.OutOfRangeError:
                print("Done training for %d epchos,%d steps."%(config.num_epochs,step))

if __name__ == "__main__":
    run_training()