如何使用 tf.data 创建多元时间序列数据集?

Posted

技术标签:

【中文标题】如何使用 tf.data 创建多元时间序列数据集?【英文标题】:How to create a multivariate timeseries dataset with tf.data? 【发布时间】:2021-12-19 09:15:49 【问题描述】:

我正在尝试为我的 LSTM 模型创建一个输入管道。我正在使用tf.data.Dataset.from_generator API 来做到这一点。在guide 之后,我当前的最小示例如下所示:

class generator:
    def __init__(self, n=5):
        self.n = n

    def __call__(self):
        for i in range(self.n):
            yield (i, 10*i)

dataset = tf.data.Dataset.from_generator(generator(), 
    output_signature=(tf.TensorSpec(shape=(), dtype=tf.uint16), tf.TensorSpec(shape=(), dtype=tf.int32)))

window_size = 3
windows = dataset.window(window_size, shift=1)

def sub_to_batch(sub):
    return sub.batch(window_size, drop_remainder=True)

final_dset = windows.flat_map(sub_to_batch)

print(list(final_dset.as_numpy_iterator()))

错误信息

TypeError: tf__sub_to_batch() takes 1 positional argument but 2 were given

只有在生成器中使用多个功能时才会出现此问题(例如更改以下行)。

yield (i)

dataset = tf.data.Dataset.from_generator(generator(), 
    output_signature=(tf.TensorSpec(shape=(), dtype=tf.uint16)))

在只有 1 个功能的版本中,输出类似于 shape=(3, 3, 1)

[ [ [0], [1], [2] ],
  [ [1], [2], [3] ],
  [ [2], [3], [4] ]  ]

我基本上尝试实现单个功能的压缩,以便我得到shape=(3, 3, 2)

[ [ [0,  0], [1, 10], [2, 20] ],
  [ [1, 10], [2, 20], [3, 30] ],
  [ [2, 20], [3, 30], [4, 40] ]  ]

如何做到这一点?

【问题讨论】:

【参考方案1】:

您可以尝试以下方法;但是,我不确定它的效率如何:

import tensorflow as tf

class generator:
    def __init__(self, n=7):
        self.n = n

    def __call__(self):
        for i in range(self.n):
            yield (i, 10*i)

dataset = tf.data.Dataset.from_generator(generator(), 
    output_signature=(tf.TensorSpec(shape=(), dtype=tf.int32), tf.TensorSpec(shape=(), dtype=tf.int32)))

window_size = 5
windows = dataset.window(window_size, shift=1)

def stack(x, y):
  x = tf.expand_dims(x, axis=1)
  y = tf.expand_dims(y, axis=1)
  result = tf.concat((x, y), axis=1)
  ta = tf.TensorArray(tf.int32, size=0, dynamic_size=True)
  for w in tf.range(3):
    ta = ta.write(w, result[w: w + 3])
  return ta.stack()

def sub_to_batch(sub1, sub2):
    sub1 = sub1.batch(5, drop_remainder=True)
    sub2 = sub2.batch(5, drop_remainder=True)

    return tf.data.Dataset.zip((sub1, sub2)).map(stack)

final_dset = windows.flat_map(sub_to_batch)
for s in final_dset.take(1):
  print(s)
tf.Tensor(
[[[ 0  0]
  [ 1 10]
  [ 2 20]]

 [[ 1 10]
  [ 2 20]
  [ 3 30]]

 [[ 2 20]
  [ 3 30]
  [ 4 40]]], shape=(3, 3, 2), dtype=int32)

如果您愿意,您也可以对索引进行硬编码,结果将是相同的:

def stack(x, y):
  x = tf.expand_dims(x, axis=1)
  y = tf.expand_dims(y, axis=1)
  result = tf.concat((x, y), axis=1)
  return tf.stack([result[0: 3], result[1: 4], result[2: 5]])

【讨论】:

很抱歉回复晚了,我忙于另一项任务,直到最近才测试您的建议。虽然我最终不得不修改生成器(它必须处理比这个虚拟示例更复杂的数据),但你的帖子肯定让我走上了正确的轨道。谢谢你:)

以上是关于如何使用 tf.data 创建多元时间序列数据集?的主要内容,如果未能解决你的问题,请参考以下文章

如何将 tf.data.Dataset 与 kedro 一起使用?

如何按特定值过滤 tf.data.Dataset?

你能交错来自多个文件的 tf.data 数据集吗?

使用 tf.data.dataset 为序列模型创建数据生成器

如何从 pandas 创建与 tf.data.experimental.make_csv_dataset 相同的结构

Tensorflow:如何查找 tf.data.Dataset API 对象的大小