也许我使用的 API 是错误的(但是 numpy 和 torch 函数的参数是相同的),但是链接的矩阵会产生完全不同的伪逆矩阵。
import numpy as np, torch
array = np.load('invertme.npy')
pinv_np = np.linalg.pinv(array)
pinv_th = torch.pinverse(torch.tensor(array))
assert np.allclose(pinv_np, pinv_th)
也许我使用的 API 是错误的(但是 numpy 和 torch 函数的参数是相同的),但是链接的矩阵会产生完全不同的伪逆矩阵。
import numpy as np, torch
array = np.load('invertme.npy')
pinv_np = np.linalg.pinv(array)
pinv_th = torch.pinverse(torch.tensor(array))
assert np.allclose(pinv_np, pinv_th)
我将其范围缩小到 SVD 的应用。numpy 和 pytorch 的结果有很大不同。U、S、V中只有S相同,其他不同。各自的文档指出,gesdd
这两种情况都使用了 LAPACK,因此如果这是由于数字问题引起的,我会感到惊讶。
这是 U 的 numpy 和 pytorch 结果之间的差异图。
如果这是真的,这听起来很糟糕
如果有人能尽快看一下这个,我将不胜感激,因为它现在严重阻碍了我。不确定我能提供什么帮助,但我欢迎建议。
我可以在 CPU(使用 LAPACK)和 GPU(使用 MAGMA)上重现这一点。
我将其标记为 1.0.1 拦截器。如果您需要进度帮助,请告诉我们@vishwakftw
当然可以,谢谢。
只是为了明确@themightyoarfish,如果矩阵是病态的,并且因为 SVD 是一种迭代方法——如果 pytorch 和 numpy 从不同的点开始,它们可能会得到不同的解决方案。所以我正在等待维什瓦克的调查结束。但我也想确保人们不会事先感到惊慌。
我可以确认矩阵的病态非常严重。
条件数 = 最大奇异值 / 最小奇异值 ~ 10^8 。
仍在寻找不一致之处。
我懂了。这很有趣;问题发生在谷歌的 svcca上下文中,其中输入矩阵由一组数据点上的一层神经元的激活组成,即每一行都是一个神经元的激活。我想知道这样一个矩阵病态的事实是否告诉了我什么。
是否有任何(可能效率较低)方法来获得病态矩阵的伪逆?
我认为这个问题可能仅限于病态矩阵。以下脚本证明了这种行为:
import torch
device = 'cpu' # modify to test on a different device
N = 954 # size
# Step 1: create an conditioned singular value vector
s = torch.arange(N + 1, 1, -1, device=device).float().log() # the condition number here is ~ log(N)
s_mat = torch.diag(s)
# Step 2: generate orthogonal matrices using QR on a random matrix
q, _ = torch.randn(N, N, device=device).qr()
assert (q @ q.t() - torch.eye(N, device=device)).abs().max() < 1e-04
# Step 3: generate the well-conditioned matrix
a = q @ s_mat @ q.t()
u, sigma, v = a.svd()
assert (a - u @ torch.diag(sigma) @ v.t()).abs().max() < 1e-04
我已经在 CPU(使用 LAPACK)和 GPU(使用 MAGMA)上运行了多次(~ 100)次,并且在所有试验中断言都没有失败。
非常感谢您快速调查这个 Vishwak。我将关闭它,因为它是病态矩阵上的预期行为。
@themightyoarfish 病态矩阵的伪逆,这在数学上是否可能作为保证?我不是线性代数专家,但我认为矩阵首先必须有一些约束。再说一次,我不是专家:)我想@SsnL 会知道他在这里是否有很多经验。
是的,我不确定我现在在问什么,因为现实更复杂(svcca 计算激活协方差矩阵的伪逆)。但如果协方差矩阵是病态的,也许它能提供某种信息?
是的,U 和 V 对于奇异输入矩阵来说并不是唯一的(考虑 e 值 = 0 时的 e 向量)。所以这是预料之中的。
torch.svd 与 numpy、scipy 和 tensorflow svd 不同
因此,如果使用 torch.svd 进行训练,则无法将模型移植到其他框架
@iperov 仅适用于与奇异 e 值相对应的 UV 矩阵部分。你永远不应该依赖那些。
@SsnL 但https://github.com/clovaai/WCT2确实
@SsnL 和 NVIDIA WCT 也依赖于它
https://github.com/NVIDIA/FastPhotoStyle/blob/master/photo_wct.py
抱歉,但是您链接的 NVIDIA WCT 脚本显然会过滤掉零个奇异值。
我正在尝试将 torch WCT 移植到纯 numpy,以便传输https://github.com/clovaai/WCT2存储库的解码器层的样式,但结果非常不同,因为网络接受了错误的 svd 实现训练。
来自 WCT2 论文: WCT 在训练中使用了错误的 svd。
同一个矩阵可以有多个 SVD 分解。我什至不知道你在抱怨什么。
我已经告诉了足够的信息。如果您不知道什么 - 就离开这个帖子。
照片 WCT 使用v
值来重建特征。但如果这些值不同,结果也会不同,因为v
矩阵乘法中使用的值。
c_u, c_e, c_v = torch.svd(contentConv, some=False)
s_u, s_e, s_v = torch.svd(styleConv, some=False)
step1 = torch.mm(c_v[:, 0:k_c], torch.diag(c_d))
step2 = torch.mm(step1, (c_v[:, 0:k_c].t()))
whiten_cF = torch.mm(step2, cont_feat)
s_d = (s_e[0:k_s]).pow(0.5)
targetFeature = torch.mm(torch.mm(torch.mm(s_v[:, 0:k_s], torch.diag(s_d)), (s_v[:, 0:k_s].t())), whiten_cF)
( numpy.svd == scipy.svd == tf.svd ) != torch.svd
这太糟糕了:(
我对 pytorch 中的 gesvd/gesdd 绑定非常熟悉,我认为您从未告诉过有关您所看到的问题的任何有用信息,即矩阵是奇异的吗?如果是这样,它的状况有多差?np、tf、pytorch 和其他库的输出是什么?而且,最重要的是,您是否使用零空间的奇异向量?
并且您坚持认为您所指的两个存储库使用零奇异值的奇异向量。我只是指出那些没有被使用。例如,在 NVIDIA WCT 的片段中,k_c
和k_s
是排名。因此,与您声称的相反,这些向量没有被使用。
你好,我在 torch 中遇到了 svd 问题,并找到了这个线程。如果你愿意的话,这里有一些“证据”。
R=[[ 0.41727819, -0.87345426, 0.25091147],
[ 0.32246181, 0.40043949, 0.85771009],
[-0.84964539, -0.27699435, 0.44875031]]
Rnp = np.array(R)
Rt = torch.from_numpy(Rnp)
# numpy
U,S,V=np.linalg.svd(np.array(R))
np.matmul(U,V) # gets back R as expected
# torch
U,S,V=torch.svd(Rt)
torch.matmul(U,V) # did not gets back R, and that's causing me headache...:(
@zawlin 你好,np
返回V^H
但pytorch
返回V
,所以你错过了 V 上的转置!
In [1]: import torch
In [2]: import numpy as np
In [3]: R=[[ 0.41727819, -0.87345426, 0.25091147],
...: [ 0.32246181, 0.40043949, 0.85771009],
...: [-0.84964539, -0.27699435, 0.44875031]]
...: Rnp = np.array(R)
...: Rt = torch.from_numpy(Rnp)
...:
In [4]:
In [4]: U,S,V=np.linalg.svd(np.array(R))
In [5]: S
Out[5]: array([1., 1., 1.])
In [6]: Rt.svd().S
Out[6]: tensor([1.0000, 1.0000, 1.0000], dtype=torch.float64)
In [7]:
...: # numpy
...: U,S,V=np.linalg.svd(np.array(R))
...: np.matmul(U,V) # gets back R as expected
Out[7]:
array([[ 0.41727819, -0.87345426, 0.25091147],
[ 0.32246181, 0.40043949, 0.85771009],
[-0.84964539, -0.27699435, 0.44875031]])
In [8]: # torch
...: U,S,V=torch.svd(Rt)
...: torch.matmul(U,V.t()) # did not gets back R, and that's causing me headache...:(
Out[8]:
tensor([[ 0.4173, -0.8735, 0.2509],
[ 0.3225, 0.4004, 0.8577],
[-0.8496, -0.2770, 0.4488]], dtype=torch.float64)
In [9]:
@SsnL,哦,非常感谢。对于噪音表示歉意。
@zawlin 不用担心!
@SsnL 很抱歉问同样的问题,您可能已经解释清楚了。我对 SVD 不太熟悉,但我确实遇到过类似的情况,我想将 numpy/scipy.linalg.svd 转换为 pytorch,希望有完全相同的分解。不幸的是,我确实需要所有 U、S、V 矩阵来执行以下代码。我并不是说这是一个错误(因为我不知道里面的技术),我只是想问,与 numpy/scipy 相比,没有解决方法可以获得完全相同的结果吗?如果是这样的话,我想我会在 CPU 上使用 numpy 计算 SVD,并将它们转换回 GPU 用于 pytorch...
这是我使用的 scipy 函数:
U, S, V = scipy.linalg.svd(X, full_matrices=False, lapack_driver='gesvd')
这里讨论了在 pytorch 中包含“ gesvd ”方法的努力:https: //github.com/pytorch/pytorch/issues/25978
这里只是评论一下。两个链接片段中的排名计算代码似乎不正确:如果没有奇异值 >= 0.00001,则它们默认为满排名,而不是零排名。OTOH,如果保证排名 >= 1,则代码将是正确的,但根本不需要默认值,因为循环中的 if 块始终会被输入,并且排名将在那里设置。
例如https://github.com/NVIDIA/FastPhotoStyle/blob/master/photo_wct.py#L150-L154