torch.linalg.svd
- torch.linalg.svd(A, full_matrices=True, *, driver=None, out=None)
-
计算矩阵的奇异值分解(SVD)。
令 $\mathbb{K}$ 为实数集 $\mathbb{R}$ 或复数集 $\mathbb{C}$,当 k = min(m,n) 时,矩阵 $A \in \mathbb{K}^{m \times n}$ 的完整SVD定义为
$A = U \operatorname{diag}(S) V^{\text{H}} \mathrlap{\qquad U \in \mathbb{K}^{m \times m}, S \in \mathbb{R}^k, V \in \mathbb{K}^{n \times n}}$其中$\operatorname{diag}(S) \in \mathbb{K}^{m \times n}$,$V^{\text{H}}$ 在 $V$ 为复数时表示共轭转置,在$V$ 为实数值时则表示普通转置。在实数情况下,矩阵$U$ 和 $V$(包括其共轭转置$V^{\text{H}}$)是正交的,在复数情况下则是酉矩阵。
当 m > n(或 m < n)时,我们可以删除矩阵 U 的最后 m - n 列(或矩阵 V 的最后 n - m 列),从而形成截断的奇异值分解:
$A = U \operatorname{diag}(S) V^{\text{H}} \mathrlap{\qquad U \in \mathbb{K}^{m \times k}, S \in \mathbb{R}^k, V \in \mathbb{K}^{k \times n}}$其中$\operatorname{diag}(S) \in \mathbb{K}^{k \times k}$。在这种情况下,$U$ 和 $V$ 的列也是正交的。
支持浮点型、双精度型、复数浮点型和复数双精度型的数据类型作为输入。还支持矩阵的批量处理,如果
A
是一组矩阵,那么输出将具有相同的批处理维度。返回的分解是一个命名元组(U, S, Vh),对应于上述的$U$、$S$和$V^{\text{H}}$。
奇异值以降序排列返回。
参数
full_matrices
决定是否使用完整的(默认)或简化的奇异值分解(SVD)。driver
参数可以在使用 cuSOLVER 后端的 CUDA 中,用来选择计算 SVD 时所使用的算法。选择不同的driver
是在精度和速度之间进行权衡。-
如果矩阵
A
的条件数不是很大,或者你能够接受一些精度损失。-
对于一般矩阵:使用‘gesvdj’(雅可比方法)
-
如果
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
。由于这种唯一性的缺失,不同的硬件和软件可能会计算出不同的奇异向量。这种非唯一性是由以下事实引起的:在实数情况下,将任意一对奇异向量$u_k, v_k$乘以-1;在复数情况下,将其乘以$e^{i \phi}, \phi \in \mathbb{R}$会产生矩阵的另外两个有效的奇异向量。因此,损失函数不应依赖于这个未明确定义的$e^{i \phi}$量。在计算此函数梯度时会检查复数输入的情况。当输入为复数且位于CUDA设备上时,该设备与CPU同步进行此函数梯度的计算。
警告
使用U或Vh计算的梯度仅在
A
没有重复奇异值时是有限的。如果A
是非方阵,零也不能是其奇异值之一。此外,当任意两个奇异值之间的距离接近于零时,梯度将变得数值不稳定,因为它的计算依赖于$\frac{1}{\min_{i \neq j} \sigma_i^2 - \sigma_j^2}$。在非方阵的情况下,当A
具有小的奇异值时,梯度也会变得数值不稳定,因为它的计算还依赖于$\frac{1}{\sigma_i}$。参见
torch.linalg.svdvals()
只计算奇异值。与torch.linalg.svd()
不同,svdvals()
的梯度始终是数值稳定的。torch.linalg.eig()
用于计算矩阵的另一种类型的谱分解。特征值分解只适用于方阵。torch.linalg.eigh()
用于计算赫mitte矩阵和对称矩阵的特征值分解,速度快于其他方法。torch.linalg.qr()
提供了一个更快的适用于通用矩阵的分解方法。- 参数
- 关键字参数
- 返回值
-
一个名为(U, S, Vh)的元组,对应于上述的$U$、$S$和$V^{\text{H}}$。
S 始终会是实数,即使
A
是复数也不例外。并且它会按照降序进行排列。矩阵 U 和 Vh 的数据类型将与
A
相同。左奇异向量由 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)
-