Python 如何在Keras中操纵(约束)Conv2D中过滤器内核的权重?

Python 如何在Keras中操纵(约束)Conv2D中过滤器内核的权重?,python,tensorflow,filter,keras,constraints,Python,Tensorflow,Filter,Keras,Constraints,我知道在Keras中Conv2D中有几个内核约束选项:max_norm、non_neg或unit_norm 但我需要的是将过滤器内核中的锚点(中心)位置设置为零。 例如,如果我们有一个大小为(width,height)=(5,5)的过滤器内核,并且我们在输入中有3个通道。我需要为每个通道将内核的锚点(中心)限制为0,比如w(2,2,:)=0,假设我们将通道维度设置为第三维。如果有多个过滤器,每个过滤器的固定位置应为零。我如何实现这一点 我假设需要自定义内核约束。此链接提供如何创建一个继承自约束的

我知道在Keras中Conv2D中有几个内核约束选项:max_norm、non_neg或unit_norm

但我需要的是将过滤器内核中的锚点(中心)位置设置为零。 例如,如果我们有一个大小为(width,height)=(5,5)的过滤器内核,并且我们在输入中有3个通道。我需要为每个通道将内核的锚点(中心)限制为0,比如w(2,2,:)=0,假设我们将通道维度设置为第三维。如果有多个过滤器,每个过滤器的固定位置应为零。我如何实现这一点

我假设需要自定义内核约束。此链接提供如何创建一个继承自约束的类的建议:。这显示了如何实现内置约束:

但是,我仍然不知道如何操纵w的尺寸,以及如何将期望的位置设置为零。感谢您的帮助。谢谢

更新: 丹尼尔·莫勒的答案被试过了。错误消息如下:
raise VALUE ERROR('一个操作对梯度有
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
连接到pydev调试器(build 181.4668.75)
/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site packages/h5py/_init_uuuuuu.py:36:FutureWarning:不赞成将issubdtype的第二个参数从'float'转换为'np.floating'。将来,它将被视为'np.float64==np.dtype(float.type`。
from.\u conv导入寄存器\u转换器作为\u寄存器\u转换器
使用TensorFlow后端。
回溯(最近一次呼叫最后一次):
文件“/snap/pycharm community/60/helpers/pydev/pydevd.py”,第1664行,在
main()
文件“/snap/pycharm community/60/helpers/pydev/pydevd.py”,第1658行,主目录
globals=debugger.run(setup['file'],None,None,is_模块)
文件“/snap/pycharm community/60/helpers/pydev/pydevd.py”,第1068行,运行中
pydev_imports.execfile(文件、全局、局部)#执行脚本
文件“/home/allen/autoticon/tentest”,第62行,在
回调=[TensorBoard(log_dir='/tmp/autoencoder')])
文件“/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site packages/keras/engine/training.py”,第1682行
self.\u make\u train\u function()
文件“/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site packages/keras/engine/training.py”,第992行,在“制造”和“训练”功能中
损失=自身总损失)
文件“/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site packages/keras/legacy/interfaces.py”,第91行,在包装器中
返回函数(*args,**kwargs)
文件“/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site packages/keras/optimizers.py”,第445行,在get_更新中
梯度=自身。获取梯度(损失,参数)
文件“/home/allen/kerasProject/keras/venv/py2.7/local/lib/python2.7/site packages/keras/optimizers.py”,第80行,在get_渐变中
raise VALUERROR('一个操作的梯度为'None'
ValueError:操作的梯度为“无”。请确保所有操作都定义了梯度(即可微分)。没有梯度的常见操作:K.argmax、K.round、K.eval。
进程已完成,退出代码为1


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

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

类ZeroCenterConv2D(Conv2D):
def uuu init uuuuu(自、过滤器、内核大小,**kwargs):
超级(ZeroCenterConv2D,self)。\uuuuu初始化(过滤器,内核大小,**kwargs)
def呼叫(自我,输入):
断言self.kernel\u size[0]%2==1,“错误:内核大小是偶数”
断言self.kernel_size[1]%2==1,“错误:内核大小是偶数”
centerX=(self.kernel\u size[0]-1)//2
centerY=(self.kernel_size[1]-1)//2
kernel\u mask=np.one(self.kernel\u size+(1,1))
内核掩码[centerX,centerY]=0
kernel\u mask=K.变量(kernel\u mask)
customKernel=self.kernel*kernel\u掩码
输出=K.2d(
投入,
自定义内核,
步幅,
padding=self.padding,
data\u format=self.data\u format,
扩张率=自身扩张率)
如果使用self.u偏差:
输出=K.bias\u add(
产出,
自我偏见,
数据格式=自。数据格式)
如果self.activation不是None:
返回自激活(输出)
返回输出
但这不会取代实际重量,但永远不会使用中心重量


当您使用
模型的
层。get\u weights()
时,您将看到初始化时的中心权重(而不是零)。

感谢您如此快速的回复!我尝试了,但得到了以下错误:“ValueError:一个操作对于渐变没有
任何值。请确保您的所有操作都定义了渐变(即是可微的)。没有梯度的普通运算:K.argmax,K.round,K.eval。”然后我在代码中加入“kernel_mask[centerX,centerY]=np.spating(1)”(替换“0”),但错误仍然存在。抱歉,这可能不是真正的错误。我将“call”替换为“call”,然后该错误不再存在。相反,它给出了