矩阵与其转置矩阵的乘法不对称且psd

问题描述 投票:0回答:1

我想使用下面的代码计算一批特征向量的协方差矩阵(这里用 torch.randn 代替):

import torch

a = torch.randn(64, 512)
cov_mat = (a.T @ a) / (a.size(0) - 1)

生成的 cov_mat 是对称的半正定的。所以我通过添加

cov_mat = (cov_mat + cov_mat.T) / 2

来更改上面的子句

现在协方差矩阵是对称的,但仍然不是半正定的。我试过 torch.mm 但还是没用。跟精度有关系吗?

这里是具体版本:
蟒蛇3.7
PyTorch 1.8.1

python pytorch matrix-multiplication
1个回答
0
投票

我也遇到过类似的问题,结论确实是精度问题。当我执行你的代码时(没有你的修改),我观察到 cov_mat 几乎是对称的,误差在 1e-6 左右。正如here所解释的那样,这实际上是预期的:

浮点精度限制了您可以准确依赖的位数。 torch.float32 的精度在 6 到 7 位数字之间,与指数无关,即值的精度问题是预期的< 1e-6. Similarly torch.float64 will have precision issues for values < 1e-15.

如果你真的需要更高的精度,你可以使用 torch.float64 代替:

# with the default float32:
a = torch.randn(64, 512)
c = (a.T @ a) / (a.size(0) - 1)
((c - c.T) < 1e-7).all()    >>> tensor(False)
((c - c.T) < 1e-6).all()    >>> tensor(True)

# with float64:
a = torch.randn(64, 512, dtype=torch.float64)
c = (a.T @ a) / (a.size(0) - 1)
((c - c.T) == 0).all()      >>> tensor(True)

虽然您使用

cov_mat = (cov_mat + cov_mat.T) / 2
的解决方法也使用 float32 实现了类似的精度(在矩阵完全对称的意义上),但它会使矩阵“更少”psd。

不幸的是,无论你做什么,你总是会遇到精度错误(float32 为 1e-6,float64 为 1e-15)。因此,我们可以看到协方差矩阵的特征值可能略低于零。我尝试手动将特征值设置为0,但仍然有错误。

TL;DR 我最后的建议是:

  • 如果你能承受较小的错误,那么就选择 float64
  • 如果您需要矩阵为 psd 以使用特定属性(例如 x.T @ C @ x > 0 的事实),则将结果值限制在 0 以上
  • 如果你绝对需要矩阵为psd,你可以这样做:
    c += 1e-12 * torch.eye(a.size(1))
    (如果你不需要它我不推荐它因为它修改了矩阵)

希望对你有帮助!

© www.soinside.com 2019 - 2024. All rights reserved.