Tensorflow 什么';梯度带、隐式梯度、梯度函数和隐式梯度值之间的区别是什么?

Tensorflow 什么';梯度带、隐式梯度、梯度函数和隐式梯度值之间的区别是什么?,tensorflow,Tensorflow,我试图切换到TensorFlow急切模式,我发现渐变带,隐式梯度,梯度函数和隐式梯度和梯度的文档令人困惑 他们之间有什么区别?什么时候我应该使用一个而不是另一个 根本没有提到隐式*函数,但TensorFlow存储库中的几乎所有示例似乎都使用该方法来计算渐变。启用急切执行时,有4种方法可以自动计算渐变(实际上,它们也可以在图形模式下工作): tf.GradientTapecontext记录计算,这样您就可以调用tfe.gradient()来获得在记录任何可训练变量时计算的任何张量的梯度 tfe.

我试图切换到TensorFlow急切模式,我发现
渐变带
隐式梯度
梯度函数
隐式梯度和梯度
的文档令人困惑

他们之间有什么区别?什么时候我应该使用一个而不是另一个


根本没有提到隐式*函数,但TensorFlow存储库中的几乎所有示例似乎都使用该方法来计算渐变。

启用急切执行时,有4种方法可以自动计算渐变(实际上,它们也可以在图形模式下工作):

  • tf.GradientTape
    context记录计算,这样您就可以调用
    tfe.gradient()
    来获得在记录任何可训练变量时计算的任何张量的梯度
  • tfe.gradients\u function()
    接受一个函数(比如
    f()
    )并返回一个梯度函数(比如
    fg()
    ),该函数可以计算
    f()
    的输出相对于
    f()
    的参数(或其子集)的梯度
  • tfe.implicit_gradients()
    非常相似,但是
    fg()
    计算
    f()
    输出的梯度,该梯度与这些输出所依赖的所有可训练变量有关
  • tfe.implicit_value_和_gradients()
    几乎相同,但是
    fg()
    还返回函数
    f()的输出
通常,在机器学习中,您需要计算与模型参数(即变量)相关的损失梯度,并且您通常也会对损失本身的值感兴趣。对于本用例,最简单和最有效的选项是
tf.GradientTape
tfe.implicit_value_和_gradients()
(其他两个选项不提供损失本身的值,因此如果需要,将需要额外的计算)。我个人更喜欢在编写生产代码时使用
tfe.implicit_value_和_gradients()
,在Jupyter笔记本中进行实验时使用
tf.GradientTape

编辑:在TF2.0中,似乎只剩下
TF.GradientTape
。也许其他的函数会被添加回来,但我不会指望它

详细示例 让我们创建一个小函数来突出区别:

import tensorflow as tf
import tensorflow.contrib.eager as tfe
tf.enable_eager_execution()

w1 = tfe.Variable(2.0)
w2 = tfe.Variable(3.0)
​
def weighted_sum(x1, x2):
    return w1 * x1 + w2 * x2

s = weighted_sum(5., 7.)
print(s.numpy()) # 31
使用
tf.GradientTape
GradientTape
上下文中,记录所有操作,然后您可以计算上下文中计算的任何张量相对于任何可训练变量的梯度。例如,此代码在
GradientTape
上下文中计算
s
,然后计算
s
相对于
w1
的梯度。由于
s=w1*x1+w2*x2
s
相对于
w1
的梯度为
x1

with tf.GradientTape() as tape:
    s = weighted_sum(5., 7.)
​
[w1_grad] = tape.gradient(s, [w1])
print(w1_grad.numpy()) # 5.0 = gradient of s with regards to w1 = x1
使用
tfe.gradients\u函数()
此函数返回另一个函数,该函数可以计算函数返回值相对于其参数的梯度。例如,我们可以使用它来定义一个函数,该函数将计算
s
相对于
x1
x2
的梯度:

grad_fn = tfe.gradients_function(weighted_sum)
x1_grad, x2_grad = grad_fn(5., 7.)
print(x1_grad.numpy()) # 2.0 = gradient of s with regards to x1 = w1
在优化的环境中,计算与我们可以调整的变量相关的梯度更有意义。为此,我们可以改变< <代码>权重>(代码)>函数,以<代码> W1 < /代码>和<代码> W2 < /代码>为参数,并告诉<代码> TFE.GraveStScript函数()/代码>只考虑参数“<代码>”W1“和 > W2

使用
tfe.implicit_gradients()
此函数返回另一个函数,该函数可以计算函数返回值相对于它所依赖的所有可训练变量的梯度。回到第一个版本的
weighted_sum()
,我们可以使用它来计算
s
相对于
w1
w2
的梯度,而无需显式传递这些变量。请注意,梯度函数返回梯度/变量对的列表:

grad_fn = tfe.implicit_gradients(weighted_sum)
[(w1_grad, w1_var), (w2_grad, w2_var)] = grad_fn(5., 7.)
print(w1_grad.numpy()) # 5.0 = gradient of s with regards to w1 = x1

assert w1_var is w1
assert w2_var is w2
该函数似乎是最简单和最有用的选项,因为通常我们感兴趣的是计算与模型参数(即变量)相关的损失梯度。 注意:尝试使
w1
不可训练(
w1=tfe.Variable(2,trainable=False)
)并重新定义
weighted_sum()
,您将看到
grad_fn
仅返回与
w2
相关的
s
梯度

使用
tfe.implicit_value_和_gradients()
此函数与
隐式梯度()
几乎相同,只是它创建的函数也返回函数被区分的结果(在本例中为
加权求和()
):

当您需要函数的输出及其渐变时,此函数可以为您提供良好的性能提升,因为在使用autodiff计算渐变时,您可以免费获得函数的输出

grad_fn = tfe.implicit_gradients(weighted_sum)
[(w1_grad, w1_var), (w2_grad, w2_var)] = grad_fn(5., 7.)
print(w1_grad.numpy()) # 5.0 = gradient of s with regards to w1 = x1

assert w1_var is w1
assert w2_var is w2
grad_fn = tfe.implicit_value_and_gradients(weighted_sum)
s, [(w1_grad, w1_var), (w2_grad, w2_var)] = grad_fn(5., 7.)
print(s.numpy()) # 31.0 = s = w1 * x1 + w2 * x2