在pandas中也可以读取数据,但是他存在的问题(仅仅以我们学过的角度来看)有:
1、一次读取数据,消耗内存
2、一次性进行训练
而在tensorflow中提供多线程,并行的执行任务,队列(数据的共享),文件(tfrecords)的方式读取数据。来提高解析速度。
你可能听过在Python中没有真正的多线程,原因是python存在GIL锁。但是你可能还不知道在numpy中释放了GIL锁,而机器学习库都是基于numpy的。
因此在学习tensorflow读取数据欠还要了解队列和线程。
队列和线程(tensorflow中)
队列
在tensorflow中对队列进行了封装:
tf.FIFOQueue(capacity,dtypes,name='info_queue')
# 前进先出队列,按顺序出队列
capacity:整数,可能存储此队列的元素上限
简单队列Demo:
# 1、定义队列
# 最多放5个数据,类型为float32
Q = tf.FIFOQueue(5,tf.float32)
# 放入一些数据,这里存放列表写成[[1,2,3,4,5],],防止认为是张量
e_many = Q.enqueue_many([[1,2,3,4,5],])
# 取出数据,乘以2
out_q = Q.dequeue()
data = out_q*2
# 再放入队列
en_q = Q.enqueue(data)
with tf.Session() as sess:
# 初始化队列
sess.run(e_many)
# 处理数据100次,这里只用运行en_q,就会运行
# 去除数据,*2,放入队列这三步操作,Tensorflow中操作具有依赖性
# 运行en_q,en_q依赖data,data依赖out_q
for i in range(100):
sess.run(en_q)
# 取数据
for i in range(Q.size().eval()):
print(sess.run(out_q))
tf.RandomShuffleQueue:随机出队列
用到的时候再说。
线程
叫做队列管理器,但是是创建线程的作用。
tf.train.QueueRunner(queque,enqueue_ops=None)
queue: 一个队列
enqueue_ops:添加线程的队列操作列表,[]*2代表创建2个线程,[]中写操作
在sess中启动线程
create_threads(sess,coord=None,start=False)
coord:线程协调器,当结束后回收子线程
start:True启动线程,如果为False,还需要条用start()启动线程。
Demo实例:
# 模拟实现子线程读取数据,而主线程进行训练,二者并行
# 定义一个队列
Q = tf.FIFOQueue(1000,tf.float32)
# 定义子线程需要做的事情 循环加1 放入队列
var = tf.Variable(0.0)
# 每次加1,如果不使用assign_add,每次都是0+1会一直是1
data = tf.assign_add(var,1.0)
# 放入队列
en_q = Q.enqueue(data)
# 定义队列管理器op,指定线程做什么
qr = tf.train.QueueRunner(Q,enqueue_ops=[en_q]*2)
# 初始化变量op
init_op = tf.global_variables_initializer()
with tf.Session() as sess:
# 初始化变量
sess.run(init_op)
# 开启线程协调器,当主线程结束回收子线程
coord = tf.train.Coordinator()
# 开启子线程
threads = qr.create_threads(sess,coord=coord,start=True)
# 主线程读取数据,训练
for i in range(1000):
print(sess.run(Q.dequeue()))
# 回收子线程
coord.request_stop()
coord.join(threads)
注意:其实以上过程以后都不需要自己写。但是要了解。
文件读取
文件读取流程
1、构建一个文件队列
2、读取队列内容
3、解码
4、批处理
文件读取api介绍
构造文件队列
tf.train.string_input_producer(string_tensor)
string_tensor:含有文件名的1阶张量
读取文件内容(不同文件,读取api不同)
文本,csv文件读取:tf.TextLineReader,按行读取
二进制文件:tf.FixedLengthRecordReader(record_bytes)
record_bytes:整型,指定每次读取的字节数
Tfrecords文件:tf.TFrecordReader
解码
解码csv文件:tf.decode_csv(records,record_defaults=None,dileld_delim=None)
将csv转换成张量,和tf.TextLineReader搭配使用。
records:读取的内容
dileld_delim:分隔符,默认为,
record_defaults:张量类型,设置缺少默认值.
解码二进制:tf.decode_raw()
csv文件读取Demo
def csvread(filelist):
# 构造文件队列,返回的是一个队列
file_queue = tf.train.string_input_producer(filelist,shuffle=False)
# 构造csv阅读器读取队列数据,默认按照行读取
reader = tf.TextLineReader()
# 得到读取的数据key是读取的文件名,value是读取的数据
key, value = reader.read(file_queue)
# 解码
# record_defaults指定读取的文件每一列的类型
# 比如csv的第一列数据是1,2,3,第二列为python,java,C
# 也就是第一列为float,第二列为string
# record_defaults就是指定每列的类型,和默认值
# 1.0为float,说明数据第一列为float类型,默认值是1
# ,""为string类型,说明第二列为string类型,默认值是None
records = [[1.0],["None"]]
# 返回为每个列的每个值
rad_num,label = tf.decode_csv(value,record_defaults=records)
# 读取多个数据,批处理
# 参数一:批处理的值
# 参数二:每批次读取多少数据
# 参数三:开启多少线程
# 参数四:队列的大小
rad_num_batch,label_batch = tf.train.batch([rad_num,label],batch_size=9,num_threads=1,capacity=9)
return rad_num_batch,label_batch
if __name__ == "__main__":
# 自己创建csv文件,列数不必太多
# 将文件放入列表
import os
# 去除警告消息
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '2'
# os.listdir:返回该目录下文件名的列表
file_name = os.listdir("./csvdata/")
# 拼接路径
filelist = [os.path.join("./csvdata",file) for file in file_name]
rad_num_batch,label_batch = csvread(filelist)
# 开启会话
with tf.Session() as sess:
# 定义线程协调器
coord = tf.train.Coordinator()
# 开启读取文件的线程,不用上面那样麻烦了
threads = tf.train.start_queue_runners(sess, coord=coord)
# 打印读取的内容
print(sess.run([rad_num_batch,label_batch]))
# 回收线程
coord.request_stop()
coord.join(threads)
读取图像和二进制下篇见。