ConvLSTM1D 的屏蔽输入

Masking input for ConvLSTM1D

我正在使用 keras 做一个二元回归问题。 输入形状为:(None, 2, 94, 3)(通道是最后一个维度)

我有以下架构:

input1 = Input(shape=(time, n_rows, n_channels))
masking = Masking(mask_value=-999)(input1)
convlstm = ConvLSTM1D(filters=16, kernel_size=15,
                      data_format='channels_last',
                      activation="tanh")(masking)
dropout = Dropout(0.2)(convlstm)
flatten1 = Flatten()(dropout)
outputs = Dense(n_outputs, activation='sigmoid')(flatten1)
model = Model(inputs=input1, outputs=outputs)
model.compile(loss=keras.losses.BinaryCrossentropy(),
              optimizer=tf.keras.optimizers.Adam(learning_rate=0.01))

但是在训练时出现此错误:Dimensions must be equal, but are 94 and 80 for '{{node conv_lstm1d/while/SelectV2}} = SelectV2[T=DT_FLOAT](conv_lstm1d/while/Tile, conv_lstm1d/while/mul_5, conv_lstm1d/while/Placeholder_2)' with input shapes: [?,94,16], [?,80,16], [?,80,16].

如果我删除遮罩层,此错误就会消失,遮罩在做什么会触发此错误?另外,我能够 运行 上述架构的唯一方法是 kernel_size 为 1.

似乎 ConvLSTM1D 层需要根据 docs 形状 (samples, timesteps) 的遮罩。您正在计算的掩码具有 (samples, time, rows) 的形状。这是解决您的问题的一种解决方案,但我不确定它是否是 'correct' 的解决方法:

import tensorflow as tf

input1 = tf.keras.layers.Input(shape=(2, 94, 3))
masking = tf.keras.layers.Masking(mask_value=-999)(input1)
convlstm = tf.keras.layers.ConvLSTM1D(filters=16, kernel_size=15,
                      data_format='channels_last',
                      activation="tanh")(inputs = masking, mask = tf.reduce_all(masking._keras_mask, axis=-1))

dropout = tf.keras.layers.Dropout(0.2)(convlstm)
flatten1 = tf.keras.layers.Flatten()(dropout)
outputs = tf.keras.layers.Dense(1, activation='sigmoid')(flatten1)
model = tf.keras.Model(inputs=input1, outputs=outputs)
model.compile(loss=tf.keras.losses.BinaryCrossentropy(),
              optimizer=tf.keras.optimizers.Adam(learning_rate=0.01))

这一行 mask = tf.reduce_all(masking._keras_mask, axis=-1) 通过对掩码的最后一个维度应用 AND 操作,实质上将掩码减少到 (samples, timesteps)。或者,您可以创建自己的自定义遮罩层:

import tensorflow as tf

class Reduce(tf.keras.layers.Layer):

  def __init__(self):
      super(Reduce, self).__init__()

  def call(self, inputs):
      return tf.reduce_all(tf.reduce_any(tf.not_equal(inputs, -999), axis=-1, keepdims=False), axis=1)

input1 = tf.keras.layers.Input(shape=(2, 94, 3))
reduce_layer = Reduce()
boolean_mask = reduce_layer(input1)
convlstm = tf.keras.layers.ConvLSTM1D(filters=16, kernel_size=15,
                      data_format='channels_last',
                      activation="tanh")(inputs = input1, mask = boolean_mask)

dropout = tf.keras.layers.Dropout(0.2)(convlstm)
flatten1 = tf.keras.layers.Flatten()(dropout)
outputs = tf.keras.layers.Dense(1, activation='sigmoid')(flatten1)
model = tf.keras.Model(inputs=input1, outputs=outputs)
model.compile(loss=tf.keras.losses.BinaryCrossentropy(),
              optimizer=tf.keras.optimizers.Adam(learning_rate=0.01))
print(model.summary(expand_nested=True))
x = tf.random.normal((50, 2, 94, 3))
y = tf.random.uniform((50, ), maxval=3, dtype=tf.int32)
model.fit(x, y)