Tensorflow框架学习记录–day01–文件读取通用流程以及案例:读取狗的图片
(相关代码和图片资料若有需要可以私信)
有三种获取数据到Tensorflow程序的方法
1、QueueRunner:基于队列的输入管道从Tensorflow图形开头的文件中读取数据。
 2、Feeding:运行每一步时,Python代码提供数据。
 3、预加载数据:Tensorflow图中的张量包含所有数据(对于小数据集)
 
 
 


 第一阶段:构造文件名队列
 第二阶段:读取与解码
 第三阶段:批处理
(注:这些操作需要启动运行这些队列操作的线程,以便我们在进行文件读取的过程中能够顺利进行入队出队操作。)
1 构造文件名队列
将需要读取的文件的文件名放入文件名队列。
	tf.train.string_input_producer(string_tensor, shuffle=True)
		string_tensor:含有文件名+路径的1阶张量
		num_epochs:过几遍数据,默认无限过数据
		return:文件队列
2 读取与解码
从队列当中读取文件内容,并进行解码操作
1)读取文件内容
阅读器默认每次只读取一个样本
具体来说:
 文本文件默认一次读取一行,图片文件默认一次读取一张图片,二进制文件一次读取指定字节数(最好是一个样本的字节数),TFRecords默认一次读取一个example。
-  tf.TextLineReader: 阅读文本文件逗号分隔值(CSV)格式,默认按行读取 
 return:读取器实例
-  tf.WholeFileReader:用于读取图片文件 return:读取器实例 
-  tf.FixedLengthRecordReader(record_bytes):二进制文件 要读取每个记录是固定数量字节的二进制文件 
 record_bytes:整型,指定每次读取(一个样本)的字节数
 return:读取器实例
-  tf.TFRecordReader:读取TFRecords文件 return:读取器实例 
注:
 1、它们有共同的读取方法:read(file_queue),并且都会返回一个Tensor元组(key文件名字,value默认的内容(一个样本))
 2、由于默认只会读取一个样本,所以如果想要进行批处理操作,需要使用tf.train.batch或tf.train.shuffle_batch进行批处理操作,便于之后指定每批次多个样本的训练。
2)内容解码
读取不同类型的文件,也应该对读取到底不同类型的内容进行相对应的解码操作,解码成统一的Tensor格式
-  tf.decode_csv:解码文本文件内容 
-  tf.image.decode_jepg(contents) 讲JEPG编码的图像解码为uint8张量 
 return:uint8张量,3-D形状(height,width,channels)
-  tf.image.decode_png(contents) 将PNG编码的图像解码为uint8张量 
 return:张量类型,3-D形状(height,width,channels)
-  tf.decode_raw:解码二进制文件内容 与tf.FixedLengthRecordReader搭配使用,二进制读取为uint8类型 
注:解码阶段,默认所有的内容都解码成uint8类型,如果之后需要转换成指定类型,则可使用tf.cast()进行相应转换。
3)批处理
解码之后,可以直接获取默认的一个样本内容了,但如果想要获取多个样本,需要加入到新的队列进行批处理。
tf.train.batch(tensor,batch_size,num_threads=1,capacity=32,name=None)
 读取指定大小(个数)的张量
-  tensors:可以是包含张量的列表,批处理的内容放到列表当中 
-  batch_size:从队列中读取的批处理大小 
-  num_threads:进入队列的线程数 
-  capacity:整数,队列中元素的最大数 
-  return:tensors 
tf.train.shuffle_batch
线程操作
以上用到的队列都是tf.train.QueueRunner对象。
每个QueueRuunner都负责一个阶段,tf.trian.start.queue_runners函数会要求图中每个QueueRunner启动它的运行队列操作的线程。(这些操作需要在会话中开启)
tf.train.start_queue_runners(sess=None, coord=None)
 收集图中所有的队列线程,默认同时启动线程
- sess:所在的会话
- coord:线程协调器
- return:返回所有线程
tf.tarin.Coordinator()
 线程协调员,对线程进行管理和协调
-  request_stop():请求停止 
-  should_stop():询问是否结束 
-  join(threads=None,stop_grace_period_secs=120):回收线程 
-  return:线程协调员实例 
图像基本知识
回忆:之前在特征抽取中讲过如何将文本处理成数值。
 思考:如何将图片文件转换成机器学习算法能够处理的数据?
 我们经常接触到的图片有两种,一种是黑白图片(灰度图),另一种是彩色图片。
 
1 图片三要素
组成一张图片特征值是所有的像素值,有三个维度:图片长度、图片宽度、图片通道数。
图片的通道数是什么?
描述一个像素点,如果是灰度图,那么只需要一个数值来描述它,就是单通道。
如果一个像素点,有RGB三种颜色来描述它,就是三通道。
 
2 张量形状
在tensorflow中如何用张量表示一张图片呢?
一张图片可以被表示成一个3D张量,即其形状为(height,width,channel),height就表示高,width就表示宽,channel表示通道数,我们会经常遇到3D和4D的表示
单个图片:[height,width,channel]
多个图片:[batch,height,width,channel],batch表示一个批次的张量数量
图片特征值处理
为什么要缩放图片到统一大小?
在进行图像识别的时候,每个图片样本的特征数量要保持相同,所以需要将所有图片张量大小统一转换。
另一方面,如果图片的像素量太大,通过这种方式适当减少像素的数量,减少训练的计算开销。
tf.image.resize_images(images,size)
-  缩小放大图片 
-  images:4-D形状[batch,height,width,channels]或3-D形状的张量[height,width,channels]的图片数据 
-  size:1-Dint32张量:new_height,new_width,图像的新尺寸 
-  返回4-D格式或者3-D格式图片 
数据格式
- 存储:uint8
- 矩阵计算:float32(提高精度)
案例:狗图片读取

 读取流程分析:
- 构造图片文件名队列
- 读取图片数据并进行解码
- 处理图片数据形状,加入批处理队列
- 开启会话线程运行
完整代码展示:
import tensorflow as tf
import os
tf.compat.v1.disable_eager_execution()
def picture_read(file_list):
    """
    狗图片读取案例
    """
    # 1、构造文件名队列
    file_queue = tf.compat.v1.train.string_input_producer(file_list)
    # 2、读取与解码
    # 读取阶段
    reader = tf.compat.v1.WholeFileReader()
    # key是文件名,value是一张图片的原始编码形式
    key, value = reader.read(file_queue)
    # 解码阶段
    image = tf.compat.v1.image.decode_jpeg(value)
    print("image:\n", image)
    # 图像的形状、类型修改
    image_resized = tf.compat.v1.image.resize_images(image, [200, 200])
    print("image_resized:\n", image_resized)
    # 静态形状修改-修改通道数为3
    image_resized.set_shape(shape=[200, 200, 3])
    print("image_resized:\n", image_resized)
    # 3、批处理
    image_batch = tf.compat.v1.train.batch([image_resized], batch_size=100, num_threads=1, capacity=100)
    print("image_batch:\n", image_batch)
    # 开启会话
    with tf.compat.v1.Session() as sess:
        # 开启线程
        # 线程协调员
        coord = tf.train.Coordinator()
        # 开启线程
        threads = tf.compat.v1.train.start_queue_runners(sess=sess, coord=coord)
        key_new, value_new, image_new, image_resized_new = sess.run([key, value, image, image_resized])
        print("key_new:\n", key_new)
        print("value_new:\n", value_new)
        print("image_new:\n", image_new)
        print("image_resized_new:\n", image_resized_new)
        # 回收线程
        coord.request_stop()
        coord.join(threads)
    return None
if __name__ == "__main__":
    # 构造路径+文件名的列表
    filename = os.listdir("./dog")
    # 拼接路径+文件名
    file_list = [os.path.join("./dog/", file) for file in filename]
    # print(file_list)
    picture_read(file_list)










