본문 바로가기
Python/Study

[창시모] DP vs DDP 정리

by beeny-ds 2022. 11. 9.

출처: better-tomorrow 님의 tistory

예전 포스팅으로 Multi-GPU 용어 관련 글을 썼다. 해당 글은 여기( link )를 참고하길 바란다. 필자의 글을 보면 마지막에 DP 방식의 학습과 DDP 방식의 학습을 비교 정리한다고 했었다. 그걸 이제 한다,,, 
DP와 DDP의 설명은 algopoolja님의 블로그를 참고하였다.

관련 글은 다음 링크를 참고하길 바란다.
https://algopoolja.tistory.com/95

 

torch의 데이터 분산 연산(DP 와 DDP)

torch parallelism Pytorch 를 사용해 모델을 학습하다 보면 여러가지 병렬화를 사용합니다. 병렬화를 사용하는 이유는 크게 2가지로 나눠볼 수 있습니다. 학습을 더 빨리 끝내기 위해 모델이 너무 커서

algopoolja.tistory.com


 

병렬화 학습은 왜 하는가?

Pytorch를 사용한 모델링을 하다보면 흔히 보는 코드가 병렬화 코드이다. HuggingFace의 Transformers, Knowledge Distillation 관련 소스들 모두 병렬화를 사용한 학습 및 검증 방법을 사용한다. 왜 유명한 패키지에서 동일하게 병렬화를 사용할까? 당연한 말이지만 딥러닝 모델을 학습하는데 큰 장점이 있기 때문이다. 장점은 다음과 같다.

  1. 학습을 빨리 끝내기 위해
    • 실시간 서비스가 필요한 경우, 큰 장점이 될 것이다.
  2. 모델 또는 데이터가 너무 커 나의 device에서는 학습할 수 없을 때
    • 모델을 분할하여 학습할 수 있다.
  3. batch_size를 크게하여 더 좋은 성능을 내기 위해
    • Bert model의 경우, batch_size가 클수록 좋은 성능을 보인다는 연구 결과가 많다.
    • 해당 연구 결과가 당장 궁금하면 RoBERTa 논문을 참고하자.

 

DataParallel(a.k.a DP)란 무엇인가? 

쉽게 말해서 데이터를 병렬화한다는 뜻이다. PyTorch의 경우, torch.nn.DataParallel으로 편하게 사용할 수 있다. 해당 모듈은 Single-Process, Multi-thread 그리고 single machine에서만 동작한다. DP의 특징 및 장점과 단점을 살펴보자.

특징

왼쪽: Forward Pass   /   오른쪽: Backward Pass (출처: https://algopoolja.tistory.com/95)

  1. Cons: 모델이 너무 크면 모든 gpu memory가 부족하다.
    • 여러 개의 gpu에 모델을 복제하기 때문이다.
    • 여러 명이 한 서버에서 작업할 때 문제가 될 수 있다.
  2. Forward Pass
    • 계산된 Logits을 첫 번째 gpu에 모아주기 때문에 첫 번째 gpu memory가 다른 gpu memory보다 상대적으로 많이 잡아먹는다. (잡아먹는다는 표현보다 적합한 표현이 있으면 댓글 부탁드립니다.)
    • 각 device에서 모델 내의 계산을 수행하고 최종 결과(Logits)는 첫 번째 gpu로 보내 마무리 하기 때문
      해당 과정은 다음과 같다.
      • 첫 번째 gpu에 올라와 있는 모델의 weight을 나머지 gpu에 보내준다.
      • 각 gpu는 모델의 동일한 weight를 사용하여 Logits 을 계산한다.
      • 계산된 Logit을 첫 번째 gpu에 모아준다. (이를 gather 연산을 한다고 한다.)
      • Logits으로부터 Loss를 계산한다.
  3. Backward Pass
    • 각 gpu에서는 전달받은 Loss를 이용해서 Backward 를 수행하여 Gradients를 계산한다.
    • 계산된 모든 Gradients를 첫 번째 gpu로 보내 모델의 weight를 업데이트 한다.
    • 업데이트된 모델을 다시 모든 gpu에 복제한다.
    • 이러한 과정을 반복하여 모델을 학습한다.

DP를 이용한 모델 학습을 해본 사람이라면 첫 번째 gpu와 나머지 gpu의 memory가 왜 다른지 DP의 단점을 보고 알 수 있을 것이다. 학습하는 모든 gpu들의 memory 사용량을 고르게 하기 위해서는 loss를 구하는 방식을 forward에서 진행해야 한다. 물론 그래도 첫 번째 gpu의 memory가 상대적으로 크겠지만 차이를 줄일 수 있다.
(그래서 huggingface transformers에서 모델 class 안에 loss를 구하도록 구성해둔 것 같다.)

장점

  1. n개의 gpu에 동일한 모델을 올려 학습하기 때문에 학습 속도가 빨라진다. (n개의 gpu에 모델을 복제한다고 이해하자.)
  2. 1번과 같은 이유로 모델의 검증 및 예측 속도도 빨라진다.
  3. 여러 개의 gpu에 데이터를 분할한 뒤 학습하기 때문에 batch_size를 크게 할 수 있다. (이를 데이터 병렬화라 한다.)

단점

  1. Multi-thread module이기 때문에 Python에서 효율적이지 않다.
    • Python은 GIL(Global Interpreter Lock)에 의해 하나의 프로세스에서 동시에 여러 개의 쓰레드가 작동할 수 없다. 따라서 근본적으로 멀티 쓰레드가 아닌 멀티 프로세스 프로그램으로 만들어서 여러 개의 프로세스를 동시에 실행하게 해야 한다.
  2. 하나의 모델에서 업데이트된 모델이 다른 gpu로 매 step마다 복제되어야 한다.
    • 위에서 언급한 특징에 의한 단점이다. 그렇다면 어떻게 효율적으로 이 단점을 해결할 수 있을까? Gradient를 Gather 하지 않고 각 GPU에서 자체적으로 step() 수행한다면 모델을 매번 복제하지 않아도 될까? 정답은 reduce를 수행한 뒤 계산된 결과를 모든 디바이스에 복사하는 All-reduce 연산을 하는 방법을 사용하면 이를 완화시킬 수 있다 한다.
  3. 단점 관련된 사항은 본 포스팅의 모티브가 된 algopoolja 님의 블로그 글을 참고하길 바란다.

 

DistributedDataParallel(a.k.a DDP)란 무엇인가? 

DDP 는 기존 DataParallel 의 문제를 개선하기 위해 등장한 데이터 병렬처리 모듈이며 single/multi-node & multi-GPU 에서 동작하는 multi-process 모듈이다. All-reduce 활용하게 되면서 마스터 프로세스의 개념이 없어졌기 때문에 학습 과정이 매우 심플하게 변한다.

출처: https://algopoolja.tistory.com/95

Python 코드를 실행할 때 torch.distributed.launch 를 사용한 적 있는 독자라면 이해하는 데 더 수월할 것이다. 보통 아래와 같은 방식으로 학습 코드가 시작된다.

python -m torch.distributed.launch --nproc_per_node=GPU_갯수 파일명

필자는 DDP와 관련된 자세한 사항을 이해하지 못했기에 algopoolja 님의 블로그 글을 참고하길 바란다. 필자가 알고 있는 DDP의 장점과 단점을 간단하게 정리하고자 한다.

장점

  1. 여러 개의 서버(a.k.a 노드)를 사용하여 학습할 수 있다.
  2. 모델 또는 데이터를 분할하여 학습하기 때문에 DP로는 학습이 불가능했던 초거대 모델도 DDP로는 학습할 수 있다.
  3. 메모리를 절약할 수 있기 때문에 큰 batch_size로 모델을 학습할 수 있다. 이는 모델의 성능에 영향을 미칠 것이다.
  4. 환경에 따른 케바케지만 학습 속도가 빠를수도 있다.
    • 만약 DP로 학습할 때 큰 batch_size를 사용하기 위해서는 accumulation step 을 크게 해야 하기 때문에 학습 속도가 느리다.
    • 반면 DDP는 accumulation step을 1로 고정해도 큰 batch_size를 사용할 수 있기 때문에 상대적으로 위의 case보다 학습 속도가 빠르다.
    • 이러한 이유 때문에 케바케라 언급했다...

단점

  1. 여러 개의 노드를 사용한다면 환경 셋팅을 할 때 많은 문제를 만날 수 있다.
    but 하나의 노드만 사용한다면 비교적 편할 것이다.
  2. 이것도 케바케지만 학습 속도가 느릴수도 있다.

 

DP vs DDP 비교 표

출처 어디인지 까먹음... 댓글 부탁드려요.


 

마무리,,

nvidia 및 torch 에서는 분석가들이 DP와 DDP를 편하게 사용할 수 있도록 지금도 열심히 개발중이다. 실제로 몇 개월 전에 nvidia에서는 "NVIDIA AI 개발자 밋업 - 딥 러닝 모델 학습을 위한 End-to-End 가속화 기술" 이라는 세션을 통해 DDP의 개념과 사용 방법, 예시 코드를 공유한 적이 있다. 그 분들의 고생으로 우리는 비교적 편하게 개발하고 실험할 수 있으니 참 감사하다.

필자는 DP, DDP 모두 사용해봤다. DDP의 경우 싱글 노드로 사용했지만 말이다. 아무래도 컴퓨터 내부 구조에 관한 지식이 없기 때문에 여러 개의 노드를 사용한 DDP 학습 및 검증은 아직 불가하다고 생각한다. 뭐,,, 그것만 한다면 할 수는 있겠지만 말이다. (이쪽에서 일하다보니까 사람이 마음만 먹으면 뭐든 할 수 있다는 생각이 들기 때문에...)

초거대 언어 모델이 실험되고 사용화되는 이 시점에서 Bert와 같은 거대 모델이 아닌 mt5, GPT-3 등등의 초거대 모델도 실험해보고 싶다. 이때 필요한 기능이 DDP다. 서버는 제한적이기 때문에 제한된 환경에서 개발 및 실험하려면 여러 기술들을 적용해야 하기 때문이다. DP, DDP 관련 다음 포스팅으로는 필자가 실제 적용한 사례에 대한 글이었으면 좋겠다는 생각을 끝으로 글을 마무리한다.

반응형

댓글