【问题标题】:Mean or max pooling with masking support in KerasKeras 支持掩蔽的平均或最大池化
【发布时间】:2017-01-23 11:05:34
【问题描述】:
...
print('Build model...')
model = Sequential()
model.add(Embedding(max_features, 128))
model.add(LSTM(size, return_sequences=True, dropout_W=0.2 dropout_U=0.2)) 
model.add(GlobalAveragePooling1D())
model.add(Dense(1))
model.add(Activation('sigmoid'))
....

我需要能够在 LSTM 层之后的样本中获取所有时间步长的向量的平均值或最大值,然后再将此平均值或最大值向量提供给 Keras 中的密集层。

我认为timedistributedmerge 能够做到这一点,但它已被弃用。使用return_sequences=True,我可以获得 LSTM 层之后样本中所有时间步长的向量。但是,GlobalAveragePooling1D() 与屏蔽不兼容,它考虑了所有时间步,而我只需要非屏蔽时间步。

我看到了推荐Lambda 层的帖子,但这些帖子也没有考虑掩蔽。任何帮助将不胜感激。

【问题讨论】:

    标签: python masking keras lstm pooling


    【解决方案1】:

    由于平均池化仅在一个轴上进行平均,因此您只需要更正均值中的元素数量,因为损失掩码是在最后处理的,而不是在这里。你可以这样做:

    class GlobalAveragePooling1DMasked(GlobalAveragePooling1D):
        def call(self, x, mask=None):
            if mask != None:
                return K.sum(x, axis=1) / K.sum(mask, axis=1)
            else:
                return super().call(x)
    

    【讨论】:

    • 请注意,在 Keras 中,您无法确定 x 中的掩码值等于 0!因此,这种实现会给出错误的结果。
    • 掩码本身,由MaskingEmbedding 层引入,是二进制的。当然,你总是可以让层以不同的方式实现compute_mask,但据我所知,这在 keras 本身并没有发生。
    • 是的,掩码是二进制的。这不是我要说的:)
    • 但这是我在上面的示例中所做的唯一假设。我不明白你在说什么,对不起。编辑:没关系,是矩阵x 的求和运算使得掩码值为零的假设。你说的对。这可以通过将x 索引到mask 来解决,但我必须先对此进行测试。
    【解决方案2】:

    为了使 x 中的掩码值等于 0,可以这样做:

    class MeanPool(Layer):
    def __init__(self, **kwargs):
        self.supports_masking = True
        super(MeanPool, self).__init__(**kwargs)
    
    def compute_mask(self, input, input_mask=None):
        # do not pass the mask to the next layers
        return None
    
    def call(self, x, mask=None):
        if mask is not None:
            # mask (batch, time)
            mask = K.cast(mask, K.floatx())
            # mask (batch, time, 'x')
            mask = mask.dimshuffle(0, 1, 'x')
            # to make the masked values in x be equal to zero
            x = x * mask
        return K.sum(x, axis=1) / K.sum(mask, axis=1)
    
    def get_output_shape_for(self, input_shape):
        # remove temporal dimension
        return input_shape[0], input_shape[2]
    

    【讨论】:

      【解决方案3】:

      Jacoxu 的回答是对的。但是如果你使用的是 keras 的 tensorflow 后端,则 Tensor 类型不支持 dimshuffle 功能,请改用这个。

      def call(self, x, mask=None):
          if mask is not None:
              # mask (batch, time)
              mask = K.cast(mask, K.floatx())
              # mask (batch, x_dim, time)
              mask = K.repeat(mask, x.shape[-1])
              # mask (batch, time, x_dim)
              mask = tf.transpose(mask, [0,2,1])
              x = x * mask
          return K.sum(x, axis=1) / K.sum(mask, axis=1)
      

      【讨论】:

        【解决方案4】:

        这就是我在 Keras 2 上的做法(借鉴所有答案,并修复尺寸):

        class MeanPool(Layer):
          def __init__(self, **kwargs):
              self.supports_masking = True
              super(MeanPool, self).__init__(**kwargs)
        
          def compute_mask(self, input, input_mask=None):
              # do not pass the mask to the next layers
              return None
        
          def call(self, x, mask=None):
              if mask is not None:
                  # mask (batch, time)
                  mask = K.cast(mask, K.floatx())
                  # mask (batch, x_dim, time)
                  mask = K.repeat(mask, x.shape[-1])
                  # mask (batch, time, x_dim)
                  mask = tf.transpose(mask, [0,2,1])
                  x = x * mask
              return K.sum(x, axis=1) / K.sum(mask, axis=1)
        
          def compute_output_shape(self, input_shape):
              # remove temporal dimension
              return (input_shape[0], input_shape[2])
        

        【讨论】:

          猜你喜欢
          • 2019-01-20
          • 2019-11-11
          • 2020-04-21
          • 2017-06-16
          • 1970-01-01
          • 2017-12-02
          • 2019-06-27
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多