再现性¶
在 PyTorch 版本中不保证完全可重现的结果, 单个提交或不同的平台。此外,结果可能不是 在 CPU 和 GPU 执行之间可重现,即使使用相同的种子也是如此。
但是,您可以采取一些步骤来限制 特定平台、设备和 PyTorch 版本的非确定性行为。 首先,您可以控制可能导致多次执行的随机性来源 的行为不同。其次,您可以配置 PyTorch 为了避免对某些操作使用非确定性算法,以便将多个 在给定相同输入的情况下,对这些操作的调用将产生相同的结果。
警告
确定性操作通常比非确定性操作慢,因此 您的模型的单次运行性能可能会降低。但是,决定论可能会 通过促进实验、调试和 回归测试。
控制随机性来源¶
PyTorch 随机数生成器¶
import torch
torch.manual_seed(0)
某些 PyTorch 操作可能在内部使用随机数。执行此操作。因此,将其称为
多次背靠背使用相同的输入参数可能会得到不同的
结果。但是,只要
设置为常量
在应用程序的开头,所有其他非确定性来源都有
被消除,每次都会生成相同系列的随机数
应用程序在同一环境中运行。
其他库中的随机数生成器¶
如果你或你正在使用的任何库依赖于 NumPy,你可以将全局 NumPy RNG 与:
import numpy as np
np.random.seed(0)
但是,某些应用程序和库可能会使用 NumPy Random Generator 对象, 不是全球 RNG (https://numpy.org/doc/stable/reference/random/generator.html),而这些将 还需要始终如一地播种。
如果您使用的是任何其他使用随机数生成器的库,请参阅 这些库的文档,了解如何为它们设置一致的种子。
CUDA 卷积基准测试¶
CUDA 卷积运算使用的 cuDNN 库可能是不确定性的来源 跨应用程序的多次执行。当使用 新的 size 参数集,一个可选功能可以运行多个卷积算法, 对它们进行基准测试以找到最快的。然后,将使用最快的算法 在其余过程中,对于相应的 size 参数集保持一致。 由于基准测试噪声和不同的硬件,基准测试可能会选择不同的 算法,甚至在同一台计算机上。
禁用基准测试功能会导致 cuDNN 确定性地选择算法,其代价可能是降低
性能。torch.backends.cudnn.benchmark = False
但是,如果您不需要在应用程序的多次执行之间实现可重复性,则
如果使用 启用了基准测试功能,则性能可能会提高。torch.backends.cudnn.benchmark = True
请注意,此设置与下面讨论的设置不同。torch.backends.cudnn.deterministic
避免非确定性算法¶
允许您配置 PyTorch 以使用
确定性算法而不是非确定性算法(如果可用),以及
如果已知操作是不确定的(并且没有
确定性的替代方案)。
请查看文档以获取受影响操作的完整列表。如果操作未正确操作
根据文档,或者如果您需要确定性实现
,请提交一个问题:https://github.com/pytorch/pytorch/issues?q=label:%22module:%20determinism%22
>>> 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 张量调用时,它通常使用
nondeterministic 算法,但是当 deterministic 标志打开时,其 alternate
将使用确定性实现:
>>> 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#results-reproducibility
CUDA 卷积确定性¶
虽然禁用 CUDA 卷积基准测试(如上所述),但可确保
CUDA 在每次运行应用程序时都会选择相同的算法,该算法
本身可能是不确定的,除非设置了 OR。后一种设置
仅控制此行为,与此行为不同,其他 PyTorch 操作也会具有确定性行为。
torch.use_deterministic_algorithms(True)
torch.backends.cudnn.deterministic = True
CUDA RNN 和 LSTM¶
填充未初始化的内存¶
操作 like 和
can return
具有包含未定义值的未初始化内存的张量。使用这样的
如果需要确定性,则作为另一个操作的输入的 Tensor 无效,
因为输出将是不确定的。但实际上没有什么可的
防止此类无效代码运行。因此,为了安全起见,
默认设置为,如果设置,它将用已知值填充未初始化的内存。这将防止
这种非确定性行为的可能性。
True
torch.use_deterministic_algorithms(True)
但是,填充未初始化的内存对性能有害。因此,如果您的 程序有效,并且不使用未初始化的内存作为 操作,则可以关闭此设置以获得更好的性能。
数据加载器¶
DataLoader 将在多进程数据加载算法中遵循随机性为 worker 重新设定种子。
使用 和 生成器 以保持可重复性:worker_init_fn()
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,
)