최근의 딥러닝은 엄청난 양의 데이터와의 싸움이다. 과거에는 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를 의미한다.
다중 GPU에 학습을 분산하는 두 가지 방법
모델을 나누는 것은 생각보다 오래된 방법이다(alexnet)
모델의 병목, 파이프라인의 어려움 등으로 인해 모델 병렬화는 고난이도 문제이다.
위의 alexnet을 보면 두 GPU간의 교차(C2와 C3사이)되는 부분이 있다.
모델 병렬화를 잘못하게 되면 각각의 GPU가 비는 시간이 생길 수 있다.
좋은 병렬화는 각각의 GPU가 동시에 작동하도록 파이프라인을 구성해야 한다.
데이터를 나눠 GPU에 할당 후 결과의 평균을 취하는 방법이다
우리가 사용하는 minibatch 수식과 유사하지만 한번에 여러 GPU에서 수행한다.
DataParallel
, DistributedDataParallel
DataParallel
: 단순 데이터를 분배한 후 평균을 취함parallel_model = torch.nn.DataParallel(model) # 이 한줄로 사용가능
preds = parallel_model(inputs)
loss = loss_func(preds, labels)
loss.mean().backward()
optimizer.step()
DistributedDataParallel
: 각 CPU마다 process 생성하여 개별 GPU에 할당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])