TensorFlow 2 Keras 中意外的掩码形状
Unexpected mask shape in TensorFlow 2 Keras
我有形状为 (batch_size, n_time_steps, n_features, n_channels)
的批量张量。它们来自形状为 (n_time_steps, n_features, n_channels)
的张量,其中 n_time_steps
是 不恒定的 。在构建批次时,张量被填充到 n_time_steps
.
的最大值
应将这些张量输入具有以下架构的神经网络:
- 由于填充,输入被屏蔽了。
- 每个时间步的张量被馈送到时间分布的 CNN 块。传播掩码。
- 提取的特征被馈送到 RNN。
在最后一层,我 运行 犯了一个错误,因为掩码的形状是 (batch_size, n_time_steps, n_features)
,但 RNN 期望它的形状是 (batch_size, n_time_steps)
。
有谁知道如何得到合适形状的面具吗?
这是一个最小的例子:
import tensorflow as tf
class TimeDistributedMaskPropagating(tf.keras.layers.TimeDistributed):
"""TimeDistributed layer that propagates mask."""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.supports_masking = True
def compute_mask(self, inputs, mask=None):
return mask
n_features = 3
n_channels = 1
cnn_block = tf.keras.layers.Flatten()
estimator = tf.keras.Sequential([
tf.keras.layers.Input(shape=(None, n_features, n_channels)),
tf.keras.layers.Masking(),
TimeDistributedMaskPropagating(cnn_block),
# tf.keras.layers.LSTM(10)
# yields ValueError: Dimensions must be equal, but are 3 and 10
])
x1 = tf.random.uniform((4, 3, 1)) # shape: 4, 3, 1
x2 = tf.random.uniform((3, 3, 1)) # shape: 3, 3, 1
paddings = tf.constant([[0, 1], [0, 0], [0, 0]])
padded_x2 = tf.pad(x2, paddings) # shape: 4, 3, 1
mini_batch = tf.stack((x1, padded_x2)) # shape: 2, 4, 3, 1
logits = estimator(mini_batch) # shape: 2, 4, 3
print(logits._keras_mask) # shape: 2, 4, 3
# mask has shape 2, 4, 3 with values
# [[[ True True True]
# [ True True True]
# [ True True True]
# [ True True True]]
#
# [[ True True True]
# [ True True True]
# [ True True True]
# [False False False]]]
# mask should have shape 2, 4 with values
# [[ True True True True]
# [ True True True False]]
在 tensorflow.keras.layers.Masking
的实现中,只要求最后一个轴的所有值都等于 mask_value
,以便在掩码中生成条目 False
。因此,mask 的张量秩变为输入张量的张量秩减 1(而不是 2,如预期的那样,batch_size
为 1,time_steps
为 1。
这个问题可以通过定义一个自定义遮罩层来解决,其中compute_mask
和call
方法中原始代码中的axis=-1
被axis=[2, 3]
替换(在我的例子中)或者更一般地说,通过 axis=list(range(2, len(inputs.shape)))
.
完整代码如下:
class CustomMasking(Layer):
def __init__(self, mask_value=0., **kwargs):
super(CustomMasking, self).__init__(**kwargs)
self.supports_masking = True
self.mask_value = mask_value
self._compute_output_and_mask_jointly = True
def compute_mask(self, inputs, mask=None):
return K.any(math_ops.not_equal(inputs, self.mask_value),
axis=list(range(2, len(inputs.shape))))
def call(self, inputs):
axes = list(range(2, len(inputs.shape)))
boolean_mask = K.any(math_ops.not_equal(inputs, self.mask_value),
axis=axes, keepdims=True)
outputs = inputs * math_ops.cast(boolean_mask, inputs.dtype)
# Compute the mask and outputs simultaneously.
outputs._keras_mask = array_ops.squeeze(boolean_mask, axis=axes) # pylint: disable=protected-access
return outputs
def compute_output_shape(self, input_shape):
return input_shape
def get_config(self):
config = {'mask_value': self.mask_value}
base_config = super(Masking, self).get_config()
return dict(list(base_config.items()) + list(config.items()))
我有形状为 (batch_size, n_time_steps, n_features, n_channels)
的批量张量。它们来自形状为 (n_time_steps, n_features, n_channels)
的张量,其中 n_time_steps
是 不恒定的 。在构建批次时,张量被填充到 n_time_steps
.
应将这些张量输入具有以下架构的神经网络:
- 由于填充,输入被屏蔽了。
- 每个时间步的张量被馈送到时间分布的 CNN 块。传播掩码。
- 提取的特征被馈送到 RNN。
在最后一层,我 运行 犯了一个错误,因为掩码的形状是 (batch_size, n_time_steps, n_features)
,但 RNN 期望它的形状是 (batch_size, n_time_steps)
。
有谁知道如何得到合适形状的面具吗?
这是一个最小的例子:
import tensorflow as tf
class TimeDistributedMaskPropagating(tf.keras.layers.TimeDistributed):
"""TimeDistributed layer that propagates mask."""
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
self.supports_masking = True
def compute_mask(self, inputs, mask=None):
return mask
n_features = 3
n_channels = 1
cnn_block = tf.keras.layers.Flatten()
estimator = tf.keras.Sequential([
tf.keras.layers.Input(shape=(None, n_features, n_channels)),
tf.keras.layers.Masking(),
TimeDistributedMaskPropagating(cnn_block),
# tf.keras.layers.LSTM(10)
# yields ValueError: Dimensions must be equal, but are 3 and 10
])
x1 = tf.random.uniform((4, 3, 1)) # shape: 4, 3, 1
x2 = tf.random.uniform((3, 3, 1)) # shape: 3, 3, 1
paddings = tf.constant([[0, 1], [0, 0], [0, 0]])
padded_x2 = tf.pad(x2, paddings) # shape: 4, 3, 1
mini_batch = tf.stack((x1, padded_x2)) # shape: 2, 4, 3, 1
logits = estimator(mini_batch) # shape: 2, 4, 3
print(logits._keras_mask) # shape: 2, 4, 3
# mask has shape 2, 4, 3 with values
# [[[ True True True]
# [ True True True]
# [ True True True]
# [ True True True]]
#
# [[ True True True]
# [ True True True]
# [ True True True]
# [False False False]]]
# mask should have shape 2, 4 with values
# [[ True True True True]
# [ True True True False]]
在 tensorflow.keras.layers.Masking
的实现中,只要求最后一个轴的所有值都等于 mask_value
,以便在掩码中生成条目 False
。因此,mask 的张量秩变为输入张量的张量秩减 1(而不是 2,如预期的那样,batch_size
为 1,time_steps
为 1。
这个问题可以通过定义一个自定义遮罩层来解决,其中compute_mask
和call
方法中原始代码中的axis=-1
被axis=[2, 3]
替换(在我的例子中)或者更一般地说,通过 axis=list(range(2, len(inputs.shape)))
.
完整代码如下:
class CustomMasking(Layer):
def __init__(self, mask_value=0., **kwargs):
super(CustomMasking, self).__init__(**kwargs)
self.supports_masking = True
self.mask_value = mask_value
self._compute_output_and_mask_jointly = True
def compute_mask(self, inputs, mask=None):
return K.any(math_ops.not_equal(inputs, self.mask_value),
axis=list(range(2, len(inputs.shape))))
def call(self, inputs):
axes = list(range(2, len(inputs.shape)))
boolean_mask = K.any(math_ops.not_equal(inputs, self.mask_value),
axis=axes, keepdims=True)
outputs = inputs * math_ops.cast(boolean_mask, inputs.dtype)
# Compute the mask and outputs simultaneously.
outputs._keras_mask = array_ops.squeeze(boolean_mask, axis=axes) # pylint: disable=protected-access
return outputs
def compute_output_shape(self, input_shape):
return input_shape
def get_config(self):
config = {'mask_value': self.mask_value}
base_config = super(Masking, self).get_config()
return dict(list(base_config.items()) + list(config.items()))