Lei Mao: 분산 딥러닝 학습에서 데이터 병렬화와 모델 병렬화Lei Mao: Data Parallelism VS Model Parallelism In Distributed Deep Learning Training
작은 배치들의 그래디언트를 가중 평균하면 큰 배치의 그래디언트와 같아진다는 식으로 데이터 병렬화가 왜 성립하는지 보이고, 층을 여러 GPU에 나눠 차례로 계산하는 모델 병렬화는 사실 병렬이라기보다 직렬에 가깝다고 짚는 Lei Mao의 짧은 글Some Simple Logic and Theory Behind
번역문 · 원저자: Lei Mao · 원문: Data Parallelism VS Model Parallelism In Distributed Deep Learning Training · 원문 라이선스: CC BY-NC 4.0. 원문을 한국어로 옮긴 것 말고는 내용을 바꾸지 않았습니다. 비영리로만 씁니다.
원문: 「Data Parallelism VS Model Parallelism In Distributed Deep Learning Training」, Lei Mao, https://leimao.github.io/blog/Data-Parallelism-vs-Model-Paralelism/, 2019년 5월 23일 게시. 이 글은 원문을 한국어로 옮긴 번역문입니다.
라이선스: 원문 글 아래 “Licensed under” 칸에 저작자 표시와 비영리 아이콘, 곧 CC BY-NC 4.0이 붙어 있습니다. 이 번역도 원저작자를 밝히고 비영리로만 쓰는 같은 조건을 따릅니다.
들어가며
요즘 딥러닝 모델의 파라미터 수는 점점 더 커지고, 데이터셋 크기도 극적으로 늘고 있습니다. 큰 데이터셋으로 정교한 최신 딥러닝 모델을 학습하려면 여러 노드로 학습해야 합니다. 그러지 않으면 한없이 오래 걸립니다. 분산 딥러닝 학습에서는 데이터 병렬화와 모델 병렬화라는 말을 늘 보게 됩니다. 이 블로그 글에서는 이 두 가지 딥러닝 병렬화 방식의 이론과 논리, 그리고 오해하기 쉬운 몇 가지를 이야기하려 합니다.
데이터 병렬화
요즘 딥러닝에서는 데이터셋이 너무 커서 메모리에 다 올릴 수 없기 때문에, 배치 단위로 확률적 경사 하강법을 쓸 수밖에 없습니다. 예를 들어 학습 데이터셋에 데이터 포인트가 1만 개 있다면, 그래디언트의 추정값을 계산할 때 한 번에 16개만 쓸 수 있습니다. 그러지 않으면 GPU 메모리가 모자라 GPU가 멈춰 버릴 수 있습니다.
확률적 경사 하강법의 약점은, 그래디언트의 추정값이 데이터셋 전체를 썼을 때의 참 그래디언트를 정확히 나타내지 못할 수 있다는 것입니다. 그래서 수렴하는 데 훨씬 오래 걸릴 수 있습니다.
그래디언트를 더 정확히 추정하는 자연스러운 방법은 배치 크기를 키우거나, 아예 데이터셋 전체를 쓰는 것입니다. 이를 위해 GPU마다 작은 배치의 그래디언트를 계산하고, 모든 작은 배치에서 계산한 그래디언트의 가중 평균을 그래디언트의 최종 추정값으로 삼습니다.
수학적으로 데이터 병렬화가 성립하는 까닭은 다음과 같습니다.
여기서 는 모델의 파라미터, 는 크기 인 큰 배치의 참 그래디언트, 는 GPU 또는 노드 에 있는 작은 배치의 그래디언트, 와 는 데이터 포인트 의 특징과 레이블, 는 순전파로 계산한 데이터 포인트 의 손실, 은 데이터셋의 전체 데이터 포인트 수, 는 전체 GPU 또는 노드 수, 는 GPU 또는 노드 에 배정된 데이터 포인트 수이고, 입니다.
이면 더 나아가 다음을 얻습니다.
이때 GPU 또는 노드마다 같은 모델과 파라미터로 순전파를 합니다. 노드마다 서로 다른 데이터로 된 작은 배치를 보내고, 평소처럼 그래디언트를 계산한 다음, 그래디언트를 주 노드로 돌려보냅니다. GPU나 노드마다 속도가 조금씩 다르기 때문에 이 단계는 비동기입니다. 그래디언트를 모두 받고 나면(여기서 동기화를 합니다), 그래디언트의 (가중) 평균을 계산하고, 그 (가중) 평균으로 모델과 파라미터를 업데이트합니다. 그런 다음 다음 반복으로 넘어갑니다.
모델 병렬화
모델 병렬화라는 말은 제게 무시무시하게 들리지만, 실은 수학과는 아무 관계가 없습니다. 컴퓨터 자원을 어떻게 나눠 쓸지에 관한 직관일 뿐입니다. 데이터를 (GPU) 메모리에 다 올리지 못하는 까닭이, 딥러닝 모델에 층과 파라미터가 너무 많아서일 때가 있습니다. 그럴 때는 딥러닝 모델을 여러 조각으로 나눠, 이어진 층 몇 개를 노드 하나에 두고 그 그래디언트를 계산할 수 있습니다. 이렇게 하면 노드 하나에 있는 파라미터 수가 줄어들고, 데이터를 써서 학습해 더 정확한 그래디언트를 얻을 수 있습니다.
예를 들어 GPU가 10개 있고 간단한 ResNet50 모델을 학습하려 한다고 합시다. 처음 5개 층을 GPU 1번에, 다음 5개 층을 GPU 2번에, 이런 식으로 배정해 마지막 5개 층을 GPU 10번에 둘 수 있습니다. 학습 중 반복마다 순전파는 먼저 GPU 1번에서 해야 합니다. GPU 2번은 GPU 1번의 출력을 기다리고, GPU 3번은 GPU 2번의 출력을 기다리는 식입니다. 순전파가 끝나면, GPU 10번에 있는 마지막 층들의 그래디언트를 계산하고 GPU 10번에서 그 층들의 모델 파라미터를 업데이트합니다. 그다음 그래디언트가 GPU 9번에 있는 앞쪽 층들로 역전파되고, 이렇게 이어집니다. GPU나 노드 하나하나가 공장 생산 라인의 한 칸과 같아서, 앞 칸에서 제품이 오기를 기다렸다가 자기가 만든 제품을 다음 칸으로 넘깁니다.
마무리하며
제 생각에 모델 병렬화라는 이름은 오해를 부르며, 병렬 컴퓨팅의 한 예로 보아서는 안 됩니다. 병렬 컴퓨팅에서 말하는 병렬 방식이 아니라 직렬 방식을 쓰는 것이므로, “모델 직렬화”가 더 나은 이름일 것입니다. 다만 시아미즈 네트워크처럼, 어떤 신경망에서는 일부 층이 실제로 “병렬”인 경우도 있습니다. 그럴 때는 모델 병렬화가 어느 정도 진짜 병렬 컴퓨팅처럼 움직일 수 있습니다. 반면 데이터 병렬화는 100% 병렬 컴퓨팅입니다.
덧붙여 재미있는 질문 몇 가지가 있습니다. A3C 같은 강화 학습 알고리즘은 데이터 병렬화일까요, 모델 병렬화일까요? 글쎄요, 저라면 A3C가 데이터 병렬화에 더 가깝다고 하겠습니다. 다만 위에서 설명한 데이터 병렬화와 똑같지는 않습니다. A3C는 학습 내내 주 노드에서 비동기로 가중치를 업데이트하는 반면, 위에서 설명한 과정은 반복의 경계가 분명하고 반복이 끝날 때마다 동기화를 하기 때문입니다. 저와 생각이 다르셔도 괜찮습니다 :)