예전에도 정리한 적이 있지만 한 게시물로 한꺼번에 정리하려고 작성한다.
딥러닝 분산 학습 방법으로 모델이나 데이터를 쪼개서 학습하는 Model Parallelism, Data Parallelism이 있다.
Data Parallelism은 데이터가 많을 때 학습 속도를 높이기 위해 사용하는 방법이다.
데이터를 나눠 여러 GPU에서 연산한 후 각 최종 업데이트 결과에 대해 평균을 내는 방식이다.
하나의 GPU가 1개의 데이터를 학습할 때 걸리는 시간이 T라면 B개의 Batch를 학습할 때 T*B의 시간이 소요된다. 하지만 N개의 GPU에 B/10만큼 나눠서 학습한다면 T*B/N으로 시간을 단축할 수 있다.
N개의 GPU에서 연산한 업데이트 결과를 모아서 평균을 내고 다시 재분배하는 Synchronization 과정이 필요하다.
Synchronization 과정에서도 시간이 소요되기 때문에 이를 단축하는 것도 중요하다. 평균 낸 weight parameter를 각 GPU에 동일하게 재분배하는데 이때 GPU 간 데이터 전송 속도가 빠르면 synchronization 시간도 단축된다. 따라서 빠른 GPU간 Interconnect를 통해 학습 시간을 단축할 수도 있다. (ex. NVIDIA의 NVLink)
Model Parallelism은 모델이 너무 커서 한 GPU 메모리에 다 들어가지 않을 때 여러 GPU에 모델 parameter를 나누어 연산하는 방법이다. (속도 개선의 목적 X, 큰 모델을 돌리는 목적)
Model Parallelism을 구현하는 방법으로는 Tensor Parallelism과 Pipeline Parallelism이 있다.
Tensor parallelism은 Weight Matrix를 나누어 여러 GPU에서 연산을 하고 결과를 concatenate 하는 방식이다.
Input과 Weight Matrix의 행렬 연산을 Weight Matrix를 나눠 한다는 뜻인데, 여러 GPU에서 병렬로 연산한 후 결과값을 합하기 때문에 학습 시간이 단축된다.
Pipeline Parallelism은 Model의 layer를 여러 대의 GPU에 쪼개서 순차적으로 학습시키는 방법이다.
병렬적으로 처리 가능했던 Tensor parallelism과 달리 각 GPU 연산의 결과를 다음 GPU에 넘겨주는 방식으로 순차적 연산을 하기 때문에 학습 시간을 단축할 수 없다. 그냥 큰 모델을 여러 GPU에 넣을 수 있다는 데에 의미가 있는 것 같다.
+) 두 가지 방법을 한 번에 사용한 2D model parallelism도 있다.
Model parallelism은 모델을 나눴기 때문에 Forward, Backward에 각각 synchronization을 해야 하기 때문에 F,B를 모두 거친 후 각 GPU에서 나온 업데이트(Weight 혹은 Gradient)들을 평균내고 재분배하는 Data parallelism에 비해 Synchronization 빈도가 높다.
accelerate는 딥러닝 학습을 돌릴 때 데이터나 모델이 크고 리소스는 한계가 있을 때 이를 해결하도록 도와주는 Huggingface의 라이브러리이다.
단 4줄의 코드만 추가하면 Multi GPU 분산 구성을 똑같이 100%로 활용할 수 있다. 기본 pytorch 코드를 통해 multi gpu를 사용하면(DDP) 0번 gpu만 100퍼센트 사용되고 나머지 GPU는 예를 들어 60% 정도로 덜 쓰인다.
각 GPU에서의 연산을 통합하여 연산하는 Synchronization이 0번 device에서 계산되기 0번 GPU의 소모만 커지기 때문이다.
accelerate을 사용하면 이러한 문제를 해결할 수 있다. (nvidia-smi를 찍어보면 모든 GPU가 100% 활용되고 있는 것을 확인할 수 있다.)
또한 accelerate를 통해 DeepSpeed를 활용할 수 있다.
DeepSpeed는 스케일링 등을 통해 학습 속도를 가속화하는 라이브러리이다. floating point를 32에서 16으로 줄이는 등의 스케일을 적용하여 학습 속도를 크게 줄이지만 성능이 저하된다.
때문에 분류 문제처럼 정량적 평가의 의미가 큰 문제에는 DeepSpeed를 덜 사용하거나 사용하지 않는게 좋고, 챗봇의 생성모델처럼 정량적 평가가 크게 의미있지 않은 문제(정성적 평가에 비중이 큰 문제)에는 DeepSpeed를 써도 감수할 만하다.
ZeRO(Zero Redundancy Optimizer)
DeepSpeed가 학습을 최적화하는 방법을 ZeRO하고 한다.
기존의 딥러닝 모델의 분산 학습(DDP)에서는 모든 GPU가 모델을 가지고 있어야 했기 때문에 모델을 학습시키기 위한 값(Optimizer State, Gradient, Parameter)을 GPU마다 복제해서 가지기 때문에 메모리 낭비가 크다.
(GPT-2 모델은 3GB 정도의 메모리를 차지하지만 32GB GPU에서 학습이 안된다.)
ZeRO는 이러한 모델(파라미터) 복제로 인한 낭비를 해결한다.
DeepSpeed의 ZeRO는 stage를 통해 최적화 정도를 조절할 수 있다.
+) Stage 3부터는 OOM가 발생하면 에러를 올리지 않고 나머지를 하드디스크에 보내고 cpu로 연산한다.
+) Stage infinity도 있음
reference
https://lifeisenjoyable.tistory.com/21