Пользовательский слой Keras не возвращает веса, в отличие от обычного слоя - PullRequest
2 голосов
/ 31 марта 2019

Я пытаюсь получить вес слоя.Кажется, что он работает правильно, когда используется слой keras и к нему подключен вход.Однако, когда я оборачиваю его в мой пользовательский слой, это больше не работает.Это ошибка или что я упускаю?

Редактировать: соображения:

Я читал, что в build () пользовательского слоя можно определить обучаемые переменные.Однако, поскольку пользовательский слой состоит из плотного слоя керас (и, возможно, позже из нескольких слоев керас), у них уже должны быть заданные обучаемые переменные и инициализаторы веса / смещения.(Я бы не увидел способа перезаписать их в init () TestLayer, с помощью переменных, которые были бы определены в build () TestLayer.

class TestLayer(layers.Layer):
    def __init__(self):
        super(TestLayer, self).__init__()
        self.test_nn = layers.Dense(3)

    def build(self, input_shape):
        super(TestLayer, self).build(input_shape)


    def call(self, inputs, **kwargs):
        test_out = test_nn(inputs) # which is test_in
        return test_out


test_in = layers.Input((2,))
test_nn = layers.Dense(3)
print(test_nn.get_weights()) # empty, since no connection to the layer
test_out = test_nn(test_in)
print(test_nn.get_weights()) # layer returns weights+biases

testLayer = TestLayer()
features = testLayer(test_in)
print(testLayer.get_weights()) # Problem: still empty, even though connected to input.

Ответы [ 2 ]

1 голос
/ 31 марта 2019

В документации говорится, что метод build() должен иметь вызовы add_weight(), которых у вас нет:

Должны иметь вызовы add_weight (), а затем вызывать build суперкомпьютера ()

Вам также не нужно определять плотный слой внутри вашего класса, если вы создаете подкласс layers.Layer. Вот как вы должны создать подкласс:

import tensorflow as tf
from tensorflow.keras import layers

class TestLayer(layers.Layer):
    def __init__(self, outshape=3):
        super(TestLayer, self).__init__()
        self.outshape = outshape

    def build(self, input_shape):
        self.kernel = self.add_weight(name='kernel',
                                      shape=(int(input_shape[1]), self.outshape),
                                      trainable=True)

        super(TestLayer, self).build(input_shape)


    def call(self, inputs, **kwargs):
        return tf.matmul(inputs, self.kernel)

test_in = layers.Input((2,))

testLayer = TestLayer()
features = testLayer(test_in)
print(testLayer.get_weights())
#[array([[-0.68516827, -0.01990592,  0.88364804],
#       [-0.459718  ,  0.19161093,  0.39982545]], dtype=float32)]

Здесь еще несколько примеров подклассов Layer class.

Однако , если вы настаиваете на его реализации по-своему и если вы хотите использовать get_weights(), вы должны переопределить его (в этом случае вы можете просто создать класс без подклассов):

import tensorflow as tf
from tensorflow.keras import layers

class TestLayer(layers.Layer):
    def __init__(self, outshape=3):
        super(TestLayer, self).__init__()
        self.test_nn = layers.Dense(outshape)
        self.outshape = outshape

    def build(self, input_shape):
        super(TestLayer, self).build(input_shape)

    def call(self, inputs, **kwargs):
        return self.test_nn(inputs)

    def get_weights(self):
        with tf.Session() as sess:
            sess.run([x.initializer for x in self.test_nn.trainable_variables])
            return sess.run(self.test_nn.trainable_variables)

test_in = layers.Input((2,))

testLayer = TestLayer()
features = testLayer(test_in)
print(testLayer.get_weights())
#[array([[ 0.5692867 ,  0.726858  ,  0.37790012],
#       [ 0.2897135 , -0.7677493 , -0.58776844]], dtype=float32), #array([0., 0., 0.], dtype=float32)]
1 голос
/ 31 марта 2019

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

Вы можете определить метод в своем пользовательском слое, например:

def dense(X, f_in, f_out):
    W = self.add_weight(name='kernel',
                        shape=(f_in, f_out))
    b = self.add_weight(name='bias',
                        shape=(f_out, ))
    return K.dot(X, W) + b

или создайте подкласс плотного слоя и используйте вывод super().call().

...