如何在Keras中构建此自定义图层?

时间:2019-04-26 07:50:50

标签: tensorflow keras deep-learning

我正在构建一个支持复数的NN。目前正在从事复杂的激活。根据Benjio的论文,这是一个很好的方法:

enter image description here

其中b是要学习的可训练参数。因此,我正在建立一个特殊的层来执行此激活。我是Keras的新手,已经被卡住了。我在下面创建了此代码,但是生成功能出错。我不知道发生了什么,我只是试图复制模板。请帮忙。

class modrelu(Layer):
    def __init__(self, **kwargs):
        super(modrelu, self).__init__(**kwargs)

    def build(self):
        self.b= K.variable(value=np.random.rand()-0.5, dtype='float64')
        super(modrelu, self).build()  # Be sure to call this at the end

    def call(self, x):
        assert isinstance(x, list)
        ip_r, ip_i = x
        comp= tf.complex(ip_r, ip_i ) 
        ABS= tf.math.abs(comp)
        ANG= tf.math.angle(comp)

        ABS= K.relu( self.b + ABS) 

        op_r=  ABS * K.sin(angle) #K.dot ??
        op_i= ABS * K.cos(angle)
        return [op_r, op_i]

    def compute_output_shape(self, input_shape):
        assert isinstance(input_shape, list)
        shape_a, shape_b = input_shape
        return [shape_a, shape_b]

对我的代码的评论: 在 init 中,我没有添加任何内容,因为它是一个激活层,在实例化时不需要任何输入。

在build方法中,我尝试添加b。不知道我是否应该使用self.add_weight方法。理想情况下,我希望与输入的维数一样多。

在调用方法中,我很确定自己在做什么。很简单,我刚刚实现了该功能。

最后一个,compute_output_shape,我只是复制粘贴了模板。输出应该与输入相同,因为它只是一个激活层。

最后,关于它的价值的错误,我知道这是胡说八道

TypeError                                 Traceback (most recent call last)
<ipython-input-5-3101a9226da5> in <module>
      1 a=K.variable(np.array([1,2]))
      2 b=K.variable(np.array([3,4]))
----> 3 act([a,b])

~\AppData\Local\conda\conda\envs\python36\lib\site-packages\keras\engine\base_layer.py in __call__(self, inputs, **kwargs)
    429                                          'You can build it manually via: '
    430                                          '`layer.build(batch_input_shape)`')
--> 431                 self.build(unpack_singleton(input_shapes))
    432                 self.built = True
    433 

TypeError: build() takes 1 positional argument but 2 were given

2 个答案:

答案 0 :(得分:1)

您未正确编码图层,build函数使用一个input_shape参数,您可以使用该参数初始化图层的权重/参数。

您可以在Keras' source code中看到一个示例。

答案 1 :(得分:1)

您的代码有几个问题。

首先,我应该解决您从解释器得到的错误:

import numpy as np

a = np.array([[0, 1, 1, 1, 0, 0, 0, 0, 1, 0],
             [0, 0, 1, 0, 0, 1, 0, 0, 0, 0],
             [1, 0, 0, 0, 0, 1, 0, 0, 1, 0]])

ones = 5

to_add = ones - np.count_nonzero(a, axis=1)

for i in range(a.shape[0]):

    idx = np.random.choice(np.flatnonzero(a[i, :] == 0), size=to_add[i], replace=False)

    a[i, idx] = 1

TypeError: build() takes 1 positional argument but 2 were given 方法应采用build参数。因此,您应该将构建方法声明为input_shape

第二个问题是build(self, input_shape)方法中变量的形状不确定。您应该显式声明变量的形状。在您的情况下,build数组应为np.random.rand形状。

另一个问题是,您试图在input_shape方法中返回2个结果([op_r, op_i])。我不是Keras的专家,但据我所知您做不到。每个Keras层应该只有一个输出。有关详情,请参见此处:https://github.com/keras-team/keras/issues/3061

但是,如果您使用tensorflow后端,则可以使用复数(call)来返回复数的实数部分(tf.complex和虚数部分(op_r)。

这是op_i层的有效实现,并带有简单的用法示例。它是TensorFlow 1.12.0的写法,它随其自己的Keras API实现一起分发,但我认为您可以轻松地将其用于原始Keras:

modrelu

附言::我没有检查数学,所以您应该自己检查。