Tensorflow的DataSet的使用

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

Dataset类是TensorFlow非常流行的存储数据的格式。常用来作为输入输出。data模块主要的用途就是通过这种方法创建Dataset。

Dataset使用过程中的一些心得

  1. 经常将自变量X数据以及target数据以元组的形式包裹如db_train=tf.data.Dataset.from_tensor_slices((x_train,y_train))创建Dataset。模型的fit()方法可以自动的解包。

  2. Dataset能够包括比较灵活的类型比如db_train=tf.data.Dataset.from_tensor_slices(({"features":features_train,"biomass_start":biomass_start_trarin},y_train))。因为数据最外部依然是最外部包裹所以model的fit()依然可以自动的对x以及target解包。但由于dataset保存component是以原始数据的形式保存的。所以fit()里的inputs一般是这个样子

    {'features': <tf.Tensor 'my_rnn/Cast_1:0' shape=(None, 5, 4) dtype=float32>, 'biomass_start': <tf.Tensor 'my_rnn/Cast:0' shape=(None, 1) dtype=float32>}
    

    对于字典内部部分需要手动的自己解包。这样的好处是给我们自定义模型的结构提供的很大的遍历输入一部分导入A网络一部分导入不同的B网络。

  3. Dataset作为模型的输入需要设定batch()。而不在模型内设定batch。更加方便。然而Dataset作为迭代器迭代完成后再次迭代数据生成数据的前后数据是不一样的。需要注意。

  4. batch的drop_remainder=True参数比较重要只有设定为Trueinput接下来的层还能正确的识别shape

Dataset的常用属性

  1. Dataset.element_spec

    这个属性可以检测每一个元素中的component的类型。返回的是一个tf.TypeSpec对象。这个对象的结构跟元素的结构是一致的。

    dataset1 = tf.data.Dataset.from_tensor_slices(tf.random.uniform([4, 10]))
    
    dataset1.element_spec
    #TensorSpec(shape=(10,), dtype=tf.float32, name=None)
    dataset2 = tf.data.Dataset.from_tensor_slices(
       (tf.random.uniform([4]),
        tf.random.uniform([4, 100], maxval=100, dtype=tf.int32)))
    
    dataset2.element_spec
    # 标量和向量
    # (TensorSpec(shape=(), dtype=tf.float32, name=None),
    #TensorSpec(shape=(100,), dtype=tf.int32, name=None))
    dataset = tf.data.Dataset.from_tensor_slices(([1, 2], [3, 4], [5, 6]))
    dataset.element_spec 
    #(TensorSpec(shape=(), dtype=tf.int32, name=None),
    # TensorSpec(shape=(), dtype=tf.int32, name=None),
    # TensorSpec(shape=(), dtype=tf.int32, name=None))
    
    # 注意这里是字典类型
    dataset = tf.data.Dataset.from_tensor_slices({"a": [1, 2], "b": [3, 4]})
    dataset.element_spec
    #{'a': TensorSpec(shape=(), dtype=tf.int32, name=None),
    # 'b': TensorSpec(shape=(), dtype=tf.int32, name=None)}
    

Dataset的常用方法

  1. apply方法

    对dataset进行转换。

    dataset = tf.data.Dataset.range(100)
    def dataset_fn(ds):
      return ds.filter(lambda x: x < 5)
    dataset = dataset.apply(dataset_fn)
    list(dataset.as_numpy_iterator())
    
  2. as_numpy_iterator

    dataset = tf.data.Dataset.from_tensor_slices([1, 2, 3])
    for element in dataset.as_numpy_iterator():
      print(element)
    

    这个在dataset比较常用。就是将dataset变成迭代器将所有元素都变成numy对象输出

  3. shuffle

    shuffle(
        buffer_size, seed=None, reshuffle_each_iteration=None, name=None
    )
    

    参数

    • buffer_size缓冲区大小
    • seed随机种子
    • reshuffle_each_iterationbool. 如果为真表示每次迭代时数据集完成后都应该是进行伪随机重新洗牌的。控制每个epoch的洗牌顺序是否不同。

    这个方法用来随机打乱数据集的元素顺序。数据集用buffer_size元素填充一个缓冲区然后从这个缓冲区随机取样元素用新元素替换选中的元素。例如如果您的数据集包含10,000个元素但是buffer_size被设置为1,000那么shuffle将首先从缓冲区中的前1,000个元素中选择一个随机元素。一旦一个元素被选中它在缓冲区中的空间就会被下一个(比如第1001个)元素替换从而保持这个1,000元素缓冲区。为了实现完美的洗牌需要一个大于或等于数据集完整大小的缓冲区。

    dataset = tf.data.Dataset.range(3)
    # 每个每个epoch重新洗牌
    dataset = dataset.shuffle(3, reshuffle_each_iteration=True)
    list(dataset.as_numpy_iterator())
    # [1, 0, 2]
    list(dataset.as_numpy_iterator())
    # [1, 2, 0]
    dataset = tf.data.Dataset.range(3)
    # 每个每个epoch不重新洗牌
    dataset = dataset.shuffle(3, reshuffle_each_iteration=False)
    list(dataset.as_numpy_iterator())
    # [1, 0, 2]
    list(dataset.as_numpy_iterator())
    # [1, 0, 2]
    
  4. batch

    batch(
        batch_size,
        drop_remainder=False,
        num_parallel_calls=None,
        deterministic=None,
        name=None
    )
    

    参数:

    • batch_size: 批处理大小
    • drop_remainder是否删除最后一个短batch。==这个比较重要只有设定为Turemodel才能正确的判断其输入的shape。==这也比较合理指定为Falsel因为谁也不知道后面是不是有一个比较短的batch只有第一维是None才能提高程序的稳定性。
    • num_parallel_calls并行计算的数量。不指定会顺序执行。如果有 tf.data.AUTOTUNE会自动动态的制定这个值。
    • deterministicbool. 指定了num_parallel_calls才有效。如果设置为False则允许转换产生无序元素以牺牲确定性来换取性能。如果不指定tf.data.Options.deterministic控制这个行为默认为True
    • name: 标识符

    这个方法经常使用将dataset进行批处理化。因为数据集比较大的时候一下子完全进行训练占用大量的内存。所以用分批处理。输出的元素增加了一个额外的维度就是batch维shape是batch的size.
    batch支持一个drop_remainder=True关键字为真意味着最后一个batch的size如果小于我们指定值就会被舍弃。

    之所以要删掉最后一个短的batch是因为如果我们的项目依赖这个batch的size那最后一个batch不等长可能会出错。

    import tensorflow as tf
    from tensorflow.python.data import Dataset
    
    dataset = tf.data.Dataset.range(8)
    dataset = dataset.batch(3)
    print(list(dataset.as_numpy_iterator()))
    # 通过这个看到这个elem也已经是分批了
    for elem in dataset:
        print(elem)
    
    # tf.Tensor([0 1 2], shape=(3,), dtype=int64)
    # tf.Tensor([3 4 5], shape=(3,), dtype=int64)
    # tf.Tensor([6 7], shape=(2,), dtype=int64)
    
    for elem in dataset.as_numpy_iterator():
        print(elem)
    
    # [0 1 2]
    # [3 4 5]
    # [6 7]
    dataset = tf.data.Dataset.range(8)
    # drop_remainder舍掉最后一个长度不够的batch
    dataset = dataset.batch(3, drop_remainder=True)
    list(dataset.as_numpy_iterator())
    

    一般情况下shuffle跟batch是连续使用的实现随机读取并批量处理数据dataset.shuffle(buffer_size).batch(batchsize)

    不能对已经batch的dataset进行连续的batch操作其batchsize不会改变而是生成了新的异常数据

  5. unbatch

    unbatch(
        name=None
    )
    

    这里是将Batchdataset这样的dataset分割为一个个元素元素的格式跟定义时的格式是一样的。而且这里固定的是对第1个维度进行split操作且生成shape[0]个元素。

  6. reduce方法

    reduce(
        initial_state, reduce_func, name=None
    )
    

    将输入数据集简化为一个元素。 reduce_func作用于dataset中每一个元素输出其dataset的聚合信息。

    参数initial_state代表进行reduce之前的初始状态。reduce_func要接收old_state, input_element两个参数然后生成新的状态newstate。old_state和new_state的结构要一致。

    dataset = tf.data.Dataset.from_tensor_slices([8, 3, 0, 8, 2, 1])
    print(dataset.reduce(0, lambda state, value: state + value).numpy())
    # 22
    

dataset不支持tf.split属性也不能直接把dataset给切分为训练集和测试集。

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6