Python 如何在tensorflow 2中获得损耗梯度wrt内层输出?
我想得到在训练过程中,模型的损失函数相对于特定层输出的梯度。接下来我想用它做的是,在下一个学习阶段,使用梯度值来修改图层中的某些内容。 那么如何获得梯度呢 这里有一个最小的例子。 MinimarNcell代码是从TensorFlow的网站上复制的,提供的玩具数据只是为了重现这种行为Python 如何在tensorflow 2中获得损耗梯度wrt内层输出?,python,tensorflow,machine-learning,tensorflow2.0,tf.keras,Python,Tensorflow,Machine Learning,Tensorflow2.0,Tf.keras,我想得到在训练过程中,模型的损失函数相对于特定层输出的梯度。接下来我想用它做的是,在下一个学习阶段,使用梯度值来修改图层中的某些内容。 那么如何获得梯度呢 这里有一个最小的例子。 MinimarNcell代码是从TensorFlow的网站上复制的,提供的玩具数据只是为了重现这种行为 import tensorflow as tf from tensorflow.keras.layers import RNN, SimpleRNNCell, SimpleRNN, Layer, Dense, Ab
import tensorflow as tf
from tensorflow.keras.layers import RNN, SimpleRNNCell, SimpleRNN, Layer, Dense, AbstractRNNCell
from tensorflow.keras import Model
import numpy as np
import tensorflow.keras.backend as K
class MinimalRNNCell(AbstractRNNCell):
def __init__(self, units, **kwargs):
self.units = units
super(MinimalRNNCell, self).__init__(**kwargs)
@property
def state_size(self):
return self.units
def build(self, input_shape):
self.kernel = self.add_weight(shape=(input_shape[-1], self.units),
initializer='uniform',
name='kernel')
self.recurrent_kernel = self.add_weight(
shape=(self.units, self.units),
initializer='uniform',
name='recurrent_kernel')
self.built = True
def call(self, inputs, states):
prev_output = states[0]
h = K.dot(inputs, self.kernel)
output = h + K.dot(prev_output, self.recurrent_kernel)
return output, output
class MyModel(Model):
def __init__(self, size):
super(MyModel, self).__init__()
self.minimalrnn=RNN(MinimalRNNCell(size), name='minimalrnn')
self.out=Dense(4)
def call(self, inputs):
out=self.minimalrnn(inputs)
out=self.out(out)
return out
x=np.array([[[3.],[0.],[1.],[2.],[3.]],[[3.],[0.],[1.],[2.],[3.]]])
y=np.array([[[0.],[1.],[2.],[3.]],[[0.],[1.],[2.],[3.]]])
model=MyModel(2)
model.compile(optimizer='sgd', loss='mse')
model.fit(x,y,epochs=10, batch_size=1, validation_split=0.2)
现在我想得到MyModel最小RNN层的输出梯度(在每一批数据之后)
如何做到这一点?我想我可以尝试使用GradientTape观看模型。get_layer('MinimarNN')。output,但我需要更多的学习资源或示例
编辑
我在Tiago Martins Peres提供的代码中使用了GradientTape,但我特别希望获得GradientWRT层输出,但我仍然无法实现这一点
现在,在类定义之后,我的代码如下所示:
x=np.array([[[3.],[0.],[1.],[2.],[3.]],[[3.],[0.],[1.],[2.],[3.]]])
y=np.array([[0., 1., 2., 3.],[0., 1., 2., 3.]])
model=MyModel(2)
#inputs = tf.keras.Input(shape=(2,5,1))
#model.call(x)
def gradients(model, inputs, targets):
with tf.GradientTape() as tape:
tape.watch(model.get_layer('minimalrnn').output)
loss_value = loss_fn(model, inputs, targets)
return tape.gradient(loss_value, model.trainable_variables)
def loss_fn(model, inputs, targets):
error = model(inputs) - targets
return tf.reduce_mean(tf.square(error))
optimizer = tf.keras.optimizers.Adam(learning_rate=0.01)
print("Initial loss: {:.3f}".format(loss_fn(model, x, y)))
for i in range(10):
grads = gradients(model, x, y)
optimizer.apply_gradients(zip(grads, model.trainable_variables))
print("Loss at step {:03d}: {:.3f}".format(i, loss_fn(model, x, y)))
print("Final loss: {:.3f}".format(loss_fn(model, x, y)))
如您所见,我在渐变函数定义中添加了tape.watch,因为我想查看层输出。但是我得到了一个错误:
Traceback (most recent call last):
File "/home/.../test2.py", line 73, in <module>
grads = gradients(model, x, y)
File "/home/.../test2.py", line 58, in gradients
print(model.get_layer('minimalrnn').output)
File "/home/.../.venv/lib/python3.6/site-packages/tensorflow_core/python/keras/engine/base_layer.py", line 1553, in output
raise AttributeError('Layer ' + self.name + ' has no inbound nodes.')
AttributeError: Layer minimalrnn has no inbound nodes.
是的,你可以用。tf.GradientTape
的目的是记录操作,以便自动微分或计算操作的梯度,或计算与输入变量相关的计算
根据,要首先使用tf.GradentTape实现模型的简单训练,请在tf.GradentTape上下文管理器中调用输入张量的前向传递,然后计算损失函数这确保所有计算都记录在梯度磁带上。
然后,计算模型中所有可训练变量的梯度。计算梯度后,在将其传递给优化器以将其应用于模型变量之前,可以执行任何所需的梯度剪裁、标准化或转换。请看以下示例:
NUM_EXAMPLES = 2000
input_x = tf.random.normal([NUM_EXAMPLES])
noise = tf.random.normal([NUM_EXAMPLES])
input_y = input_x * 5 + 2 + noise
def loss_fn(model, inputs, targets):
error = model(inputs) - targets
return tf.reduce_mean(tf.square(error))
def gradients(model, inputs, targets):
with tf.GradientTape() as tape:
loss_value = loss_fn(model, inputs, targets)
return tape.gradient(loss_value, model.trainable_variables)
model = tf.keras.Sequential(tf.keras.layers.Dense(1))
optimizer = tf.keras.optimizers.Adam(learning_rate=0.01)
print("Initial loss: {:.3f}".format(loss_fn(model, input_x, input_y)))
for i in range(500):
grads = gradients(model, input_x, input_y)
optimizer.apply_gradients(zip(grads, model.trainable_variables))
if i % 20 == 0:
print("Loss at step {:03d}: {:.3f}".format(i, loss_fn(model, input_x, input_y)))
print("Final loss: {:.3f}".format(loss(model, input_x, input_y)))
print("W = {}, B = {}".format(*model.trainable_variables))
好的,我最终找到的一个答案隐藏在这里:。我甚至可以使用子类模型 另外,AttributeError的问题很奇怪,因为当我使用Sequential而不是子类化模型时,AttributeError神奇地消失了,也许它与这个问题有关
尽管如此,我还是想知道为什么我不能将层的输出作为第二个参数传递给tape.gradient。感谢您的回答,这有助于我在使用GradientTape时构建代码。但我仍然无法获得渐变wrt层输出。你能看看我编辑过的问题吗?我在哪里提供了更新的代码?嗨@lida。当然从你得到的错误中,你是否也阅读了相同错误的以下答案,是的,谢谢,我想说我很擅长谷歌搜索:)但这次我找不到答案。我尝试在模型的定义中指定输入形状,我也将把它添加到我的问题中。我还将尝试使用顺序而不是子类来构建我的模型,但我希望它在将来无论如何都是子类化的。请在编辑中自由地改进这个问题,并清楚地说明为什么其他模型不起作用。当我有更多的时间时,我会进来看看!你说的文档链接是什么意思?我已经写过,我在子类模型中指定了输入形状,但它不起作用,所以按顺序指定输入形状并不是我想要的区别。这是一个不同问题的答案吗?不,为什么?如果你指的是我答案中的最后一句话,那么这一切都与我的问题有关,并试图解决它。我还是不知道你的链接是什么意思。
NUM_EXAMPLES = 2000
input_x = tf.random.normal([NUM_EXAMPLES])
noise = tf.random.normal([NUM_EXAMPLES])
input_y = input_x * 5 + 2 + noise
def loss_fn(model, inputs, targets):
error = model(inputs) - targets
return tf.reduce_mean(tf.square(error))
def gradients(model, inputs, targets):
with tf.GradientTape() as tape:
loss_value = loss_fn(model, inputs, targets)
return tape.gradient(loss_value, model.trainable_variables)
model = tf.keras.Sequential(tf.keras.layers.Dense(1))
optimizer = tf.keras.optimizers.Adam(learning_rate=0.01)
print("Initial loss: {:.3f}".format(loss_fn(model, input_x, input_y)))
for i in range(500):
grads = gradients(model, input_x, input_y)
optimizer.apply_gradients(zip(grads, model.trainable_variables))
if i % 20 == 0:
print("Loss at step {:03d}: {:.3f}".format(i, loss_fn(model, input_x, input_y)))
print("Final loss: {:.3f}".format(loss(model, input_x, input_y)))
print("W = {}, B = {}".format(*model.trainable_variables))