【问题标题】:Applying a mask to Conv2D kernel in Keras在 Keras 中将掩码应用于 Conv2D 内核
【发布时间】:2020-10-14 04:15:41
【问题描述】:

我希望在 Keras 中将遮罩应用到 Conv2D 层的内核。我在理解内核形状方面有点困难。

对于kernel_size = 3,filters = 1,内核的形状是(3, 3, 4, 1) => (kernel_size, kernel_size, ???, filters)

内核中的第 3 维代表什么?

如何获取 NxN 掩码并将其与每个内核过滤器相乘?

这是我到目前为止的代码。我不确定它是否会按预期工作,因为我不完全了解内核形状。

class MaskedConv2D(tf.keras.layers.Layer):
    def __init__(self, *args, **kwargs):
        super(MaskedConv2D, self).__init__()
        self.conv2d = Conv2D(*args, **kwargs)
        
    def build(self, input_shape):
        self.conv2d.build(input_shape[0])
        self._convolution_op = self.conv2d._convolution_op
        
    def masked_convolution_op(self, filters, kernel, mask):
        m = K.expand_dims(K.expand_dims(mask[0, ...], axis=2), axis=3) # (3, 3) => (3, 3, 1, 1)
        m = K.tile(m, (1, 1, kernel.shape[2], kernel.shape[3])) # (3, 3, 1, 1) => (3, 3, 4, 1)
        return self._convolution_op(filters, tf.math.multiply(kernel, m))        
        
    def call(self, inputs):
        x, mask = inputs
        self.conv2d._convolution_op = functools.partial(self.masked_convolution_op, mask=mask)
        return self.conv2d.call(x)

【问题讨论】:

    标签: python tensorflow machine-learning keras convolution


    【解决方案1】:

    首先:内核大小

    2D卷积的核大小如下

    [ height, width, input_filters, output_filters ]
    

    第三个维度与输入过滤器的大小相同。这很关键。

    让我们考虑一下卷积是如何手动完成的。步骤如下:

    • 从一批图像中获取一个补丁(BatchSize,height,width,filters)
    • 将其重塑为 [BatchSize, height * width * filters]
    • 矩阵乘以重构后的内核 [height * width * filters, output_filters]
    • 此时我们的数据的形状为 [BatchSize, output_filters]
    • 通过在整个批次中广播来添加形状 [output_filters] 的偏差

    输出是每个补丁的过滤器。

    如何将 NxN 蒙版应用于过滤器

    鉴于我们知道卷积中的权重是成形的 比如[ height, width, input_filters, output_filters ],我们想正确应用[ height, width ]的掩码,可以像这样广播那个掩码

    masked_weight = weight * mask.reshape([height,width,1,1])
    

    我们的 Tensorflow keras 层可以这样写

    class MaskedConv2D(tf.keras.layers.Layer):
        def __init__(self, *args, **kwargs):
            super(MaskedConv2D, self).__init__()
            self.conv2d = tf.keras.layers.Conv2D(*args, **kwargs)
            
        def build(self, input_shape):
            self.conv2d.build(input_shape[0])
            self._convolution_op = self.conv2d._convolution_op
            
        def masked_convolution_op(self, filters, kernel, mask):
            return self._convolution_op(filters, tf.math.multiply(kernel, tf.reshape(mask, mask.shape + [1,1] )))
            
        def call(self, inputs):
            x, mask = inputs
            self.conv2d._convolution_op = functools.partial(self.masked_convolution_op, mask=mask)
            return self.conv2d.call(x)
    

    我们可以使用以下脚本对其进行测试

    mcon = MaskedConv2D(filters=2,kernel_size=[3,3])
    
    # hack: initialize it by running some data through it
    mcon((np.ones([1,4,4,3], dtype=np.float32), tf.constant([[1,1,0],[1,1,1],[0,1,1]], dtype=tf.float32)))
    
    # set all the weights to 1 for testing
    mcon.set_weights([ np.ones([3,3,3,2]) , np.zeros([2]) ])
    
    # pass in a matrix of 1s and mask out 2 elements for each input filter
    mcon((np.ones([1,4,4,3], dtype=np.float32), tf.constant([[1,1,0],[1,1,1],[0,1,1]], dtype=tf.float32)))
    

    具有可预测的输出

    <tf.Tensor: shape=(1, 2, 2, 2), dtype=float32, numpy=
        array([[[[21., 21.],
                 [21., 21.]],
                [[21., 21.],
                 [21., 21.]]]], dtype=float32)>
    

    【讨论】:

      猜你喜欢
      • 2021-02-16
      • 1970-01-01
      • 1970-01-01
      • 2018-03-10
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多