随机 SVD 和奇异值

机器算法验证 矩阵分解 svd
2022-03-30 15:13:09

随机 SVD 通过使用 k+p 随机投影提取前 k 个奇异值/向量来分解矩阵。这对于大型矩阵非常有效。

我的问题涉及算法输出的奇异值。如果您执行完整的 SVD,为什么这些值不等于第一个 k 奇异值?

下面我在 R 中有一个简单的实现。任何关于提高性能的建议都将不胜感激。

 rsvd = function(A, k=10, p=5){
       n = nrow(A)
       y = A %*% matrix(rnorm(n * (k+p)), nrow=n)
       q = qr.Q(qr(y))
       b = t(q) %*% A
       svd = svd(b)
       list(u=q %*% svd$u, d=svd$d, v=svd$v)
    }

    > set.seed(10)

    > A <- matrix(rnorm(500*500),500,500)

    > svd(A)$d[1:15]
     [1] 44.94307 44.48235 43.78984 43.44626 43.27146 43.15066 42.79720 42.54440 42.27439 42.21873 41.79763 41.51349 41.48338 41.35024 41.18068

    > rsvd.o(A,10,5)$d
     [1] 34.83741 33.83411 33.09522 32.65761 32.34326 31.80868 31.38253 30.96395 30.79063 30.34387 30.04538 29.56061 29.24128 29.12612 27.61804

    B <- matrix(rnorm(500*50),500,500)  # rank 50

> rsvd(B,10,5)$d
 [1] 86.48035 83.02114 81.03988 80.04358 77.24979 76.10945 74.47357 74.08382
 [9] 72.85898 72.06897 69.59526 67.70750 66.53867 62.96446 61.50838

> svd(B)$d[1:15]
 [1] 92.44779 91.47689 88.71948 88.08170 87.24533 85.13312 84.14741 83.71757
 [9] 82.80832 81.43005 80.73903 79.92959 78.87421 78.33509 77.38431

正如 Joris 指出的那样,我也在 stackoverflow 上发布了这个。你可以在这里找到相关的对话

https://stackoverflow.com/questions/4224031/randomized-svd-singular-values

另请参阅 Martinsson 等人的相关论文:矩阵分解的随机算法

2个回答

我们已经在scikit-learn python 包中实现了这一点(以及幂迭代改进) 。

如果 k + p > rank(M) 如测试所示,我们的实现能够找到完全相同的奇异值和向量

如果你在接近零奇异值之前切割 (k + p)(即在 k + p < rank(M) 的情况下),那么奇异向量确实与你使用未截断版本得到的不同,但它们可能仍然在实践中对于机器学习中的特征提取非常有用:例如,150 的“截断”特征脸对于使用 SVM 的人脸识别任务与完全分解的前 150 个第一奇异向量一样好,即使我的人脸数据集的排名似乎要高得多。

这种随机/截断的 SVD 方法在实践中看起来非常有趣:它可以真正减少计算时间,如本基准所示:

比较随机和确定性 SVD 实现

我认为奇异值不应与完整矩阵的奇异值相匹配。随机向量上来计算输入矩阵的近似值。对于一个秩矩阵来近似一个秩矩阵,轨迹应该是相同的,但是如果前个奇异值要重叠,你必须推动很多“方差”到近似值的最后个奇异值(可能太多以至于它们不再是最不重要的奇异值)。k+pk+pnk+pkp

另一种看待这个问题的方法是通过另一种分解 ' 。我们不应该期望快速随机算法能够神奇地工作,使得的前的子矩阵,等等。 A=UΣVTΓWTkUΓΣ