首页 > 解决方案 > Tensorflow - autodiff 是否让我们从 back-prop 实现中解脱出来?

问题描述

问题

使用 Tensorflow 时,例如实现自定义神经网络层,实现反向传播的标准做法是什么?我们不需要研究自动微分公式吗?

背景

使用 numpy,在创建层时,例如matmul,反向传播梯度首先被解析推导并相应地编码。

def forward(self, X):
    self._X = X
    np.matmul(self.X, self.W.T, out=self._Y)
    return self.Y

def backward(self, dY):
    """dY = dL/dY is a jacobian where L is loss and Y is matmul output"""
    self._dY = dY
    return np.matmul(self.dY, self.W, out=self._dX)

在 Tensorflow 中,有autodiff似乎负责雅可比计算。这是否意味着我们不必手动推导出梯度公式,而是让 Tensorflow 磁带来处理它?

计算梯度

为了自动区分,TensorFlow 需要记住在前向传递过程中以什么顺序发生的操作。然后,在反向传递期间,TensorFlow 以相反的顺序遍历这个操作列表来计算梯度。

标签: pythontensorflowdeep-learningneural-networkbackpropagation

解决方案


基本上,Tensorflow是一个基于数据流和可微分编程的符号数学库。我们不必手动处理自动微分公式。所有这些数学运算都将在后台自动完成。您从官方文档中正确引用了有关梯度计算的内容。但是,如果您想知道如何手动完成numpy,我建议您查看神经网络和深度学习这门精彩的课程,尤其是第 4 周,或者这里的替代来源。


仅供参考,TF 2我们可以通过覆盖类从头开始进行自定义训练,train_steptf.keras.Model那里我们可以使用tf.GradientTapeAPI 进行自动区分;也就是说,计算关于某些输入的计算梯度。同一官方页面包含有关此的更多信息。此外,必须看到这篇写得很好的文章。例如,使用此 API,我们可以轻松计算梯度,如下所示:tf.GradientTape

import tensorflow as tf 

# some input 
x = tf.Variable(3.0, trainable=True)

with tf.GradientTape() as tape:
    # some output 
    y = x**3 + x**2 + x + 5

# compute gradient of y wrt x 
print(tape.gradient(y, x).numpy()) 
# 34

此外,我们可以计算更高阶的导数,例如

x = tf.Variable(3.0, trainable=True)

with tf.GradientTape() as tape1:

    with tf.GradientTape() as tape2:
        y = x**3 + x**2 + x + 5
    # first derivative 
    order_1 = tape2.gradient(y, x)

# second derivative 
order_2 = tape1.gradient(order_1, x)

print(order_2.numpy()) 
# 20.0

现在,在自定义模型训练中tf. keras,我们首先forward通过并计算loss模型gradients的可训练变量相对于loss. 稍后,我们根据这些更新模型的权重gradients。下面是它的代码片段,这里是端到端的详细信息。从头开始编写训练循环。

# Open a GradientTape to record the operations run
# during the forward pass, which enables auto-differentiation.
with tf.GradientTape() as tape:

    # Run the forward pass of the layer.
    # The operations that the layer applies
    # to its inputs are going to be recorded
    # on the GradientTape.
    logits = model(x_batch_train, training=True)  # Logits for this minibatch

    # Compute the loss value for this minibatch.
    loss_value = loss_fn(y_batch_train, logits)

# Use the gradient tape to automatically retrieve
# the gradients of the trainable variables with respect to the loss.
grads = tape.gradient(loss_value, model.trainable_weights)

# Run one step of gradient descent by updating
# the value of the variables to minimize the loss.
optimizer.apply_gradients(zip(grads, model.trainable_weights))

推荐阅读