3

我正在尝试获取图层的权重。当使用 keras 层并且输入连接到它时,它似乎可以正常工作。但是,在将其包装到我的自定义层中时,它不再起作用了。这是一个错误还是我错过了什么?

编辑:注意事项:

我读到可以在自定义层的 build() 中定义可训练变量。但是,由于自定义层由 keras 层 Dense (以及以后可能更多的 keras 层)组成,那些应该已经定义了可训练变量和权重/偏差初始化器。(我看不到在 TestLayer 的init () 中使用将在 TestLayer 的 build() 中定义的变量来覆盖它们的方法。

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.
4

2 回答 2

2

文档说该方法build()应该有add_weight()你没有的调用:

应该调用 add_weight(),然后调用 super 的 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类化的例子。

但是,如果您坚持以自己的方式实现它并且如果您想使用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)]
于 2019-03-31T15:50:13.160 回答
1

不幸的是,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

或对 Dense 层进行子类化并使用super().call().

于 2019-03-31T15:09:40.790 回答