Tensorflow 2.0 创建一个数据集以在延迟评估时为模型提供具有不同形状的多个输入

Tensorflow 2.0 Create a Dataset to feed a model with multiple inputs of different shapes on lazy evaluation

我有一个带有两个不同形状输入的 keras 模型。一侧采用少量分类特征,而另一侧采用长度为 PAST_HISTORY 的多个时间序列。输出也是多个时间序列:

# Categorical data input
input_ct = keras.Input(shape=(len(categ_cols),),
                       name='categorical_input')

# Timeseries input
input_ts = keras.Input(shape=(PAST_HISTORY, len(series_cols)),
                       name='timeseries_input')

...

model = keras.models.Model(inputs=[input_ct, input_ts], outputs=outputs)

我使用 pandas DataFrame 和一些 tf.data.Dataset 操作为每个输入和输出创建了一个数据集。

df_ts = df[series_cols][:-FUTURE_TARGET]
ts_batch = lambda window: window.batch(PAST_HISTORY)
time_series_data = tf.data.Dataset.from_tensor_slices(df_ts)\
    .window(PAST_HISTORY, 1, 1, True)\
    .flat_map(ts_batch)

df_cat = df[categ_cols][PAST_HISTORY - 1:-FUTURE_TARGET]
date_data = tf.data.Dataset.from_tensor_slices(df_cat)

df_target = df[target_cols][PAST_HISTORY:]
target_batch = lambda window: window.batch(FUTURE_TARGET)
target_data = tf.data.Dataset.from_tensor_slices(df_target)\
    .window(FUTURE_TARGET, 1, 1, True)\
    .flat_map(target_batch)

为了创建最终的数据集,我使用了生成器:

def generator():
    for d1, d2, t in zip(date_data, time_series_data, target_data):
        yield {"categorical_input": d1, "timeseries_input": d2}, tf.transpose(t)

dataset = tf.data.Dataset.from_generator(generator,
    output_types=(
        {'categorical_input': tf.int64, 'timeseries_input': tf.float64},
        tf.float64),
    output_shapes=(
        {'categorical_input': (len(categ_cols),),'timeseries_input': (PAST_HISTORY, len(series_cols))},
        (len(target_cols), FUTURE_TARGET),))

这很有效,我通过调用 model.fit 设法训练了一个急切执行的模型。但是,现在我正在尝试从此模型创建一个 Estimator,数据集的创建不再有效,因为它隐式使用了惰性评估不允许的 __iterator__ 函数。具体问题在于生成器上的 zip 操作。

我尝试使用以下代码在没有生成器的情况下创建相同的数据集:

dataset = tf.data.Dataset.from_tensors(
        ({'categorical_input': date_data, 'timeseries_input': time_series_data}, target_data)
)

当我尝试调用 estimator.train:

时出现以下错误
TypeError: Failed to convert object of type <class 'tensorflow.python.data.ops.dataset_ops._NestedVariant'> to Tensor.
Contents: <tensorflow.python.data.ops.dataset_ops._NestedVariant object at 0x7f5bf84a97f0>.
Consider casting elements to a supported type.

解决这个错误的方法是什么?或者有没有另一种方法来构建这个数据集而不必在数据集上调用迭代器?

此外,我尝试转换数据集并在窗口数据集上出现以下错误:

TypeError: Failed to convert object of type <class 'tensorflow.python.data.ops.dataset_ops.FlatMapDataset'> to Tensor.
Contents: <FlatMapDataset shapes: (None, 2), types: tf.float64>.
Consider casting elements to a supported type.

虚拟数据:

df = pd.DataFrame(data={
        'ts_1': np.random.rand(10000),
        'ts_2': np.random.rand(10000),
        'ts_objective': np.random.rand(10000),
        'cat_1': np.random.randint(1, 10 + 1, 10000),
        'cat_2': np.random.randint(1, 25 + 1, 10000),
        'cat_3': np.random.randint(1, 30 + 1, 10000),
        'cat_4': np.random.randint(1, 50 + 1, 10000)})

categ_cols = ['cat_1', 'cat_2', 'cat_3', 'cat_4']
series_cols = ['ts_1', 'ts_2']
target_cols = ['ts_objective']

PAST_HISTORY = 24
FUTURE_TARGET = 8

您可以在不使用生成器的情况下构建所需的数据集(并且速度更快)仅使用 Dataset 操作:

import tensorflow as tf

date_data = ...
time_series_data = ...
target_data = ...

def data_tx(d1, d2, t):
    return {"categorical_input": d1, "timeseries_input": d2}, tf.transpose(t)
dataset = tf.data.Dataset.zip((date_data, time_series_data, target_data)).map(data_tx)