Using autodiff

前面的代码工作正常,但它需要从代价函数(MSE)中利用数学公式推导梯度。 在线性回归的情况下,这是相当容易的,但是如果你必须用深层神经网络来做这个事情,你会感到头痛:这将是乏味和容易出错的。 您可以使用符号求导来为您自动找到偏导数的方程式,但结果代码不一定非常有效。

为了理解为什么,考虑函数f(x) = exp(exp(exp(x)))。如果你知道微积分,你可以计算出它的导数f'(x) = exp(x) * exp(exp(x)) * exp(exp(exp(x)))。如果您按照普通的计算方式分别去写f(x)f'(x),您的代码将不会如此有效。 一个更有效的解决方案是写一个首先计算exp(x),然后exp(exp(x)),然后exp(exp(exp(x)))的函数,并返回所有三个。这直接给你(第三项)f(x),如果你需要求导,你可以把这三个子式相乘,你就完成了。 通过传统的方法,您不得不将exp函数调用 9 次来计算f(x)f'(x)。 使用这种方法,你只需要调用它三次。

当您的功能由某些任意代码定义时,它会变得更糟。 你能找到方程(或代码)来计算以下函数的偏导数吗?

提示:不要尝试。

  1. def my_func(a, b):
  2. z = 0
  3. for i in range(100):
  4. z = a * np.cos(z + i) + z * np.sin(b - i)
  5. return z

幸运的是,TensorFlow 的自动计算梯度功能可以计算这个公式:它可以自动高效地为您计算梯度。 只需用以下面这行代码替换上一节中代码的gradients = ...行,代码将继续工作正常:

  1. gradients = tf.gradients(mse, [theta])[0]

gradients()函数使用一个op(在这种情况下是MSE)和一个变量列表(在这种情况下只是theta),它创建一个ops列表(每个变量一个)来计算op的梯度变量。 因此,梯度节点将计算 MSE 相对于theta的梯度向量。

自动计算梯度有四种主要方法。 它们总结在表 9-2 中。 TensorFlow 使用反向模式,这是完美的(高效和准确),当有很多输入和少量的输出,如通常在神经网络的情况。 它只需要通过 n_{outputs} + 1 次图遍历即可计算所有输出的偏导数。

Using autodiff - 图2