tensorflow入门学习(2)——tensorflow数据读取&多线程

一、供给数据

TensorFlow的数据供给机制允许你在TensorFlow运算图中将数据注入到任一张量中。因此,python运算可以把数据直接设置到TensorFlow图中。
通过给run()或者eval()函数输入feed_dict参数, 可以启动运算过程。

with tf.Session():
    input = tf.placeholder(tf.float32)
    classifier = ...
    print classifier.eval(feed_dict={input: my_python_preprocessing_fn()})

二、从文件读取数据

首先要知道你要读取的文件的格式,选择对应的文件读取器;

CSV 文件

从CSV文件中读取数据, 需要使用TextLineReader和decode_csv 操作, 如下面的例子所示:

1. tf.train.string_input_producer()

选择要读取的文件的名字形成list,用 tf.train.string_input_producer 函数来生成文件名队列,
这个函数可以设置shuffle = Ture,来打乱队列,可以设置epoch = 5,过5遍训练数据

2. tf.TextFileReader(), tf.decode_csv()

选择的文件读取器,解码器,读取文件名队列并解码
CSV 那样的文本文件,用的文件读取器和解码器就是 TextLineReader 和 decode_csv

二进制文件

图片文件

三、Tensorflow多线程

TensorFlow的Session对象是支持多线程的,可以在同一个会话(Session)中创建多个线程,并行执行。在Session中的所有线程都必须能被同步终止,异常必须能被正确捕获并报告,会话终止的时候, 队列必须能被正确地关闭。

TensorFlow提供了两个类来实现对Session中多线程的管理:tf.Coordinator和 tf.QueueRunner,这两个类往往一起使用。

3. tf.train.Coordinator(): tensorflow协调器

Coordinator类用来管理在Session中的多个线程,可以用来同时停止多个工作线程并且向那个在等待所有工作线程终止的程序报告异常,该线程捕获到这个异常之后就会终止所有线程。使用 tf.train.Coordinator()来创建一个线程管理器(协调器)对象。

4. tf.train.start_queue_runners()

QueueRunner类用来启动tensor的入队线程,可以用来启动多个工作线程同时将多个tensor(训练数据)推送入文件名称队列中,具体执行函数是 tf.train.start_queue_runners , 只有调用 tf.train.start_queue_runners 之后,才会真正把tensor推入内存序列中,供计算单元调用,否则会由于内存序列为空,数据流图会处于一直等待状态。

tf中的数据读取机制如下图:

1.调用 tf.train.slice_input_producer,从 本地文件里抽取tensor,准备放入Filename Queue(文件名队列)中;
2.调用 tf.train.batch,从文件名队列中提取tensor,使用单个或多个线程,准备放入文件队列;
3.调用 tf.train.Coordinator() 来创建一个线程协调器,用来管理之后在Session中启动的所有线程;
4.调用tf.train.start_queue_runners, 启动入队线程,由多个或单个线程,按照设定规则,把文件读入Filename Queue中。函数返回线程ID的列表,一般情况下,系统有多少个核,就会启动多少个入队线程(入队具体使用多少个线程在tf.train.batch中定义);
5.文件从 Filename Queue中读入内存队列的操作不用手动执行,由tf自动完成;
6.调用sess.run 来启动数据出列和执行计算;
7.使用coord.should_stop()来查询是否应该终止所有线程,当文件队列(queue)中的所有文件都已经读取出列的时候,会抛出一个 OutofRangeError 的异常,这时候就应该停止Sesson中的所有线程了;
8.使用coord.request_stop()来发出终止所有线程的命令,使用coord.join(threads)把线程加入主线程,等待threads结束。

示例:

这里写图片描述
这里写图片描述

5. tf.cast() 类型转化函数

tf.cast(x, dtype, name=None)
输入:
x:输入
dtype:转换目标类型
name:名称

返回:Tensor

6. tf.train.slice_input_producer()

tf.train.slice_input_producer是一个tensor生成器,作用是按照设定,每次从一个tensor列表中按顺序或者随机抽取出一个tensor放入文件名队列。

    slice_input_producer(tensor_list, num_epochs=None, shuffle=True, seed=None,  
                             capacity=32, shared_name=None, name=None)  
第一个参数tensor_list:包含一系列tensor的列表,表中tensor的第一维度的值必须相等,即个数必须相等,有多少个图像,就应该有多少个对应的标签。
第二个参数num_epochs: 可选参数,是一个整数值,代表迭代的次数,如果设置 num_epochs=None,生成器可以无限次遍历tensor列表,如果设置为 num_epochs=N,生成器只能遍历tensor列表N次。
第三个参数shuffle: bool类型,设置是否打乱样本的顺序。一般情况下,如果shuffle=True,生成的样本顺序就被打乱了,在批处理的时候不需要再次打乱样本,使用 tf.train.batch函数就可以了;如果shuffle=False,就需要在批处理时候使用 tf.train.shuffle_batch函数打乱样本。
第四个参数seed: 可选的整数,是生成随机数的种子,在第三个参数设置为shuffle=True的情况下才有用。
第五个参数capacity:设置tensor列表的容量。
第六个参数shared_name:可选参数,如果设置一个‘shared_name’,则在不同的上下文环境(Session)中可以通过这个名字共享生成的tensor。
第七个参数name:可选,设置操作的名称。

tf.train.slice_input_producer 函数中设置了 num_epochs 的数量, 所以在文件队列末尾有结束标志,读到这个结束标志的时候抛出 OutofRangeError 异常,就可以结束各个线程了。
按照0,1,2,3,4,0,1,2,3…
如果不设置 num_epochs 的数量,则文件队列是无限循环的,没有结束标志,程序会一直执行下去。

7. tf.train.batch()

tf.train.batch是一个tensor队列生成器,作用是按照给定的tensor顺序,把batch_size个tensor推送到文件队列,作为训练一个batch的数据,等待tensor出队执行计算。

    batch(tensors, batch_size, num_threads=1, capacity=32,  
              enqueue_many=False, shapes=None, dynamic_pad=False,  
              allow_smaller_final_batch=False, shared_name=None, name=None)  
第一个参数tensors:tensor序列或tensor字典,可以是含有单个样本的序列;
第二个参数batch_size: 生成的batch的大小;
第三个参数num_threads:执行tensor入队操作的线程数量,可以设置使用多个线程同时并行执行,提高运行效率,但也不是数量越多越好;
第四个参数capacity: 定义生成的tensor序列的最大容量;
第五个参数enqueue_many: 定义第一个传入参数tensors是多个tensor组成的序列,还是单个tensor;
第六个参数shapes: 可选参数,默认是推测出的传入的tensor的形状;
第七个参数dynamic_pad: 定义是否允许输入的tensors具有不同的形状,设置为True,会把输入的具有不同形状的tensor归一化到相同的形状;
第八个参数allow_smaller_final_batch: 设置为True,表示在tensor队列中剩下的tensor数量不够一个batch_size的情况下,允许最后一个batch的数量少于batch_size, 设置为False,则不管什么情况下,生成的batch都拥有batch_size个样本;
第九个参数shared_name: 可选参数,设置生成的tensor序列在不同的Session中的共享名称;
第十个参数name: 操作的名称;

如果tf.train.batch的第一个参数 tensors 传入的是tensor列表或者字典,返回的是tensor列表或字典,如果传入的是只含有一个元素的列表,返回的是单个的tensor,而不是一个列表。

8. tf.Session().run()

tf.session.run()单函数运行和多函数运行区别

sess.run([a,b]) # (1)同时运行a,b两个函数

sess.run(a)
sess.run(b)     # (2)运行完a函数后再运行b函数

这两个语句初看时没有任何区别,但是如果a,b函数恰好是读取example_batch和label_batch这种需要使用到 数据批次输入输出函数时 例如(tf.train.shuffle_batch.tf.reader.read).

(1)式只会调用一次输入数据函数,则得到的example_batch和label_batch来自同一批次。
(2)式会单独调用两次输入数据函数,则得到的example_batch来自上一批次而label_batch来自下一批次。

这个需要十分注意,因为如果我们想要实时打印出label_batch和inference(example_batch)时,即将输入数据的标签和经过模型预测推断的结果进行比较时.如果我们使用(2)中的写法,则label_batch和inference(example_batch)并不是来自与同一批次数据。

所以tf.train.batch() 得到的 image_batch 和 label_batch 要一起放入sess.run()中

PS: 一般在session结束后,最好要加一个sess.close()不然很有可能忘记关掉,一直运行,占用资源
可能会报错:Tensorflow+InternalError: Blas GEMM launch failed
因为session用毕没有及时close, 导致系统和GPU的很大部分被占用过却没有归还, 当前资源便不够了; 或是多个session争用GPU.

猜你喜欢

转载自blog.csdn.net/qq_37423198/article/details/80524600