TensorFlow线程对列&IO操作

TensorFlow--IO操作
  • TensorFlow 异步IO操作的原理
    • 如下如, 文件对列用来存储需要读取文件或者文本, 阅读器用来不断从对列中获取文件进行内容的读取, Deoder用来对读取出来的内容进行解码, 结果对列用来存储读取的结果
    • IO操作是真正的多线程(异步)
    • 操作流程如下图
  • IO操作是怎么实现异步的
    • 当数据量很大时,入队操作从硬盘中读取数据,放入内存中,主线程需要等待入队操作完成,才能进行训练。会话里可以运行多个线程,实现异步读取。
TensorFlow--队列
  • 队列的创建
    • Q = tf.FIFOQueue(capacity, dtypes, name="fifo_queue")     创建先进先出的对列,按照顺序出对列
      • capacity: 整数, 对列的容量
      • dtypes: dtype 数据类型
    • tf.RandomShuffleQueue()     创建随机出队的对列
  • 队列的操作
    • Q.dequeue()    出列操作
    • Q.enqueue(vals)     单个元素入队
    • Q.enqueue_many(vals)     多个元素入队
      • vals:  列表或者元组, 包含需要入队的元素
    • Q.size()     返回一个tensor类型的对象, value是对列的大小
  • 使用示例
TensorFlow--对列管理器
  • 队列管理器的作用
    • 当直接通过对列的方法向队列中添加数据的时候, 需要等待数据添加完成才能执行下一步操作, 这样的操作不是异步的
    • 当我们想一边自动的向对列中添加数据, 一边进行其他的操作的时候, 我们可以使用对列管理器
    • 其会自动的绑定对列和一些对对列的操作, 并另外开启线程执行绑定的操作
  • 对列管理器的创建
    • qr = tf.train.QueueRunner(queue, enqueue_ops=None)    创建对列管理器
      • queue:  绑定到对列管理器的对列
      • enqueue_ops: 代表对列操作列表,每个操作会创建一个子线程来执行
  • 创建线程让对列管理器执行
    • thd = qr.create_threads(sess, coord=None, start=False)    创建线程来执行队列管理器绑定的方法
      • start: True, 直接启动队列管理器线程。False, 需要手动调用start来让线程运行
      • coord:线程协调器
      • return:  返回线程对象
  • 线程资源问题的解决
    • 问题: 
      • 当在会话中开启线程的时候, 当使用with方式开启线程并执行后, 当主线程结束后, 由于with方式开启会话会对资源进行回收
      • 这时候子线程失去会话资源, 会导致程序崩溃
    • 解决方法
      • 使用线程协调器
TensorFlow--线程协调器
  • 线程协调器的作用
    • 实现一个简单的机制来协调一组线程的终止阻塞等操作
  • 创建线程协调器
    • coord = tf.train.Coordinator()    创建线程斜体其起
  • 线程协调器的方法
    • coord.request_stop()    终止绑定在线程协调器的所有线程
    • coord.should_stop()    检查是否满足停止条件,如果满足便退出线程
    • coord.join(threads=None)      阻塞等待线程结束
  • 使用代码示例
文件读取
  • 文件队列的创建
    • tf.train.string_input_producer(string_tensor, num_opochs=None, shuffle=True)    创建文件队列,用来存储即将操作的文件
      • string_tensor:  含有文件名的1阶张量
      • num_epochs:  过几遍数据,默认无限过数据
      • return:  输出字符串的队列
  • 文件队列线程开启操作
    • 作用:开启线程创建图中定义的对列,并将设置的待读取内容读取到对列中
    • thd = tf.train.start_queue_runners(sess=None,coord=None, start=True)
      • sess:   所在的会话中
      • coord:线程协调器
      • start: 是否直接开启线程
  • 管道读取批量处理
    • 作用
      • 可以每次批量的进行文件内容的读取
      • 原理是会创建一个批处理对列,
      • 当读取文件内容的时候, 批处理对列会预先从文件对列中选取文件,读取内容将对列填满
      • 然后根据设定的batch_size, 返回对列中的内容
      • 当内容取出后, 再从读取文件将对列填满, 等待下一次的读取
    • 使用方法
      • tf.train.batch(tensors, batch_size, num_threads=1, capacity=32, name=None)   读取指定大小(个数)的张量
        • tensors:可以是包含张量的列表
        • batch_size:从队列中读取的批处理大小
        • num_threads:进入队列的线程数
        • capacity:整数,队列中元素的最大数量
        • return: tensors, 读取到内容的数组
      • tf.train.shuffle_batch(tensors, batch_size, capacity, min_after_dequeue, num_threads=1)    乱序读取指定大小(个数)的张量
        • min_after_dequeue:留下队列里的张量个数,能够保持随机打乱
      • 注意:批处理接收的tensow对象必须都是规定了shape,并且统一的对象
  • 文件阅读器创建
    • 文本阅读器
      • Reader = tf.TextLineReader()
        • 阅读文本,默认按行读取, 默认分隔符为,
    • 二进制文件阅读器
      • Reader = tf.FixedLengthRecordReader(record_bytes)
        • 阅读二进制文件,可以指定每次读取的字节数
        • record_bytes:整型,指定每次读取的字节数
    • TFRecord文件阅读器
      • Reader  = tf.TFRecordReader()
        • 读取TfRecords文件
    • 图片阅读器
      • Reader = tf.WholeFileReader()   
        • 图片阅读器
  • 文件阅读器的方法
    • Reader.read(file_queue)    从队列中读取指定数量的内容
    • 返回一个Tensors元组(key文件名字,value默认的内容(行或者字节或者图片), tensow类型)
  • 文件内容解码器
    • 文本文件解码器
      • tf.decode_csv(records, record_defaults=None, field_delim = None, name = None)
        • 由于从文件中读取的是字符串,需要函数去解析这些字符串到张量
        • record_defaults:  字段的默认值,比如[[1],[],['string']],不指定类型(设为空[])也可以
        • field_delim:  默认分割符”,”
        • records:  tensor型字符串,每个字符串是csv中的记录行
    • 二进制文件解码器
      • tf.decode_raw(bytes, out_type, little_endian=None, name = None)   
        • 将字符串类型的二进制数据, 转换为uint8  或者int32类型的数据
        • 与函数tf.FixedLengthRecordReader搭配使用,将字符串表示的二进制读取为uint8格式
        • bytes:   读取到的bytes字节内容
        • out_type:  读取后输出的类型
    • 图片文件解码器
      • 解码方法
        • tf.image.decode_jpeg(content, out_type)
          • 配合tf.WholiFileReader 使用,
          • 将JPEG编码的图像解码为uint8张量
          • return:uint8张量,3-D形状[height, width, channels]
        • tf.image.decode_png(contents, out_type)
          • 将PNG编码的图像解码为uint8或uint16张量
          • return:张量类型,3-D形状[height, width, channels]
      • 图片的基本操作api
        • tf.image.resize_images(images, size)     更改图片尺寸(只能更改尺寸, 不能更改通道)
          • images:4-D形状[batch, height, width, channels]或3-D形状的张量[height, width, channels]的图片数据
          • size:1-D int32张量:new_height, new_width,图像的新尺寸
          • return:   返回4-D格式或者3-D格式图片的tensow类型,并且tensow对象的shape对应通道数为? 不固定类型
    • TFRecords文件解码器
      • feature = tf.parse_single_example(value,features={
      •     "image": tf.FixedLenFeature([], tf.string),
      •     "label": tf.FixedLenFeature([], tf.int64)
      • })      根据协议将TFRecords的内容转化为feature
      • image = feature['image']        通过feature可以读取里面的特征值
      • label = feature['label']
  • 文件存储器(TFRecords文件存储器)
    • 建立TFRecord存储器
      • Saver = tf.python_io.TFRecordWriter(path)   建立存储器
        • path:  TFRecords文件存储的路径
    • 存储器的方法
      • write(record):  向文件中写入一个字符串记录(下面介绍)
      • close():  关闭文件写入器
  • TFRecords存储的字符串记录
    • 构造样本的Example协议块
      • example = tf.train.Example(features=None)     创建协议块
        • features:  tf.train.Features类型的特征实例
    • feature 特征实例的创建
      • feature 的创建
        • feature = tf.train.Features(feature=None)     构建每个样本的信息键值对
      • feature:  字典数据,  key为要保存的名字,value为tf.train.Feature实例
    • feature的value的创建
      • tf.train. Int64List(value=[Value])
      • tf.train. BytesList(value=[Bytes])
      • tf.train. FloatList(value=[value])
  • TFRecords的字符串记录创建实例
    • example = tf.train.Example(features=tf.train.Features(feature={
      • "image": tf.train.Feature(bytes_list=tf.train.BytesList(value=[image])),
      • "label": tf.train.Feature(int64_list=tf.train.Int64List(value=[label]))
    • }))
  • 文本文件读取代码示例
  • 图片文件的读取示例
  • 二进制文件读取示例
  • TFRecords文件存储示例
  • TFRecords文件读取示例


刘小恺(Kyle) wechat
如有疑问可联系博主