複數#
創建於:2025 年 6 月 16 日 | 最後更新於:2025 年 6 月 16 日
複數是可以表示為 形式的數字,其中 a 和 b 是實數,j 是虛數單位,滿足方程 。複數在數學和工程領域經常出現,尤其是在訊號處理等主題中。傳統上,許多使用者和庫(例如 TorchAudio)透過使用形狀為 的浮點張量來表示複數,其中最後一個維度包含實部和虛部。
複數資料型別的張量在處理複數時提供了更自然的程式設計體驗。複數張量上的操作(例如 torch.mv(),torch.matmul())可能比模擬它們的浮點張量上的操作更快、記憶體效率更高。PyTorch 中涉及複數的操作經過最佳化,可以使用向量化彙編指令和專用核心(例如 LAPACK,cuBlas)。
注意
torch.fft 模組中的頻譜運算支援原生複數張量。
警告
複數張量是一項測試版功能,可能會發生更改。
建立複數張量#
我們支援兩種複數資料型別:torch.cfloat 和 torch.cdouble
>>> x = torch.randn(2,2, dtype=torch.cfloat)
>>> x
tensor([[-0.4621-0.0303j, -0.2438-0.5874j],
[ 0.7706+0.1421j, 1.2110+0.1918j]])
注意
複數張量的預設資料型別由預設浮點資料型別決定。如果預設浮點資料型別是 torch.float64,則複數將被推斷為 torch.complex128 資料型別,否則假定它們的資料型別為 torch.complex64。
除 torch.linspace()、torch.logspace() 和 torch.arange() 外,所有工廠函式均支援複數張量。
從舊錶示過渡#
對於那些目前透過形狀為 的實數張量來處理缺乏複數張量問題的使用者,可以使用 torch.view_as_complex() 和 torch.view_as_real() 輕鬆地將其程式碼切換為使用複數張量。請注意,這些函式不會執行任何複製,而是返回輸入張量的檢視。
>>> x = torch.randn(3, 2)
>>> x
tensor([[ 0.6125, -0.1681],
[-0.3773, 1.3487],
[-0.0861, -0.7981]])
>>> y = torch.view_as_complex(x)
>>> y
tensor([ 0.6125-0.1681j, -0.3773+1.3487j, -0.0861-0.7981j])
>>> torch.view_as_real(y)
tensor([[ 0.6125, -0.1681],
[-0.3773, 1.3487],
[-0.0861, -0.7981]])
訪問實部和虛部#
可以使用 real 和 imag 屬性訪問複數張量的實部和虛部。
注意
訪問 real 和 imag 屬性不會分配任何記憶體,並且對 real 和 imag 張量的原地更新將修改原始複數張量。此外,返回的 real 和 imag 張量不是連續的。
>>> y.real
tensor([ 0.6125, -0.3773, -0.0861])
>>> y.imag
tensor([-0.1681, 1.3487, -0.7981])
>>> y.real.mul_(2)
tensor([ 1.2250, -0.7546, -0.1722])
>>> y
tensor([ 1.2250-0.1681j, -0.7546+1.3487j, -0.1722-0.7981j])
>>> y.real.stride()
(2,)
角度和模#
可以使用 torch.angle() 和 torch.abs() 計算複數張量的角度和模。
>>> x1=torch.tensor([3j, 4+4j])
>>> x1.abs()
tensor([3.0000, 5.6569])
>>> x1.angle()
tensor([1.5708, 0.7854])
線性代數#
許多線性代數運算,如 torch.matmul()、torch.linalg.svd()、torch.linalg.solve() 等,都支援複數。如果您想請求我們目前不支援的操作,請搜尋是否已有相關 issue,如果沒有,請提交一個。
序列化#
複數張量可以被序列化,允許將資料儲存為複數值。
>>> torch.save(y, 'complex_tensor.pt')
>>> torch.load('complex_tensor.pt')
tensor([ 0.6125-0.1681j, -0.3773+1.3487j, -0.0861-0.7981j])
自動微分#
PyTorch 支援複數張量的自動微分。計算出的梯度是共軛維丁格(Conjugate Wirtinger)導數,其負值正是梯度下降演算法中使用的最陡下降方向。因此,所有現有的最佳化器都可以直接用於複數引數。更多詳情,請參閱筆記 複數自動微分。
最佳化器#
從語義上講,我們將透過 PyTorch 最佳化器處理複數引數定義為等同於在複數引數的 torch.view_as_real() 等效表示上使用相同的最佳化器進行更新。更具體地說:
>>> params = [torch.rand(2, 3, dtype=torch.complex64) for _ in range(5)]
>>> real_params = [torch.view_as_real(p) for p in params]
>>> complex_optim = torch.optim.AdamW(params)
>>> real_optim = torch.optim.AdamW(real_params)
real_optim 和 complex_optim 將在引數上計算相同的更新,儘管兩者之間可能存在輕微的數值差異,類似於 foreach 與 forloop 最佳化器以及可捕獲與預設最佳化器之間的數值差異。更多詳情,請參閱 數值精度。
具體來說,雖然您可以將我們最佳化器處理複數張量的方式視為分別最佳化它們的 p.real 和 p.imag 部分,但實現細節並非完全如此。請注意,torch.view_as_real() 等效操作會將複數張量轉換為一個形狀為 的實數張量,而將複數張量拆分為兩個張量則會得到兩個大小為 的張量。這一區別對逐元素最佳化器(如 AdamW)沒有影響,但對於執行全域性約簡的最佳化器(如 LBFGS)可能會導致輕微的差異。我們目前沒有執行每張量約簡的最佳化器,因此尚未定義此行為。如果您有需要精確定義此行為的用例,請提交一個 issue。
我們尚未完全支援以下子系統:
量化
JIT
稀疏張量
分散式