[Pytorch] Multi-GPU 학습

hyunsooo·2022년 9월 28일
2

최근의 딥러닝은 엄청난 양의 데이터와의 싸움이다. 과거에는 GPU한대로도 충분히 학습이 가능했지만 근래에는 한대로는 감당할 수 없는 데이터양을 다루는 현실이다. 이번 시간에는 이런 상황을 대비해 Multi-GPU에 대해서 알아본다.

개념정리

  • Single(1개의 GPU) vs. Multi(2개 이상)

  • GPU vs. Node : Node는 한대의 컴퓨터를 의미한다. 따라서 1대의 GPU를 사용한다는 것은 1대의 Node(컴퓨터)에 있는 GPU를 사용한다는 의미이다.

  • Single Node Single GPU : 1대의 컴퓨터에 1대의 GPU

  • Single Node Multi GPU : 1대의 컴퓨터에 여러개의 GPU

  • Multi Node Multi GPU : 여러개의 컴퓨터에 여러개의 GPU

  • 우리가 사용하는 Multi GPU는 Single Node Multi GPU를 의미한다.

Model parallel

  • 다중 GPU에 학습을 분산하는 두 가지 방법

    • 모델을 나누기 or 데이터를 나누기
  • 모델을 나누는 것은 생각보다 오래된 방법이다(alexnet)

  • 모델의 병목, 파이프라인의 어려움 등으로 인해 모델 병렬화는 고난이도 문제이다.

  • 위의 alexnet을 보면 두 GPU간의 교차(C2와 C3사이)되는 부분이 있다.

  • 모델 병렬화를 잘못하게 되면 각각의 GPU가 비는 시간이 생길 수 있다.

  • 좋은 병렬화는 각각의 GPU가 동시에 작동하도록 파이프라인을 구성해야 한다.

Data parallel

  • 데이터를 나눠 GPU에 할당 후 결과의 평균을 취하는 방법이다

  • 우리가 사용하는 minibatch 수식과 유사하지만 한번에 여러 GPU에서 수행한다.

  • PyTorch에서는 2가지 방식을 제공한다.
    • DataParallel, DistributedDataParallel
  • DataParallel : 단순 데이터를 분배한 후 평균을 취함
    • GPU 사용 불균형(1개의 GPU가 메인처리를 하기 때문), Batch 사이즈 감소(1개의 GPU가 더 많은 메모리를 사용하고 있기 때문에 거기에 맞춰 감소), GIL
parallel_model = torch.nn.DataParallel(model) # 이 한줄로 사용가능

preds = parallel_model(inputs)
loss = loss_func(preds, labels)
loss.mean().backward()
optimizer.step()
  • DistributedDataParallel : 각 CPU마다 process 생성하여 개별 GPU에 할당
    • 위의 이미지 처럼 모으는 작업이 없이 각각의 평균을 나중에 반영하는 방식(GPU 뿐만 아니라 CPU도 할당되기 때문)
train_sampler = torch.utils.data.distributed.DistributedSampler(train_data)
shuffle = False
pin_memory = True # 메모리에 바로 데이터를 올릴 수 있도록 하는 옵션

trainloader = torch.utils.data.DataLoader(train_data, batch_size=20, shuffle=shuffle,
pin_memory=pin_memory, num_workers=GPU*4, sampler=train_sampler)
def main():
	n_gpus = torch.cuda.device_count()
    # python의 멀티프로세싱 코드 -> map(func, args)
    torch.multiprocessing.spawn(main_worker, npocs=n_gpus, args=(n_gpus,))
    
def main_worker(gpu, n_gpus):
	image_size = 112
    num_worker = 8
    ...
    
    batch_size = int(batch_size / n_gpus)
    num_worker = int(num_worker/n_gpus)
    
    # 멀티프로세싱 통신 규약 정의
    torch.distributed.init_process_group(
    		backend='nccl', init_method='tcp://127.0.0.1:2568', world_size=n_gpus, rank=gpu)
            
    model = MODEL
    
    torch.cuda.set_device(gpu)
    model = model.cuda(gpu)
    #Distributed DataParallel 정의
    model = torch.nn.parallel.DistributedDataParallel(model, device_ids=[gpu])
profile
지식 공유

0개의 댓글