首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >GradientTape,implicit_gradients,gradients_function和implicit_value_and_gradients有什么区别?

GradientTape,implicit_gradients,gradients_function和implicit_value_and_gradients有什么区别?
EN

Stack Overflow用户
提问于 2018-04-30 10:50:58
回答 1查看 5.9K关注 0票数 11

我正在尝试切换到TensorFlow热切模式,我发现GradientTapeimplicit_gradientsgradients_functionimplicit_value_and_gradients的文档令人费解。

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

文档介绍点根本没有提到隐式*函数,但是TensorFlow存储库中的几乎所有示例似乎都使用该方法来计算梯度。

EN

回答 1

Stack Overflow用户

回答已采纳

发布于 2018-05-12 10:21:28

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

  • tf.GradientTape上下文记录计算,以便您可以调用tfe.gradient()来获得计算出的任何张量的梯度,同时记录任何可训练变量。
  • tfe.gradients_function()接受一个函数(例如f()),并返回一个梯度函数(例如fg()),该函数可以计算f()输出相对于f()参数(或其中一个子集)的梯度。
  • tfe.implicit_gradients()非常相似,但是fg()计算f()输出对于这些输出所依赖的所有可训练变量的梯度。
  • tfe.implicit_value_and_gradients()几乎是相同的,但是fg()也返回函数f()的输出。

通常,在机器学习中,您将希望计算与模型参数有关的损失的梯度(即。,您通常也会对损失本身的价值感兴趣。对于这个用例,最简单和最有效的选项是tf.GradientTapetfe.implicit_value_and_gradients() (其他两个选项不会给出损失本身的值,所以如果需要它,它将需要额外的计算)。我个人更喜欢在编写生产代码时使用tfe.implicit_value_and_gradients(),在木星笔记本上进行实验时更喜欢tf.GradientTape

编辑:在TF2.0中,似乎只有tf.GradientTape仍然存在。也许其他函数会被添加回来,但我不会指望它。

详细实例

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

代码语言:javascript
复制
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上下文中,所有操作都被记录下来,然后您就可以计算出上下文中计算的任何张量的梯度,以及任何可训练变量。例如,此代码在s上下文中计算GradientTape,然后计算s相对于w1的梯度。自s = w1 * x1 + w2 * x2以来,s相对于w1的梯度为x1

代码语言:javascript
复制
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_function()

此函数返回另一个函数,该函数可以计算函数的返回值与其参数的梯度。例如,我们可以使用它定义一个函数来计算s相对于x1x2的梯度。

代码语言:javascript
复制
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

在优化的背景下,对于我们可以调整的变量,它将具有更合理的计算梯度。为此,我们可以更改weighted_sum()函数以w1w2作为参数,并告诉tfe.gradients_function()只考虑名为"w1""w2"的参数。

代码语言:javascript
复制
def weighted_sum_with_weights(w1, x1, w2, x2):
    return w1 * x1 + w2 * x2

grad_fn = tfe.gradients_function(weighted_sum_with_weights, params=["w1", "w2"])
[w1_grad, w2_grad] = grad_fn(w1, 5., w2, 7.)
print(w2_grad.numpy()) # 7.0 = gradient of s with regards to w2 = x2

使用tfe.implicit_gradients()

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

代码语言:javascript
复制
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_and_gradients()

该函数几乎与implicit_gradients()相同,但它创建的函数还返回被区分的函数的结果(在本例中为weighted_sum()):

代码语言:javascript
复制
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

当您同时需要一个函数的输出和它的梯度时,这个函数可以给您一个很好的性能提升,因为在使用autodiff计算梯度时可以免费获得函数的输出。

票数 16
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/50098971

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档