重复使用 GradientTape 进行多次雅可比计算

Repeated use of GradientTape for multiple Jacobian calculations

我正在尝试计算 TensorFlow 神经网络输出相对于其输入的雅可比行列式。这很容易通过 tf.GradientTape.jacobian 方法实现。 TensorFlow 文档中提供的简单示例如下:

with tf.GradientTape() as g:
  x  = tf.constant([1.0, 2.0])
  g.watch(x)
  y = x * x
jacobian = g.jacobian(y, x)

如果我只想计算输入张量 x 的单个实例的雅可比矩阵,这很好。但是,我需要针对 x 的各种实例多次多次计算此 Jacobian 行列式。对于非平凡的 Jacobian 计算(例如,对于具有非线性激活函数的深度卷积神经网络),重复重新运行 GradientTape 计算和评估 jacobian 方法的成本非常高。我从 TensorFlow documentation 知道梯度(以及雅可比矩阵)是通过自动微分计算的。我必须想象有一些内部存储的网络分析梯度(通过自动微分计算),它是在给定的输入下评估的。

我的问题:我假设 TensorFlow 构建和存储(至少部分)计算雅可比矩阵所需的分析梯度是否正确?如果是这样,是否有办法保存此分析梯度并使用新输入重新评估雅可比矩阵,而无需通过 GradientTape 方法重建它?

A "persistent" GradientTape 似乎没有解决这个问题:它只允许针对计算的多个内部参数重复评估单个 GradientTape 实例。

我假设 TensorFlow 构建和存储(至少部分)计算雅可比矩阵所需的分析梯度是否正确?

不对 - 我认为您一定对自动微分有误解。

虽然 tf "knows" 中的每个基本运算都关于其输出相对于输入的解析导数,但在计算实际梯度或雅可比值时,伴随值(输出的导数)是传递给反向传递的操作,然后使用每个初等操作的解析公式和链式法则计算更多的数值。

如果是这样,是否有办法保存此分析梯度并使用新输入重新评估雅可比行列式,而无需通过 GradientTape 方法重建它?

没有。如果要计算新输入的梯度或雅可比矩阵,则需要再次执行整个计算。对于深度神经网络,没有办法解决这个问题。

顺便说一下,如果您根据网络参数对神经网络的损失函数进行梯度计算,则计算梯度的时间将为 O(1) 计算损失本身的成本.这就是反向传播,是反向模式自动微分之美的一部分。但是,如果您的网络有 N 个输出,并且您想要计算网络的完整雅可比矩阵,那么计算网络输出的时间将花费 O(N)。这可能就是计算雅可比矩阵如此昂贵的原因。

例如,如果您在 MNIST 上训练网络,并且您的网络有 10 个输出,您将它们组合成一个损失函数,计算损失函数的梯度将花费 O(1) 时间,但计算关于参数的 10 个输出的雅可比矩阵将花费 O(10) 时间。

也许你觉得这有帮助:

我需要多次计算任意函数的雅可比。我的问题是我使用 GradientTape 不当,但我发布的代码可能会帮助您或给您一些见解。我发布了一个使用基于会话的 tf.gradient() 函数和现代 GriadientTape 方法计算雅可比矩阵的自包含示例。在帮助下,我让它们 运行 在彼此相同的数量级内。

  • 如果您的问题集中在尝试重用调用之间的中间计算以提高速度,那么我认为 Nick 的回答更适用。
  • 如果您的问题集中于尝试使 GradientTape 与静态图一样快,请确保将其包装在 @tf.function 中,因为它就是这样做的。

看我的问题:Abysmal tf.GradientTape performance compared to tf.gradients() for computing jacobians