赞
踩
主要参考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 数据读取三种:
一、直接供给数据
这种方式比较简单,直接定义输入的placeholder,然后每次run的时候输入feed_dict参数就行
一般通过在网络中定义:
- x=tf.placeholder(tf.float32,shape=[None,_IMAGE_SIZE*_IMAGE_SIZE*_IMAGE_CHANNELS],name='images')
- 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
测试代码:
- #coding=utf-8
- import tensorflow as tf
- #read from csv
-
- #这里的[fil1.csv,file0]就是文件名列表,
- filename_queue=tf.train.string_input_producer(["path/file0.csv","path/file1.csv"])
- reader=tf.TextLineReader()
- key,value=reader.read(filename_queue)
-
- record_default=[[1],[1],[1],[1],[1]]
-
- col1,col2,col3,col4,col5=tf.decode_csv(value,record_defaults=record_default)
- features = tf.stack([col1,col2,col3,col4],axis=0) #串接成一维张量,如果col1不是标量,则可以用tf.concat()
-
- with tf.Session() as sess:
- coord=tf.train.Coordinator() #This class implements a simple mechanism to coordinate the termination of a set of threads.
- threads=tf.train.start_queue_runners(coord=coord)
-
- for i in range(30):
- example,label=sess.run([features,col5])
- print(example,label)
-
- coord.request_stop()
- 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的张量的标准操作就可以从中获取图像片并且根据需要进行重组。
示例代码:
- #coding=utf-8
- # 2018 04 07
- #从二进制文件中读取数据
-
- import tensorflow as tf
- import os
- import matplotlib.pyplot as pyplot
- import PIL.Image as Image
-
- def read_cifar10(filename_queue):
- record_bytes=1+32*32*3
- reader=tf.FixedLengthRecordReader(record_bytes=record_bytes)
-
- key,value=reader.read(filename_queue)
-
- record_bytes=tf.decode_raw(value,tf.uint8)
- label=tf.cast(tf.slice(record_bytes,[0],[1]),tf.uint8)
- depth_major = tf.reshape(tf.slice(record_bytes, [1], [32*32*3]),[3, 32, 32])
-
- unit8image=tf.transpose(depth_major,[1,2,0])
-
- return label,unit8image
-
- def inputs(eval_data,data_path,batch_size):
- if not eval_data:
- filenames=[os.path.join(data_path,'data_batch_%d.bin' % i) for i in range(1,6)]
- else :
- filenames = [os.path.join(data_path, 'test_batch.bin')]
-
- #接下来生成文件名队列
- filename_queue=tf.train.string_input_producer(filenames)
-
- #接下来读取数据
- label,image=read_cifar10(filename_queue)
- reshaped_image=tf.cast(image,tf.float32)
-
- #
- #可以在这里对数据进行预处理
- #
-
-
- images,labels=tf.train.shuffle_batch([reshaped_image,label],batch_size=batch_size,num_threads=8,
- capacity=6+3,min_after_dequeue=6)
- return images,labels
-
-
- images,labels=inputs(False,'/home/ximao/models/data/cifar-10-batches-bin/',2)
-
- print(images)
- with tf.Session() as sess :
- #这个函数将会启动输入管道的线程,填充样本到队列中,以便出队操作可以从队列中拿到样本
- #这种情况下最好配合使用一个tf.train.Coordinator,这样可以在发生错误的情况下正确地关闭这些线程
- coord=tf.train.Coordinator()
- threads=tf.train.start_queue_runners(sess=sess,coord=coord)
- for i in range(2):
- print(i)
- image,label=sess.run([images,labels])
- print(type(image),image.shape)
- r=Image.fromarray(image[0,:,:,0]).convert('L')
- g = Image.fromarray(image[0, :, :, 1]).convert('L')
- b = Image.fromarray(image[0, :, :, 2]).convert('L')
- image1=Image.merge("RGB",(r,g,b))
- pyplot.imshow(image1)
- pyplot.show()
- image1.save('/home/ximao/result'+str(i)+'.png','png')
-
- coord.request_stop()
- 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数据集读取示例:
- import os
- import tensorflow as tf
- from Resnet_On_Imagenet import imagenet_preprocessing
-
- _DEFAULT_IMAGE_SIZE = 224
- _NUM_CHANNELS = 3
- _NUM_CLASSES = 1001
-
- _NUM_IMAGES = {
- 'train': 1281167,
- 'validation': 50000,
- }
- _NUM_TRAIN_FILES = 1024
- _SHUFFLE_BUFFER = 1500
-
-
- # 获取文件名
-
- def get_filenames(is_training, data_dir):
- if is_training:
- return [
- os.path.join(data_dir, 'train-%05d-of-01024' % i)
- for i in range(_NUM_TRAIN_FILES)]
- else:
- return [
- os.path.join(data_dir, 'validation-%05d-of-00128' % i)
- for i in range(128)]
-
-
- # 解析一个例子
- def _parse_example_proto(example_serialized): # example_serialized
- feature_map = {'image/encoded': tf.FixedLenFeature([], dtype=tf.string, default_value=''),
- 'image/class/label': tf.FixedLenFeature([1], dtype=tf.int64, default_value=-1),
- 'image/class/text': tf.FixedLenFeature([], tf.string, default_value='')}
- # 输入数据类型
- sparse_float32 = tf.VarLenFeature(dtype=tf.float32)
- feature_map.update({k: sparse_float32 for k in ['image/object/bbox/xmin',
- 'image/object/bbox/ymin',
- 'image/object/bbox/xmax',
- 'image/object/bbox/ymax']})
- # print(feature_map)
- for var in feature_map:
- print(var, ':', feature_map[var])
- # Parses a single Example proto.,这里example_serialized是tensorflow的一种数据格式
- features = tf.parse_single_example(example_serialized, feature_map)
- label = tf.cast(features['image/class/label'], dtype=tf.int32)
- xmin = tf.expand_dims(features['image/object/bbox/xmin'].values, 0)
- ymin = tf.expand_dims(features['image/object/bbox/ymin'].values, 0)
- xmax = tf.expand_dims(features['image/object/bbox/xmax'].values, 0)
- ymax = tf.expand_dims(features['image/object/bbox/ymax'].values, 0)
-
- bbox = tf.concat([ymin, xmin, ymax, xmax], 0)
- # Inserts a dimension of 1 into a tensor's shape.
- bbox = tf.expand_dims(bbox, 0)
- bbox = tf.transpose(bbox, [0, 2, 1])
-
- return features['image/encoded'], label, bbox
-
-
- def parse_record(raw_record, is_training):
- image_buffer, label, bbox = _parse_example_proto(raw_record)
-
- image = imagenet_preprocessing.preprocess_image(
- image_buffer=image_buffer,
- bbox=bbox,
- output_height=_DEFAULT_IMAGE_SIZE,
- output_width=_DEFAULT_IMAGE_SIZE,
- num_channels=_NUM_CHANNELS,
- is_training=is_training)
-
- label = tf.one_hot(tf.reshape(label, shape=[]), _NUM_CLASSES) # _NUM_CLASSES=1001
- print(image,':',label,)
- #image.eval()
- return image, label
-
-
- def input_fn(is_training, data_dir, batch_size, num_epochs=1, num_threads=1, multi_gpu=False):
- filenames = get_filenames(is_training, data_dir)
- print(filenames)
- #Splits each rank-N tf.SparseTensor in this dataset row-wise. (deprecated:弃用)
- dataset = tf.data.Dataset.from_tensor_slices(filenames)
- print(dataset)
- if is_training:
- # Shuffle the input files
- dataset = dataset.shuffle(buffer_size=_NUM_TRAIN_FILES)
- # 如果is_training=True 则num_images=_NUM_IMAGES['train']
- num_images = is_training and _NUM_IMAGES['train'] or _NUM_IMAGES['validation']
-
- # Convert to individual records
- #此处分析以下这一行代码的运行过程,先是dataset调用自己的属性函数flat_map(self,map_func),self传递的是自己本身即dataset,在调用函数的时候这一参数忽略了,自动传递
- #map_func传递的是tf.data.TFRecordDataset,tf.data.TFRecordDataset就是指TFRecordDataset这个对象,没有实例化,相当于
- #我们在传递函数时传递的函数名
- dataset = dataset.flat_map(tf.data.TFRecordDataset)
-
- # We prefetch a batch at a time, This can help smooth out the time taken to
- # load input files as we go through shuffling and processing.
- dataset=dataset.prefetch(buffer_size=batch_size)
- print(dataset)
- if is_training:
- dataset=dataset.shuffle(buffer_size=_SHUFFLE_BUFFER)
- dataset=dataset.repeat(num_epochs)
- if multi_gpu:
- total_examples = num_epochs * num_images
- dataset = dataset.take(batch_size * (total_examples // batch_size))
-
- # Parse the raw records into images and labels
- dataset=dataset.map(lambda value:parse_record(value,is_training),num_parallel_calls=num_threads)
- dataset=dataset.batch(batch_size)
- dataset = dataset.prefetch(1)
- print(dataset)
- 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)>)的数据格式,还不能直接用,训练时需要如下操作
- import tensorflow as tf
-
- import os
- import Resnet_On_Imagenet.ReadData as ReadData
- from Resnet_On_Imagenet.config import cfg
-
-
- with tf.Graph().as_default():
- is_training=tf.placeholder(tf.bool,[],'is_training')
- with tf.device('/cpu:0'):
- training_dataset=ReadData.input_fn(True,cfg.data_dir,cfg.batch_size,
- num_epochs=cfg.train_epochs,num_threads=8,multi_gpu=False)
- handle=tf.placeholder(tf.string,shape=[])
- iterator = tf.data.Iterator.from_string_handle(handle,
- training_dataset.output_types,training_dataset.output_shapes)
-
- images,labels=iterator.get_next()
- print(images, ':', labels)
-
- with tf.Session() as sess:
- training_iterator = training_dataset.make_one_shot_iterator()
- training_handle = sess.run(training_iterator.string_handle())
- sess.run(tf.global_variables_initializer())
- print(sess.run(images,feed_dict={handle:training_handle}))
最后一句可以打印出获取到的一个image的值,上面这段代码只是一个示例获取image数据
三、预加载数据
当你的数据集比较小的时候(比如mnist),你可把所有的数据都先加载到内存(这种方式简单,但一般不推荐这种方式)
这里有两种方式:
使用常数更简单一些,但是会使用更多的内存(因为常数会内联的存储在数据流图数据结构中,这个结构体可能会被复制几次)。
- training_data = ...
- training_labels = ...
- with tf.Session():
- input_data = tf.constant(training_data)
- input_labels = tf.constant(training_labels)
- ...
要改为使用变量的方式,您就需要在数据流图建立后初始化这个变量。
- 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_initalizer, trainable=False, collections=[])
- input_labels = tf.Variable(label_initalizer, trainable=False, collections=[])
- ...#以下两行代码是初始化input_data,input_labels变量的
- sess.run(input_data.initializer,
- feed_dict={data_initializer: training_data})
- sess.run(input_labels.initializer,
- 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非常重要的一个点(我认为),有空单独给共享变量写篇文章。
~~~~~~~~~~~~
到此结束啦,有错误的欢迎大家指正评论啦,欢迎与我讨论~~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。