Python_ML-Day05: TensorFlow的线程队列与IO操作、TFRecords文件的存取

Python_ML-Day5: TensorFlow的线程队列与IO操作、TFRecords文件的存取

1.TensorFlow 队列
    - 在训练样本的时候,希望读入的训练样本是有序的
    - 考虑使用队列机制: 先进先出
    - tf.FIFOQueue(capacity, dtypes, name='fifo_queue')
        1.先进先出队列
        2.参数
            - capacity:整数。可能存储在此队列中的元素数量的上限
            - dtypes:DType对象列表。长度dtypes必须等于每个队列元
            素中的张量数,dtype的类型形状,决定了后面进队列元素形状
        4.方法
            - dequeue(name=None)
            - enqueue(vals, name=None):
            - enqueue_many(vals, name=None):vals列表或者元组
            返回一个进队列操作
            - size(name=None): 查看队列的元素个数
    - tf.RandomShuffleQueue 随机出队列

2.队列管理器
    - 创建一个QueueRunner:tf.train.QueueRunner(queue, enqueue_ops=None)
    - 参数说明:
        1. queue:A Queue
        2. enqueue_ops:添加线程的队列操作列表,[queue1, queue2...]*2,指定两个线程
    - 创建好队列管理器之后,在sess中开启
        1. create_threads(sess, coord=None,start=False)
            - start:布尔值,如果True启动线程;如果为False调用者
                必须调用start()启动线程
            - coord:线程协调器,后面线程管理需要用到

3.线程协调器
    - 线程协调员,实现一个简单的机制来协调一组线程的终止
    - tf.train.Coordinator()
    - 方法:
        1. request_stop(): 强制停止
        2. should_stop() 检查是否要求停止
        3. join(threads=None, stop_grace_period_secs=120) 等待线程终止
        4.return:线程协调员实例

4.文件读取
    - 流程
        1. 构造一个文件队列
            - 将输出字符串(例如文件名)输入到管道队列
            - tf.train.string_input_producer(string_tensor,,shuffle=True)
            - 参数说明:
                1.string_tensor    含有文件名的1阶张量
                2.num_epochs:过几遍数据,默认无限过数据
                3.return:具有输出字符串(文件名)的队列
        2. 读取队列的中的文件的内容,解码[默认只读取一个样本]
            - 读取read:
                1. csv文件: 读取一行
                2. 二进制文件: 读取指定一个样本的bytes的字节
                3. 图片文件: 按一张一张的读取
            - 根据文件格式选择合适的文件阅读器,并返回一个阅读器Reader:
                1. tf.TextLineReader
                    - 阅读文本文件。逗号分割 csv文件。默认按行读取
                2. tf.FixedLengthRecordReader(record_bytes)
                    - 读取二进制文件,每次读取固定字节数量
                    - record_bytes: 整型,指定每次读取的字节数
                3. tf.TFRecordReader
                    - 读取TfRecords文件
            - Reader.read(file_queue)
                1. 读取文件队列中的文件内容
                2. 返回一个Tensors元组,key文件名字,value为文件内容
            - 解码
                1. 由于从文件中读取的是字符串,需要函数去解析这些字符串到张量
                2. 将CSV转换为张量,与tf.TextLineReader搭配使用
                    - tf.decode_csv(records,record_defaults=None,field_delim = None,name = None)
                    - records:tensor型字符串,每个字符串是csv中的记录行,Reader中的Value
                    - field_delim:默认分割符”,”
                    - record_defaults:参数决定了所得张量的类型. 逗号分割的每一列的类型可能都不同,通过此参数指定. 当值为空时,也可以通过此参数指定默认值
                3.将字节转换为一个数字向量表示,字节为一字符串类型的张量,与函数tf.FixedLengthRecordReader搭配使用,二进制读取为uint8格式
                    - tf.decode_raw(bytes,out_type,little_endian = None,name = None)
        3. 批处理
            - 每次读取一个样本,然后加入到一个批次
            - tf.train.batch(tensors,batch_size,num_threads = 1,capacity = 32,name=None)
                1. 读取指定大小(个数)的张量
                2. tensors:可以是包含张量的列表
                3. batch_size:从队列中读取的批处理大小 - 决定每批次取的数据条数
                4. num_threads:进入队列的线程数
                5. capacity:整数,队列中元素的最大数量
                6. return:tensors
            - tf.train.shuffle_batch(tensors,batch_size,capacity,min_after_dequeue,    num_threads=1,) 
                1. 乱序读取指定大小(个数)的张量
                2. min_after_dequeue:留下队列里的张量个数,能够保持随机打乱
        4. 子线程读取文件形成批次,主线程从批次中取数据去训练模型

    - 开启线程的另外一种操作
        1. 收集所有图中的队列线程,并启动线程
        2. tf.train.start_queue_runners(sess=None,coord=None)
            - sess:所在的会话中
            - coord:线程协调器
            - return:返回所有线程队列

5.图片的读取
    - 图片三要素: 长度,宽度,通道数
        1. 长度,宽度 - 像素个数
        2. 单通道 - 灰度值 / 三通道 - RGB值
    - 三要素与张量的关系
        1. [height,width,channels]
    - 图片的基本操作
        1. 每一个样本必须保持特征值数量一致
        2. 所有的图片,要统一特征的数量。像素一样。改变长宽
        3. 缩小图片 - tf.image.resize_image(images, size)
            - images:4-D形状[batch, height, width, channels]或3-D形状的张量[height, width, channels]的图片数据
            - size:1-D int32张量:new_height, new_width,图像的新尺寸
            - 返回4-D格式或者3-D格式图片
    - 图片读取器 tf.WholeFileReader
        1. 将文件的全部内容作为值输出的读取器
        2. rerurn 读取器实例
        3. 方法:
            - read(file_queue)
            - 输出 key value
    - 图片解码器
        1. tf.image.decode_jpeg(contents)
            - 将JPEG编码的图像解码为uint8张量
            - return:uint8张量,3-D形状[height, width, channels]
        2. tf.image.decode_png(contents)
            - 将PNG编码的图像解码为uint8或uint16张量
            - return:张量类型,3-D形状[height, width, channels]
    - 图片批处理案例流程
        1. 构造图片文件队列
        2. 构造图片阅读器
        3. 读取图片数据,解码
        4. 处理图片数据,大小

6. 二进制文件读取
    - 二进制数据下载地址:http://www.cs.toronto.edu/~kriz/cifar.html
    - 二进制文件读取器
        1. reader = tf.FixedLengthRecordReader(record_bytes)
            - record_bytes: 每条记录的字节数
    - 二进制文件解码
        1. label_image = tf.decode_raw(value, tf.uint8)
    - 案例流程
        1. 构造文件队列
        2. 新建二进制文件阅读器,读取文件
        3. 新建二进制文件解码,解码成utf-8文件[每个utf-8的值,对应一个字节]
        4. 图片切分
            - 前1个字节,表示label
            - 后32*32*3个字节,表示image
            - tf.slice()
        5.批处理
        6.多线程处理

7.TFRecords文件
    - TFRecords是Tensorflow设计的一种内置文件格式,是一种二进制文件,它能更好的利用内存,更方便复制和移动
    - 为了将二进制数据和标签(训练的类别标签)数据存储在同一个文件中
    - 文件格式:*.tfrecords
    - 写入文件内容:Example协议块,类字典格式
    - 存储tfrecords文件
        1. 建立存储器,写入器
            - tf.python_io.TFRecordWriter(path)
            - path: tf文件存储路径
            - return 写入器
            - 方法:
                1. write(record): 向文件中写入一个字符串记录record
                    - 此字符串record为一个序列化的example
                    - 使用 Example.SerializeToString()
                2. close(): 关闭写入器
        2. 为每个样本构造协议块Example
            - 构建单个特征
                1.tf.train.Feature(**options)
                    - **options:一个指定格式的列表
                    - 指定格式有Int64,Bytes,Float:
                        1.tf.train. Int64List(value=[int])
                        2.tf.train. BytesList(value=[string])
                        3.tf.train. FloatList(value=[float])
                    - value: 为具体的数值类型的值
                    - 注:
                        1. 比如图片信息:value = [img_tensor.eval().tostring()]
                        2. 比如label int值:value= [int(label_tensor.eval())]

            - 为每个样本构建信息键值对
                1. tf.train.Features(feature=None)
                2. 参数说明:
                    - feature:字典数据,key为要保存的名字,value为tf.train.Feature实例
                3. 返回值:
                    - return:Features类型
            - 构造每个样本的Example协议块,提供给写入器写入record
                1. tf.train.Example(features=None)
                2. 参数说明:
                    - features:tf.train.Features类型的特征实例
                3. 返回值:
                    - return:example格式协议块
        3. 序列化Example
            - example.SerializeToString()
            - 返回可存储的序列化的Example
        4. 写入
            writer.write(example.SerializeToString())

    - 读取tfrecords文件
        1. 构建文件队列
        2. 构造文件阅读器,读取example
            tf.TFRecordReader()
        3. 解析TFRecords的example协议内存块
            - 解析一个单一的Example原型
                1. tf.parse_single_example(serialized,features=None,name=None)
                2. 参数说明:
                    - serialized:标量字符串Tensor,一个序列化的Example
                    - features模板:dict字典数据,键为读取的名字,值为FixedLenFeature
                    - return:一个键值对组成的字典,键为读取的名字
            - tf.FixedLenFeature(shape,dtype)
                - shape:输入数据的形状,一般不指定,为空列表
                - dtype:输入数据类型,与存储进文件的类型要一致,类型只能是float32,int64,string
        4. 解码: 如果读取的string,需要解码。其他不需要解码
            tf.decode_raw(value,tf.unit8)

8.源码
    import os
    import tensorflow as tf

    def fifo():
        """
        模拟队列操作
        :return:
        """
        # 1. 定义队列
        Q = tf.FIFOQueue(3, tf.float32)
        en_Q = Q.enqueue_many([[0.1, 0.2, 0.3]])
        # 2. 定义读取数据过程
        out_dt = Q.dequeue()
        de_Q = Q.enqueue(out_dt + 1)
        # 3. 定义数据处理过程
        # 4. 处理数据再次入队列

        with tf.Session() as sess:
            # 执行队列初始化
            sess.run(en_Q)
            # 执行队列进出操作
            for i in range(100):
                sess.run(de_Q)
            # 训练数据
            for i in range(Q.size().eval()):
                print(sess.run(Q.dequeue()))


    def queueRunner():
        """
        队列管理器, 异步处理数据
        :return:
        """
        # 定义一个队列 1000
        Q = tf.FIFOQueue(1000, tf.float32)
        # 定义一个变量
        var = tf.Variable(0.0, tf.float32)
        # 变量自增 + 1
        data = var.assign_add(1)
        # 入队列
        en_q = Q.enqueue(data)
        # 定义一个队列管理器,去运行上述队列过程
        qr = tf.train.QueueRunner(Q, enqueue_ops=[en_q] * 2)
        # 初始化init_op
        init_op = tf.global_variables_initializer()
        with tf.Session() as sess:
            # 初始化op
            sess.run(init_op)
            # 创建并开启子线程,并制定协调员 -- 开启队列管理器
            coord = tf.train.Coordinator()
            threads = qr.create_threads(sess, coord=coord, start=True)
            # 主线程去读取数据,然后进行训练等操作
            for i in range(300):
                print(sess.run(Q.dequeue()))
            # 协调器向你发送停止请求
            coord.request_stop()
            # 协调器回收资源
            coord.join(threads)


    def readCSVFile():
        """
        读取csv文件
        :return:
        """
        # 1.找到文件目录,构造一个文件列表
        file_name = os.listdir("./data")
        file_path = [os.path.join('./data', file) for file in file_name]
        file = tf.constant(file_path)
        # 2.构造文件队列
        queue = tf.train.string_input_producer(file, shuffle=True)
        # 3.构造阅读器
        reader = tf.TextLineReader()
        key, value = reader.read(queue)
        # 4.解码
        # 每行记录分为两列,都是字符串格式,并且默认值分别为None和default
        records = [["None"], ["default"]]
        line1, line2 = tf.decode_csv(value, record_defaults=records)
        # 5.批处理
        line1_batch, line2_batch = tf.train.batch(tensors=[line1, line2], batch_size=9, num_threads=1, capacity=9)
        init_op = tf.global_variables_initializer()
        with tf.Session() as sess:
            sess.run(init_op)
            coord = tf.train.Coordinator()
            threads = tf.train.start_queue_runners(sess, coord=coord)
            print(sess.run([line1_batch]))
            coord.request_stop()
            coord.join(threads)


    def readImags():
        """
        读取图片文件
        :return:
        """
        # 1.找到文件目录,构造一个文件列表
        file_name = os.listdir("./image")
        file_path = [os.path.join('./image', file) for file in file_name]
        file = tf.constant(file_path)
        # 2.构造文件队列
        queue = tf.train.string_input_producer(file, shuffle=True)
        # 3.构造阅读器
        reader = tf.WholeFileReader()
        key, value = reader.read(queue)
        # 4.解码
        img = tf.image.decode_jpeg(value)
        # 处理图片的大小
        img_resize = tf.image.resize(img, [200, 200])
        # 设置形状固定[200,200,3]
        img_resize.set_shape([200, 200, 3])
        # 5.批处理
        img_batch = tf.train.batch(tensors=[img_resize], batch_size=10, num_threads=1, capacity=10)
        print(img_batch)
        init_op = tf.global_variables_initializer()
        with tf.Session() as sess:
            sess.run(init_op)
            coord = tf.train.Coordinator()
            threads = tf.train.start_queue_runners(sess, coord=coord)
            print(sess.run([img_batch]))
            coord.request_stop()
            coord.join(threads)


    # 定义命令行参数
    FLAGS = tf.app.flags.FLAGS
    tf.app.flags.DEFINE_string("cifar_dir", "./bin", "文件的目录")
    tf.app.flags.DEFINE_string("tfrecords_dir", "./tfrecords/a.tfrecords", "tfrecords文件的目录")


    class CifarRead(object):
        """
        完成读取二级制文件,写进tfRecords
        """

        def __init__(self, pathlist):
            self.path_list = pathlist
            self.bytes = 32 * 32 * 3 + 1

        def getRecord(self):
            # 创建队列
            queue = tf.train.string_input_producer(self.path_list)
            # 读取数据
            reader = tf.FixedLengthRecordReader(record_bytes=self.bytes)
            key, value = reader.read(queue)
            # 解码器
            label_image = tf.decode_raw(value, tf.uint8)
            print(label_image)
            # 切分图片和目标值
            label = tf.cast(tf.slice(label_image, [0], [1]), tf.int32)
            image = tf.slice(label_image, [1], [self.bytes - 1])
            print(label)
            print(image)
            reshape = tf.reshape(image, [32, 32, 3])
            print(reshape)
            # 批处理数据
            img_batch, label_batch = tf.train.batch([reshape, label], batch_size=10, num_threads=1, capacity=10)
            print(img_batch)
            print(label_batch)
            return img_batch, label_batch

        def write_to_tfrecords(self, img_batch, label_batch, batch_size=10):
            """
            将批量获取的数据,存储为tfrecords文件
            :param img_batch: 批量的图片信息
            :param label_batch: 批量的目标值信息
            :return: 返回要存储的tftrcord信息
            """
            # 1. 创建一个写入器
            writer = tf.python_io.TFRecordWriter(FLAGS.tfrecords_dir)
            # 2. 创建要写入的example实例
            # 2.1 因为是批次数据,所以要分割[因为有eval所以要在sess中运行]
            for i in range(batch_size):
                image = img_batch[i].eval().tostring()
                label = int(label_batch[i].eval()[0])
                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]))
                    }
                ))
                # 3. 序列化,写入
                writer.write(example.SerializeToString())
            # 写完关闭
            writer.close()

        def readTfrecords(self):
            # 构造文件队列
            queue = tf.train.string_input_producer([FLAGS.tfrecords_dir])
            # 创建阅读器
            reader = tf.TFRecordReader()
            # 读取文件
            key, value = reader.read(queue)
            # 读取的value 是string, example.SerializeToString(),所以需要反序列化parse_single_example
            features = tf.parse_single_example(value, features={
                "image": tf.FixedLenFeature(shape=[], dtype=tf.string),
                "label": tf.FixedLenFeature(shape=[], dtype=tf.int64)
            })
            # 读取的image是string, 所以,需要解码成utf-8
            image = tf.decode_raw(features["image"], tf.uint8)
            label = features["label"]
            print(image, label)
            # 固定图片的形状,方便后续的处理
            image_reshape = tf.reshape(image, [32, 32, 3])
            # 进行批处理
            img_batch, label_batch = tf.train.batch([image_reshape, label], batch_size=5, num_threads=1, capacity=10)
            return img_batch, label_batch


    if __name__ == '__main__':
        # 1. 找到文件,放入列表
        file_list = os.listdir(FLAGS.cifar_dir)
        path_list = [os.path.join(FLAGS.cifar_dir, file) for file in file_list if file[:5] == "data_"]
        print(path_list)
        cr = CifarRead(path_list)
        img_batch, label_batch = cr.readTfrecords()
        with tf.Session() as sess:
            coord = tf.train.Coordinator()
            threads = tf.train.start_queue_runners(sess, coord=coord)
            #
            print(sess.run([label_batch]))
            print(sess.run([label_batch]))
            print(sess.run([label_batch]))
            coord.request_stop()
            coord.join(threads)















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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值