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)