我正在尝试切换到TensorFlow急切模式,我发现GradientTape()上下文implicit_gradients()和implicit_value_and_gradients()函数之间的文档差异有点令人困惑.它们之间的区别是什么?最好使用哪一个?文档中的介绍点根本没有提到隐式*函数,但是tf repo中的几乎所有示例似乎都使用该方法来计算渐变.
Min*_*ark 14
启用eager执行时,有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.GradientTape和tfe.implicit_value_and_gradients()(其他两个选项不给你失去本身的价值,所以如果你需要它,它就会需要额外计算).我个人更喜欢tfe.implicit_value_and_gradients()在编写生产代码时,以及tf.GradientTape在Jupyter笔记本中进行实验时.
编辑:在TF 2.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
Run Code Online (Sandbox Code Playgroud)
tf.GradientTape在GradientTape上下文中,记录所有操作,然后您可以计算在任何可训练变量方面在上下文中计算的任何张量的梯度.例如,此代码s在GradientTape上下文中计算,然后计算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
Run Code Online (Sandbox Code Playgroud)
tfe.gradients_function()此函数返回另一个函数,该函数可以计算函数返回值与其参数的渐变.例如,我们可以使用它来定义一个函数来计算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
Run Code Online (Sandbox Code Playgroud)
在优化的上下文中,对于我们可以调整的变量,它会更有意义地计算梯度.为此,我们可以更改weighted_sum()要采用的函数w1和w2作为参数,并告诉tfe.gradients_function()只考虑命名的参数"w1"和"w2":
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
这个函数似乎是最简单和最有用的选项,因为通常我们感兴趣的是计算与模型参数(即变量)有关的损失的梯度.注意:尝试使用w1无限制(w1 = tfe.Variable(2., trainable=False))并重新定义weighted_sum(),您将看到grad_fn只返回s关于的渐变w2.
tfe.implicit_value_and_gradients()这个函数几乎完全相同,implicit_gradients()除了它创建的函数还返回被区分的函数的结果(在这种情况下weighted_sum()):
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
Run Code Online (Sandbox Code Playgroud)
当你需要一个函数的输出和它的渐变时,这个函数可以给你一个很好的性能提升,因为你在使用autodiff计算渐变时可以免费获得函数的输出.
| 归档时间: |
|
| 查看次数: |
3568 次 |
| 最近记录: |