Keras 自定义遮罩层

时间:2021-02-21 11:18:38

标签: python tensorflow keras

我正在努力处理来自带有 tf.boolean_mask 的 Flatten 层的自定义屏蔽输入。你能不能给我一个提示,为什么没有屏蔽产生(无,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

2 个答案:

答案 0 :(得分:0)

您可能希望使用 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

答案 1 :(得分:-1)

一开始你创建了你定义层的一个实例并传递了一个列表:

    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 层之后的地方吗?