pytorch 矩阵与其转置矩阵之间的乘法是不对称的和PSD的

x33g5p2x  于 2023-05-17  发布在  其他
关注(0)|答案(1)|浏览(221)

我想用下面的代码计算一批特征向量的协方差矩阵(这里用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更改了上面的子句
现在协方差矩阵是对称的,但仍然不是半正定的。我试过手电筒,但还是不行。是不是和精确度有关?
以下是具体版本:
Python3.7
PyTorch1.8.1

fzsnzjdm

fzsnzjdm1#

我得到了类似的问题,结论确实是这是一个精度问题。当我执行你的代码时(没有你的修改),我观察到cov_mat几乎是对称的,有一个大约1 e-6的错误。这实际上是预期的,如here所解释的:
浮点精度限制了您可以准确依赖的位数。torch.float32的精度在6到7位之间,与指数无关,即对于<1 e-6的值,预计会出现精度问题。类似地,torch.float64对于<1 e-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的解决方案也可以使用float 32实现类似的精度(在矩阵完全对称的意义上),但它会使矩阵“更少”psd。
不幸的是,无论你做什么,你总是会受到精度误差的影响(float 32为1 e-6,float 64为1 e-15)。因此,我们可以看到协方差矩阵的特征值可能略低于零。我尝试手动将特征值设置为0,但仍然存在错误。

TL;DR我的最终建议是:

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

希望对你有帮助!

相关问题