์ ์: Wanchao Liang, Tianyu Liu ๋ฒ์ญ: ๊ฐํธํ
์ด ํํ ๋ฆฌ์ผ์์๋ Tensor Parallel๊ณผ Fully Sharded Data Parallel๋ฅผ ํ์ฉํ์ฌ, ์๋ฐฑ์์ ์์ฒ ๊ฐ์ GPU๋ก ๋๊ท๋ชจ ํธ๋์คํฌ๋จธ ๊ณ์ด์ ๋ชจ๋ธ์ ํ๋ จํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํฉ๋๋ค.
์ฌ์ ์ค๋น:
- CUDA/Linux ํ๊ฒฝ์์ PyTorch 2.3.0 ์ด์ ์ค์น๋์ด์ผ ํฉ๋๋ค.
- Tensor Parallel APIs
- DeviceMesh ์์ํ๊ธฐ
- Fully Sharded Data Parallel ์์ํ๊ธฐ
Tensor Parallel (TP)๋ ๊ธฐ์กด Megatron-LM ๋
ผ๋ฌธ์์ ์ ์๋ ๋ฐฉ์์ผ๋ก, ๋๊ท๋ชจ ํธ๋์คํฌ๋จธ(Transformer) ๋ชจ๋ธ์ ํจ์จ์ ์ผ๋ก ํ๋ จํ๊ธฐ ์ํ ๋ชจ๋ธ ๋ณ๋ ฌ์ฒ๋ฆฌ(parallelism) ๊ธฐ๋ฒ์
๋๋ค.
์ด ํํ ๋ฆฌ์ผ์์ ์ธ๊ธํ Sequence Parallel (SP)๋ Tensor Parallel์ ํ ๋ณํ์ผ๋ก, ํ๋ จ ์ค ํ์ฑํ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ ์ฝํ๊ธฐ ์ํด nn.LayerNorm ํน์ RMSNorm ๋ฅผ ์ํ์ค ์ฐจ์์ผ๋ก ์ค๋ฉ ํฉ๋๋ค.
๋ชจ๋ธ์ด ์ปค์ง์๋ก, ํ์ฑํ ๋ฉ๋ชจ๋ฆฌ๊ฐ ๋ณ๋ชฉ์ด ๋๋ฏ๋ก, Tensor Parallel ํ์ต์์๋ ์ฃผ๋ก LayerNorm ์ด๋ RMSNorm ๊ณ์ธต์ ์ํ์ค ๋ณ๋ ฌ(Sequence Parallel)์ ์ ์ฉํฉ๋๋ค.
๊ทธ๋ฆผ 1. ํธ๋์คํฌ๋จธ ๋ชจ๋ธ์ MLP ๋ฐ Self-Attention ๊ณ์ธต์ ํ๋ ฌ ์ฐ์ฐ์ด attention/MLP์์ ์ค๋ฉ๋ ๊ณ์ฐ์ผ๋ก ์ด๋ฃจ์ด์ง๊ณ , ์ด๋ Tensor Parallel ๋ฐฉ์์ผ๋ก sharding๋ ๊ตฌ์กฐ๋ฅผ ๋ํ๋ ๋๋ค. (์ด๋ฏธ์ง ์ถ์ฒ)
๊ณ ์์ค์์ PyTorch Tensor Parallel์ ๋ค์๊ณผ ๊ฐ์ด ์๋ํฉ๋๋ค.
Sharding ์ด๊ธฐํ
- ๊ฐ ๊ณ์ธต์ ์ด๋ค
ParallelStyle์ ์ ์ฉํ ์ง ๊ฒฐ์ ํ๊ณ ,parallelize_module์ ํธ์ถํด์ ์ด๊ธฐํ๋ ๋ชจ๋์ ์ค๋ฉํฉ๋๋ค. - ๋ณ๋ ฌํ๋ ๋ชจ๋์ ๋ชจ๋ธ ๋งค๊ฐ๋ณ์๋ฅผ DTensor๋ก ๊ต์ฒดํ๊ณ , DTensor๋ ์ค๋ฉํ๋ ์ฐ์ฐ์ ์ฌ์ฉํ์ฌ ๋ณ๋ ฌํ๋ ๋ชจ๋์ ์คํํ๋ ์ญํ ์ ๋ด๋นํฉ๋๋ค.
๋ฐํ์ ์๋ฐฉํฅ/์ญ๋ฐฉํฅ
- ์ฌ์ฉ์๊ฐ ์ง์ ํ ๊ฐ๋ณ
ParallelStyle์ ์ ๋ ฅ/์ถ๋ ฅ DTensor ๋ ์ด์์์ ๋ฐ๋ผ, ์ ๋ ฅ/์ถ๋ ฅ์ ๋ํ DTensor ๋ ์ด์์์ ๋ณํํ๋ ์ ์ ํ ์ปค๋ฎค๋์ผ์ด์ ๋์์ ์คํํฉ๋๋ค. (์๋ฅผ ๋ค์ด,allreduce,allgather,reduce_scatter) - ๋ณ๋ ฌํ๋ ๊ณ์ธต(
nn.Linear,nn.Embedding)์ ์ฐ์ฐ ๋ฐ ๋ฉ๋ชจ๋ฆฌ๋ฅผ ์ ์ฝํ๊ธฐ ์ํด ์ค๋ฉ๋ ์ฐ์ฐ์ ์คํํฉ๋๋ค.
PyTorch์ Fully Sharded Data Parallel(FSDP)๋ ์ด๋ฏธ ๋ชจ๋ธ ํ์ต์ ํน์ ์์ GPU๋ก ์กฐ์ ํ ์ ์๋ ๊ธฐ๋ฅ์ ๊ฐ์ถ๊ณ ์์ต๋๋ค. ๊ทธ๋ฌ๋, ๋ชจ๋ธ ํฌ๊ธฐ์ GPU ์ ์ธก๋ฉด์์ ๋ชจ๋ธ ํ์ต์ ๋ ํ์ฅํ๋ ค๋ฉด, Tensor Parallel๊ณผ FSDP์ ๊ฒฐํฉ์ด ํ์ํ, ๋ค์๊ณผ ๊ฐ์ ์ถ๊ฐ์ ์ธ ๊ณผ์ ๊ฐ ๋ค์ ๋ฐ์ํ ์ ์์ต๋๋ค.
- GPU ์๊ฐ ์ง๋์น๊ฒ ์ปค์ง์ ๋ฐ๋ผ (128/256 GPU ์ด๊ณผ), FSDP ์งํฉ(์๋ฅผ ๋ค์ด,
allgather)์ ring latency์ ๋ง์ ์ํฅ์ ๋ฐ์ต๋๋ค. TP/SP๋ฅผ FSDP ์์ ๊ตฌํํ์ฌ, FSDP๋ฅผ ํธ์คํธ ๊ฐ์๋ง ์ ์ฉํ์ฌ FSDP์ ๊ท๋ชจ๋ฅผ 8๊ฐ๋ก ์ค์ผ ์ ์์ผ๋ฉฐ, ๊ทธ์ ๋ฐ๋ผ ์ง์ฐ ๋น์ฉ๋ ๋์ผํ๊ฒ ์ค์ผ ์ ์์ต๋๋ค. - ์๋ ด ๋ฐ GPU ๋ฉ๋ชจ๋ฆฌ ์ ํ์ผ๋ก ์ธํด ๊ธ๋ก๋ฒ ๋ฐฐ์น ํฌ๊ธฐ๋ฅผ GPU ์๋ณด๋ค ๋๊ฒ ์ค์ ํ ์ ์๋ ๋ฐ์ดํฐ ๋ณ๋ ฌ ์ฒ๋ฆฌ์ ํ๊ณ๋ฅผ ๋ฌ์ฑํ๋ ค๋ฉด, Tensor/Sequence Parallel์ด ๊ธ๋ก๋ฒ ๋ฐฐ์น ํฌ๊ธฐ๋ฅผ "์ถ์ (ballpark)"ํ๊ณ , ๋ ๋ง์ GPU๋ก ํ์ฅํ๋ ์ ์ผํ ๋ฐฉ๋ฒ์ ๋๋ค.
- ํน์ ์ ํ์ ๋ชจ๋ธ์์๋ ๋ก์ปฌ ๋ฐฐ์น ํฌ๊ธฐ๊ฐ ์์์ง๋ฉด, TP/SP๊ฐ ๋ถ๋ ์์์ ์ฐ์ฐ(FLOPS)์ ๋ ์ต์ ํ๋ ํ๋ ฌ ๊ณฑ ํํ๋ฅผ ์์ฑํ ์ ์์ต๋๋ค.
์ฌ์ ํ์ต ์ ์ด๋ฌํ ํ๊ณ๋ฅผ ๊ฒฝํํ๋ ๊ฒ์ ํํ ์ผ์ ๋๋ค. ํ์ฌ๋ก์๋ ์์ญ์ต ํน์ ์์กฐ ๋จ์์ ํ ํฐ์ผ๋ก ๋๊ท๋ชจ ์ธ์ด ๋ชจ๋ธ(LLM)์ ํ์ตํ๋ ค๋ฉด ์์ฒ ๋์ GPU๋ฅผ ์ฌ์ฉํ๋๋ผ๋ ์๊ฐ์์ด ๊ฑธ๋ฆด ์ ์์ต๋๋ค.
- LLM์ ๋๊ท๋ชจ๋ก ํ๋ จํ ๋๋ ํญ์ ํ๊ณ 1์ ๋๋ฌํฉ๋๋ค. ์๋ฅผ ๋ค์ด, Llama 2 70B ๋ชจ๋ธ์ 35์ผ ๋์ 2์ฒ๊ฐ GPU๋ก ํ๋ จ๋์๊ณ , 2์ฒ๊ฐ ๊ท๋ชจ์์๋ ๋ค์ฐจ์ ๋ณ๋ ฌ ์ฒ๋ฆฌ๊ฐ ํ์ํฉ๋๋ค.
- Transformer ๋ชจ๋ธ์ด ์ปค์ง๋ฉด (์๋ฅผ ๋ค๋ฉด, Llama2 70B), ๋น ๋ฅด๊ฒ ํ๊ณ 2์ ๋๋ฌํ ๊ฒ์
๋๋ค. ๋ฉ๋ชจ๋ฆฌ ๋ฐ ์๋ ด ์ ์ฝ ์กฐ๊ฑด ๋๋ฌธ์ ๋ก์ปฌ
batch_size=1์กฐ๊ฑด ์กฐ์ฐจ๋ FSDP๋ฅผ ๋จ๋ ์ผ๋ก ์ฌ์ฉํ ์ ์์ต๋๋ค. ์๋ฅผ ๋ค์ด, Llama2 ๊ธ๋ก๋ฒ ๋ฐฐ์น ํฌ๊ธฐ๋ 1K์ด๋ฏ๋ก, 2K GPU์์ ์ค์ง ๋ฐ์ดํฐ ๋ณ๋ ฌ ์ฒ๋ฆฌ๋ง์ผ๋ก ์ฌ์ฉ๋ ์ ์์ต๋๋ค.
PyTorch Tensor Parallel API๋ ๋ชจ๋ธ์ ๊ฐ ๊ฐ๋ณ ๊ณ์ธต์ ๋ํ ์ค๋ฉ์ ๊ตฌ์ฑํ๊ธฐ ์ํด ๋ค์๊ณผ ๊ฐ์ ๋ชจ๋ ์์ค์ ์ด์ ์ธํธ (ParallelStyle)๋ฅผ ์ ๊ณตํฉ๋๋ค.
ColwiseParallel๋ฐRowwiseParallel: ์ด ํน์ ํ ๋ฐฉ์์ผ๋กnn.Linear๊ณผnn.Embedding๋ฅผ ๊ณต์ ํฉ๋๋ค.SequenceParallel:nn.LayerNorm,nn.Dropout,RMSNormPython๋ฑ์์ ์ค๋ฉ ์ฐ์ฐ์ ์ํํฉ๋๋ค.PrepareModuleInput๋ฐPrepareModuleOutput: ์ ์ ํ ์ปค๋ฎค๋์ผ์ด์ ์์ ์ ๊ฐ์ง ๋ชจ๋ ์ ๋ ฅ/์ถ๋ ฅ ์ค๋ฉ ๋ ์ด์์์ ๊ตฌ์ฑํฉ๋๋ค.
PyTorch ๋ค์ดํฐ๋ธ Tensor Parallel API๋ฅผ ์ฌ์ฉํ๋ ๋ฒ์ ์ค๋ช ํ๊ธฐ ์ํด, ์ผ๋ฐ์ ์ธ ํธ๋์คํฌ๋จธ ๋ชจ๋ธ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค. ์ด๋ฒ ํํ ๋ฆฌ์ผ์์๋ ์ปค๋ฎค๋ํฐ์์๋ ๋๋ฆฌ ์ฌ์ฉ๋๋ ์ต์ Llama2 ๋ชจ๋ธ ์ ๋ ํผ๋ฐ์ค ํธ๋์คํฌ๋จธ ๋ชจ๋ธ ๊ตฌํ์ผ๋ก ์ฌ์ฉํฉ๋๋ค. Tensor Parallel์ด ๊ฐ๋ณ tensor๋ฅผ ์ฌ๋ฌ ๋๋ฐ์ด์ค์์ ์ค๋ฉํ๊ธฐ ๋๋ฌธ์, ๋จผ์ ๋ถ์ฐ ํ๊ฒฝ(NCCL ํต์ ๊ธฐ)์ ์ค์ ํด์ผ ํฉ๋๋ค.
Tensor Parallelism์ PyTorch DDP/FSDP์ ์ ์ฌํ ๋จ์ผ ํ๋ก๊ทธ๋จ ๋ฉํฐ ๋ฐ์ดํฐ (SPMD) ์ค๋ฉ ์๊ณ ๋ฆฌ์ฆ์ด๋ฉฐ, ์ด ์๊ณ ๋ฆฌ์ฆ์ PyTorch DTensor ๋ด๋ถ ์๋ฆฌ๋ฅผ ๋ฐํ์ผ๋ก ์ค๋ฉ์ ์ํํฉ๋๋ค. ๋ํ ๋๋ฐ์ด์ค ๊ด๋ฆฌ ๋ฐ ์ค๋ฉ์ ์ํด DeviceMesh ์ถ์ํ(๋ด๋ถ์ ์ผ๋ก ํ๋ก์ธ์ค ๊ทธ๋ฃน ๊ด๋ฆฌ)๋ฅผ ํ์ฉํฉ๋๋ค. DeviceMesh๋ฅผ ํ์ฉํ์ฌ ๋ค์ฐจ์ ๋ณ๋ ฌํ๋ฅผ ํ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ด ํํ ๋ฆฌ์ผ ์ ์ฐธ์กฐํ์ธ์. Tensor Parallel์ ์ผ๋ฐ์ ์ผ๋ก ๊ฐ ํธ์คํธ ๋ด๋ถ์์ ์๋ํ๋ฏ๋ก, ๋จผ์ ํธ์คํธ ๋ด 8๊ฐ์ GPU๋ฅผ ์ฐ๊ฒฐํ๋ DeviceMesh๋ฅผ ์ด๊ธฐํํด๋ณด๊ฒ ์ต๋๋ค.
from torch.distributed.device_mesh import init_device_mesh
tp_mesh = init_device_mesh("cuda", (8,))์ด์ DeviceMesh๋ฅผ ์ด๊ธฐํํ์ผ๋ฏ๋ก, Llama 2 ๋ชจ๋ธ ์ํคํ
์ฒ๋ฅผ ์์ธํ ์ดํด๋ณด๊ณ Tensor Parallel ์ค๋ฉ์ ์ํํ๋ ๋ฐฉ๋ฒ์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
์ฌ๊ธฐ์ ํธ๋์คํฌ๋จธ ๋ชจ๋ธ์ด ํ์ฅํ๊ธฐ ์ํด ๋์ผํ TransformerBlock ์ ์๋ ํต์ฌ TransformerBlock ์ ์ด์ ์ ๋ก๋๋ค.
ํต์ฌ TransformerBlock ์ Attention ๊ณ์ธต๊ณผ FeedForward ๊ณ์ธต์ผ๋ก ๊ตฌ์ฑ๋์ด ์์ต๋๋ค. ๋จผ์ ๋ ๊ฐ๋จํ FeedForward ๊ณ์ธต์ ์ดํด๋ณด๊ฒ ์ต๋๋ค.
FeedForward ๊ณ์ธต์ ๊ฒฝ์ฐ, ์ธ ๊ฐ์ ์ ํ ๊ณ์ธต์ผ๋ก ๊ตฌ์ฑ๋์ด ์๊ณ , ์๋ฐฉํฅ ํจ์๋ฅผ ๊ณ ๋ คํด์ SwiGLU ์คํ์ผ์ MLP๋ฅผ ์ํํฉ๋๋ค.
# ์์ ํ ๊ณ์ธต์์ ์๋ฐฉํฅ์ผ๋ก
def forward(self, x):
return self.w2(F.silu(self.w1(x)) * self.w3(x))w1 ๋ฐ w3 ํ๋ ฌ๊ณฑ์ ๋์์ ์ํํ๊ณ , ๊ฒฐํฉ๋ w1/w3 ์ ํ ํฌ์ ๊ฒฐ๊ณผ์ ํจ๊ป w2 ํ๋ ฌ๊ณฑ์ ์ํํฉ๋๋ค.
์ด๋ Tensor Parallelism ๋
ผ๋ฌธ์ ์์ด๋์ด๋ฅผ ์ฌ์ฉํด์ w1/w3 ์ ํ ๊ณ์ธต์ ์ด ์ฐ์ ๋ฐฉ์์ผ๋ก ์ค๋ฉํ๊ณ , ํ ์ฐ์ ๋ฐฉ์์ผ๋ก w2 ์ ํ ๊ณ์ธต์ ์ค๋ฉํ์ฌ, ์ธ ๊ณ์ธต ๋ชจ๋ ๋์์ ํ๋์ allreduce ํต์ ๋ง ๋ฐ์ํ๋ ๊ฒ์ ์๋ฏธํฉ๋๋ค.
PyTorch ๋ค์ดํฐ๋ธ Tensor Parallel์ ์ฌ์ฉํ์ฌ ๋ค์๊ณผ ๊ฐ์ด FeedForward ๊ณ์ธต์ ๋ํด parallelize_plan ์ ๊ฐ๋จํ ๋ง๋ค ์ ์์ต๋๋ค.
from torch.distributed.tensor.parallel import ColwiseParallel, RowwiseParallel, parallelize_module
layer_tp_plan = {
# ๊ธฐ๋ณธ์ ์ผ๋ก ColwiseParallel์ผ๋ก ์
๋ ฅ ๋ ์ด์์์ด ๋ณต์ ๋ฉ๋๋ค
# RowwiseParallel์ผ๋ก ์ถ๋ ฅ ๋ ์ด์์์ด ๋ณต์ ๋ฉ๋๋ค
"feed_foward.w1": ColwiseParallel(),
"feed_forward.w2": RowwiseParallel(),
"feed_forward.w3": ColwiseParallel(),
}- ์ด๋ ๋จ์ํ PyTorch Tensor Parallel API๋ฅผ ์ด์ฉํ์ฌ
FeedForward๊ณ์ธต์ ์ค๋ฉ์ ๊ตฌ์ฑํ๋ ๋ฐฉ์์ ๋๋ค. ์ฌ์ฉ์๋ ๊ฐ๋ณ ๊ณ์ธต์ ์ค๋ฉํ๋ ๋ฐฉ๋ฒ๋ง ์ง์ ํ๋ฉด ๋๊ณ , ํต์ (์๋ฅผ ๋ค์ด,allreduce)์ ๋ด๋ถ์ ์ผ๋ก ๋ฐ์ํ๋ค๋ ์ ์ ๊ธฐ์ตํฉ๋๋ค. Attention๊ณ์ธต์ผ๋ก ๋์ด ๊ฐ๋๋ค. ์ด ๊ณ์ธต์wq,wk,wv์ ํ ๊ณ์ธต์ผ๋ก ๊ตฌ์ฑ๋์ด, ์ ๋ ฅ์q/k/v๋ก ํฌ์ํ ๋ค์์wo์ ํ ๊ณ์ธต์ผ๋ก ์ดํ ์ ๋ฐ ์ถ๋ ฅ ํฌ์์ ์ํํฉ๋๋ค.
์ฌ๊ธฐ์ Tensor Parallelism์ q/k/v ํฌ์์ ๋ํด ์ด ์ค์ฌ์ผ๋ก ์ค๋ฉ์ ์ํํ๊ณ , wo ์ ํ ํฌ์์ ๋ํด ํ ์ค์ฌ์ผ๋ก ์ค๋ฉ์ ์ํํฉ๋๋ค. ๋ฐ๋ผ์, ๋ฐฉ๊ธ ์์ฑํ tp_plan ์ ์ดํ
์
ํ๋์ ์ถ๊ฐํ ์ ์์ต๋๋ค.
layer_tp_plan = {
# ๊ธฐ๋ณธ์ ์ผ๋ก ColwiseParallel ์
๋ ฅ ๋ ์ด์์ ๋ฐ๋ณต
# ๊ทธ๋ฆฌ๊ณ RowwiseParallel ์ถ๋ ฅ ๋ ์ด์์ ๋ฐ๋ณต
"attention.wq": ColwiseParallel(use_local_output=False),
"attention.wk": ColwiseParallel(use_local_output=False),
"attention.wv": ColwiseParallel(use_local_output=False),
"attention.wo": RowwiseParallel(),
"feed_forward.w1": ColwiseParallel(),
"feed_forward.w2": RowwiseParallel(),
"feed_forward.w3": ColwiseParallel(),
}์ด๋ ๋์ฒด๋ก TransformerBlock ์ Tensor Parallel์ ์ ์ฉํด์ผํ๋ layer_tp_plan ์
๋๋ค. ๊ทธ๋ฌ๋ ์์์ผํ๋ ํ๊ฐ์ง๋ ์ ํ ๊ณ์ธต์ ์ด ๋จ์๋ก ์ค๋ฉํ ๋, ์ ํ ๊ณ์ธต์ ์ถ๋ ฅ์ด ๋ง์ง๋ง tensor ์ฐจ์์์ ์ค๋ฉ๋๊ณ , ํ ๋จ์๋ก ์ค๋ฉ๋ ์ ํ ๊ณ์ธต์ด ๋ง์ง๋ง ์ฐจ์์์ ์ค๋ฉ๋ ์
๋ ฅ์ ์ง์ ๋ฐ์๋ค์ธ๋ค๋ ๊ฒ์
๋๋ค.
๋ง์ผ ์ด ๋จ์ ์ ํ๊ณผ ํ ๋จ์ ์ ํ ์ฌ์ด์ ๋ ๋ง์ tensor ์ฐ์ฐ (์๋ฅผ ๋ค์ด, view operation) ์ด ์๋ค๋ฉด, ์ค๋ฉ๋ ํํ๋ก ๊ด๋ จ ๋ชจ์์ ์ฐ์ฐ์ ์กฐ์ ํด์ผ ํฉ๋๋ค.
Llama ๋ชจ๋ธ์ ๊ฒฝ์ฐ, ์ดํ
์
๊ณ์ธต์์๋ ํํ์ ๊ด๋ จ๋ ์ฌ๋ฌ ๋ทฐ ์ฐ์ฐ์ด ์์ต๋๋ค. ๊ตฌ์ฒด์ ์ผ๋ก, wq / wk / wv ์ ํ ๊ณ์ธต์์ ์ด ๋จ์ ๋ณ๋ ฌํ์ ๊ฒฝ์ฐ, ํ์ฑํ tensor๋ num_heads ์ฐจ์์์ ์ค๋ฉ๋ฉ๋๋ค.
๋ง์ง๋ง์ผ๋ก, ๊ฐ TransformerBlock ์ ๋ํ ๊ณํ์ ํจ๊ณผ์ ์ผ๋ก ์คํํ๋ ค๋ฉด parallelize_module API๋ฅผ ํธ์ถํด์ผ ํฉ๋๋ค. ๋ด๋ถ์ ์ผ๋ก๋ Attention ๋ฐ FeedForward ๊ณ์ธต ๋ด๋ถ ๋ชจ๋ธ ๋งค๊ฐ๋ณ์๋ฅผ DTensor์ ๋ถ๋ฐฐํ๊ณ , ํ์ํ๋ค๋ฉด ๋ชจ๋ธ ์
๋ ฅ๊ณผ ์ถ๋ ฅ(๊ฐ๊ฐ ๋ชจ๋ ์ด์ ๋ฐ ์ดํ)์ ๋ํ ํต์ ํ
์ ๋ฑ๋กํฉ๋๋ค.
for layer_id, transformer_block in enumerate(model.layers):
layer_tp_plan = {...} # ์๋ฅผ ๋ค์ด, ์ด์ ์ ์์ฑ๋ ํ๋
parallelize_module(
module=transformer_block,
device_mesh=tp_mesh,
parallelize_plan=layer_tp_plan,
)๊ฐ TransformerBlock ์ ๋ํ ์ค๋ฉ ๊ณํ์ ๊ตฌ์ฒดํํ๊ณ , ๋ณดํต ์ฒซ ๋ฒ์งธ ๊ณ์ธต์ nn.Embedding``๊ฐ ์๊ณ , ๋ง์ง๋ง ``nn.Linear ํฌ์ ๊ณ์ธต์ด ์๋๋ฐ, ์ฒซ ๋ฒ์งธ nn.Embedding ์๋ ํ ๋จ์ ํน์ ์ด ๋จ์ ์ค๋ฉ์ ์ ํํ๊ณ , ์ฌ์ฉ์๊ฐ ์ ์ ํ ์
๋ ฅ ๋ฐ ์ถ๋ ฅ ๋ ์ด์์์ด ์ง์ ๋ ๋ง์ง๋ง nn.Linear ํฌ์ ๊ณ์ธต์๋ ์ด ๋จ์ ์ค๋ฉ์ ์ ํํ ์ ์์ต๋๋ค.
๋ค์ ์์๋ฅผ ์ฐธ๊ณ ํฉ๋๋ค.
model = parallelize_module(
model,
tp_mesh,
{
"tok_embeddings": RowwiseParallel(
input_layouts=Replicate(),
),
"output": ColwiseParallel(
output_layouts=Replicate(),
),
}
)Note
ํด๋น ๋ชจ๋ธ์ด ๋๋ฌด ์ปค์ CPU ๋ฉ๋ชจ๋ฆฌ์ ๋ง์ง ์๋ ๊ฒฝ์ฐ, meta ์ฅ์น ์ด๊ธฐํ (์๋ฅผ ๋ค์ด, ๋ฉํ ์ฅ์น์์ ๋จผ์ ์ด๊ธฐํํ๊ฑฐ๋ ๊ณ์ธต์ ์ค๋ฉํ๊ณ ๋ชจ๋ธ์ ๊ตฌ์ฒดํํ๋ ๋ฑ)๋ฅผ ์ฌ์ฉํ๊ฑฐ๋ ํธ๋์คํฌ๋จธ ๋ชจ๋ธ ์ด๊ธฐํ ์ค์ TransformerBlock ๊ณ์ธต์ ๊ณ์ธต๋ณ๋ก ๋ณ๋ ฌํํ ์ ์์ต๋๋ค.
์ํ์ค ๋ณ๋ ฌ(Sequence Parallel)์ ์์ ์ค๋ช
ํ Tensor Parallel ์์์ ๋์ํฉ๋๋ค. ๊ธฐ๋ณธ์ ์ธ Tensor Parallel์ Attention ๋ชจ๋๊ณผ FeedForward ๋ชจ๋ ๋ด์์๋ง tensor๋ฅผ ์ค๋ฉํ๊ณ ๋ชจ๋ ์
๋ ฅ๊ณผ ์ถ๋ ฅ (์ฆ, forward pass์ ํ์ฑํ ๋ฐ backward pass์์ ๋ณํ๋)์ ๋ณต์ ๋๋๋ก ์ ์งํ๋ ๊ฒ๊ณผ ๋น๊ตํ ๋, ์ํ์ค ๋ณ๋ ฌ์ ์ํ์ค ์ฐจ์์์ ์ค๋ฉ๋ ์ํ๋ฅผ ์ ์งํฉ๋๋ค.
์ผ๋ฐ์ ์ธ TransformerBlock ์์ ์๋ฐฉํฅ ํจ์๋ norm ๊ณ์ธต( LayerNorm ํน์ RMSNorm ), ์ดํ
์
๊ณ์ธต, ์์ ํ ๊ณ์ธต, residual ์ฐ๊ฒฐ์ ๊ฒฐํฉํฉ๋๋ค. ์๋ฅผ ๋ค๋ฉด, ๋ค์๊ณผ ๊ฐ์ต๋๋ค.
# TransformerBlock์์ ์๋ฐฉํฅ
def forward(self, x):
h = x + self.attention(self.attention_norm(x))
out = h + self.feed_forward(self.ffn_norm(h))
return out๋๋ถ๋ถ ์ ์ฆ์ผ์ด์ค์์, ํ์ฑํ (๊ทธ๋ฆฌ๊ณ ๋ณํ๋)๋ Attention ๋ฐ FeedForward ๋ชจ๋ ์ธ๋ถ์ [batch size, sequence length, hidden dimension] ๋ชจ์์
๋๋ค. DTensor์ ์ธ์ด๋ก, ์ํ์ค ๋ณ๋ ฌ์ ๋ชจ๋์ ์๋ฐฉํฅ/์ญ๋ฐฉํฅ ๋ชจ๋ Shard(1) ๋ ์ด์์์ ์ฌ์ฉํ์ฌ ํ์ฑํ ์ฐ์ฐ์ ์ํํฉ๋๋ค.
์ด์ ์ฝ๋ ์์์ ์ด์ด์, ์๋ ์ฝ๋๋ TransformerBlock ๋ด๋ถ์ norm ๊ณ์ธต์ ์ํ์ค ๋ณ๋ ฌ์ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช
ํฉ๋๋ค.
๋จผ์ ์ํ์ค ๋ณ๋ ฌ์ ํ์ํ ์์กด์ฑ์ ๊ฐ์ ธ์ค๊ฒ ์ต๋๋ค.
from torch.distributed.tensor.parallel import (
PrepareModuleInput,
SequenceParallel,
)๋ค์์ผ๋ก layer_tp_plan ์ ์์ ํด์ RMSNorm ๊ณ์ธต์ ์ํ์ค ๋ณ๋ ฌ์ ๊ฐ๋ฅํ๊ฒ ๋ง๋ญ๋๋ค.
layer_tp_plan = {
# ์ด์ SequenceParallel์ ์
๋ ฅ๊ณผ ์ถ๋ ฅ์ Shard(1) ๋ ์ด์์์ ๊ฐ์ง๊ณ ,
# ์ํ์ค ์ฐจ์์์ ์ค๋ฉ๋ ์
๋ ฅ/์ถ๋ ฅ tensor๋ฅผ ๋ํ๋
๋๋ค
"attention_norm": SequenceParallel(),
"attention": PrepareModuleInput(
input_layouts=(Shard(1), Replicate()),
desired_input_layouts=(Replicate(), Replicate()),
),
"attention.wq": ColwiseParallel(use_local_output=False),
"attention.wk": ColwiseParallel(use_local_output=False),
"attention.wv": ColwiseParallel(use_local_output=False),
"attention.wo": RowwiseParallel(output_layouts=Shard(1)),
"ffn_norm": SequenceParallel(),
"feed_forward": PrepareModuleInput(
input_layouts=(Shard(1),),
desired_input_layouts=(Replicate(),),
),
"feed_forward.w1": ColwiseParallel(),
"feed_forward.w2": RowwiseParallel(output_layouts=Shard(1)),
"feed_forward.w3": ColwiseParallel(),
}์ด์ PrepareModuleInput ์ ์ด์ฉํด์ ์ดํ
์
๊ณผ ์์ ํ ๊ณ์ธต์ ๋ชจ๋ ์
๋ ฅ ๋ ์ด์์์ Shard(1) ์์ Replicate() ๋ก ์์ ํ๊ณ , ์ถ๋ ฅ ๋ ์ด์์์ Shard(1) ์ผ๋ก ํ์ํ๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
Tensor Parallelism๊ณผ ๋ง์ฐฌ๊ฐ์ง๋ก, ์
๋ ฅ๊ณผ ์ถ๋ ฅ์ tensor ์ค๋ฉ ๋ ์ด์์๋ง ์ง์ ํ๋ฉด, ๊ณ์ธต ๊ฐ ํต์ ์ด ์๋์ผ๋ก ์ด๋ฃจ์ด์ง๋๋ค.
์ํ์ค ๋ณ๋ ฌ์ ํ์ฉํ๋ฉด, ์ํ์ค ์ฐจ์์์ ํญ์ TransformerBlock ์ ์
๋ ฅ๊ณผ ์ถ๋ ฅ์ด ์ค๋ฉ๋์ด, ๋ค์ค TransformerBlocks ์ด ์ํํ๊ฒ ์ฐ๊ฒฐํ ์ ์๋ค๊ณ ๊ฐ์ ํฉ๋๋ค.
์ด๋ ์์ํ๋ nn.Embedding ๊ณ์ธต์ ์ถ๋ ฅ๊ณผ ์ต์ข
nn.Linear ์
๋ ฅ ๊ณ์ธต์ Shard(1) ์ผ๋ก ๋ช
์์ ์ผ๋ก ์ง์ ํ์ฌ ์ด์งํ ์ ์์ต๋๋ค.
model = parallelize_module(
model,
tp_mesh,
{
"tok_embeddings": RowwiseParallel(
input_layouts=Replicate(),
output_layouts=Shard(1),
),
"norm": SequenceParallel(),
"output": ColwiseParallel(
input_layouts=Shard(1),
output_layouts=Replicate()
),
}
)์์ค ๋ณ๋ ฌ(Loss Parallel)์ ์์ค ํจ์๋ฅผ ๊ณ์ฐํ ๋ ๋ฉ๋ชจ๋ฆฌ์ ํต์ ์ ์ ์ฝํ๋ ๊ด๋ จ ๊ธฐ์ ๋ก, ์ผ๋ฐ์ ์ผ๋ก ๋ชจ๋ธ ์ถ๋ ฅ์ด ๋งค์ฐ ํฌ๊ธฐ ๋๋ฌธ์ ์ฌ์ฉํฉ๋๋ค. ์์ค ๋ณ๋ ฌ์์๋ ๋ชจ๋ธ ์ถ๋ ฅ์ด (์์ฃผ ๊ฑฐ๋ํ) ์ดํ ์ฐจ์์์ ์ค๋ฉ๋ ๋, ๋ชจ๋ ๋ชจ๋ธ ์ถ๋ ฅ์ ๋งค๋ฒ ๋จ์ผ GPU์ ๋ชจ์ผ์ง ์๊ณ ๋ ๊ต์ฐจ ์ํธ๋กํผ ์์ค์ ํจ์จ์ ์ผ๋ก ๊ณ์ฐํ ์ ์์ต๋๋ค. ์ด๋ ๋ฉ๋ชจ๋ฆฌ ์๋น๋ฅผ ์ ์ํ๊ฒ ์ค์ผ ๋ฟ๋ง ์๋๋ผ, ํต์ ์ค๋ฒํค๋๋ฅผ ์ค์ด๊ณ ์ค๋ฉ๋ ์ฐ์ฐ์ ๋ณ๋ ฌ๋ก ์ฒ๋ฆฌํ์ฌ ํ์ต ์๋๋ฅผ ๊ฐ์ ํฉ๋๋ค. ์๋ ๊ทธ๋ฆผ์ ์์ค ๋ณ๋ ฌ์ด ์ค๋ฉ๋ ์ฐ์ฐ์ ํตํด ๋จ์ผ GPU๋ง๋ค ๋ชจ๋ ๋ชจ๋ธ์ ์ถ๋ ฅ์ ๋ชจ์ผ๋ ๊ฒ์ ํผํ๋ ๋ฐฉ๋ฒ์ ๊ฐ๋ตํ ๋ณด์ฌ์ค๋๋ค.
๊ทธ๋ฆผ 2. ๋จ์ผ GPU์์ ์์ค์ด ๋ณ๋ ฌ๋ก ๋ฐ์ํ๋ ๊ต์ฐจ ์ํธ๋กํผ ์์ค์ ์๋ฐฉํฅ ๊ณ์ฐ. ํ๋์์ ์ค๋ฉ๋ tensor๋ฅผ ๋ํ๋ด๊ณ , ๋ น์์ ๋ณต์ ๋ tensor๋ฅผ ๋ํ๋ด๋ฉฐ, ๋ ธ๋์์ ๋ถ๋ถ ๊ฐ์ ๊ฐ์ง๋ tensor๋ฅผ ๋ํ๋ ๋๋ค (๋ชจ๋ ์ถ์๋ ์์ ์ ๋๋ค). ๊ฒ์ ํ์ดํ๋ ๋ก์ปฌ ๊ณ์ฐ์ด๊ณ , ๋ถ์ ํ์ดํ๋ GPU ๊ฐ์ ๊ธฐ๋ฅ์ ์งํฉ์ฒด์ ๋๋ค.
PyTorch Tensor Parallel API์์, ์์ค ๋ณ๋ ฌ์ ์ปจํ
์คํธ ๊ด๋ฆฌ์ loss_parallel ์ ํตํด ์ฌ์ฉํ ์ ์์ผ๋ฉฐ, ์ด๋ฅผ ํตํด ์ฝ๋์ ๋ค๋ฅธ ๋ถ๋ถ์ ์์ ํ์ง ์๊ณ ๋ torch.nn.functional.cross_entropy ํน์ torch.nn.CrossEntropyLoss ๋ฅผ ์ง์ ์ฌ์ฉํ ์ ์์ต๋๋ค.
์์ค ๋ณ๋ ฌ์ ์ ์ฉํ๋ ค๋ฉด, ์ผ๋ฐ์ ์ผ๋ก [batch size, sequence length, vocabulary size] ๋ชจ์์ ๋ชจ๋ธ ์์ธก์ ์ดํ ์ฐจ์์์ ์ค๋ฉ๋์ด์ผ ํฉ๋๋ค. ์ด๋ ๋ง์ง๋ง ์ ํ ํฌ์ ๊ณ์ธต ๊ฒฐ๊ณผ์์ ์ถ๋ ฅ ๋ ์ด์์์ ํ๊ธฐํ์ฌ ์ฝ๊ฒ ์ํํ ์ ์์ต๋๋ค.
model = parallelize_module(
model,
tp_mesh,
{
"tok_embeddings": RowwiseParallel(
input_layouts=Replicate(),
output_layouts=Shard(1),
),
"norm": SequenceParallel(),
"output": ColwiseParallel(
input_layouts=Shard(1),
# DTensor๋ฅผ ์ถ๋ ฅ์ผ๋ก ์ฌ์ฉ
use_local_output=False,
),
},
)์ ์ฝ๋์์๋ ์ถ๋ ฅ ์ norm ๊ณ์ธต์๋ ์ํ์ค ๋ณ๋ ฌ์ ์ ์ฉํฉ๋๋ค. ์ถ๋ ฅ์ด DTensor๋ก ์ ์งํ๊ณ loss_parallel ์ปจํ
์คํธ ๊ด๋ฆฌ์์ ํจ๊ป ์๋ํ๋๋ก use_local_output=False ์ ์ ์ฉํฉ๋๋ค. ๊ทธ ํ, ๋ค์๊ณผ ๊ฐ์ด ๋จ์ํ cross_entropy ์์ค ํจ์๋ผ๊ณ ๋ถ๋ฅผ ์ ์์ต๋๋ค. ์ญ๋ฐฉํฅ ๊ณ์ฐ๋ ์ปจํ
์คํธ ๋ด์์ ์ด๋ฃจ์ด์ ธ์ผ ํ๋ ์ ๋ ์ ์ํ์ธ์.
import torch.nn.functional as F
from torch.distributed.tensor.parallel import loss_parallel
pred = model(input_ids)
with loss_parallel():
# pred ๋ฐ labels๋ [batch, seq, vocab] ๋ชจ์์ผ๋ก ๊ฐ์
loss = F.cross_entropy(pred.flatten(0, 1), labels.flatten(0, 1))
loss.backward()์ด์ Tensor/Sequence Parallel์ ๋ชจ๋ธ์ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ๋๋ ธ์ผ๋, Tensor Parallel๊ณผ Fully Sharded Data Parallel์ด ์ด๋ป๊ฒ ํจ๊ป ์๋ํ ์ ์๋์ง๋ ์ดํด๋ณด๊ฒ ์ต๋๋ค. Tensor Parallelism๋ ์ฐ์ฐ์ ๋ฐฉํดํ๋ ํต์ ์ ๋ฐ์ํ๋ฏ๋ก, NVLink์ ๊ฐ์ ๋น ๋ฅธ ํต์ ์ฑ๋ ๋ด์์ ์คํ๋๋๋ก ํ๊ณ ์ถ์ต๋๋ค. ์ค์ ๋ก, ์ผ๋ฐ์ ์ผ๋ก ๊ฐ ํธ์คํธ ๋ด์์ Tensor Parallel์ ์ ์ฉํ๊ณ , ํธ์คํธ ๊ฐ Fully Sharded Data Parallel๋ฅผ ์ ์ฉํฉ๋๋ค.
๊ทธ๋ฆผ 3. FSDP์ TP๋ ๋ณ๋์ ๋๋ฐ์ด์ค ์ฐจ์์์ ์๋ํ๋ฉฐ, FSDP ํต์ ์ ํธ์คํธ ๊ฐ์, TP ํต์ ์ ํธ์คํธ ๋ด์์ ์ด๋ฃจ์ด์ง๋๋ค.
์ด 2-D ๋ณ๋ ฌ ์ฒ๋ฆฌ ํจํด์ 2-D DeviceMesh๋ฅผ ํตํด ์ฝ๊ฒ ํํํ ์ ์์ผ๋ฉฐ, ๊ฐ๊ฐ์ "ํ์" DeviceMesh๋ฅผ ๊ฐ๊ฐ์ ๊ฐ๋ณ ๋ณ๋ ฌ ์ฒ๋ฆฌ API๋ก ์ ๋ฌํ๊ธฐ๋ง ํ๋ฉด ๋ฉ๋๋ค.
from torch.distributed.device_mesh import init_device_mesh
from torch.distributed.tensor.parallel import ColwiseParallel, RowwiseParallel, parallelize_module
from torch.distributed.fsdp import fully_shard
# ์๋ฅผ ๋ค์ด, 2-D mesh๋ [dp, tp]์ด๊ณ , 8 ๋ฐฉํฅ DP์ 8 ๋ฐฉํฅ TP๋ฅผ ์ํํ๋ 64๊ฐ์ GPU์์ ํ๋ จํฉ๋๋ค
mesh_2d = init_device_mesh("cuda", (8, 8))
tp_mesh = mesh_2d["tp"] # ํธ์คํธ ๋ด ๋๋ฐ์ด์ค๋ฅผ ์ฐ๊ฒฐํ๋ submesh
dp_mesh = mesh_2d["dp"] # ํธ์คํธ ๊ฐ ๋๋ฐ์ด์ค๋ฅผ ์ฐ๊ฒฐํ๋ submesh
model = Model(...)
tp_plan = {...}
# tp_mesh์์ Tensor Parallel์ ํธ์คํธ ๋ด ์ ์ฉ
model_tp = parallelize_module(model, tp_mesh, tp_plan)
# dp_mesh์์ FSDP๋ฅผ ํธ์คํธ ๊ฐ ์ ์ฉ
model_2d = fully_shard(model_tp, mesh=dp_mesh, ...)์ด๋ ๊ฒ ํ๋ฉด ๊ฐ ํธ์คํธ ๋ด (intra-host)์์ Tensor Parallel์ ์ฝ๊ฒ ์ ์ฉํ๊ณ ํธ์คํธ ๊ฐ์ (inter-hosts) FSDP๋ฅผ ์ฝ๋ ๋ณ๊ฒฝ ์์ด Llama ๋ชจ๋ธ์ ์ ์ฉํ ์ ์์ต๋๋ค. tensor(๋ชจ๋ธ) ๋ณ๋ ฌ ๋ฐ ๋ฐ์ดํฐ ๋ณ๋ ฌ ๊ธฐ์ ์ ํจ๊ป ๊ฒฐํฉํ๋ฉด ๋ง์ GPU๋ฅผ ์ด์ฉํด์ ๋ชจ๋ธ ํฌ๊ธฐ๋ฅผ ์ง์์ ์ผ๋ก ๋๋ฆฌ๊ณ ํจ์จ์ ์ผ๋ก ํ์ตํ ์ ์์ต๋๋ค.
์ด ํํ ๋ฆฌ์ผ์ Tensor Parallel๊ณผ Fully Sharded Data Parallel์ ๊ฒฐํฉํ์ฌ ์๋ฐฑ์์ ์์ฒ ๊ฐ GPU์์ ๋๊ท๋ชจ ํธ๋์คํฌ๋จธ์ ์ ์ฌํ ๋ชจ๋ธ์ ํ์ตํ๋ ๋ฐฉ๋ฒ์ ๋ณด์ฌ์ค๋๋ค. Tensor Parallel์ ๋ชจ๋ธ์ ์ฌ๋ฌ ๋ถ๋ถ์ ์ ์ฉํ๊ณ ์ฝ๋ ๋ณ๊ฒฝ ์์ด ๋ชจ๋ธ ์์ฒด์ ์ ์ฉํ๋ ๋ฐฉ๋ฒ์ ์ค๋ช ํฉ๋๋ค. Tensor Parallel์ ๋๊ท๋ชจ ํ์ต์ ์ํ ํจ์จ์ ์ธ ๋ชจ๋ธ ๋ณ๋ ฌํ ๊ธฐ์ ์ ๋๋ค.
์ด ํํ ๋ฆฌ์ผ์์ ์ค๋ช ํ๋ ์ ์ฒด(end-to-end) ์ฝ๋ ์์ ๋ฅผ ๋ณด๋ ค๋ฉด, pytorch/examples ์ ์๋ Tensor Parallel ์์ ๋ฅผ ์ฐธ๊ณ ํ์ธ์.