目录

可复现性

完全可复现的结果在PyTorch的不同版本、单独的提交或不同的平台上不能保证。此外,即使使用相同的种子,CPU和GPU执行之间的结果也可能无法复现。

然而,你可以采取一些措施来限制特定平台、设备和PyTorch版本中非确定性行为的来源数量。首先,你可以控制可能导致应用程序多次执行行为不同的随机性来源。其次,你可以配置PyTorch避免在某些操作中使用非确定性算法,这样在给定相同输入的情况下,多次调用这些操作将产生相同的结果。

警告

确定性操作通常比非确定性操作慢,因此您的模型的单次运行性能可能会下降。然而,确定性可能通过促进实验、调试和回归测试,在开发过程中节省时间。

控制随机性的来源

PyTorch 随机数生成器

你可以使用 torch.manual_seed() 为所有设备(包括CPU和CUDA)设置RNG种子:

import torch
torch.manual_seed(0)

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 卷积基准测试

cuDNN库,用于CUDA卷积操作,可能会在应用程序的多次执行中成为非确定性的来源。当使用一组新的尺寸参数调用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() 的文档,以获取受影响操作的完整列表。如果某个操作的行为与文档描述不符,或者您需要某个没有确定性实现的操作的确定性实现,请提交一个 issue: https://github.com/pytorch/pytorch/issues?q=label:%22topic:%20determinism%22

例如,运行非确定性的CUDA实现 torch.Tensor.index_add_() 将抛出一个错误:

>>> 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)'. ...

torch.bmm() 被调用时,如果使用的是稀疏-密集型CUDA张量,它通常会使用一个非确定性算法,但当确定性标志被打开时,将使用其替代的确定性实现:

>>> 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_CONFIG : https://docs.nvidia.com/cuda/cublas/index.html#cublasApi_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()

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 的全面开发人员文档

查看文档

教程

获取面向初学者和高级开发人员的深入教程

查看教程

资源

查找开发资源并解答您的问题

查看资源