Sooftware NLP - Megatron LM Paper Review
Megatron-LM: Training Multi-Billion Parameter Language Models Using Model Parallelism
- Mohammad Shoeybi et al. 2019.
- NVIDIA Corp.
Summary
-
Transformer Language Model Parallelism
-
새로운 컴파일러나 기존 라이브러리 변경 없이 Very Big-Model을 학습시킬 수 있는 Megatron-LM을 제안 (PyTorch 기반)
-
8.3 billion 파라미터를 성공적으로 학습시킴 (GPT-3: 175 billion)
Backgrounds
-
최근 Large-scale의 Transformer를 이용한 Language Model(LM)이 대세
-
하지만 너무 큰 모델은 하드웨어적 메모리 제약으로 인해 학습이 어려움
-
이를 해결하기 위해 여러 방법이 나왔지만, 새로운 컴파일러 혹은 기존 라이브러리를 건드려야 한다는 불편함이 있음
-
새로운 컴파일러나 기존 라이브러리를 변경하는 일 없이 간단한 방법으로 Model Parallelism 하는 Simple하면서도 Efficient한 방법 제안
Model Parallel Transformers
- Transformer는 self attention block과 multi-layer perceptron (MLP) 로 구성되어 있음.
MLP Block
MLP Block Model Parallelism
위의 공식을 따르는 MLP 블록을 Model Parallel하게 적용하기 위해서는 2가지 방법이 있을 수 있음.
방법 1: 입력 X를 column으로, weight matrix A를 row로 split하는 방법.
하지만 이 방법은 GeLU(X1A1 + X2A2) 6= GeLU(X1A1) + GeLU(X2A2)이 성립하지 않기 때문에 GeLU 입력 전에 동기화가 필요하다는 단점이 있음.
방법 2: weight matrix A를 column으로 split하는 방법이 있음.
이 방법은 위의 그림에서 볼 수 있듯이, GeLU 입력 전후로도 GPU간에 통신이 필요 없다는 장점이 있음.
정리
- Code
import torch
import torch.nn as nn
class Method1(nn.Module):
def __init__(self):
super().__init__()
self.a1 = nn.Linear(5, 10, bias=False)
self.a2 = nn.Linear(5, 10, bias=False)
def forward(self, x):
x1, x2 = torch.chunk(x, 2, dim=-1)
y1 = self.a1(x1)
y2 = self.a2(x2)
y = y1 + y2
return y
class Method2(nn.Module):
def __init__(self):
super().__init__()
self.a1 = nn.Linear(10, 5, bias=False)
self.a2 = nn.Linear(10, 5, bias=False)
def forward(self, x):
y1 = self.a1(x)
y2 = self.a2(x)
y = torch.cat((y1, y2), dim=-1)
return y
gelu = nn.GELU()
a = torch.FloatTensor([[i for i in range(10)]])
b = torch.FloatTensor([[i for i in range(1, 11)]])
- 방법1 Test
print("GeLU(X1A1) + GeLU(X2A2) != GeLU(X1A1 + X2A2)\n")
print(gelu(a + b), end="\n\n")
print(gelu(a) + gelu(b))
GeLU(X1A1) + GeLU(X2A2) != GeLU(X1A1 + X2A2)
tensor([[ 0.8413, 2.9960, 5.0000, 7.0000, 9.0000, 11.0000, 13.0000, 15.0000,
17.0000, 19.0000]])
tensor([[ 0.8413, 2.7958, 4.9504, 6.9958, 8.9999, 11.0000, 13.0000, 15.0000,
17.0000, 19.0000]])
- 방법2 Test
print("GeLU(concat(X1A1, X2A2)) == concat(GeLU(X1A1) + GeLU(X2A2))\n")
print(gelu(torch.cat((a, b))), end="\n\n")
print(torch.cat((gelu(a), gelu(b))))
GeLU(concat(X1A1, X2A2)) == concat(GeLU(X1A1) + GeLU(X2A2))
tensor([[ 0.0000, 0.8413, 1.9545, 2.9960, 3.9999, 5.0000, 6.0000, 7.0000,
8.0000, 9.0000],
[ 0.8413, 1.9545, 2.9960, 3.9999, 5.0000, 6.0000, 7.0000, 8.0000,
9.0000, 10.0000]])
tensor([[ 0.0000, 0.8413, 1.9545, 2.9960, 3.9999, 5.0000, 6.0000, 7.0000,
8.0000, 9.0000],
[ 0.8413, 1.9545, 2.9960, 3.9999, 5.0000, 6.0000, 7.0000, 8.0000,
9.0000, 10.0000]])
위의 코드에서 방법2로 계산시, Model Parallel하게 MLP Block을 진행할 수 있음을 알 수 있음.
Attention Block
- MLP Block과 같은 방법으로 Model Parallelism을 적용할 수 있음.
Model Parallelism
-
결과적으로 트랜스포머 블록 하나당 총 4번의 GPU간 통신만 있으면 되는 구조가 됨.
-
ALL-Reduce란 해당 블록의 결과물을 모든 프로세서가 Return하는 것을 의미함.
Experiment
Subscribe to SOOFTWARE
Get the latest posts delivered right to your inbox