| Reproducibility |
| =============== |
| |
| Completely reproducible results are not guaranteed across PyTorch releases, |
| individual commits or different platforms. Furthermore, results need not be |
| reproducible between CPU and GPU executions, even when using identical seeds. |
| |
| However, in order to make computations deterministic on your specific problem on |
| one specific platform and PyTorch release, there are a couple of steps to take. |
| |
| There are two pseudorandom number generators involved in PyTorch, which you will |
| need to seed manually to make runs reproducible. Furthermore, you should ensure |
| that all other libraries your code relies on and which use random numbers also |
| use a fixed seed. |
| |
| PyTorch |
| ....... |
| You can use :meth:`torch.manual_seed()` to seed the RNG for all devices (both |
| CPU and CUDA):: |
| |
| import torch |
| torch.manual_seed(0) |
| |
| |
| There are some PyTorch functions that use CUDA functions that can be a source |
| of nondeterminism. One class of such CUDA functions are atomic operations, |
| in particular :attr:`atomicAdd`, which can lead to the order of additions being |
| nondetermnistic. Because floating-point addition is not perfectly associative |
| for floating-point operands, :attr:`atomicAdd` with floating-point operands can |
| introduce different floating-point rounding errors on each evaluation, which |
| introduces a source of nondeterministic variance (aka noise) in the result. |
| |
| PyTorch functions that use :attr:`atomicAdd` in the forward kernels include |
| :meth:`torch.Tensor.index_add_`, :meth:`torch.Tensor.scatter_add_`, |
| :meth:`torch.bincount`. |
| |
| A number of operations have backwards kernels that use :attr:`atomicAdd`, |
| including :meth:`torch.nn.functional.embedding_bag`, |
| :meth:`torch.nn.functional.ctc_loss`, :meth:`torch.nn.functional.interpolate`, |
| and many forms of pooling, padding, and sampling. |
| |
| There is currently no simple way of avoiding nondeterminism in these functions. |
| |
| Additionally, the backward path for :meth:`repeat_interleave` operates |
| nondeterministically on the CUDA backend because :meth:`repeat_interleave` |
| is implemented using :meth:`index_select`, the backward path for |
| which is implemented using :meth:`index_add_`, which is known to operate |
| nondeterministically (in the forward direction) on the CUDA backend (see above). |
| |
| CuDNN |
| ..... |
| When running on the CuDNN backend, two further options must be set:: |
| |
| torch.backends.cudnn.deterministic = True |
| torch.backends.cudnn.benchmark = False |
| |
| .. warning:: |
| |
| Deterministic operation may have a negative single-run performance impact, |
| depending on the composition of your model. Due to different underlying |
| operations, which may be slower, the processing speed (e.g. the number of |
| batches trained per second) may be lower than when the model functions |
| nondeterministically. However, even though single-run speed may be |
| slower, depending on your application determinism may save time by |
| facilitating experimentation, debugging, and regression testing. |
| |
| Numpy |
| ..... |
| If you or any of the libraries you are using rely on Numpy, you should seed the |
| Numpy RNG as well. This can be done with:: |
| |
| import numpy as np |
| np.random.seed(0) |