【问题标题】:How to manipulate (constrain) the weights of the filter kernel in Conv2D in Keras?如何在 Keras 的 Conv2D 中操纵(约束)滤波器内核的权重?
【发布时间】:2018-05-24 15:52:45
【问题描述】:

我了解 Keras 的 Conv2D 中的 kernel_constraint 有几个选项:max_norm、non_neg 或 unit_norm..

但我需要将过滤器内核中的锚点(中心)位置设置为零。 例如,如果我们有一个大小为 (width, height) = (5, 5) 的过滤器内核,并且输入中有 3 个通道。我需要将此内核的锚点(中心)约束为每个通道为 0,例如 w(2,2,:)=0,假设我们将通道维度放在第 3 维度。如果有多个过滤器,则每个过滤器的锚点位置应为零。我该如何实现呢?

我假设需要自定义内核约束。这个链接给出了如何创建一个继承自约束的类的建议:https://github.com/keras-team/keras/issues/8196。这显示了如何实现内置约束: https://github.com/keras-team/keras/blob/master/keras/constraints.py

但是,我仍然不知道如何操纵 w 的尺寸,以及如何将所需位置设置为零。任何帮助表示赞赏。谢谢。

更新: Daniel Möller 的回答被尝试过了。错误信息如下:
raise ValueError('一个操作有None 用于梯度。' ValueError: 一个操作有None 用于梯度。请确保您的所有操作都定义了渐变(即可微分)。无梯度的常用操作:K.argmax、K.round、K.eval。

由于 Daniel 可以毫无问题地运行它,为了检查我的程序中出了什么问题,我在此处发布了我的简化代码。我的数据有 8 个通道,但你有多少并不重要。

from keras.layers import Input, Conv2D
from keras.models import Model, optimizers
import numpy as np
import tensorflow as tf
from keras import backend as K
from keras.callbacks import ModelCheckpoint


class ZeroCenterConv2D(Conv2D):
    def __init__(self, filters, kernel_size, **kwargs):
        super(ZeroCenterConv2D, self).__init__(filters, kernel_size, **kwargs)

    def call(self, inputs):
        assert self.kernel_size[0] % 2 == 1, "Error: the kernel size is an even number"
        assert self.kernel_size[1] % 2 == 1, "Error: the kernel size is an even number"

        centerX = (self.kernel_size[0] - 1) // 2
        centerY = (self.kernel_size[1] - 1) // 2

        kernel_mask = np.ones(self.kernel_size + (1, 1))
        kernel_mask[centerX, centerY] = 0
        kernel_mask = K.constant(kernel_mask)

        customKernel = self.kernel * kernel_mask

        outputs = K.conv2d(
            inputs,
            customKernel,
            strides=self.strides,
            padding=self.padding,
            data_format=self.data_format,
            dilation_rate=self.dilation_rate)

        if self.activation is not None:
            return self.activation(outputs)

        return outputs


size1 = 256
size2 = 256
input_img = Input(shape=(size1, size2, 8))
conv1 = ZeroCenterConv2D(8, (5, 5), padding='same', activation='relu')(input_img)
autoencoder = Model(input_img, conv1)
adam = optimizers.Adam(lr=0.001, beta_1=0.9, beta_2=0.999, epsilon=1e-8)
autoencoder.compile(optimizer=adam, loss='mean_squared_error')


import scipy.io
A = scipy.io.loadmat('data_train')
x_train = A['data']
x_train = np.reshape(x_train, (1, 256, 256, 8))


from keras.callbacks import TensorBoard

autoencoder.fit(x_train, x_train,
                epochs=5,
                batch_size=1,
                shuffle=False,
                validation_data=(x_train, x_train),
                callbacks=[TensorBoard(log_dir='/tmp/autoencoder')])


decoded_imgs = autoencoder.predict(x_train)

当 conv1 = ZeroCenterConv2D... 被传统的 conv1 = Conv2D... 取代时,一切正常。

完整的错误信息:

Connected to pydev debugger (build 181.4668.75)
/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site-packages/h5py/__init__.py:36: FutureWarning: Conversion of the second argument of issubdtype from `float` to `np.floating` is deprecated. In future, it will be treated as `np.float64 == np.dtype(float).type`.
  from ._conv import register_converters as _register_converters
Using TensorFlow backend.
Traceback (most recent call last):
  File "/snap/pycharm-community/60/helpers/pydev/pydevd.py", line 1664, in <module>
    main()
  File "/snap/pycharm-community/60/helpers/pydev/pydevd.py", line 1658, in main
    globals = debugger.run(setup['file'], None, None, is_module)
  File "/snap/pycharm-community/60/helpers/pydev/pydevd.py", line 1068, in run
    pydev_imports.execfile(file, globals, locals)  # execute the script
  File "/home/allen/autotion/temptest", line 62, in <module>
    callbacks=[TensorBoard(log_dir='/tmp/autoencoder')])
  File "/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site-packages/keras/engine/training.py", line 1682, in fit
    self._make_train_function()
  File "/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site-packages/keras/engine/training.py", line 992, in _make_train_function
    loss=self.total_loss)
  File "/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site-packages/keras/legacy/interfaces.py", line 91, in wrapper
    return func(*args, **kwargs)
  File "/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site-packages/keras/optimizers.py", line 445, in get_updates
    grads = self.get_gradients(loss, params)
  File "/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site-packages/keras/optimizers.py", line 80, in get_gradients
    raise ValueError('An operation has `None` for gradient. '
ValueError: An operation has `None` for gradient. Please make sure that all of your ops have a gradient defined (i.e. are differentiable). Common ops without gradient: K.argmax, K.round, K.eval.

Process finished with exit code 1

进一步更新:在 Daniel 的回答中的代码中添加“偏见”部分(已经完成),问题解决了!

【问题讨论】:

    标签: python tensorflow filter keras constraints


    【解决方案1】:

    为此,您需要一个自定义的 Conv2D 层,在其中更改其调用方法以在中心应用零。

    class ZeroCenterConv2D(Conv2D):
        def __init__(self, filters, kernel_size, **kwargs):
            super(ZeroCenterConv2D, self).__init__(filters, kernel_size, **kwargs)
    
        def call(self, inputs):
            assert self.kernel_size[0] % 2 == 1, "Error: the kernel size is an even number"
            assert self.kernel_size[1] % 2 == 1, "Error: the kernel size is an even number"
    
            centerX = (self.kernel_size[0] - 1) // 2
            centerY = (self.kernel_size[1] - 1) // 2
    
            kernel_mask = np.ones(self.kernel_size + (1, 1))
            kernel_mask[centerX, centerY] = 0
            kernel_mask = K.variable(kernel_mask)
    
            customKernel = self.kernel * kernel_mask
    
            outputs = K.conv2d(
                inputs,
                customKernel,
                strides=self.strides,
                padding=self.padding,
                data_format=self.data_format,
                dilation_rate=self.dilation_rate)
    
            if self.use_bias:
                outputs = K.bias_add(
                    outputs,
                    self.bias,
                    data_format=self.data_format)
    
            if self.activation is not None:
                return self.activation(outputs)
    
            return outputs
    

    不过,这不会替换实际的权重,但永远不会使用中间的权重。

    当您使用layer.get_weights() 或model.get_weights() 时,您将看到初始化时的中心权重(而不是零)。

    【讨论】:

    • 感谢您的快速回复!我试过了,但得到了这个错误:“ValueError: An operation has None for gradient。请确保你的所有操作都定义了一个梯度(即是可微分的)。没有梯度的常见操作:K.argmax,K.round , K.eval." 然后我把"kernel_mask[centerX,centerY] = np.spacing(1)" (替换"0") 放入代码中,但错误仍然存​​在。
    • 对不起,这可能不是真正的错误。我将“call”替换为“__ call __”,然后该错误不再存在。相反,它给出了这个错误消息“AttributeError:'ZeroCenterConv2D'对象没有属性'内核'”
    • 我在我的电脑上测试了这段代码,所以它没有问题,因为它是写的。您可能在其他地方有另一个操作存在梯度问题,或者您使用的是 keras/tensorflow 的旧版本。
    • 更新。 1.我在这里用“filers”替换“kernel”“customKernel = self.filters * kernel_mask”。我认为这是发生错误的地方,对此不确定。 2.我添加了“kernel_mask = np.repeat(kernel_mask,inputs.get_shape()[3],axis=2)”以摆脱抱怨“ValueError:输入通道数与过滤器的相应维度不匹配,3! = 1"。 3.当前错误:“TypeError: Output tensors to a Model must be Keras tensors. Found: Tensor("Relu:0", shape=(?, 256, 256, 1), dtype=float32)".
    • 你的 keras 和 tensorflow 版本是什么?更改此代码对您没有帮助
    猜你喜欢
    • 2021-02-16
    • 2021-09-21
    • 2018-01-16
    • 1970-01-01
    • 2018-02-23
    • 2017-09-04
    • 2018-12-13
    • 1970-01-01
    • 2020-12-31
    相关资源
    最近更新 更多