torch.linalg.svd#
- torch.linalg.svd(A, full_matrices=True, *, driver=None, out=None)#
计算矩阵的奇异值分解 (SVD)。
令 为 或 ,对于矩阵 ,如果 k = min(m,n),则 **完整 SVD** 定义为
其中 , 是 为复数时的共轭转置,当 为实数时的转置。矩阵 , (因此也包括 ) 在实数情况下是正交的,在复数情况下是酉的。
当 m > n (或 m < n) 时,我们可以去掉 U (或 V) 的最后 m - n (或 n - m) 列,形成 **约简 SVD**
其中 . 在这种情况下, 和 也具有正交列。
支持浮点 (float)、双精度浮点 (double)、复数浮点 (cfloat) 和复数双精度浮点 (cdouble) 数据类型。还支持矩阵批处理,如果 `A` 是一个矩阵批处理,则输出具有相同的批处理维度。
返回的分解是一个命名元组 (U, S, Vh),对应于上面的 , , .
奇异值按降序返回。
参数
full_matrices选择完整 SVD(默认)或约简 SVD。在 CUDA 上使用 cuSOLVER 后端时,可以使用
driver关键字参数来选择用于计算 SVD 的算法。选择驱动程序是在准确性和速度之间进行权衡。如果
A是良态的(其 条件数 不是太大),或者您不介意一些精度损失。对于一般矩阵:‘gesvdj’ (Jacobi 方法)
如果
A是高瘦或宽扁的(m >> n 或 m << n):‘gesvda’ (近似方法)
如果
A不是良态的或精度很重要:‘gesvd’ (基于 QR)
默认情况下(
driver= None),我们调用 ‘gesvdj’,如果失败,则回退到 ‘gesvd’。与 numpy.linalg.svd 的区别
与 numpy.linalg.svd 不同,此函数始终返回一个包含三个张量的元组,并且不支持 compute_uv 参数。请使用
torch.linalg.svdvals()(它仅计算奇异值)而不是 compute_uv=False。
注意
当
full_matrices= True 时,将忽略关于 U[…, :, min(m, n):] 和 Vh[…, min(m, n):, :] 的梯度,因为这些向量可以是相应子空间的任意基。警告
返回的张量 U 和 V 不是唯一的,也不是关于
A连续的。由于这种非唯一性,不同的硬件和软件可能会计算出不同的奇异向量。这种非唯一性是由以下事实引起的:将任意一对奇异向量 乘以 -1 (在实数情况下) 或乘以 (在复数情况下) 会产生另外两个有效的奇异向量。因此,损失函数不应依赖于这个 量,因为它不是良定义的。在计算此函数的梯度时,会针对复数输入进行检查。因此,当输入是复数且在 CUDA 设备上时,此函数的梯度计算会使该设备与 CPU 同步。
警告
使用 U 或 Vh 计算的梯度仅在
A没有重复的奇异值时才为有限值。如果A是矩形的,此外,零也不能是其奇异值之一。此外,如果任何两个奇异值之间的距离接近于零,则梯度将不稳定,因为它取决于奇异值 的计算,通过 . 在矩形情况下,当A具有较小的奇异值时,梯度也会不稳定,因为它还取决于 的计算。另请参阅
torch.linalg.svdvals()仅计算奇异值。与torch.linalg.svd()不同,svdvals()的梯度始终是数值稳定的。对于计算矩阵另一种谱分解的函数,请使用
torch.linalg.eig()。特征值分解仅适用于方阵。对于计算 Hermitian 和对称矩阵的特征值分解的(更快的)函数,请使用
torch.linalg.eigh()。对于另一个(快得多)适用于一般矩阵的分解,请使用
torch.linalg.qr()。- 参数
- 关键字参数
- 返回
一个命名元组 (U, S, Vh),对应于上面的 , , .
S 始终是实数值,即使
A是复数。它也将按降序排序。U 和 Vh 将具有与
A相同的 dtype。左/右奇异向量将分别由 U 的列和 Vh 的行给出。
示例
>>> A = torch.randn(5, 3) >>> U, S, Vh = torch.linalg.svd(A, full_matrices=False) >>> U.shape, S.shape, Vh.shape (torch.Size([5, 3]), torch.Size([3]), torch.Size([3, 3])) >>> torch.dist(A, U @ torch.diag(S) @ Vh) tensor(1.0486e-06) >>> U, S, Vh = torch.linalg.svd(A) >>> U.shape, S.shape, Vh.shape (torch.Size([5, 5]), torch.Size([3]), torch.Size([3, 3])) >>> torch.dist(A, U[:, :3] @ torch.diag(S) @ Vh) tensor(1.0486e-06) >>> A = torch.randn(7, 5, 3) >>> U, S, Vh = torch.linalg.svd(A, full_matrices=False) >>> torch.dist(A, U @ torch.diag_embed(S) @ Vh) tensor(3.0957e-06)