与普通层不同,Keras 自定义层不返回权重
Keras custom layer not returning weights, unlike normal layer
我正在尝试获取层的权重。当使用 keras 层并将输入连接到它时,它似乎可以正常工作。
但是,在将它包装到我的自定义层中时,它不再起作用了。这是错误还是我遗漏了什么?
编辑:注意事项:
我读到可以在自定义层的 build() 中定义可训练变量。但是,由于自定义层由密集的 keras 层组成(之后可能还有更多的 keras 层),因此这些层应该已经定义了可训练变量和 weight/bias 初始化器。 (我看不到覆盖它们的方法,在 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.
遗憾的是,Keras 不支持在其他图层中使用图层。
我以前遇到过这个问题,并开了一个issue here,但是团队向我确认这是故意的。
您可以在自定义层中定义一个方法,例如:
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()
.
的输出
documentation 说 build()
方法应该调用 add_weight()
而你没有:
Should have the calls to add_weight(), and then call the super's build()
如果您正在 classlayers.Layer
,您也不需要在 class 内部定义致密层。
这就是你应该如何 subclass:
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)]
Here 是 classing Layer
class.
的更多示例
但是,如果你坚持按照你的方式实现它并且如果你想使用get_weights()
你必须覆盖它(在这种情况下你可以创建一个class 没有 subclassing):
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)]
我正在尝试获取层的权重。当使用 keras 层并将输入连接到它时,它似乎可以正常工作。 但是,在将它包装到我的自定义层中时,它不再起作用了。这是错误还是我遗漏了什么?
编辑:注意事项:
我读到可以在自定义层的 build() 中定义可训练变量。但是,由于自定义层由密集的 keras 层组成(之后可能还有更多的 keras 层),因此这些层应该已经定义了可训练变量和 weight/bias 初始化器。 (我看不到覆盖它们的方法,在 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.
遗憾的是,Keras 不支持在其他图层中使用图层。 我以前遇到过这个问题,并开了一个issue here,但是团队向我确认这是故意的。
您可以在自定义层中定义一个方法,例如:
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()
.
documentation 说 build()
方法应该调用 add_weight()
而你没有:
Should have the calls to add_weight(), and then call the super's build()
如果您正在 classlayers.Layer
,您也不需要在 class 内部定义致密层。
这就是你应该如何 subclass:
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)]
Here 是 classing Layer
class.
但是,如果你坚持按照你的方式实现它并且如果你想使用get_weights()
你必须覆盖它(在这种情况下你可以创建一个class 没有 subclassing):
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)]