torch.linalg.svd¶
- torch.linalg.svd(A, full_matrices=True, *, driver=None, out=None)¶
計算矩陣的奇異值分解 (SVD)。
令 為 或 ,若 k = min(m,n),矩陣 的**完整 SVD** 定義為:
其中 , 是共軛轉置,當 是複數時;當 是實數值時,則是轉置。矩陣 , (以及 ) 在實數情況下是正交的,而在複數情況下是么正的。
當 m > n (resp. m < n) 時,我們可以捨棄 U (resp. V) 最後的 m - n (resp. n - m) 行,以形成簡化奇異值分解 (reduced SVD)
其中 。在這種情況下, 和 也具有正交列向量。
支援 float、double、cfloat 和 cdouble 等資料類型作為輸入。也支援矩陣批次,且如果
A
是一批矩陣,則輸出具有相同的批次維度。返回的分解是一個名為 (U, S, Vh) 的具名元組,對應於上面的 、、。
奇異值會以遞減順序返回。
參數
full_matrices
選擇完整(預設)或簡化 SVD。在 CUDA 中,
driver
kwarg 可與 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) 的具名元組,對應於上面的 、、。
即使
A
是複數,S 也始終是實數值。它也會以降序排列。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)