捷徑

重現性

無法保證在 PyTorch 版本、個別提交或不同平台之間完全重現結果。此外,即使使用相同的種子,也可能無法在 CPU 和 GPU 執行之間重現結果。

但是,您可以採取一些步驟來限制特定平台、裝置和 PyTorch 版本的非確定性行為來源數量。首先,您可以控制隨機性的來源,這些隨機性可能會導致應用程式的多次執行表現不同。其次,您可以將 PyTorch 設定為避免對某些操作使用非確定性演算法,以便在給定相同輸入的情況下,多次呼叫這些操作將產生相同的結果。

警告

確定性操作通常比非確定性操作慢,因此模型的單次執行效能可能會降低。但是,確定性可以透過促進實驗、除錯和回歸測試來節省開發時間。

控制隨機性的來源

PyTorch 隨機數產生器

您可以使用 torch.manual_seed() 為所有裝置(CPU 和 CUDA)設定 RNG 種子

import torch
torch.manual_seed(0)

某些 PyTorch 操作可能會在內部使用隨機數。例如,torch.svd_lowrank() 就是這樣。因此,使用相同的輸入引數多次連續呼叫它可能會產生不同的結果。但是,只要在應用程式開始時將 torch.manual_seed() 設定為常數,並且消除了所有其他非確定性來源,則每次在相同環境中執行應用程式時,都會產生相同的隨機數序列。

也可以透過在後續呼叫之間將 torch.manual_seed() 設定為相同的值,從使用隨機數的操作中獲得相同的結果。

Python

對於自訂運算子,您可能也需要設定 Python 種子

import random
random.seed(0)

其他函式庫中的隨機數產生器

如果您或您正在使用的任何函式庫依賴 NumPy,則可以使用以下方法設定全域 NumPy RNG 種子

import numpy as np
np.random.seed(0)

但是,某些應用程式和函式庫可能會使用 NumPy 隨機數產生器物件,而不是全域 RNG(https://numpy.org/doc/stable/reference/random/generator.html),這些物件也需要一致地設定種子。

如果您正在使用任何其他使用隨機數產生器的函式庫,請參閱這些函式庫的文件,以了解如何為它們設定一致的種子。

CUDA 卷積基準測試

由 CUDA 卷積操作使用的 cuDNN 函式庫可能是應用程式多次執行之間非確定性的來源。當使用一組新的尺寸參數呼叫 cuDNN 卷積時,一個可選功能可以執行多個卷積演算法,對它們進行基準測試以找到最快的演算法。然後,在剩餘的流程中,將針對相應的尺寸參數集一致地使用最快的演算法。由於基準測試雜訊和不同的硬體,基準測試可能會在後續執行中選擇不同的演算法,即使在同一台機器上也是如此。

使用 torch.backends.cudnn.benchmark = False 禁用基準測試功能會導致 cuDNN 確定性地選擇演算法,但可能會降低效能。

但是,如果您不需要在應用程式的多次執行之間保持重現性,則啟用基準測試功能(torch.backends.cudnn.benchmark = True)可能會提高效能。

請注意,此設定與下面討論的 torch.backends.cudnn.deterministic 設定不同。

避免非確定性演算法

torch.use_deterministic_algorithms() 可讓您將 PyTorch 設定為在可用時使用確定性演算法而不是非確定性演算法,並在已知操作是非確定性時(並且沒有確定性替代方案)擲出錯誤。

請查看 torch.use_deterministic_algorithms() 的文件以獲取受影響操作的完整清單。如果操作未按照文件正確執行,或者您需要沒有確定性實作的操作的確定性實作,請提交問題:https://github.com/pytorch/pytorch/issues?q=label:%22module:%20determinism%22

例如,執行 torch.Tensor.index_add_() 的非確定性 CUDA 實作將擲出錯誤

>>> import torch
>>> torch.use_deterministic_algorithms(True)
>>> torch.randn(2, 2).cuda().index_add_(0, torch.tensor([0, 1]), torch.randn(2, 2))
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
RuntimeError: index_add_cuda_ does not have a deterministic implementation, but you set
'torch.use_deterministic_algorithms(True)'. ...

當使用稀疏密集 CUDA 張量呼叫 torch.bmm() 時,它通常使用非確定性演算法,但是當啟用確定性旗標時,將使用其備用的確定性實作

>>> import torch
>>> torch.use_deterministic_algorithms(True)
>>> torch.bmm(torch.randn(2, 2, 2).to_sparse().cuda(), torch.randn(2, 2, 2).cuda())
tensor([[[ 1.1900, -2.3409],
         [ 0.4796,  0.8003]],
        [[ 0.1509,  1.8027],
         [ 0.0333, -1.1444]]], device='cuda:0')

此外,如果您使用的是 CUDA 張量,並且您的 CUDA 版本為 10.2 或更高版本,則應根據 CUDA 文件設定環境變數 CUBLAS_WORKSPACE_CONFIGhttps://docs.nvidia.com/cuda/cublas/index.html#results-reproducibility

CUDA 卷積確定性

雖然停用 CUDA 卷積基準測試(如上所述)可確保 CUDA 在每次執行應用程序時都選擇相同的演算法,但除非設定了 torch.use_deterministic_algorithms(True)torch.backends.cudnn.deterministic = True,否則該演算法本身可能是非確定性的。 與 torch.use_deterministic_algorithms()(它也會使其他 PyTorch 操作表現出確定性)不同,後一種設定僅控制此行為。

CUDA RNN 和 LSTM

在某些版本的 CUDA 中,RNN 和 LSTM 網絡可能具有非確定性行為。有關詳細資訊和解決方法,請參閱 torch.nn.RNN()torch.nn.LSTM()

填充未初始化的內存

torch.empty()torch.Tensor.resize_() 這樣的操作可能會返回具有包含未定義值的未初始化內存的張量。如果需要確定性,則使用這樣的張量作為另一個操作的輸入是無效的,因為輸出將是非確定性的。但是,實際上沒有什麼可以阻止運行此類無效代碼。因此,為了安全起見,預設情況下 torch.utils.deterministic.fill_uninitialized_memory 設定為 True,如果設定了 torch.use_deterministic_algorithms(True),它將使用已知值填充未初始化的內存。這將防止這種非確定性行為的可能性。

但是,填充未初始化的內存會損害性能。因此,如果您的程序有效並且不使用未初始化的內存作為操作的輸入,則可以關閉此設定以獲得更好的性能。

DataLoader

DataLoader 將按照 多進程數據加載中的隨機性 演算法重新設定工作進程的種子。使用 worker_init_fn()generator 來保持可重複性。

def seed_worker(worker_id):
    worker_seed = torch.initial_seed() % 2**32
    numpy.random.seed(worker_seed)
    random.seed(worker_seed)

g = torch.Generator()
g.manual_seed(0)

DataLoader(
    train_dataset,
    batch_size=batch_size,
    num_workers=num_workers,
    worker_init_fn=seed_worker,
    generator=g,
)

文件

訪問 PyTorch 的完整開發者文檔

查看文檔

教學課程

獲取針對初學者和高級開發者的深入教學課程

查看教學課程

資源

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

查看資源