Randomness 제어
랜덤성 제어를 위해 필요한 것
- 초기 가중치 고정
- augmentation에 사용되는 random값 고정
def set_seed(seed=990912):
torch.manual_seed(seed)
torch.cuda.manual_seed(seed)
torch.cuda.manual_seed_all(seed)
torch.backends.cudnn.deterministic = True
torch.backends.cudnn.benchmark = False
np.random.seed(seed)
random.seed(seed)
torch.manual_seed
랜덤한 숫자를 생성하기 위한 시드를 고정한다. return은 torch.Generator 오브젝트를 반환한다. 즉, Pytorch 난수 생성기에서 random seed를 설정한다.
그래서 아래와 같은 코드를 작성하면, 매번 같은 결과를 얻을 수 있게 된다.
import torch
torch.manual_seed(2)
print(torch.rand(2))
tensor([0.6147, 0.3810])
위 텐서의 결과값인 0.6147, 0.3810은 바뀌지 않는다.
Albumnetation 시드 고정
Albumnetation은 numpy난수 텐서플로우 난수를 사용하지 않는다. 파이썬 난수 생성기에만 의존하므로 재현 가능한 augmentation을 얻으려면 python의 random seed를 수정해야 하며, 이것만 seed를 고정하면 고정된 결과를 얻을 수 있을 것이다,
네트워크 선언 전 그냥 코드 처음부터 이것들을 선언해놓는 것이 마음 편하다. 애매하게 뒤에 선언했다가 안됨.
번외
manual_seed의 간단한 동작과정
[docs]def manual_seed(seed) -> torch._C.Generator:
r"""Sets the seed for generating random numbers. Returns a
`torch.Generator` object.
Args:
seed (int): The desired seed. Value must be within the inclusive range
`[-0x8000_0000_0000_0000, 0xffff_ffff_ffff_ffff]`. Otherwise, a RuntimeError
is raised. Negative inputs are remapped to positive values with the formula
`0xffff_ffff_ffff_ffff + seed`.
"""
seed = int(seed)
import torch.cuda
if not torch.cuda._is_in_bad_fork():
torch.cuda.manual_seed_all(seed)
import torch.mps
if not torch.mps._is_in_bad_fork():
torch.mps.manual_seed(seed)
if hasattr(torch, 'xpu') and not torch.xpu._is_in_bad_fork():
torch.xpu.manual_seed_all(seed)
_seed_custom_device(seed)
return default_generator.manual_seed(seed)
default_generator.manual_seed(seed)를 호출함으로 인하여 seed를 설정해준다.
default_generator 확인
from torch._C import default_generator
위 import 내용에서 definition을 타고 들어가면 다음과 같은 코드가 나온다.
has_openmp: _bool
has_mkl: _bool
has_mps: _bool
has_lapack: _bool
has_cuda: _bool
has_mkldnn: _bool
has_cudnn: _bool
has_spectral: _bool
_GLIBCXX_USE_CXX11_ABI: _bool
default_generator: Generator
맨 아래에 default_generator에 대한 선언이 있으며, Generator 타입 힌트가 붙어있는 것을 확인 가능하다. 해당 코드는 site-packages / torch / _C / __init__.pyi 파일에서 확인할 수 있다.
default_generator는 Generator타입의 객체이다.
# Defined in torch/csrc/Generator.cpp
class Generator(object):
device: _device
def __init__(self, device: Union[_device, str, None] = None) -> None: ...
def get_state(self) -> Tensor: ...
def set_state(self, _new_state: Tensor) -> Generator: ...
def manual_seed(self, seed: _int) -> Generator: ...
def seed(self) -> _int: ...
def initial_seed(self) -> _int: ...
클래스의 자세한 내부 구현은 cpp코드를 참조하여 확인할 수 있을 것 같다. 우선 해당 내용들까지는 필요하지 않으니 확인하지 않는다.
static PyObject * THPGenerator_manualSeed(THPGenerator *self, PyObject *seed)
{
HANDLE_TH_ERRORS
auto generator = self->cdata;
THPUtils_assert(THPUtils_checkLong(seed), "manual_seed expected a long, "
"but got %s", THPUtils_typename(seed));
// See Note [Acquire lock when using random generators]
std::lock_guard<std::mutex> lock(generator->mutex_);
generator->set_current_seed(THPUtils_unpackLong(seed));
Py_INCREF(self);
return (PyObject*)self;
END_HANDLE_TH_ERRORS
}
혹시 몰라 궁금한 사람이 있을 것 같아, manualSeed함수의 구현 부분을 남긴다.
참고자료
- https://discuss.pytorch.org/t/what-is-manual-seed/5939
- https://pytorch.org/docs/stable/generated/torch.manual_seed.html
- https://pytorch.org/docs/stable/_modules/torch/random.html#manual_seed
- https://github.com/pytorch/pytorch/blob/ac7996ccd3a13528519beb398e418d7131a5ed52/torch/csrc/Generator.cpp
- https://hoya012.github.io/blog/reproducible_pytorch/
- https://github.com/albumentations-team/albumentations/issues/93
'Python 관련 > Pytorch' 카테고리의 다른 글
[Pytorch] torchview를 사용한 모델 plot 시각화 (ubuntu) (0) | 2024.05.29 |
---|---|
RuntimeError: CUDA error: device-side assert triggered (0) | 2024.04.05 |
Albumentation Color jitter 사용 오류 (0) | 2024.04.05 |
[Pytorch] 모델 저장 오류 (0) | 2024.03.07 |
[Pytorch] Generator (0) | 2024.02.27 |