为什么损失函数在tf.GradientTape块内部而梯度计算在外部?

时间:2020-07-17 08:34:33

标签: python tensorflow2.0

我是Tensorflow的新朋友。在教科书示例中,我看到了以下旨在使用Tensorflow 2.x API训练简单线性模型的代码:

m = tf.Variable(0.)
b = tf.Variable(0.)
def predict_y_value(x):
    y = m * x + b
    return y
def squared_error(y_pred, y_true):
    return tf.reduce_mean(tf.square(y_pred - y_true))
learning_rate = 0.05
steps = 500
for i in range(steps):
    with tf.GradientTape() as tape:
        predictions = predict_y_value(x_train)
        loss = squared_error(predictions, y_train)
    gradients = tape.gradient(loss, [m, b])
    m.assign_sub(gradients[0] * learning_rate)
    b.assign_sub(gradients[1] * learning_rate)
print ("m: %f, b: %f" % (m.numpy(), b.numpy()))

为什么有必要在块with tf.GradientTape() as tape中包含损失函数的定义,但是gradients = tape.gradient(loss, [m, b])代码行在with块之外?

我知道这可能是特定于Python语言的,但是这种构造对我来说似乎还不清楚。 Python上下文管理器在这里的作用是什么?

1 个答案:

答案 0 :(得分:1)

从tensorflow文档中

默认情况下,GradientTape将自动监视在上下文中访问的所有可训练变量。

从直觉上讲,这种方法增强了很多灵活性。例如,它允许您编写如下的(伪)代码:

inputs, labels = get_training_batch()
inputs_preprocessed = some_tf_ops(inputs)
with tf.GradientTape() as tape:
    pred = model(inputs_preprocessed)
    loss = compute_loss(labels, pred)

grads = tape.gradient(loss, model.trainable_variables)
optimizer.apply_gradients(zip(grads, model.trainable_variables))

# For example, let's attach a model that takes the above model's output as input
next_step_inputs, next_step_labels = process(pred)

with tf.GradientTape() as tape:
    pred = another_model(next_step_inputs)
    another_loss = compute_loss(next_step_labels, pred)

grads = tape.gradient(another_loss, another_model.trainable_variables)
optimizer.apply_gradients(zip(grads, another_model.trainable_variables))

上面的示例可能看起来很复杂,但是它说明了需要极端灵活性的极端情况。

  1. 我们不希望some_tf_opsprocess在梯度计算中发挥作用,因为它们是预处理步骤。

  2. 我们想为多个具有一定关系的模型计算梯度

一个实际的例子是训练GAN,尽管可能更简单的实现。