Как построить этот пользовательский слой в Керасе? - PullRequest
2 голосов
/ 26 апреля 2019

Я строю NN, который поддерживает комплексные числа. В данный момент работаю над комплексной активацией. По словам Бенджио, это хороший документ:

enter image description here

Где b - обучаемый параметр, который нужно выучить . Поэтому я создаю специальный слой для этой активации. Я новичок в Керасе и уже застрял. Я создал этот код ниже, но он дает ошибку с функцией сборки. Я понятия не имею, что происходит, я просто попытался скопировать шаблон. Пожалуйста, помогите.

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 я ничего не добавил, потому что это слой активации, который не требует ввода при создании экземпляра.

В методе сборки я попытался добавить буквы b. Не уверен, стоит ли мне использовать метод self.add_weight. В идеале, я хочу иметь столько же b, сколько и размер входных данных.

В этом методе вызова я почти уверен, что делаю. Это просто, я только что реализовал функцию.

Последний, 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 ]

1 голос
/ 26 апреля 2019

Есть несколько проблем с вашим кодом.

Прежде всего я должен устранить ошибку, которую вы получаете от интерпретатора:

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]) в методе call.Я не специалист по Керасу, но насколько я знаю, ты не сможешь этого сделать.Каждый слой Keras должен иметь один и только один выход.Подробности смотрите здесь: https://github.com/keras-team/keras/issues/3061

Однако, если вы используете бэкэнд тензорного потока, вы можете использовать комплексные числа (tf.complex), чтобы возвращать как действительные (op_r), так и мнимые (op_i) частикомплексное число.

Вот рабочая реализация слоя modrelu с простым примером использования.Он написан для TensorFlow 1.12.0, который распространяется с собственной реализацией API Keras, но я думаю, что вы легко можете принять его для оригинального Keras:

import tensorflow as tf
from tensorflow.python.keras import backend as K
from tensorflow.python.keras.engine import Layer
import numpy as np


class modrelu(Layer):

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

    # provide input_shape argument in the build method
    def build(self, input_shape):
        # You should pass shape for your variable
        self.b= K.variable(value=np.random.rand(*input_shape)-0.5,
                           dtype='float32')
        super(modrelu, self).build(input_shape)  # Be sure to call this at the end

    def call(self, inputs, **kwargs):
        assert inputs.dtype == tf.complex64

        ip_r = tf.math.real(inputs)
        ip_i = tf.math.imag(inputs)

        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(ANG) #K.dot ??
        op_i = ABS * K.cos(ANG)

        # return single tensor in the call method
        return tf.complex(op_r, op_i)


real = tf.constant([2.25, 3.25])
imag = tf.constant([4.75, 5.75])

x = tf.complex(real, imag)

y = modrelu()(x)

with tf.Session() as sess:
    sess.run(tf.global_variables_initializer())

    print(sess.run(y))

PS: Я не сделалне проверяйте математику, поэтому вы должны проверить это самостоятельно.

1 голос
/ 26 апреля 2019

Вы неправильно кодируете слой, функция build принимает параметр input_shape, который можно использовать для инициализации весов / параметров вашего слоя.

Вы можете увидеть пример в исходном коде Keras .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...