torch.linalg.svd¶
- torch.linalg.svd(A, full_matrices=True, *, driver=None, out=None)¶
計算矩陣的奇異值分解 (SVD)。
令 是 或 ,矩陣 的 完全 SVD,如果 k = min(m,n),定義為:
其中 , 在 為複數時是共軛轉置,在 為實數時是轉置。矩陣 、 (以及 ) 在實數情況下是正交矩陣,在複數情況下是酉矩陣。
當 m > n (或 m < n) 時,我們可以丟棄 U 的後 m - n 列 (或 V 的後 n - m 列),形成 簡化 SVD:
其中 。在這種情況下, 和 也具有標準正交列。
支援 float、double、cfloat 和 cdouble dtypes 輸入。也支援批次矩陣輸入,如果
A是一個批次矩陣,則輸出具有相同的批次維度。返回的分解是一個命名元組 (U, S, Vh),分別對應於上面的 、 和 。
奇異值按降序返回。
引數
full_matrices選擇完全 (預設) SVD 或簡化 SVD。driver關鍵字引數可用於 CUDA,使用 cuSOLVER 後端選擇計算 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()計算矩陣的另一種譜分解。特徵值分解僅適用於方陣。torch.linalg.eigh()是一個 (更快地) 函式,用於計算 Hermitian 矩陣和對稱矩陣的特徵值分解。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)