Python 利用eig实现SVD

Python 利用eig实现SVD,python,numpy,svd,Python,Numpy,Svd,我正在尝试使用np.linalg.eig方法实现SVD,用于图像压缩分配。我们不允许直接使用np.linalg.svd方法 以下是我的svd方法: def svd(A): evals, U = LA.eig(A @ A.T) evals2, V = LA.eig(A.T @ A) idx = evals.argsort()[::-1] evals = evals[idx] U = U[:, idx] idx = evals2.argsort()[:

我正在尝试使用
np.linalg.eig
方法实现SVD,用于图像压缩分配。我们不允许直接使用
np.linalg.svd
方法

以下是我的svd方法:

def svd(A):
    evals, U = LA.eig(A @ A.T)
    evals2, V = LA.eig(A.T @ A)
    idx = evals.argsort()[::-1]
    evals = evals[idx]
    U = U[:, idx]
    idx = evals2.argsort()[::-1]
    V = V[ :, idx]
    sigma = np.array(list(map(math.sqrt, evals)))
    return U, sigma, V.T
但是,当我尝试使用上述svd返回的U和V重建图像时,错误率非常高,以至于即使使用了所有奇异向量,图像也完全模糊。然而,当我用
np.linalg.svd
返回的U&V矩阵尝试相同的重建过程时,我能够清晰地重建图像


如果我的奇异值分解方法有任何错误,请告诉我。

奇异值分解和特征向量都不是完全唯一的。在奇异值分解(SVD)中,只要对V中相应的向量进行同样的操作,就可以对U中的任何向量进行符号翻转。得到的特征向量不是以这种方式耦合的,因此符号不匹配的可能性很大。你可以通过使用以下事实来检查和纠正。T@A@V.T是sigma,所以检查U的对角线元素的符号。T@A@V.T,对于每个负向量,翻转U或V中的相应向量(但不是同时翻转)

其他建议:

由于您只需要对角线元素,因此计算完整乘积U是浪费的。T@A@V.T;只计算对角线元素的最简单方法是
np.einsum('ij,ik,jk->j',U,A,V)

使用
eig
而不是
eig
,因为您知道A@A.T和A。T@A它们是对称的


您可以保存一个特征分解,因为sigma@V=U。T@Asigma是对角的,很容易倒置。这还有一个优点,就是上面的符号问题不会发生。

对于一般矩阵,奇异值分解和特征值分解不以这种方式相关。只有正规矩阵和半正定矩阵才有这种关系,显然你的图像不是这样的矩阵。有关更多信息,请参阅。根据SVD的定义实现。它适用于任何m*n实矩阵。他们提到的是EVD的一个特例。