我可以将张量的一部分设置为不可训练吗?
Could I set a part of a tensor untrainable?
设置一个不可训练的张量很容易,trainable=False
。但是我可以只设置张量的一部分不可训练吗?
假设我有一个 2*2 张量,我只希望一个元素不可训练,而其他三个元素可训练。
像这样(我希望1,1元素始终为零,其他三个元素由优化器更新)
untrainable trainable
trainable trainable
谢谢。
简答:你不能。
更长的答案:您可以通过在计算梯度后将梯度的一部分设置为零来模拟该效果,这样变量的一部分就永远不会更新。
这是一个例子:
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]]))
然后,在 运行 那个循环之后,我们可以再次检查权重:
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)>
而且只更改了第一行。
设置一个不可训练的张量很容易,trainable=False
。但是我可以只设置张量的一部分不可训练吗?
假设我有一个 2*2 张量,我只希望一个元素不可训练,而其他三个元素可训练。
像这样(我希望1,1元素始终为零,其他三个元素由优化器更新)
untrainable trainable
trainable trainable
谢谢。
简答:你不能。
更长的答案:您可以通过在计算梯度后将梯度的一部分设置为零来模拟该效果,这样变量的一部分就永远不会更新。
这是一个例子:
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]]))
然后,在 运行 那个循环之后,我们可以再次检查权重:
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)>
而且只更改了第一行。