当前位置:   article > 正文

tensorflow 数据读取总结---(直接供给数据(feeding) 从文件中以管线形式读取数据 预加载数据)

tensorflow 数据读取总结---(直接供给数据(feeding) 从文件中以管线形式读取数据 预加载数据)

主要参考tensorflow官方中文社区,链接:

http://www.tensorfly.cn/tfdoc/how_tos/reading_data.html#AUTOGENERATED-file-formats,

这个社区中中给的一些示例链接有的不对,可以到这个链接里面找:

https://tensorflow.googlesource.com/tensorflow/+/master/tensorflow/examples/

官方链接:https://www.tensorflow.org/programmers_guide/datasets,这个主要用来进行管道读取的介绍,打不开请翻墙

tensorflow 数据读取三种:

  • 直接供给数据(feeding)
  • 从文件中以管线形式读取数据
  • 预加载数据

一、直接供给数据

这种方式比较简单,直接定义输入的placeholder,然后每次run的时候输入feed_dict参数就行

一般通过在网络中定义:

  1. x=tf.placeholder(tf.float32,shape=[None,_IMAGE_SIZE*_IMAGE_SIZE*_IMAGE_CHANNELS],name='images')
  2. y=tf.placeholder(tf.float32,shape=[None,_NUM_CLASSES],name='Output')

然后run的时候

 _loss,batch_acc=sess.run([loss,accuracy],feed_dict={x:batch_xs,y:batch_ys})

这里可以参考我的另一篇文章:Alexnet网络模型在cifar-10数据集上的实现(基于tensorflow-gpu)  的数据供给方式

二、从文件中以管线形式读取数据

一般包括:

文件名列表
可配置的 文件名乱序(shuffling)
可配置的 最大训练迭代数(epoch limit)
文件名队列
针对输入文件格式的阅读器
纪录解析器
可配置的预处理器
样本队列

以上操作我们会以不同格式文件进行举例说明

1.csv文件

(1)先说一下CSV文件格式

csv文件为按行读取数据,每一行的数据以空格或者逗号分开,比如我自己定义了几个个.csv文件,文件内容如下:

1,2,3,4,5
1,2,3,4,5
6,7,8,9,0
1,2,3,4,5
1,2,3,4,5
6,7,8,9,0
1,2,3,4,5
1,2,3,4,5
6,7,8,9,0
1,2,3,4,5
1,2,3,4,5
6,7,8,9,0
1,2,3,4,5
1,2,3,4,5
6,7,8,9,0
1,2,3,4,5
1,2,3,4,5

测试代码:

  1. #coding=utf-8
  2. import tensorflow as tf
  3. #read from csv
  4. #这里的[fil1.csv,file0]就是文件名列表,
  5. filename_queue=tf.train.string_input_producer(["path/file0.csv","path/file1.csv"])
  6. reader=tf.TextLineReader()
  7. key,value=reader.read(filename_queue)
  8. record_default=[[1],[1],[1],[1],[1]]
  9. col1,col2,col3,col4,col5=tf.decode_csv(value,record_defaults=record_default)
  10. features = tf.stack([col1,col2,col3,col4],axis=0) #串接成一维张量,如果col1不是标量,则可以用tf.concat()
  11. with tf.Session() as sess:
  12. coord=tf.train.Coordinator() #This class implements a simple mechanism to coordinate the termination of a set of threads.
  13. threads=tf.train.start_queue_runners(coord=coord)
  14. for i in range(30):
  15. example,label=sess.run([features,col5])
  16. print(example,label)
  17. coord.request_stop()
  18. coord.join(threads) #Wait for threads to terminate.

这里有必要对tf.train.string_input_producer函数进行说明

string_input_producer(    string_tensor,    num_epochs=None,    shuffle=True,    seed=None,    capacity=32,    shared_name=None,    name=None,    cancel_op=None)

这个函数里的参数分别是文件名列表,最大迭代数,是否进行乱序,seed:确定每次乱序的结果是否一样,后面的都可以根据需要添加

最后返回的是文件名队列


2.固定长度记录(二进制文件)

从二进制文件中读取固定长度纪录, 可以使用tf.FixedLengthRecordReader的tf.decode_raw操作。decode_raw操作可以讲一个字符串转换为一个uint8的张量。

举例来说,the CIFAR-10 dataset的文件格式定义是:每条记录的长度都是固定的,一个字节的标签,后面是3072(32*32*3)字节的图像数据。也就是说我们每次固定获取3073个字节的数据。uint8的张量的标准操作就可以从中获取图像片并且根据需要进行重组。

示例代码:

  1. #coding=utf-8
  2. # 2018 04 07
  3. #从二进制文件中读取数据
  4. import tensorflow as tf
  5. import os
  6. import matplotlib.pyplot as pyplot
  7. import PIL.Image as Image
  8. def read_cifar10(filename_queue):
  9. record_bytes=1+32*32*3
  10. reader=tf.FixedLengthRecordReader(record_bytes=record_bytes)
  11. key,value=reader.read(filename_queue)
  12. record_bytes=tf.decode_raw(value,tf.uint8)
  13. label=tf.cast(tf.slice(record_bytes,[0],[1]),tf.uint8)
  14. depth_major = tf.reshape(tf.slice(record_bytes, [1], [32*32*3]),[3, 32, 32])
  15. unit8image=tf.transpose(depth_major,[1,2,0])
  16. return label,unit8image
  17. def inputs(eval_data,data_path,batch_size):
  18. if not eval_data:
  19. filenames=[os.path.join(data_path,'data_batch_%d.bin' % i) for i in range(1,6)]
  20. else :
  21. filenames = [os.path.join(data_path, 'test_batch.bin')]
  22. #接下来生成文件名队列
  23. filename_queue=tf.train.string_input_producer(filenames)
  24. #接下来读取数据
  25. label,image=read_cifar10(filename_queue)
  26. reshaped_image=tf.cast(image,tf.float32)
  27. #
  28. #可以在这里对数据进行预处理
  29. #
  30. images,labels=tf.train.shuffle_batch([reshaped_image,label],batch_size=batch_size,num_threads=8,
  31. capacity=6+3,min_after_dequeue=6)
  32. return images,labels
  33. images,labels=inputs(False,'/home/ximao/models/data/cifar-10-batches-bin/',2)
  34. print(images)
  35. with tf.Session() as sess :
  36. #这个函数将会启动输入管道的线程,填充样本到队列中,以便出队操作可以从队列中拿到样本
  37. #这种情况下最好配合使用一个tf.train.Coordinator,这样可以在发生错误的情况下正确地关闭这些线程
  38. coord=tf.train.Coordinator()
  39. threads=tf.train.start_queue_runners(sess=sess,coord=coord)
  40. for i in range(2):
  41. print(i)
  42. image,label=sess.run([images,labels])
  43. print(type(image),image.shape)
  44. r=Image.fromarray(image[0,:,:,0]).convert('L')
  45. g = Image.fromarray(image[0, :, :, 1]).convert('L')
  46. b = Image.fromarray(image[0, :, :, 2]).convert('L')
  47. image1=Image.merge("RGB",(r,g,b))
  48. pyplot.imshow(image1)
  49. pyplot.show()
  50. image1.save('/home/ximao/result'+str(i)+'.png','png')
  51. coord.request_stop()
  52. coord.join(threads) # Wait for threads to terminate.


  这里你要先去下载cifar-10的数据集,地址:https://www.cs.toronto.edu/~kriz/cifar.html  ,注意这里下载的要是CIFAR-10 binary version (suitable for C programs)这个版本的。不同于我在:Alexnet网络模型在cifar-10数据集上的实现(基于tensorflow-gpu)所使用的版本。


对于有想对数据进行预处理的同学,包括裁剪,翻转等,可以在代码中所描述的位置添加操作就行了。

此外,我获取image的数据后,通过matplotlib,将图片绘制出来(如果你在linux运行程序报错:no display name and no $DISPLAY environment variable,则可以参考我这篇blog),图片如下:

    


3.标准TensorFlow格式数据读取

你可以将你自己的任意数据转成TFRecord格式文件,官方给了一个简单mnist的示例:链接,但是我没有尝试这个代码,

对于TFRecord数据的读取需要用到tf.data或者tf.contrib.data里的一些操作,我是读取的imagenet的数据集,因为这个数据集比较大,上面的两种方式不适合。你也可以先尝试tensorflow中文社区给的一个简单mnist tfrecord的读取例子:链接

我自己ImageNet数据集读取示例:

  1. import os
  2. import tensorflow as tf
  3. from Resnet_On_Imagenet import imagenet_preprocessing
  4. _DEFAULT_IMAGE_SIZE = 224
  5. _NUM_CHANNELS = 3
  6. _NUM_CLASSES = 1001
  7. _NUM_IMAGES = {
  8. 'train': 1281167,
  9. 'validation': 50000,
  10. }
  11. _NUM_TRAIN_FILES = 1024
  12. _SHUFFLE_BUFFER = 1500
  13. # 获取文件名
  14. def get_filenames(is_training, data_dir):
  15. if is_training:
  16. return [
  17. os.path.join(data_dir, 'train-%05d-of-01024' % i)
  18. for i in range(_NUM_TRAIN_FILES)]
  19. else:
  20. return [
  21. os.path.join(data_dir, 'validation-%05d-of-00128' % i)
  22. for i in range(128)]
  23. # 解析一个例子
  24. def _parse_example_proto(example_serialized): # example_serialized
  25. feature_map = {'image/encoded': tf.FixedLenFeature([], dtype=tf.string, default_value=''),
  26. 'image/class/label': tf.FixedLenFeature([1], dtype=tf.int64, default_value=-1),
  27. 'image/class/text': tf.FixedLenFeature([], tf.string, default_value='')}
  28. # 输入数据类型
  29. sparse_float32 = tf.VarLenFeature(dtype=tf.float32)
  30. feature_map.update({k: sparse_float32 for k in ['image/object/bbox/xmin',
  31. 'image/object/bbox/ymin',
  32. 'image/object/bbox/xmax',
  33. 'image/object/bbox/ymax']})
  34. # print(feature_map)
  35. for var in feature_map:
  36. print(var, ':', feature_map[var])
  37. # Parses a single Example proto.,这里example_serialized是tensorflow的一种数据格式
  38. features = tf.parse_single_example(example_serialized, feature_map)
  39. label = tf.cast(features['image/class/label'], dtype=tf.int32)
  40. xmin = tf.expand_dims(features['image/object/bbox/xmin'].values, 0)
  41. ymin = tf.expand_dims(features['image/object/bbox/ymin'].values, 0)
  42. xmax = tf.expand_dims(features['image/object/bbox/xmax'].values, 0)
  43. ymax = tf.expand_dims(features['image/object/bbox/ymax'].values, 0)
  44. bbox = tf.concat([ymin, xmin, ymax, xmax], 0)
  45. # Inserts a dimension of 1 into a tensor's shape.
  46. bbox = tf.expand_dims(bbox, 0)
  47. bbox = tf.transpose(bbox, [0, 2, 1])
  48. return features['image/encoded'], label, bbox
  49. def parse_record(raw_record, is_training):
  50. image_buffer, label, bbox = _parse_example_proto(raw_record)
  51. image = imagenet_preprocessing.preprocess_image(
  52. image_buffer=image_buffer,
  53. bbox=bbox,
  54. output_height=_DEFAULT_IMAGE_SIZE,
  55. output_width=_DEFAULT_IMAGE_SIZE,
  56. num_channels=_NUM_CHANNELS,
  57. is_training=is_training)
  58. label = tf.one_hot(tf.reshape(label, shape=[]), _NUM_CLASSES) # _NUM_CLASSES=1001
  59. print(image,':',label,)
  60. #image.eval()
  61. return image, label
  62. def input_fn(is_training, data_dir, batch_size, num_epochs=1, num_threads=1, multi_gpu=False):
  63. filenames = get_filenames(is_training, data_dir)
  64. print(filenames)
  65. #Splits each rank-N tf.SparseTensor in this dataset row-wise. (deprecated:弃用)
  66. dataset = tf.data.Dataset.from_tensor_slices(filenames)
  67. print(dataset)
  68. if is_training:
  69. # Shuffle the input files
  70. dataset = dataset.shuffle(buffer_size=_NUM_TRAIN_FILES)
  71. # 如果is_training=True 则num_images=_NUM_IMAGES['train']
  72. num_images = is_training and _NUM_IMAGES['train'] or _NUM_IMAGES['validation']
  73. # Convert to individual records
  74. #此处分析以下这一行代码的运行过程,先是dataset调用自己的属性函数flat_map(self,map_func),self传递的是自己本身即dataset,在调用函数的时候这一参数忽略了,自动传递
  75. #map_func传递的是tf.data.TFRecordDataset,tf.data.TFRecordDataset就是指TFRecordDataset这个对象,没有实例化,相当于
  76. #我们在传递函数时传递的函数名
  77. dataset = dataset.flat_map(tf.data.TFRecordDataset)
  78. # We prefetch a batch at a time, This can help smooth out the time taken to
  79. # load input files as we go through shuffling and processing.
  80. dataset=dataset.prefetch(buffer_size=batch_size)
  81. print(dataset)
  82. if is_training:
  83. dataset=dataset.shuffle(buffer_size=_SHUFFLE_BUFFER)
  84. dataset=dataset.repeat(num_epochs)
  85. if multi_gpu:
  86. total_examples = num_epochs * num_images
  87. dataset = dataset.take(batch_size * (total_examples // batch_size))
  88. # Parse the raw records into images and labels
  89. dataset=dataset.map(lambda value:parse_record(value,is_training),num_parallel_calls=num_threads)
  90. dataset=dataset.batch(batch_size)
  91. dataset = dataset.prefetch(1)
  92. print(dataset)
  93. return dataset


上面这个数据读取的代码是从官方给的一个ImageNet Resnet的model改过来的,其中imagenet_preprocessing是对数据预处理的一个文件,我就不放出来了。在input_fn函数中有多个shuffle,prefetch以及多个参数buffer_size,batch_size,num_parallel_calls,我会在下一篇文章中解释

  此外,tfrecord文件读取有一个重要的参数feature_map,这个是表示你要读取tfrecord哪些参数的参数名字符串列表,如果你想去理解为什么这样定义以及代码中bbox为什么这样做,你需要查看官方给的建立ImageNet数据集tfrecord文件代码,理解其中生成tfrecord文件的过程。如果你找不到官方给的代码,可以评论联系我。

  以上input_fn返回的是包含image和label(<PrefetchDataset shapes: ((?, 224, 224, 3), (?, 1001)), types: (tf.float32, tf.float32)>)的数据格式,还不能直接用,训练时需要如下操作

  1. import tensorflow as tf
  2. import os
  3. import Resnet_On_Imagenet.ReadData as ReadData
  4. from Resnet_On_Imagenet.config import cfg
  5. with tf.Graph().as_default():
  6. is_training=tf.placeholder(tf.bool,[],'is_training')
  7. with tf.device('/cpu:0'):
  8. training_dataset=ReadData.input_fn(True,cfg.data_dir,cfg.batch_size,
  9. num_epochs=cfg.train_epochs,num_threads=8,multi_gpu=False)
  10. handle=tf.placeholder(tf.string,shape=[])
  11. iterator = tf.data.Iterator.from_string_handle(handle,
  12. training_dataset.output_types,training_dataset.output_shapes)
  13. images,labels=iterator.get_next()
  14. print(images, ':', labels)
  15. with tf.Session() as sess:
  16. training_iterator = training_dataset.make_one_shot_iterator()
  17. training_handle = sess.run(training_iterator.string_handle())
  18. sess.run(tf.global_variables_initializer())
  19. print(sess.run(images,feed_dict={handle:training_handle}))
最后一句可以打印出获取到的一个image的值,上面这段代码只是一个示例获取image数据



三、预加载数据

当你的数据集比较小的时候(比如mnist),你可把所有的数据都先加载到内存(这种方式简单,但一般不推荐这种方式)

这里有两种方式:

  • 存储在常数中。
  • 存储在变量中,初始化后,永远不要改变它的值

使用常数更简单一些,但是会使用更多的内存(因为常数会内联的存储在数据流图数据结构中,这个结构体可能会被复制几次)。

  1. training_data = ...
  2. training_labels = ...
  3. with tf.Session():
  4. input_data = tf.constant(training_data)
  5. input_labels = tf.constant(training_labels)
  6. ...

要改为使用变量的方式,您就需要在数据流图建立后初始化这个变量。

  1. training_data = ...
  2. training_labels = ...
  3. with tf.Session() as sess:
  4. data_initializer = tf.placeholder(dtype=training_data.dtype,
  5. shape=training_data.shape)
  6. label_initializer = tf.placeholder(dtype=training_labels.dtype,
  7. shape=training_labels.shape)
  8. input_data = tf.Variable(data_initalizer, trainable=False, collections=[])
  9. input_labels = tf.Variable(label_initalizer, trainable=False, collections=[])
  10. ...#以下两行代码是初始化input_data,input_labels变量的
  11. sess.run(input_data.initializer,
  12. feed_dict={data_initializer: training_data})
  13. sess.run(input_labels.initializer,
  14. feed_dict={label_initializer: training_lables})

设定trainable=False 可以防止该变量被数据流图的 GraphKeys.TRAINABLE_VARIABLES 收集, 这样我们就不会在训练的时候尝试更新它的值; 设定 collections=[] 可以防止GraphKeys.VARIABLES 收集后做为保存和恢复的中断点。

上面面的两段代码,无论以哪种方式存储数据集,在给训练网络的输出传递images的时候都要通过tf.train.slice_input_producer function函数每次产生一个切片。

两种变量存储示例代码:使用常量使用变量


四、多输入管道,

通常你会在一个数据集上面训练,然后在另外一个数据集上做评估计算(或称为 "eval")。 这样做的一种方法是,实际上包含两个独立的进程:

  • 训练过程中读取输入数据,并定期将所有的训练的变量写入还原点文件)。
  • 在计算过程中恢复还原点文件到一个推理模型中,读取有效的输入数据

这一个我认为特别好用,因为你能够训练一段时间就可以看到网络在测试集上的表现,不然等训练完了进行测试不对的话就浪费时间了

  这里可以参见社区这篇文章:http://www.tensorfly.cn/tfdoc/tutorials/deep_cnn.html#save-and-restore-checkpoints


当然多管道训练与测试存在共享变量的问题,而共享变量是tensorflow非常重要的一个点(我认为),有空单独给共享变量写篇文章。


~~~~~~~~~~~~

到此结束啦,有错误的欢迎大家指正评论啦,欢迎与我讨论~~

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/很楠不爱3/article/detail/237095
推荐阅读
相关标签
  

闽ICP备14008679号