|
|
환경 변수 설정
$ export NCCL_P2P_DISABLE=1
$ export NCCL_IB_DISABLE=1
$ export NCCL_NET=Socket
$ export NCCL_SOCKET_IFNAME=eno1
$ export NCCL_DEBUG=WARN
https://docs.nvidia.com/deeplearning/nccl/user-guide/docs/env.html
https://github.com/NVIDIA/nccl/issues/570
실행 명령어
Master node (*제일 첫 번째로 실행해야 함)
$ torchrun --nproc_per_node=1 --nnodes=3 --node_rank=0 --master_addr=<MASTER_IP> --master_port=<PORT> train.py
Worker node (*이후 실행할 rank가 낮은 거 실행)
$ torchrun --nproc_per_node=1 --nnodes=3 --node_rank=1 --master_addr=<MASTER_IP> --master_port=<PORT> train.py
이후 보드부터는 node_rank 순서대로 실행하면 됨
nnodes: 사용할 보드 개수 (전체 학습에 참여하는 보드 수)
nproc_per_node: 한 노드에서 실행할 GPU 개수 (Jetson은 GPU가 하나이므로 1로 설정)
node_rank: 현재 노드가 전체 노드 중 몇 번째인지 (*마스터는 rank=0 고정)
이전 정리에서는 mpirun을 사용해서 진행하려고 했는데 안하는 이유
https://cafe.daum.net/SmartRobot/RoVa/2184
| 항목 | mpirun | torchrun |
| 설치 필요 | O (OpenMPI 등) | X (PyTorch 포함됨) |
| PyTorch 친화성 | 낮음 | 매우 높음 |
| 디버깅 | 복잡 | 직관적 |
| Jetson 호환 | 종종 문제 | 잘 작동 |
| 권장 사용 | HPC 시스템 | 딥러닝 모델 학습 |
> Jetson에서는 모델 학습을 위한 것이라면 torchrun이 사용하기 친화적임
> 다른 환경에서는 mpirun을 사용해야 할 수도 있으므로 잘 알아봐야 함
Python code 수정 및 동작 방식
torch.distributed 초기화
device = torch.device("cuda" if torch.cuda.is_available() else "cpu") | cs |
위 코드를 아래와 같이 변경함
import torch.distributed as dist from torch.nn.parallel import DistributedDataParallel as DDP dist.init_process_group(backend='gloo') torch.cuda.set_device(local_rank) device = torch.device(f'cuda:{local_rank}') | cs |
https://pytorch.org/docs/stable/distributed.html
모델을 DistributedDataParallel로 묶기 ( DDP )
model = timm.create_model(...).to(device) model = DDP(model, device_ids=[local_rank]) | cs |
DistributedDataParallel은 각각의 GPU에 데이터와 모델이 분배
각각의 GPU에서 계산된 그래디언트들이 전체적으로 동기화되며 합쳐지는 방식으로 학습함
각 worker node에서 계산된 그래디언트들이 master node에서 처리되어 가중치 업데이트를 함
각 프로세스에서 CPU는 1개만 쓰니까 local_rank로 지정
https://pytorch.org/docs/stable/generated/torch.nn.parallel.DistributedDataParallel.html
DistributedSampler
from torch.utils.data import DistributedSampler train_sampler = DistributedSampler(train_dataset) train_loader = DataLoader(train_dataset, batch_size=..., sampler=train_sampler) train_sampler.set_epoch(epoch) | cs |
shuffle 대신 DistributedSampler 사용
각 프로세스에 전체 데이터셋을 균등하게 분산
DistributedSampler는 데이터셋의 각 샘플에 대한 인덱스를 분산처리에 맞게 새로운 순서로 만들어주고
해당 인덱스를 이용하여 프로세스들 간의 중복 없는 데이터 분배 가능
epoch마다 셔플 세팅
https://discuss.pytorch.org/t/distributedsampler/90205
이외 master node에서만 추론 및 저장, 검증을 실행하도록 설정함
-> if로 조건문 걸고 rank==0에서만 실행되게 하면 됨
종료 시 프로세스 그룹 해제
dist.destroy_process_group() | cs |
결과
2개 엮은 모습
현재 resnet101, batch size 96, 보드 3개 엮은 결과 1epoch당 45분 걸리는 거 확인함.
이후 학습 완료하면 결과 보고할 예정