如何在Keras中使用自定义2D卷积内核进行实验?

时间:2019-01-08 14:30:21

标签: python tensorflow keras deep-learning conv-neural-network

在具有Conv2D的默认kernel_size=3层中,一个过滤器之一的切片的权重可以这样命名:

A B C
D E F
G H I

使用kernel_size=5这样:

A B C D E
F G H I J
K L M N O
P Q R S T
U V W X Y

现在,我想基于具有conv层的内核构建(并训练/测试)这样的模型:

A A B C C
A A B C C
D D E F F
G G H I I
G G H I I

这样的custom layer的实现看起来如何?

2 个答案:

答案 0 :(得分:1)

我认为这是您想要的基本版本:

from keras import backend as K

class Conv2DTiledKernel(Layer):
    def __init__(self, filters, kernel_size, multiplies, **kwargs):
        self.filters = filters
        self.kernel_size = kernel_size
        self.multiplies = multiplies
        super(Conv2DTiledKernel, self).__init__(**kwargs)
    def build(self, input_shape):
        shape = list(self.kernel_size) + [input_shape[-1], self.filters]
        self.kernel = self.add_weight(name='kernel', shape=shape,
                                      initializer='glorot_uniform')
        super(Conv2DTiledKernel, self).build(input_shape)
    def call(self, x):
        mult = list(self.multiplies) + [1, 1]
        kernel_tiled = K.tile(self.kernel, mult)
        return K.conv2d(x, kernel_tiled)
    def compute_output_shape(self, input_shape):
        return input_shape[:-1] + (self.filters,)

fitlers是输出通道数,kernel_size每个内核通道的大小和multiplies拼接因子。您将使用类似以下的方式:

from keras.models import Model
from keras.layers import Input, Layer

img = Input(shape=(64, 64, 3))
output = Conv2DTiledKernel(10, [1, 5], [5, 1])(img)
model = Model(inputs=img, outputs=output)

这是一个非常基本的版本。稍后您可以添加用于偏见,正则化,初始化,填充,跨距,膨胀等的选项。您可以查看the source code来了解如何在Keras中实现卷积层。如果只可以将其中一个类作为子类,这样可以免费获得所有其他选项,那将是理想的选择,但是我不确定当前代码是否可以以实用的方式完成。

答案 1 :(得分:1)

也许是这样吗?

class CustomConv2D(Layer):
    def __init__(self, filters, **kwargs):
        self.filters = filters
        self.kernel_size = (3, 3)
        super(CustomConv2D, self).__init__(**kwargs)

    def build(self, input_shape):
        # only have a 3x3 kernel
        shape = self.kernel_size + (input_shape[-1], self.filters)
        self.kernel = self.add_weight(name='kernel', shape=shape,
                                      initializer='glorot_uniform')
        super(CustomConv2D, self).build(input_shape)

    def call(self, x):
        # duplicate rows 0 and 2
        dup_rows = K.stack([self.kernel[0]]*2 + [self.kernel[1]] + [self.kernel[2]]*2, axis=0)
        # duplicate cols 0 and 2
        dup_cols = K.stack([dup_rows[:,0]]*2 + [dup_rows[:,1]] + [dup_rows[:,2]]*2, axis=1)
        # having a 5x5 kernel now
        return K.conv2d(x, dup_cols)

    def compute_output_shape(self, input_shape):
        return input_shape[:-1] + (self.filters,)

诀窍是在3x3内核中仅将每个过滤器仅存储9个权重(硬编码,您可能需要将其概括化),并复制第一行和最后一行和最后一列,以使其成为所需的5x5内核。然后,就像在original Conv2d implementation中一样,将此内核传递给K.conv2d()

我对其进行了测试,它似乎正在工作。您可能需要添加其他参数,例如padding,bias等。