读取图片文件
# 有三种获取数据到TensorFlow程序的方法:
# 1. QueueRunner:基于队列的输入管道从TensorFlow图形开头的文件中读取数据。
# 2.Feeding:运行每一步时,Python代码提供数据。
# 3.预加载数据:TensorFlow图中的张量包含所有数据(对于小数据集)。
文件读取流程:
第一阶段构造文件名队列
第二阶段读取与解码
第三阶段批处理 注:这些操作需要启动运行这些队列操作的线程,以便我们在进行文件读取的过程中能够顺利进行入队出队操作。
一般数据文件格式有文本、excel和图片数据。那么TensorFlow都有对应的解析函数,除了这几种。还有TensorFlow指定的文件格式
# 3.1 文件读取流程
# 多线程 + 队列
# 3.1.1 文件读取流程
# 1)构造文件名队列
# file_queue = tf.train.string_input_producer(string_tensor,shuffle=True)
# 2)读取与解码
# 文本:
# 读取:tf.TextLineReader()
# 解码:tf.decode_csv()
# 图片:
# 读取:tf.WholeFileReader()
# 解码:
# tf.image.decode_jpeg(contents)
# tf.image.decode_png(contents)
# 二进制:
# 读取:tf.FixedLengthRecordReader(record_bytes)
# 解码:tf.decode_raw()
# TFRecords
# 读取:tf.TFRecordReader()
# key, value = 读取器.read(file_queue)
# key:文件名
# value:一个样本
# 3)批处理队列
# tf.train.batch(tensors, batch_size, num_threads = 1, capacity = 32, name=None)
# 手动开启线程
# tf.train.QueueRunner()
# 开启会话:
# tf.train.start_queue_runners(sess=None, coord=None)
1.文件队列生成函数
tf.train.string_input_producer(string_tensor, num_epochs=None, shuffle=True, seed=None, capacity=32, name=None)
string_tensor:含有文件名+路径的1阶张量 [这里传一个文件路径列表就可以]
num_epochs:过几遍数据,默认无限过数据 [一直过道训练出你满意的结果,无线循环,结果会越来越拟合]
return文件队列
产生指定文件张量
2.文件阅读器类
class tf.TextLineReader
阅读文本文件逗号分隔值(cSV)格式,默认按行读取
return:读取器实例
阅读文本文件逗号分隔值(CSV)格式
tf.FixedLengthRecordReader
return:读取器实例
tf.FixedLengthRecordReader(record_bytes):二进制文件
要读取每个记录是固定数量字节的二进制文件
record_bytes:整型,指定每次读取(一个样本)的字节数o return:读取器实例
要读取每个记录是固定数量字节的二进制文件
tf.TFRecordReader
读取TFRecords文件
return:读取器实例
解码
2)内容解码 读取不同类型的文件,也应该对读取到的不同类型的内容进行相对应的解码操作,解码成统一的Tensor格式
tf.decode_csv:解码文本文件内容
tf.image.decode _jpeg(contents)
将JPEG编码的图像解码为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类型
将CSV转换为张量,与tf.TextLineReader搭配使用
tf.decode_raw(bytes,out_type,little_endian = None,name = None)
将字节转换为一个数字向量表示,字节为一字符串类型的张量,与函数tf.FixedLengthRecordReader
搭配使用
# 读取CSV格式文件
# 1、构建文件队列
# 2、构建读取器,读取内容
# 3、解码内容
# 4、现读取一个内容,如果有需要,就批处理内容
import tensorflow as tf
import os
def readcsv_decode(filelist):
# 把文件目录和文件名合并
flist = [os.path.join("./csvdata/",file) for file in filelist]
# 构建文件队列
file_queue = tf.train.string_input_producer(flist,shuffle=False)
# 构建阅读器,读取文件内容
reader = tf.TextLineReader()
key,value = reader.read(file_queue)
record_defaults = [["null"],["null"]] # [[0],[0],[0],[0]]
# 解码内容,按行解析,返回的是每行的列数据
example,label = tf.decode_csv(value,record_defaults=record_defaults)
# 通过tf.train.batch来批处理数据
example_batch,label_batch = tf.train.batch([example,label],batch_size=9,num_threads=1,capacity=9)
with tf.Session() as sess:
# 线程协调员
coord = tf.train.Coordinator()
# 启动工作线程
threads = tf.train.start_queue_runners(sess,coord=coord)
# 这种方法不可取
# for i in range(9):
# print(sess.run([example,label]))
# 打印批处理的数据
print(sess.run([example_batch,label_batch]))
coord.request_stop()
coord.join(threads)
return None
if __name__=="__main__":
filename_list = os.listdir("./csvdata")
readcsv_decode(filename_list)
图片数据
组成一张图片特征值是所有的像素值,有这么几个要素。图片长度、图片宽度、图片通道数。什么是图片的通道数呢,描述一个像素点,如果是灰度,那么只需要一个数值来描述它,就是单通道。如果一个像素点,有RGB三种颜色来描述它,就是三通道。那所以灰度图片:单通道;彩色图片:三通道
假设一张彩色图片的长200,宽200,通道数为3,那么总的像素数量为200x200x3
张量形状
读取图片之后,怎么用张量形状来表示呢。一张图片就是一个3D张量,[height, width, channel],height就表示高,width表示宽,channel表示通道数。我们会经常遇到3D和4D的表示
单个图片:[height, width, channel]
多个图片(4D):[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-D int32张量:new_height, new_width,图像的新尺寸
返回4-D格式或者3-D格式图片
数据格式
存储:uint8(节约空间)
矩阵计算:float32(提高精度)
import tensorflow as tf
import os
def picture_read(filename_list):
# 1. 构造文件名队列
file_queue = tf.train.string_input_producer(filename_list)
# 2. 读取与解码
reader = tf.WholeFileReader()
# key 文件名 value 一张图片的原始编码形式
key, value = reader.read(file_queue)
# 解码阶段
image = tf.image.decode_jpeg(value)
# 图像的形状类型修改,改成统一的宽高
image_resized = tf.image.resize_images(image, [200, 200])
# 静态形状修改,添加通道数
image_resized.set_shape(shape=[200, 200, 3])
image_batch = tf.train.batch([image_resized], batch_size=10, num_threads=1, capacity=100)
print(image_batch)
with tf.Session() as sess:
# 开启县城
# 线程协调员
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
print(image_resized.shape)
print(image_resized.eval())
# 回收线程
coord.request_stop()
coord.join(threads)
if __name__ == "__main__":
# 构造路径+ 文件名列表
filename = os.listdir("dog")
filename_list = [os.path.join('dog', i) for i in filename]
picture_read(filename_list)
二进制文件
import tensorflow as tf
import os
class Cifar():
def __init__(self):
# 设置图像大小
self.height = 32
self.width = 32
self.channel = 3
# 设置图像字节数 一张图片大小 是 3*32*32
self.image = self.height * self.width * self.channel
self.label = 1
self.sample = self.image + self.label
def read_and_decode(self, file_list):
# 1. 构造文件名队列
file_queue = tf.train.string_input_producer(file_list)
# 2. 读取与解码
reader = tf.FixedLengthRecordReader(self.sample)
# key 文件名 value 一个样本
key, value = reader.read(file_queue)
# 解码阶段
decoded = tf.decode_raw(value, tf.uint8) # 得到一张图片的label数字和三通道数字 [1+ 3*32*32] 一维张量
# 把目标值和特征值切开
label = tf.slice(decoded, [0], [self.label])
image = tf.slice(decoded, [self.label], [self.image])
# 调整图片形状
image_reshaped = tf.reshape(image, shape=[self.channel, self.height, self.width]) # 3*32*32
# 但是tensorflow 的世界里想要 32*32*3这种形式的图片 我们要把这个三维张量的坐标轴转换一下
image_transposed = tf.transpose(image_reshaped, [1, 2, 0]) # 32*32 *3
# 调整图像类型
image_cast = tf.cast(image_transposed, dtype=tf.float32)
# 3.批处理
label_batch, image_batch = tf.train.batch([label, image_cast], batch_size=100, num_threads=1, capacity=100)
with tf.Session() as sess:
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
key_new, value_new = key.eval(), value.eval()
print("key_new:\n", key_new)
print("value_new:\n", value_new)
label_value, image_value = label_batch.eval(), image_batch.eval()
# 回收线程
coord.request_stop()
coord.join(threads)
return label_value, image_value
if __name__ == "__main__":
cifar = Cifar()
file_name = os.listdir('cifar-10-batches-bin')
# 构造问及高明路径列表
file_list = [os.path.join('cifar-10-batches-bin', file) for file in file_name if file[-3:] == 'bin']
cifar.read_and_decode(file_list)
TFRecords文件读取
TFRecords其实是一种二进制文件,虽然它不如其他格式好理解,但是它能更好的利用内存,更方便复制和移动,并且不需要单独的标签文件。
使用步骤︰
1)获取数据 2)将数据填入到 Example协议内存块(protocol buffer) 3)将协议内存块序列化为字符串,并且通过 tf.python_io.TFRecordwriter写入到TFRecords文件。
文件格式 *.tfrecords
import tensorflow as tf
def read_tfrecords():
# 1. 构造文件名队列
file_queue = tf.train.string_input_producer(["cifar10.tfrecords"])
# 读取和解码
# 读取
reader = tf.TFRecordReader()
key, value = reader.read(file_queue)
# 解析example
feature = tf.parse_single_example(value, features={
"image": tf.FixedLenFeature([], tf.string),
"label": tf.FixedLenFeature([], tf.int64) # 这里的数据类型要与之前创建的时候保持一直
})
image = feature["image"] # 图片是二进制,要解码成张量[32,32,3]
label = feature["label"]
# 解码成一维张量
image_decode = tf.decode_raw(image, tf.float32) # 这里的数据类型一定要与之前一致是tf.float32 教程里是uint 8 搞混了,总之一定要跟以前一样,否则形状转化不来
# 改变形状
img_reshaped = tf.reshape(image_decode, [32, 32, 3])
# 解码
# 3. 构造批处理队列
image_batch, label_batch = tf.train.batch([img_reshaped, label], batch_size=2, num_threads=2, capacity=100)
print("image_batch", image_batch)
print('label_batch:', label_batch)
# 开启回话
with tf.Session() as sess:
# 开启县城
coord = tf.train.Coordinator()
threads = tf.train.start_queue_runners(sess=sess, coord=coord)
for i in range(4):
# print(img_reshaped.eval())
print('第%d批label:'%(i+1),label_batch.eval())
# 回收资源
coord.request_stop()
coord.join(threads)