Source code for pypielm.utils.reproducibility
"""Utility helpers: reproducibility and device selection."""
from __future__ import annotations
import os
import random
import numpy as np
import torch
[docs]
def seed_everything(seed: int = 42, *, deterministic: bool = True) -> None:
"""Set all relevant random seeds for full reproducibility.
Seeds: Python ``random``, ``numpy.random``, PyTorch CPU, PyTorch CUDA, and
Apple MPS (seeded implicitly via :func:`torch.manual_seed`).
Args:
seed: Integer seed value.
deterministic: If ``True``, enables deterministic CUDA algorithms
(may reduce performance but guarantees reproducibility).
Has no effect on MPS (MPS operations are always deterministic).
"""
random.seed(seed)
np.random.seed(seed)
torch.manual_seed(seed) # also covers MPS
if torch.cuda.is_available(): # pragma: no cover
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = deterministic
torch.backends.cudnn.benchmark = not deterministic
if deterministic:
# Required for deterministic CuBLAS ops on CUDA >= 10.2
if torch.cuda.is_available(): # pragma: no cover
os.environ.setdefault("CUBLAS_WORKSPACE_CONFIG", ":4096:8")
import contextlib
with contextlib.suppress(RuntimeError): # pragma: no cover
torch.use_deterministic_algorithms(True)
[docs]
def get_device(prefer_cuda: bool = True, prefer_mps: bool = True) -> torch.device:
"""Return the best available :class:`torch.device`.
Priority order: CUDA > MPS (Apple Silicon) > CPU.
Args:
prefer_cuda: If ``True`` and CUDA is available, returns a CUDA device.
prefer_mps: If ``True`` and Apple MPS is available (and CUDA is not),
returns an MPS device. Ignored when ``prefer_cuda=True`` and CUDA
is present.
Returns:
A :class:`torch.device`.
"""
if prefer_cuda and torch.cuda.is_available(): # pragma: no cover
return torch.device("cuda")
if prefer_mps and torch.backends.mps.is_available():
return torch.device("mps")
return torch.device("cpu")