tensorflow多线程

本文所有内容均不是原创,仅是看到好的资源,转载到这里,方便自己查找,所有来源都会标注清楚。

https://www.cnblogs.com/demian/p/8005407.html

如果你打开了这篇博客,推荐去上面链接读原文,原文写的更好。

Tf中的队列tensorflow的session对象可以支持多线程,多线程可以方便地使用同一个Session并执行,然而,Python中的并行运算并不容易。所有的线程必须能被同部终止,异常也必须能被正确捕获并报告,会话终止时,队列必须能够被正确关闭。

Tensorflow提供了两个类来实现多线程:tf.Coordinator和tf.QueueRunner

tf.Coordinator类用于同时停止多个线程并向等待所有线程终止的程序报告异常

tf.QueueRunner类用于协调多个线程同时将多个张量推入同一队列中。存储操作队列

队列tf.FIFOQueue(capacity, dtypes)

Capacity:制定队列中元素数量的上限

Dtypes:Dtype对象的列表,dtypes的长度必须等于每个队列元素中张量的数量。

注意:tf.initialize_all_variables()被弃用,采用tf.global_variables_initializer()

Tensorflow读取数据的基本机制:将读入数据和计算分别放在两个线程中,读取线程源源不断地将文件系统中的数据读入到一个内存队列中,负责计算的则是另一个线程,计算需要数据时,直接从内存队列中取就可以了。Tensorflow使用文件名队列+内存队列双队列的形式读入文件,可以很好地管理epoch。

https://i-blog.csdnimg.cn/blog_migrate/97c1b2047bdd36760ebd5827cf88e353.png

对于文件名队列,使用tf.train.string_input_producer生成,tf.train.string_input_producer格式如下

filename_queue = tf.train.string_input_producer([tfRecord_path]) tf.train.string_input_producer( string_tensor, num_epochs=None, shuffle=True, seed=None, capacity=32, shared_name=None, name=None, cancel_op=None)

该函数会生成一个先入先出的队列,文件阅读器会使用它来读取数据。

参数说明:

string_tensor: TFRecord 文件名列表

num_epochs: 循环读取的轮数(可选)

shuffle:布尔值(可选),如果为 True,则在每轮随机打乱读取顺序

seed:随机读取时设置的种子(可选)

capacity:设置队列容量shared_name:(可选) 如果设置,该队列将在多个会话中以给定名称共享。所有具有此队列的设备都可以通过 shared_name 访问它。在分布式设置中使用这种方法意味着每个名称只能被访问此操作的其中一个会话看到。

name:操作的名称(可选)

cancel_op:取消队列(None)

使用tf.train.string_input_producer创建文件名队列后,整个系统其实还是处于停滞状态的,也就是说,我们文件名并没有真正被加入到队列中,此时如果我们开始计算,因为内存队列中什么也没有,计算单元就会一直等待,导致整个系统被阻塞。使用tf.train.start_queue_runners之后,才会启动填充队列的线程,这时系统就不再停滞。此后计算单元就可以拿到数据并进行计算,整个程序也就跑起来了。

Queue:tf队列和缓存机制的实现;

类型:

tf.FIFOQueue先进先出队列

tf.RandomShuffleQueue随机出列队列

tf.PaddingFIFOQueue以固定长度批量出列队列

tf.PriorityQueue带优先级出列队列

操作:

入列enqueue返回计算图中的一个Operation节点

出列dequeue返回一个Tensor值

QueueRunner:tf中对操作Queue的线程的封装;

Tensorflow计算主要使用CPU/GPU和内存,而数据读取涉及磁盘操作,速度远低于计算,因此通常会使用多个线程读取数据,然后使用一个线程计算数据,QueueRunner则是管理这些读写队列的线程。

代码:

import tensorflow as tf 

import sys 

q = tf.FIFOQueue(10, "float") 

counter = tf.Variable(0.0)  #计数器

# 给计数器加一

increment_op = tf.assign_add(counter, 1.0)

# 将计数器加入队列

enqueue_op = q.enqueue(counter)

 

# 创建QueueRunner

# 用多个线程向队列添加数据

# 这里实际创建了4个线程,两个增加计数,两个执行入队

qr = tf.train.QueueRunner(q, enqueue_ops=[increment_op, enqueue_op] * 2)

 

# 主线程

sess = tf.InteractiveSession()

tf.global_variables_initializer().run()

# 启动入队线程

qr.create_threads(sess, start=True)

for i in range(20):

print (sess.run(q.dequeue()))

上述代码解释:增加计数的进程会不停的后台运行,执行入队的进程会先执行10次(因为队列长度只有10),然后主线程开始消费数据,当一部分数据消费被后,入队的进程又会开始执行。最终主线程消费完20个数据后停止,但其他线程继续运行,程序不会结束。

Coordinator:tf中用来协调线程运行的工具,保存线程组运行状态的协调器对象。

要么用create_threads创建并启动线程,要么tf.train.start_queue_runners(sess = sess)启动线程,两者效果一样。

Create_threads代码如下:

import tensorflow as tf

 

# 1000个4维输入向量,每个数取值为1-10之间的随机数

data = 10 * np.random.randn(1000, 4) + 1

# 1000个随机的目标值,值为0或1

target = np.random.randint(0, 2, size=1000)

 

# 创建Queue,队列中每一项包含一个输入数据和相应的目标值

queue = tf.FIFOQueue(capacity=50, dtypes=[tf.float32, tf.int32], shapes=[[4], []])

 

# 批量入列数据(这是一个Operation)

enqueue_op = queue.enqueue_many([data, target])

# 出列数据(这是一个Tensor定义)

data_sample, label_sample = queue.dequeue()

 

# 创建包含4个线程的QueueRunner

qr = tf.train.QueueRunner(queue, [enqueue_op] * 4)

 

with tf.Session() as sess:

    # 创建Coordinator

    coord = tf.train.Coordinator()

    # 启动QueueRunner管理的线程

    enqueue_threads = qr.create_threads(sess, coord=coord, start=True)

    # 主线程,消费100个数据

    for step in range(100):

        if coord.should_stop():

            break

        data_batch, label_batch = sess.run([data_sample, label_sample])

    # 主线程计算完成,停止所有采集数据的进程

    coord.request_stop()

coord.join(enqueue_threads)

 

 

start_queue_runners代码如下:

import tensorflow as tf

 

# 同时打开多个文件,显示创建Queue,同时隐含了QueueRunner的创建

filename_queue = tf.train.string_input_producer(["data1.csv","data2.csv"])

reader = tf.TextLineReader(skip_header_lines=1)

# Tensorflow的Reader对象可以直接接受一个Queue作为输入

key, value = reader.read(filename_queue)

 

with tf.Session() as sess:

    coord = tf.train.Coordinator()

    # 启动计算图中所有的队列线程

    threads = tf.train.start_queue_runners(coord=coord)

    # 主线程,消费100个数据

    for _ in range(100):

        features, labels = sess.run([data_batch, label_batch])

    # 主线程计算完成,停止所有采集数据的进程

    coord.request_stop()

coord.join(threads)

 

2)reader = tf.TFRecordReader() #新建一个 reader

3)_, serialized_example = reader.read(filename_queue)

把读出的每个样本保存在 serialized_example 中进行解序列化,标签和文本的键名应该和制作 tfrecords 的键名相同。

4)context_parsed, sequence_parsed = tf.parse_single_sequence_example(

        serialized=serialized_example,

        context_features=context_features,

        sequence_features=sequence_features

    )

函数格式:parse_single_sequence_example (

    serialized ,

    context_features = None ,

    sequence_features = None ,

    example_names = None ,

    name = None

 )

函数功能:可以将serialized单个序列化成SequenceExample,解析为字典的元组 tf.train.Example 协议内存块(protocol buffer)解析为张量。

参数说明:serialized: 一个标量字符串张量

features: 一个字典映射功能键 FixedLenFeature 或 VarLenFeature值,也就是在协议内存块中储存的

name:操作的名称(可选)

example_names: 标量字符串联的名称(可选)

4)labels = context_parsed['label']

   text = sequence_parsed['text']

5)input_tensors = [labels, text]

6)

针对固定长度的序列:

tf.train.shuffle_batch( tensors,batch_size, capacity, min_after_dequeue, num_threads=1, seed=None, enqueue_many=False, shapes=None, allow_smaller_final_batch=False, shared_name=None, name=None)

函数功能:随机读取一个 batch 的数据。

参数说明:

tensors: 待乱序处理的列表中的样本(图像和标签)

batch_size: 从队列中提取的新批量大小

capacity:队列中元素的最大数量

min_after_dequeue: 出队后队列中的最小数量元素,用于确保元素的混合级别

num_threads: 排列 tensors 的线程数

seed:用于队列内的随机洗牌

enqueue_many: tensor 中的每个张量是否是一个例子

shapes: 每个示例的形状

allow_smaller_final_batch: (可选)布尔值,如果为 True,则在队列中剩余数量不足时允许最终批次更小。

shared_name:(可选)如果设置,该队列将在多个会话中以给定名称共享。

name:操作的名称(可选)

7)tf.ConfigProto()配置tf.Session的运算方式,比如gpu运算或者cpu运算

参数:

log_device_placement= True,打印出tf使用的操作

inter_op_parallelism_threads = 0,设置线程一个操作内部并行运算的线程数,0表示以最优线程数处理

intra_op_parallelism_threads = 0,设置多个操作并行运算的线程数

allow_soft_placement = True,当运行设备不满足要求时,自动分配gpu或者cpu

8)tf.train.batch([example, label], batch_size=batch_size, capacity=capacity):[example, label]表示样本和样本标签,这个可以是一个样本和一个样本标签,batch_size是返回的一个batch样本集的样本个数。capacity是队列中的容量。这主要是按顺序组合成一个batch.

遗留的问题:针对变长序列的shuffle_batch

  • 1
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值