捷徑

數值準確度

在現代電腦中,浮點數使用 IEEE 754 標準表示。 關於浮點運算和 IEEE 754 標準的更多詳細資訊,請參閱 浮點運算。 特別是,請注意浮點數提供有限的準確度(單精度浮點數約為 7 個十進位數字,雙精度浮點數約為 16 個十進位數字),並且浮點數加法和乘法不具結合律,因此運算的順序會影響結果。 因此,PyTorch 無法保證對於數學上相同的浮點數計算產生位元相同的結果。 同樣,無法保證跨 PyTorch 版本、個別提交或不同平台的位元相同結果。 特別是,即使對於位元相同的輸入,即使在控制隨機性來源之後,CPU 和 GPU 結果也可能不同。

批次計算或切片計算

PyTorch 中的許多操作都支援批次運算,也就是對輸入批次的元素執行相同的操作。 其中一個例子是 torch.mm()torch.bmm()。 可以將批次運算實現為對批次元素進行迴圈,並將必要的數學運算應用於個別批次元素。但為了效率考量,我們通常不會這麼做,而是對整個批次執行運算。 在這種情況下,我們呼叫的數學庫以及 PyTorch 內部操作的實作,與非批次運算相比,可能會產生略有不同的結果。 特別是,假設 AB 是 3D 張量,其維度適合批次矩陣乘法。 那麼 (A@B)[0] (批次結果的第一個元素) 並不能保證與 A[0]@B[0] (輸入批次的第一個元素的矩陣乘積) 在位元上完全相同,即使在數學上它是相同的計算。

同樣地,應用於張量切片的操作也不能保證產生與應用於完整張量相同操作的結果切片完全相同的結果。 例如,假設 A 是一個二維張量。 A.sum(-1)[0] 並不保證與 A[:,0].sum() 在位元上相等。

極端值

當輸入包含很大的值,使得中間結果可能溢出所使用資料類型的範圍時,最終結果也可能溢出,即使它可以在原始資料類型中表示。例如:

import torch
a=torch.tensor([1e20, 1e20]) # fp32 type by default
a.norm() # produces tensor(inf)
a.double().norm() # produces tensor(1.4142e+20, dtype=torch.float64), representable in fp32

線性代數 (torch.linalg)

非有限值

torch.linalg 使用的外部函式庫(後端)在輸入具有非有限值(例如 infNaN)時,不保證其行為。 因此,PyTorch 也不保證。 這些操作可能會傳回具有非有限值的張量,或引發例外狀況,甚至導致程式崩潰。

請考慮在呼叫這些函式之前使用 torch.isfinite() 來偵測這種情況。

linalg 中的極端值

torch.linalg 中的函式比其他 PyTorch 函式具有更多的 極端值

求解器反矩陣 假設輸入矩陣 A 是可逆的。 如果它接近不可逆(例如,如果它具有非常小的奇異值),則這些演算法可能會靜默地傳回不正確的結果。 這些矩陣被稱為 病態。 如果提供病態的輸入,則當在不同裝置上使用相同輸入或透過關鍵字 driver 使用不同後端時,這些函式的結果可能會有所不同。

當輸入的奇異值彼此接近時,像 svdeigeigh 這樣的頻譜運算也可能傳回不正確的結果(並且它們的梯度可能是無限的)。 這是因為用於計算這些分解的演算法難以收斂於這些輸入。

float64 中執行計算(就像 NumPy 預設所做的那樣)通常會有幫助,但它並不能解決所有情況下的這些問題。 透過 torch.linalg.svdvals() 分析輸入的頻譜或透過 torch.linalg.cond() 分析其條件數可能有助於偵測這些問題。

Nvidia Ampere (及更高版本) 上的 TensorFloat-32 (TF32)

在 Ampere (及更高版本) Nvidia GPU 上,PyTorch 可以使用 TensorFloat32 (TF32) 來加速數學密集型操作,特別是矩陣乘法和卷積。 當使用 TF32 Tensor Core 執行操作時,只會讀取輸入尾數的前 10 位元。 這可能會降低準確度並產生令人驚訝的結果(例如,將矩陣乘以單位矩陣可能會產生與輸入不同的結果)。 預設情況下,TF32 Tensor Core 對於矩陣乘法是被禁用的,而對於卷積則是啟用的,儘管大多數神經網路工作負載在使用 TF32 時與使用 fp32 時具有相同的收斂行為。 如果您的網路不需要完整的 float32 精度,我們建議透過 torch.backends.cuda.matmul.allow_tf32 = True 為矩陣乘法啟用 TF32 Tensor Core。 如果您的網路需要矩陣乘法和卷積的完整 float32 精度,那麼也可以透過 torch.backends.cudnn.allow_tf32 = False 為卷積禁用 TF32 Tensor Core。

如需更多資訊,請參閱 TensorFloat32

FP16 和 BF16 GEMM 的降精度歸約 (Reduced Precision Reduction)

為了數值準確性和提高對溢出的抵抗力,半精度 GEMM 操作通常使用單精度進行中間累加(歸約)。 為了提高效能,某些 GPU 架構,尤其是較新的架構,允許將中間累加結果截斷為降精度(例如,半精度)。 從模型收斂的角度來看,這種變化通常是良性的,儘管它可能導致意外的結果(例如,當最終結果應該可以在半精度中表示時,出現 inf 值)。 如果降精度歸約有問題,可以使用 torch.backends.cuda.matmul.allow_fp16_reduced_precision_reduction = False 將其關閉。

BF16 GEMM 操作也存在類似的旗標,預設情況下是開啟的。 如果 BF16 降精度歸約有問題,可以使用 torch.backends.cuda.matmul.allow_bf16_reduced_precision_reduction = False 將其關閉。

如需更多資訊,請參閱 allow_fp16_reduced_precision_reductionallow_bf16_reduced_precision_reduction

Scaled Dot Product Attention (SDPA) 中 FP16 和 BF16 的降精度歸約 (Reduced Precision Reduction)

當使用 FP16/BF16 輸入時,一個初步的 SDPA 數學後端可能會因使用低精度的中間緩衝區而累積顯著的數值誤差。為了緩解這個問題,現在的預設行為包含將 FP16/BF16 輸入向上轉換 (upcasting) 為 FP32。計算會在 FP32/TF32 中執行,最終的 FP32 結果再向下轉換 (downcasting) 回 FP16/BF16。這將改善使用 FP16/BF16 輸入的數學後端,其最終輸出的數值準確性,但會增加記憶體使用量,並可能導致數學後端的效能衰退,因為計算會從 FP16/BF16 BMM 轉移到 FP32/TF32 BMM/Matmul。

對於偏好使用降低精度 (reduced-precision) 的簡化計算以提高速度的情境,可以使用以下設定啟用它們:torch.backends.cuda.allow_fp16_bf16_reduction_math_sdp(True)

在 AMD Instinct MI200 裝置上降低精度的 FP16 和 BF16 GEMM 與卷積

在 AMD Instinct MI200 GPU 上,FP16 和 BF16 的 V_DOT2 和 MFMA 矩陣指令會將輸入和輸出的非正規化 (denormal) 值刷新為零。FP32 和 FP64 的 MFMA 矩陣指令不會將輸入和輸出的非正規化值刷新為零。受影響的指令僅由 rocBLAS (GEMM) 和 MIOpen (卷積) 核心使用;所有其他 PyTorch 運算都不會遇到這種行為。所有其他支援的 AMD GPU 都不會遇到這種行為。

rocBLAS 和 MIOpen 為受影響的 FP16 運算提供替代實作。未提供 BF16 運算的替代實作;BF16 數字具有比 FP16 數字更大的動態範圍,並且不太可能遇到非正規化值。對於 FP16 替代實作,FP16 輸入值會被轉換為中間 BF16 值,然後在累加 FP32 運算後轉換回 FP16 輸出。 這樣,輸入和輸出類型保持不變。

當使用 FP16 精度進行訓練時,某些模型可能無法在 FP16 非正規化值被刷新為零的情況下收斂。非正規化值更常出現在訓練的反向傳播過程中,在梯度計算期間。PyTorch 預設情況下會在反向傳播期間使用 rocBLAS 和 MIOpen 替代實作。可以使用環境變數 ROCBLAS_INTERNAL_FP16_ALT_IMPL 和 MIOPEN_DEBUG_CONVOLUTION_ATTRIB_FP16_ALT_IMPL 覆蓋預設行為。這些環境變數的行為如下:

前向傳播

反向傳播

環境變數未設定

原始實作

替代實作

環境變數設定為 1

替代實作

替代實作

環境變數設定為 0

原始實作

原始實作

以下是 rocBLAS 可能使用的運算列表:

  • torch.addbmm

  • torch.addmm

  • torch.baddbmm

  • torch.bmm

  • torch.mm

  • torch.nn.GRUCell

  • torch.nn.LSTMCell

  • torch.nn.Linear

  • torch.sparse.addmm

  • 以下 torch._C._ConvBackend 實作:

    • slowNd

    • slowNd_transposed

    • slowNd_dilated

    • slowNd_dilated_transposed

以下是 MIOpen 可能使用的運算列表:

  • torch.nn.Conv[Transpose]Nd

  • 以下 torch._C._ConvBackend 實作:

    • ConvBackend::Miopen

    • ConvBackend::MiopenDepthwise

    • ConvBackend::MiopenTranspose

文件

存取 PyTorch 的全面開發人員文件

查看文件

教學

獲取適用於初學者和高級開發人員的深入教學

查看教學

資源

查找開發資源並獲得您的問題的解答

查看資源