详解tensorflow加载数据的多种方式

详解tensorflow加载数据的多种方式

  1. 预加载数据:用一个constant常量将数据集加载到计算图中(主要用于小数据集)

    预加载:将数据直接内嵌到Graph中,再把Graph传入Session中运行。当数据量比较大时,Graph的传输会遇到效率问题。

import tensorflow as tf
# 设计Graph
x1 = tf.constant([2, 3, 4])
x2 = tf.constant([4, 0, 1])
y = tf.add(x1, x2)
# 创建session --> 计算y,session是在默认graph中
with tf.Session() as sess:
    print(sess.run(y))
  1. placehold feed_dict:从内存中读取数据,占位符填充数据

    用占位符替代数据,待运行的时候填充数据。当数据量比较大的时候,Graph的传输会遇到效率底下问题,特别是数据转换。

import tensorflow as tf
# 设计Graph
x1 = tf.placeholder(tf.int32)  # placeholder 占位数据
x2 = tf.placeholder(tf.int32)
y = tf.add(x1, x2)
# 用Python产生数据
li1 = [2, 3, 4]
li2 = [4, 0, 1]
# 打开一个session --> 喂数据 --> 计算y
with tf.Session() as sess:
  print(sess.run(y, feed_dict={
   x1: li1, x2: li2}))
  1. queue队列:基于队列的输入通道(在计算图计算前从队列中读取数据)

上面两种方式由于读取数据和处理数据在同一个进程是有先后关系的,意味着数据处理完后必须花时间读取数据,然后才能进行计算处理。这样的一来GPU并没有高效的专一做一件事情,从而大大的降低的效率,queue创建多线程彻底的解决了这个问题。

​ 为了充分的利用时间,减少GPU等待的空闲时间,使用了两个线程(文件名队列内存队列)分别执行数据读入和数据计算。文件名队列源源不断的将硬盘中的图片数据,内存队列负责给GPU送数据,所需数据直接从内存队列中获取。两个线程之间互不干扰,同时运行。
在这里插入图片描述
因此 tensorflow 在内存队列之前,还要使用tf.train.slice_input_producer或tf.train.string_input_producer函数,创建一个文件名队列或者图像数据队列,文件名队列存放的是参与训练的文件名,要训练N个epoch,则文件名队列中就含有N个批次的所有文件名,若创建的是图像tensor队列,道理也一样。

注意:文件名队列与内存队列之间是需要Reader,Decoder来读取图片解码成tensor数组的过渡,

tf.train.slice_input_producer,是一个tensor生成器,作用是按照设定,每次从一个tensor列表中按顺序或者随机抽取出一个tensor放入文件名队列。

"""
返回值是list,长度与输入tensor_list相同,且是tensor生成器,每次只能获取一个
input_queue=slice_input_producer(tensor_list, 
                    num_epochs=None, 
                    shuffle=True, 
                    seed=None,
                    capacity=32, 
                    shared_name=None, 
                    name=None)

参数:
tensor_list:tensor的列表,可tensor_list=[paths_list,lables_list]或tensor_list=[paths_list]

num_epochs: 迭代的次数,num_epochs=None,生成器可以无限次遍历tensor列表;num_epochs=N,生成器只能遍历tensor列表N次,如果设置了epoch,则后面训练的时候,不需要for循环epoch,只需要设置coord.should_stop。

shuffle: bool,是否打乱样本的顺序。一般情况下,如果shuffle=True,生成的样本顺序就被打乱了,在批处理的时候不需要再次打乱样本,使用 tf.train.batch函数就可以了;如果shuffle=False,就需要在批处理时候使用 tf.train.shuffle_batch函数打乱样本

seed: 生成随机数的种子,shuffle=True的情况下才有用

capacity:队列容量的大小,为整数

shared_name:可选参数,如果设置一个"shared_name",则在不同的上下文Session中可以通过这个名字共享生成的tensor

name:设置操作的名称
"""

import tensorflow as tf

paths = ["img1", "img2", "img3", "img4", "img5"]
labels = [1, 2, 3, 4, 5]

epoch_num = 8
# 文件名队列
# input_queue = tf.train.slice_input_producer([paths], num_epochs=None, shuffle=False)
input_queue = tf.train.slice_input_producer([paths, labels], num_epochs=None, shuffle=False)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())
    coord = tf.train.Coordinator()  # 创建一个协调器,管理线程
    # 启动QueueRunner, 执行文件名队列的填充 此时真正将文件名放入文件名队列
    threads = tf.train.start_queue_runners(sess=sess, coord=coord)
    for i in range(epoch_num):
        k = sess.run(input_queue)
        print(i, k)

    coord.request_stop()
    coord.join(threads)
"""
运行结果:
# 0 [b'img1']
# 1 [b'img2']
# 2 [b'img3']
# 3 [b'img4']
# 4 [b'img5']
# 5 [b'img1']
# 6 [b'img2']
# 7 [b'img3']

0 [b'img1', 1]
1 [b'img2', 2]
2 [b'img3', 3]
3 [b'img4', 4]
4 [b'img5', 5]
5 [b'img1', 1]
6 [b'img2', 2]
7 [b'img3', 3]
"""

tf.train.batch与tf.train.shuffle_batch的作用都是从队列中读取数据,它们的区别是是否随机打乱数据来读取

"""
tf.train.batch是一个tensor队列生成器,作用是按照给定的tensor顺序,把batch_size个tensor组装到一起
tf.train.batch(
    tensors_list,
    batch_size,
    num_threads=1,
    capacity=32,
    enqueue_many=False,
    shapes=None,
    dynamic_pad=False,
    allow_smaller_final_batch=False,
    shared_name=None,
    name=None)
参数:
tensors:一个列表或字典的tensor用来进行入队,可以是文件名队列或图像数据队列
batch_size: 每次从队列中获取出队数据的数量
num_threads:用来控制入队tensors线程的数量,如果num_threads大于1,则batch操作将是非确定性的,输出的batch可能会乱序
capacity: 设置队列中元素的最大数量
enqueue_many: 在第一个参数tensors中的tensor是否是单个样本
shapes: 可选,每个样本的shape,默认是tensors的shape
dynamic_pad: Boolean值;允许输入变量的shape,出队后会自动填补维度,来保持与batch内的shapes相同
allow_smaller_final_batch: 设置为True,表示在tensor队列中剩下的tensor数量不够一个batch_size的情况下,允许最后一个batch的数量少于batch_size进行出队, 设置为False,小于batch_size的样本不会做出队处理
shared_name: 可选参数,设置生成的tensor序列在不同的Session中的共享名称;
name: 操作的名称;
"""
import tensorflow as tf
import numpy as np

sample_num = 5  # 样本个数
epoch_num = 2  # 设置迭代次数
batch_size = 3  # 设置一个批次中包含样本个数
batch_total = int(sample_num / batch_size) + 1  # 计算每一轮epoch中含有的batch个数


# 生成4个数据和标签
def generate_data(sample_num=sample_num):
    labels = np.asarray(range(0, sample_num))
    images = np.random.random([sample_num, 224, 224, 3])
    print("image size {}, label size: {}".format(images.shape, labels.shape))
    # image size (5, 224, 224, 3), label size: (5,)
    return images, labels


def get_batch_data(batch_size=batch_size):
    images, label = generate_data()
    images = tf.cast(images, tf.float32)  # 数据类型转换为tf.float32
    label = tf.cast(label, tf.int32)  # 数据类型转换为tf.int32

    # 从tensor列表中按顺序或随机抽取一个tensor,注意这里返回值
    input_queue = tf.train.slice_input_producer([images, label], shuffle=False)
    # 返回一个batch的数据,其实tf.train.batch内部要获取batch_size次调用input_queue
    image_batch, label_batch = tf.train.batch(input_queue, batch_size=batch_size,
                                              num_threads=1, capacity=64)
    return image_batch, label_batch


image_batch, label_batch = get_batch_data(batch_size=batch_size)

with tf.Session() as sess:
  
  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值