首页 > 解决方案 > 使用 Masking 为 tf.data.Dataset 找到正确的形状馈入 LSTM

问题描述

我正在执行时间序列分类任务,但找不到正确的使用方法tf.data.Dataset。我可以使用 numpy 数组创建一个工作模型,如下面的代码所示(数据已经预先用零填充到最大长度为 180):

tf_data.shape, labels.shape
> ((225970, 180, 1), (225970,))

所以我有 180 个时间步长的 225970 个实例和 1 个特征。我可以按如下方式拟合模型。这可以正常工作并创建适当的输出/预测:


model = keras.Sequential(
    [
         layers.Masking(mask_value=0, input_shape=(180,1)),
         layers.LSTM(16),
         layers.Dense(1, activation='sigmoid')
    ]
)

model.compile(
    optimizer='adam',
    loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
    metrics=['accuracy']
)

model.fit(tf_data,  labels, epochs=5)

但是,当我尝试以下使用时tf.data.Dataset.from_tensors

tf_dataset = tf.data.Dataset.from_tensors((tf_data, labels.astype(int)))

tf_dataset = tf_dataset.shuffle(buffer_size=1024).batch(64)

model_v1 = keras.Sequential(
    [
        layers.Input(shape=(180,1), batch_size=64),
        layers.Masking(mask_value=0),
        layers.LSTM(16),
        layers.Dense(1, activation='sigmoid')
    ]
)
model_v2 = keras.Sequential(
    [
        layers.Masking(mask_value=0, shape=(180,1), batch_size=64),
        layers.LSTM(16),
        layers.Dense(1, activation='sigmoid')
    ]
)

<model_v1 or model_v2>.compile(
    optimizer='adam',
    loss=tf.keras.losses.BinaryCrossentropy(from_logits=True),
    metrics=['accuracy']
)

<model_v1 or model_v2>.fit(tf_dataset, epochs=10, steps_per_epoch=30)

我遇到了错误

model_v1 - ValueError: Error when checking input: expected input_48 to have 3 dimensions, but got array with shape (None, 225970, 180, 1)
model_v2 - ValueError: Error when checking input: expected masking_70_input to have 3 dimensions, but got array with shape (None, 225970, 180, 1)

谁能解释我需要对我的 tensorflow 数据集或我的模型做些什么,以确保它可以与 numpy 数组一起工作,tf.data.Dataset而不仅仅是 numpy 数组?

标签: pythontensorflowmachine-learningkeras

解决方案


你应该tf.data.Dataset.from_tensor_slices改用

tf_dataset = tf.data.Dataset.from_tensor_slices((tf_data, labels.astype(int)))

根据方法的官方文档tf.data.Dataset.from_tensors

from_tensors生成仅包含单个元素的数据集。要将输入张量切成多个元素,请from_tensor_slices 改用。

虽然官方文档tf.data.Dataset.from_tensor_slices说,

给定的张量沿它们的第一维进行切片。此操作保留输入张量的结构,删除每个张量的第一个维度并将其用作数据集维度。所有输入张量的第一个维度必须具有相同的大小。

*.from_tensor_slices方法对输入张量进行切片,并将给定数组(在我们的例子中为张量)视为 225970 个数据实例。这允许分别调用方法,例如*.shuffle*.batch()which shuffle 和 batch 数据实例。

我们可以通过一个例子来理解这一点。首先让我们生成一些虚拟数据实例。

x = np.random.rand( 2500 , 180 , 1 )
y = np.random.rand( 2500 , 1 )

*.from_tensors,

tensor_ds = tf.data.Dataset.from_tensors( ( x , y ) )
for sample in tensor_ds.take( 1 ):
    print( sample[ 0 ].shape )
    print( sample[ 1 ].shape )

输出是,

(2500, 180, 1)
(2500, 1)

*.from_tensor_slices,

tensor_ds = tf.data.Dataset.from_tensor_slices( ( x , y ) )
for sample in tensor_ds.take( 1 ):
    print( sample[ 0 ].shape )
    print( sample[ 1 ].shape )

输出是,

(180, 1)
(1,)

推荐阅读