【问题标题】:Keras custom masking layerKeras 自定义遮罩层
【发布时间】:2021-02-22 00:24:07
【问题描述】:

我正在努力使用 tf.boolean_mask 处理来自 Flatten 层的自定义屏蔽输入。您能否给我一个提示,为什么没有产生 (None, 1024) 输出的掩蔽?我将不胜感激任何帮助。
谢谢你:)

class InputReduction(keras.layers.Layer):
    def __init__(self, mask_idx):
        super(InputReduction, self).__init__()
        self.mask_idx = mask_idx

    def call(self, inputs):
        mask = np.array([True for _ in range(inputs.shape[1])])
        for idx in self.mask_idx:
            mask[idx] = False
            
        print(mask)
        inputs = tf.boolean_mask(inputs, mask)
        print(inputs.shape)
        
        return inputs
model = keras.models.Sequential([
    keras.layers.Conv2D(32, (3, 3), activation='relu', input_shape=x_train.shape[1:]),
    keras.layers.Conv2D(32, (3, 3), activation='relu'),
    keras.layers.MaxPooling2D((2, 2)),
    keras.layers.Dropout(0.25),
    
    keras.layers.Conv2D(64, (3, 3), activation='relu'),
    keras.layers.Conv2D(64, (3, 3), activation='relu'),
    keras.layers.MaxPooling2D((2, 2)),
    keras.layers.Dropout(0.25),
    
    keras.layers.Flatten(),
    InputReduction(mask_idx=[1,2,3]),
    keras.layers.Dense(512, activation = 'relu'),
    keras.layers.Dropout(0.5),
    keras.layers.Dense(num_classes, activation='softmax')
])

model.summary()

我的输出:

input_reduction_5 (InputRedu (None, 1024) 0

【问题讨论】:

  • 您的代码不会重现您的问题。在您的示例中,model 是什么?它从未被定义。了解如何创建minimal, reproducible example
  • @gobrewers14 抱歉,我粘贴了我的模型。看起来形状有问题。
  • 你在 Flatten 之后有一个 1D 张量,(Batchsize,Channels)。您想屏蔽每个样本的 N 个元素,将其设为 (Batchsize, N) (在您的问题中,N=3 aggregation axis=1,2, 3) 。我说的对吗?
  • @Watanabe.N 是的,我想用数组中的索引屏蔽 (Batchsize, N) 的输入。例如:batch_size = 3, N = 5. input = [[1, 2, 3, 4, 5], [6, 7, 8, 9, 10], [11, 12, 13, 14, 15]] ,让 mask_idx = [1,3],所以输出应该是 [[1,3,5], [6,8,10], [11,13,15]]

标签: python tensorflow keras


【解决方案1】:

您可能想要使用tf.gather 而不是tf.mask_boolean。在所有解决方案中,inputs.shape 应为 [Batchsize, Channels]。

解决方案 1:tf.mask(..., axis=1)

import tensorflow as tf

print('tf.__version__ =', tf.__version__)


class InputReduction(tf.keras.layers.Layer):
    def __init__(self, mask_idx):
        super(InputReduction, self).__init__()
        self.mask_idx = mask_idx

    def call(self, inputs):
        batchsize, channels = inputs.shape
        mask = tf.constant([True if i in self.mask_idx else False  for i in range(channels)], dtype=tf.bool)  # [C,]
        tf.print('mask =', mask)
        return tf.boolean_mask(inputs, mask, axis=1)  # mask from axis=1 to ignore batchsize axis

x = tf.constant([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])  # (3, 4)
print('x =', x)
y = InputReduction(mask_idx=[0, 2])(x)
print('y =', y)

输出

tf.__version__ = 2.4.1
x = tf.Tensor(
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]], shape=(3, 4), dtype=int32)
mask = [1 0 1 0]
y = tf.Tensor(
[[ 1  3]
 [ 5  7]
 [ 9 11]], shape=(3, 2), dtype=int32)

解决方案 2:匹配掩码和输入的形状,然后 tf.reshape 输出

import tensorflow as tf

print('tf.__version__ =', tf.__version__)


class InputReduction(tf.keras.layers.Layer):
    def __init__(self, mask_idx):
        super(InputReduction, self).__init__()
        self.mask_idx = mask_idx

    def call(self, inputs):
        batchsize, channels = inputs.shape
        mask = tf.constant([True if i in self.mask_idx else False  for i in range(channels)], dtype=tf.bool)  # [C,]
        mask = tf.stack((mask,) * batchsize, axis=0)
        tf.print('mask =', mask)
        outputs = tf.boolean_mask(inputs, mask)  # [Batchsize * N]
        return tf.reshape(outputs, (batchsize, -1))  # [Batchsize, N]

x = tf.constant([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])  # (3, 4)
print('x =', x)
y = InputReduction(mask_idx=[0, 2])(x)
print('y =', y)

输出

tf.__version__ = 2.4.1
x = tf.Tensor(
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]], shape=(3, 4), dtype=int32)
mask = [[1 0 1 0]
 [1 0 1 0]
 [1 0 1 0]]
y = tf.Tensor(
[[ 1  3]
 [ 5  7]
 [ 9 11]], shape=(3, 2), dtype=int32)

解决方案 3:tf.gather(推荐)

不需要面具。

import tensorflow as tf

print('tf.__version__ =', tf.__version__)


class InputReduction(tf.keras.layers.Layer):
    def __init__(self, mask_idx):
        super(InputReduction, self).__init__()
        self.mask_idx = mask_idx

    def call(self, inputs):
        return tf.gather(inputs, self.mask_idx, axis=1)

x = tf.constant([[1, 2, 3, 4], [5, 6, 7, 8], [9, 10, 11, 12]])  # (3, 4)
print('x =', x)
y = InputReduction(mask_idx=[0, 2])(x)
print('y =', y)

输出

tf.__version__ = 2.4.1
x = tf.Tensor(
[[ 1  2  3  4]
 [ 5  6  7  8]
 [ 9 10 11 12]], shape=(3, 4), dtype=int32)
y = tf.Tensor(
[[ 1  3]
 [ 5  7]
 [ 9 11]], shape=(3, 2), dtype=int32)

https://www.tensorflow.org/api_docs/python/tf/boolean_mask
https://www.tensorflow.org/api_docs/python/tf/gather

【讨论】:

  • 非常感谢!解决方案 3 完美运行。我之前尝试过解决方案 1,但是当您的自定义图层后面跟着另一个图层时它不起作用。
  • 解决方案 1 即使您添加另一个图层也有效。我通过z = tf.keras.layers.Dense(1)(y) print('z=', z)z= tf.Tensor( [[3.1496382] [5.236237 ] [7.322836 ]], shape=(3, 1), dtype=float32)确认了
【解决方案2】:

在开始时,您创建了定义层的实例并传递了一个列表:

    keras.layers.Flatten(),
    InputReduction(mask_idx=[1,2,3]),  # <---
    keras.layers.Dense(512, activation = 'relu'),

在构造函数中,列表已被保存。

class InputReduction(keras.layers.Layer):
    def __init__(self, mask_idx):
        super(InputReduction, self).__init__()
        self.mask_idx = mask_idx  # <---

在调用中,您遍历此三个数字列表[1, 2, 3] 并将值设置为False

    def call(self, inputs):
        mask = np.array([True for _ in range(inputs.shape[1])])
        for idx in self.mask_idx:  # <--- `[1, 2, 3]`
            mask[idx] = False

结果是……

[True, False, False, False, True, True, True, True, True, True, ...]

最后tf.boolean_mask 缩小输出:

tensor = [0, 1, 2, 3]  # 1-D example
mask = np.array([True, False, True, False])
tf.boolean_mask(tensor, mask)
# <tf.Tensor: shape=(2,), dtype=int32, numpy=array([0, 2], dtype=int32)>

来源:https://www.tensorflow.org/api_docs/python/tf/boolean_mask

从技术上讲,这应该可行,但覆盖输入没有意义。所以我的问题是:你想做什么?这个自定义层的期望结果是什么?这是Flatten层之后的地方吗?

【讨论】:

  • 感谢您的回复。我明白我在做什么。我的问题是如何按索引屏蔽批次元素。假设我有输入 (batch_size, N) 并且我想删除每个样本的最后一个元素。它应该放在 Flatten 层之后,它是我研究的一部分。
  • 这不是答案。这应该进入评论部分。
  • @Watanabe.N 到目前为止,不可能引用多行代码,这对于讨论和保持概述和简单性至关重要。就是这么简单。
  • 我知道。即使答案就是答案,也不是为了保持概述和简单性。
猜你喜欢
  • 2020-02-17
  • 2020-09-11
  • 1970-01-01
  • 2019-04-10
  • 1970-01-01
  • 1970-01-01
  • 2011-12-30
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多