【问题标题】:Why do TensorFlow and PyTorch gradients of the eigenvalue decomposition differ from each other and the analytic solution?为什么 TensorFlow 和 PyTorch 的特征值分解梯度和解析解不同?
【发布时间】:2020-03-10 09:00:24
【问题描述】:

以下代码计算实对称矩阵的特征值分解。然后,计算第一个特征值相对于矩阵的梯度。这样做了 3 次:1) 使用解析公式,2) 使用 TensorFlow,3) 使用 PyTorch。这会产生三种不同的结果。有人可以向我解释这种行为吗?

import numpy as np
import torch
import tensorflow as tf


np.set_printoptions(precision=3)
np.random.seed(123)

# random matrix
matrix_np = np.random.randn(4, 4)
# make symmetric
matrix_np = matrix_np + matrix_np.T
matrix_torch = torch.autograd.Variable(torch.from_numpy(matrix_np), requires_grad=True)
matrix_tf = tf.constant(matrix_np, dtype=tf.float64)

#
# compute eigenvalue decompositions
#
# NumPy
eigvals_np, eigvecs_np = np.linalg.eigh(matrix_np)
# PyTorch
eigvals_torch, eigvecs_torch = torch.symeig(matrix_torch, eigenvectors=True, upper=True)
# TensorFlow
eigvals_tf, eigvecs_tf = tf.linalg.eigh(matrix_tf)

# make sure all three versions computed the same eigenvalues
if not np.allclose(eigvals_np, eigvals_torch.data.numpy()):
    print('NumPy and PyTorch have different eigenvalues')
if not np.allclose(eigvals_np, tf.keras.backend.eval(eigvals_tf)):
    print('NumPy and TensorFlow have different eigenvalues')

#
# compute derivative of first eigenvalue with respect to the matrix
#
# analytic gradient, see "On differentiating eigenvalues and eigenvectors" by Jan R. Magnus
grad_analytic = np.outer(eigvecs_np[:, 0], eigvecs_np[:, 0])
# PyTorch gradient
eigvals_torch[0].backward()
grad_torch = matrix_torch.grad.numpy()
# TensorFlow gradient
grad_tf = tf.gradients(eigvals_tf[0], matrix_tf)[0]
grad_tf = tf.keras.backend.eval(grad_tf)

#
# print all derivatives
#
print('-'*6, 'analytic gradient', '-'*6)
print(grad_analytic)
print('-'*6, 'Pytorch gradient', '-'*6)
print(grad_torch)
print('-'*6, 'TensorFlow gradient', '-'*6)
print(grad_tf)

打印

------ analytic gradient ------
[[ 0.312 -0.204 -0.398 -0.12 ]
 [-0.204  0.133  0.26   0.079]
 [-0.398  0.26   0.509  0.154]
 [-0.12   0.079  0.154  0.046]]
------ Pytorch gradient ------
[[ 0.312 -0.407 -0.797 -0.241]
 [ 0.     0.133  0.52   0.157]
 [ 0.     0.     0.509  0.308]
 [ 0.     0.     0.     0.046]]
------ TensorFlow gradient ------
[[ 0.312  0.     0.     0.   ]
 [-0.407  0.133  0.     0.   ]
 [-0.797  0.52   0.509  0.   ]
 [-0.241  0.157  0.308  0.046]]

三个结果的主对角线相同。 TensorFlow 和 PyTorch 的非对角元素是解析元素的两倍或等于零。

这是预期的行为吗?为什么没有记录?梯度错了吗?

版本信息:TensorFlow 1.14.0、PyTorch 1.0.1

【问题讨论】:

  • 仅供参考:我使用 Ppytorch 1.3 运行您的代码,matrix_torch.grad.numpy() 与我的分析梯度相同。
  • 谢谢!我发现了这个问题github.com/pytorch/pytorch/pull/23018 显然,下三角矩阵确实是一个错误,PyTorch 修复了它。所以这可能也是 TensorFlow 中的一个错误。

标签: numpy tensorflow pytorch derivative automatic-differentiation


【解决方案1】:

相对于保证对称的矩阵的梯度并没有很好地定义(对角线之外),因为有效的实现可能取决于一个元素或其对立元素(或两者的加权和) .

例如,对 2x2 对称矩阵 x 的元素求和的函数的有效实现是

f(x) = x[0][0]+x[0][1]+x[1][0]+x[1][1]

但另一个有效的实现是

f(x) = x[0][0]+x[1][1]+2*x[0][1]

如果对称矩阵是确保矩阵始终对称的较大计算的一部分(例如x = [[a, b], [b, c]],其中abc 是一些标量),则较大计算的梯度不受您如何定义对称矩阵函数的梯度的影响(在我在这里运行的示例中,无论您如何定义f,我们都会有df/da = df/dc = 1df/db = 2)。

也就是说,对称梯度是一个不错的选择(正如评论中链接的 PyTorch PR 中所解释的那样),因为这意味着如果您碰巧对对称矩阵进行梯度下降更新,则矩阵将保持对称。

另外,请注意,TensorFlow 确实 document 仅使用矩阵的下三角部分进行计算,deliberately adjusts 相应地报告了梯度。

【讨论】:

  • 谢谢!有人让我知道这篇论文:arxiv.org/pdf/1911.06491.pdf 该论文讨论了对称矩阵的标量函数的梯度存在两种概念 - 但正如作者所证明和证明的那样,其中一个是错误的。根据作者的说法,错误的定义主要由统计学家和电气工程师使用。特别是,正如我所注意到的,在著名的矩阵食谱中可以找到的公式是不正确的。
猜你喜欢
  • 1970-01-01
  • 2021-09-02
  • 2016-05-31
  • 1970-01-01
  • 1970-01-01
  • 2016-06-23
  • 2020-09-15
  • 2018-04-06
  • 1970-01-01
相关资源
最近更新 更多