对keras函数中mask的个人理解

   由于keras中许多网络并不支持mask,但最近本菜需要在自己的网络中实现mask,如果想让keras中的自定义函数支持mask,就必须要实现comput_mask方法,因为在官方的文档中我并没有找到想要的东西,因此只能通过看源码的方式来学习,下面这一段就是keras中masking层的源码:

class Masking(Layer):
    def __init__(self, mask_value=0., **kwargs):
        super(Masking, self).__init__(**kwargs)
        self.supports_masking = True
        self.mask_value = mask_value

    def compute_mask(self, inputs, mask=None):
        output_mask = K.any(K.not_equal(inputs, self.mask_value), axis=-1)
        return output_mask

    def call(self, inputs):
        boolean_mask = K.any(K.not_equal(inputs, self.mask_value),
                             axis=-1, keepdims=True)
        return inputs * K.cast(boolean_mask, K.dtype(inputs))

    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()))

    def compute_output_shape(self, input_shape):
        return input_shape

   在compute_mask方法中,any函数实现的是按位规约,not_equal函数的功能正如其名,是逐个元素对比两个张量的不相等情况。

# x: 张量或变量 axis: 执行归约操作的轴 keepdims: 是否放弃或广播归约的轴。
keras.backend.any(x, axis=None, keepdims=False)

# x: 张量或变量 y: 张量或变量
keras.backend.not_equal(x, y)

   这里面有几个疑惑,第一个是mask_value是一个常数,而inputs是一个张量,为什么这两者可以进行比较。我猜想是mask_value进行了扩展,简单测试如下:

from keras import backend as K
import tensorflow as tf

# inputs = K.constant([1,2,3])
inputs = K.constant([[1, 2, 3], [1, 2, 0], [0, 0, 0]])

mask_value = 0
output_mask = K.not_equal(inputs, mask_value)
print(output_mask)
with tf.Session() as sess:
    print(output_mask.eval())

# 输出结果如下:

Tensor("NotEqual:0", shape=(3, 3), dtype=bool)
[[ True  True  True]
 [ True  True False]
 [False False False]]
 
# 由此可以看出的确是进行了扩展

   第二个疑惑是compute_mask()函数是向下传递mask,那么这个函数到底向下传递的是什么呢,从代码来看是对第一个维度进行了规约,我们也跑一下程序验证一下

from keras import backend as K
import tensorflow as tf

# inputs = K.constant([1,2,3])
inputs = K.constant([[1, 2, 3], [1, 0, 0]])

mask_value = 0
output_mask = K.any(K.not_equal(inputs, mask_value), axis=-1)
print(output_mask)
with tf.Session() as sess:
    print(output_mask.eval())

# 输出结果如下:
Tensor("Any:0", shape=(3,), dtype=bool)
[ True  True False]

   这样一个(3,3)的矩阵被规约成了(1,3)的矩阵,第三个维度位False,也就表明了这个维度对应的特征将会被mask,这个矩阵也会作为mask的返回值传递下去。再来看一下官方给出的例子

model = Sequential()
model.add(Masking(mask_value=0., input_shape=(timesteps, features)))
model.add(LSTM(32))

  这里masking层的输入是格式是input_shape=(timesteps, features),由刚才的测试结果可以得出,向下传递的mask维度应该是(1,timesteps),这样我们就可以根据传递下去的mask值来对LSTM层中的一些timesteps进行屏蔽。
  综上不那么严谨的得出结论,对于支持mask的网络层,在各层之间传递数据的同时,也传递着一个bool型的mask矩阵,矩阵中的True与False决定着对应位置的特征是否被屏蔽,并且这个矩阵的维度是(1,timesteps)。因此,在自定义函数中,我们要根据需求自己改变mask矩阵并继续传递下去,来作为下一层的mask,这里要注意的是,mask是不考虑batch_size的,也就是说我们只需要针对单个样本写好mask的传递函数就可以了。

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值