이번에는 multi gpu를 사용하면서 나올 용어들과 개념들을 정리해보았다.
multi gpu하면 꼭 같이 나오는 parallel을 data와 model로 나누어 정리하였다.
코드
원래 옛날에는 GPU를 어떻게 하면 적게 쓸까를 고민했지만
최근에는 성능에 초점을 두면서 엄청난 양의 GPU를 쓰고 있다.
Single : 1개 사용 vs Multi : 2개 이상 사용
GPU vs Node : Node는 1대의 컴퓨터를 말한다.
Single Node Single GPU : 1대의 컴퓨터에서 1개의 GPU 사용
Single Node Multi GPU : 1대의 컴퓨터에서 여러 개의 GPU 사용
Multi Node Multi GPU : 서버실에서 여러 개의 GPU 사용
class ModelParallelResNet(ResNet):
def __init__():
...
self.seq1 = nn.Sequential(
self.conv2,...
).to('cuda:0') # cuda0에 할당
self.seq2 = nn.Sequential(
self.conv2,...
).to('cuda:1') # cuda1에 할당
...
def forward(self,x):
x = self.seq2(self.seq1(x).to('cuda:1')) # cuda0에서 cuda1로 복사한다
minibatch와 비슷한 느낌이다.
minibatch처럼 데이터를 나누어서 병렬적으로 돌리고
이를 나중에 합쳐서 평균을 구하는 방법이다.
parallel_model = torch.nn.DataParallel(model)
...
# backward 할 때 Average GPU-losses + backward pass
loss.mean().backward()
각 GPU에 CPU도 할당해줘서 각 CPU마다 process 생성하여 개별 GPU에 할당한다.
⇒ 기본적으로 DataParallel로 하나 개별적으로 연산의 평균을 낸다.
train_sampler = torch.utils.data.distributed.DistributedSampler(data)
loader = torch.utils.data.DataLoader(data,batch_size=20,shuffle = False,
pin_memory = True,sampler=train_sampler)
def main():
n_gpus = torch.cuda.device_count()
torch.multiprocessing.spawn(main_worker,nprocs=n_gpus,args=(n_gpus,)
def main_worker(gpu,n_gpus):
...
# 멀티프로세싱 통신 규약 정의
torch.distributed.init_process_group(backend='nccl',
init_method='tcpL//~',world_size=n_gpus,rank=gpu)
# Distributed DataParallel 정의
torch.nn.parallel.DistributedDataParallel(model,device_idx=[gpu])
추가로, num_workers는 GPU x 4를 많이한다.
이것도 pytorch-lightning을 사용하면 쉽게 multi-gpu를 이용할 수 있는데요.
시간이 될 때 직접 작성하는 것과 lightning 을 사용하는 것을 비교해보면 좋을 것 같습니다.