我想创建一个包含tensorflow.keras的图层,其中包含可训练和不可训练的权重。我尝试通过子类keras.layers.Layer来实现此目的,如本例所示:
class MySum(keras.layers.Layer):
def __init__(self, units=32, **kwargs):
super(MySum, self).__init__(**kwargs)
self.units = units
def build(self, input_shape):
n_input = input_shape[-1] # nb of input elements
n_output = self.units # nb of layer neurons
n_input_div_2 = input_shape[-1] // 2
# 1. add the trainable weights
self.w = self.add_weight(shape=(n_input_div_2, self.units),
initializer=tf.ones_initializer(),
trainable=True)
# 2. add the non trainable weights
self.w = self.add_weight(shape=(input_shape[-1]-n_input_div_2, self.units),
initializer=tf.keras.initializers.Constant(value=3),
trainable=False)
def call(self, inputs):
return tf.matmul(inputs, self.w)
不幸的是,这样做所有的重量都是无法训练的。如果我先添加不可训练的权重,则所有权重都是可训练的(似乎可训练标志是根据最后添加的权重设置的)。 我在这里想念什么?
编辑: 我试图在构建函数中使用Snoopy博士建议的其他名称:
# 1. add the trainable weights
w1 = self.add_weight(shape=(n_input_div_2, self.units),
initializer=tf.ones_initializer(),
trainable=True)
# 2. add the non trainable weights
w2 = self.add_weight(shape=(input_shape[-1]-n_input_div_2, self.units),
initializer=tf.keras.initializers.Constant(value=3),
trainable=False)
self.w = tf.concat([w1, w2], 0)
但是,当我尝试使用这样的图层时:
custom = customLayer.MySum(1, name='somme')
my_input = keras.Input(shape=(2,), name="input")
my_output = custom(my_input)
print(custom.get_weights())
我通过get_weights()函数获得:
tf.Tensor(
[[1.]
[3.]], shape=(2, 1), dtype=float32)
[array([[1.],
[1.]], dtype=float32), array([[1.]], dtype=float32), array([[3.]], dtype=float32)]
[[1。],[1。]]数组从哪里来? (我只想拥有[[1。] [3。]]数组)
训练模型时,我有很多警告: “警告:tensorflow:变量['somme / Variable:0','somme / Variable:0']不存在渐变尽量减少损失。” keras如何将我自己的权重(self.w)与get_weights()返回的权重联系起来?
注意:当我创建自定义图层而不混合可训练和不可训练的权重时,我没有这些问题。
答案 0 :(得分:0)
正如Snoopy博士所指出的那样,您的第一个解决方案是使用相同的变量名覆盖先前定义的权重。
关于为什么第二个解决方案也不起作用的原因是,在两个tf.concat
tf.Variable
和w1
上调用w2
之后,e梯度消失了。这是Tensorflow上的已知错误,您可以在github上找到问题:Gradients do not exist for variables after tf.concat(). #37726
让我们使用tf.GradientTape
进行一些实验来计算梯度:
w1 = tf.Variable([1.0])
w2 = tf.Variable([3.0])
w = tf.expand_dims(tf.concat([w1,w2],0),-1)
X = tf.random.normal((1,2))
y = tf.reduce_sum(X,1)
with tf.GradientTape(persistent=True) as tape:
r = tf.matmul(w,X)
loss = tf.metrics.mse(y, w)
print(tape.gradient(loss, r))
结果为None
。
一种解决方案是将变量分开。对于您的图层,其中的数字为units=1
,这是tf.matmul
的简单替换:
w1 = tf.Variable([1.0])
w2 = tf.Variable([3.0], trainable=False)
X = tf.random.normal((1,2))
y = tf.reduce_sum(X,1)
with tf.GradientTape(persistent=True) as tape:
r = X[:,0]*w1 + X[:,1]*w2
loss = tf.metrics.mse(y,r)
print(tape.gradient(loss, r))
输出:tf.Tensor([-3.1425157], shape=(1,), dtype=float32)