【问题标题】:Could I set a part of a tensor untrainable?我可以设置张量的一部分不可训练吗?
【发布时间】:2021-05-13 03:48:54
【问题描述】:

设置一个不可训练的张量很容易,trainable=False。但是我可以只设置张量的一部分不可训练吗?

假设我有一个 2*2 的张量,我只希望一个元素不可训练,而其他三个元素可训练。

像这样(我希望 1,1 元素始终为零,而其他三个元素由优化器更新)

untrainable trainable 
trainable   trainable

谢谢。

【问题讨论】:

  • 我会在调用optimizer.apply_gradients 之前尝试保存所需的权重,并在调用optimizer.apply_gradients 之后将它们更改回之前的状态。但它并不能阻止反向传播

标签: python tensorflow keras gradient tensor


【解决方案1】:

简短的回答:你不能。

更长的答案:您可以通过在计算梯度后将部分梯度设置为零来模拟这种效果,这样部分变量就永远不会更新。

这是一个例子:

import tensorflow as tf
tf.random.set_seed(0)
model = tf.keras.Sequential([tf.keras.layers.Dense(2, activation="sigmoid", input_shape=(2,), name="first"), tf.keras.layers.Dense(1,activation="sigmoid")])
X = tf.random.normal((1000,2))
y = tf.reduce_sum(X, axis=1)
ds = tf.data.Dataset.from_tensor_slices((X,y))

在该示例中,第一层的权重 W 如下:

>>> model.get_layer("first").trainable_weights[0]
<tf.Variable 'first/kernel:0' shape=(2, 2) dtype=float32, numpy=
array([[ 0.13573623, -0.68269   ],
       [ 0.8938798 ,  0.6792033 ]], dtype=float32)>

然后我们编写自定义循环,它只会更新该权重的第一行W

loss = tf.losses.MSE
opt = tf.optimizers.SDG(1.) # high learning rate to see the change
for xx,yy in ds.take(1):
    with tf.GradientTape() as tape:
        l = loss(model(xx),yy)
    g = tape.gradient(l,model.get_layer("first").trainable_weights[0])
    gradient_slice = g[:1] # first row
    new_grad = tf.concat([gradient_slice, tf.zeros((1,2), dtype=tf.float32),], axis=0) # replacing the rest with zeros
    opt.apply_gradients(zip([new_grad], [model.get_layer("first").trainable_weights[0]]))

然后,在运行该循环之后,我们可以再次检查 wieghts:

model.get_layer("first").trainable_weights[0]
<tf.Variable 'first/kernel:0' shape=(2, 2) dtype=float32, numpy=
array([[-0.08515069, -0.51738167],
       [ 0.8938798 ,  0.6792033 ]], dtype=float32)>

只有第一行发生了变化。

【讨论】:

  • 谢谢!这是一个优雅的解决方案:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-09-16
  • 1970-01-01
  • 2018-06-01
  • 1970-01-01
  • 1970-01-01
  • 2020-06-03
  • 1970-01-01
相关资源
最近更新 更多