【问题标题】:Sparse training of convolutional layers in KerasKeras中卷积层的稀疏训练
【发布时间】:2019-12-23 08:55:05
【问题描述】:

我想在 Keras 中使用卷积层训练 CNN,例如

x_1 = Conv2D(16, (kernel_size, kernel_size))(x_in)

x_in 这里包含 3 个输入特征层,因此这里必须训练 3*16 = 48 个 kernel_size*kernel_size 的内核。假设我希望这 48 个内核中的 5 个完全为 0(所以它的所有元素),我怎样才能有效地训练呢?

提前致谢。

我的总配置是这样的:

x_in = Input(shape=(None, None, 3))

x_1 = Conv2D(16, (kernel_size, kernel_size))(x_in)
x_1 = ReLU()(x_1)
x_2 = Conv2D(16, (kernel_size, kernel_size))(x_1)
x_2 = ReLU()(x_2)
x_3 = Conv2D(16, (kernel_size, kernel_size))(x_2)
return Model(inputs=x_in, outputs=x_3) 

【问题讨论】:

  • x_in的形状是什么?
  • 3 个通道,通道的维度未知,因为我使用的数据集包含不同分辨率的图像
  • 如果我没记错的话,必须训练 (3x3) 的 16 个内核而不是 48 个,对吗? 16 个内核将在 3 个通道上共享,进行 48 次卷积操作?
  • 不,必须训练 48 个内核。每个输入通道-输出通道组合一个。
  • 在默认卷积操作的情况下,16 个过滤器(不是 48 个)将在通道之间共享(3x3x16(权重)+ 16(偏差)= 448 个可训练参数)。那么您是否正在尝试自定义此操作?

标签: python tensorflow keras conv-neural-network


【解决方案1】:

在这种情况下,您必须实现自定义卷积层。你必须创建一个类,它应该是 keras 的 Layer 类的实例。这需要为前馈计算实现 call 方法。

这可能是您正在寻找的东西。

class CustomConv2D(Layer):
    def __init__(self, k=3):
      super(CustomConv2D, self).__init__()

      c1_1 = self.add_weight(shape=(k,k, 1, 5), initializer='zeros', dtype=tf.float32, trainable=False)
      c1_2 = self.add_weight(shape=(k,k, 1, 11), initializer='zeros', dtype=tf.float32, trainable=True)
      self.c1 = tf.concat([c1_1,c1_2], axis=-1)

      self.c2 = self.add_weight(shape=(k,k, 1, 16), initializer='zeros', dtype=tf.float32, trainable=True)
      self.c3 = self.add_weight(shape=(k,k, 1, 16), initializer='zeros', dtype=tf.float32, trainable=True)

    def call(self, inputs):
        x_1_c1 = tf.nn.conv2d(tf.expand_dims(inputs[:,:,:,0],-1), self.c1,padding='VALID')
        x_1_c2 = tf.nn.conv2d(tf.expand_dims(inputs[:,:,:,1],-1), self.c2,padding='VALID')
        x_1_c3 = tf.nn.conv2d(tf.expand_dims(inputs[:,:,:,2],-1), self.c3,padding='VALID')

        x_1 = tf.concat([x_1_c1,x_1_c2, x_1_c3], -1)
        return x_1

在这种情况下,我们有三组过滤器(每个通道 16 个),对于第一个通道,我们将 5 个过滤器保持为不可训练,其余 11 个作为可训练过滤器,其余 32 个(用于通道 2 和 3)过滤器是可训练的。

这是 keras 中 Layer 类的实例,可以像任何普通层一样使用。

model = tf.keras.models.Sequential()
model.add(CustomConv2D(3))

model.build(input_shape=(None,None,None,3))
I = tf.keras.Input((None,None,3))
model.call(I)
model.summary()
'''
Model: "sequential_3"
_________________________________________________________________
Layer (type)                 Output Shape              Param #   
=================================================================
custom_conv2d_2 (CustomConv2 (None, None, None, 48)    432       
=================================================================
Total params: 432
Trainable params: 387
Non-trainable params: 45
_________________________________________________________________
'''


如您所见,我们没有训练 5 个过滤器,因此有 45 个 (3x3x5) 不可训练参数

这里我有没有添加偏见这个词。您可以进一步添加并自定义您的 Conv 层。还可以更改过滤器的顺序,只需将可训练参数设置为 False,然后将 initializer 更改为您想要训练的层的其他值。

【讨论】:

  • 非常感谢,这看起来像我一直在寻找的东西,我会试试的。还有一个问题:您现在已经决定 5 个未训练的内核都来自第一个输入通道。模型能否训练这 5 个中的多少个从第 1 个、第 2 个和第 3 个开始,以及对哪些输出通道最好进行内核的修剪?还是这太难了?
  • 如果它最终检查每个频道,那么没有什么是不可训练的!查看这个 tensorflow blog 在训练时进行权重修剪。