Skip to content

Latest commit

ย 

History

History
351 lines (245 loc) ยท 23.3 KB

File metadata and controls

351 lines (245 loc) ยท 23.3 KB

Tensor Parallel (TP)๋ฅผ ํ™œ์šฉํ•œ ๋Œ€๊ทœ๋ชจ ํŠธ๋žœ์Šคํฌ๋จธ ๋ชจ๋ธ ํ›ˆ๋ จ

์ €์ž: Wanchao Liang, Tianyu Liu ๋ฒˆ์—ญ: ๊ฐ•ํ˜ธํ˜„

Note

|edit| ์ด ํŠœํ† ๋ฆฌ์–ผ์€ github ์—์„œ ํ™•์ธํ•˜๊ณ  ํŽธ์ง‘ํ•˜์„ธ์š”.

์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ๋Š” Tensor Parallel๊ณผ Fully Sharded Data Parallel๋ฅผ ํ™œ์šฉํ•˜์—ฌ, ์ˆ˜๋ฐฑ์—์„œ ์ˆ˜์ฒœ ๊ฐœ์˜ GPU๋กœ ๋Œ€๊ทœ๋ชจ ํŠธ๋žœ์Šคํฌ๋จธ ๊ณ„์—ด์˜ ๋ชจ๋ธ์„ ํ›ˆ๋ จํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ์„ค๋ช…ํ•ฉ๋‹ˆ๋‹ค.

์‚ฌ์ „ ์ค€๋น„:

Tensor Parallel์€ ์–ด๋–ป๊ฒŒ ์ž‘๋™ํ•ฉ๋‹ˆ๊นŒ?

Tensor Parallel (TP)๋Š” ๊ธฐ์กด Megatron-LM ๋…ผ๋ฌธ์—์„œ ์ œ์•ˆ๋œ ๋ฐฉ์‹์œผ๋กœ, ๋Œ€๊ทœ๋ชจ ํŠธ๋žœ์Šคํฌ๋จธ(Transformer) ๋ชจ๋ธ์„ ํšจ์œจ์ ์œผ๋กœ ํ›ˆ๋ จํ•˜๊ธฐ ์œ„ํ•œ ๋ชจ๋ธ ๋ณ‘๋ ฌ์ฒ˜๋ฆฌ(parallelism) ๊ธฐ๋ฒ•์ž…๋‹ˆ๋‹ค. ์ด ํŠœํ† ๋ฆฌ์–ผ์—์„œ ์–ธ๊ธ‰ํ•œ Sequence Parallel (SP)๋Š” Tensor Parallel์˜ ํ•œ ๋ณ€ํ˜•์œผ๋กœ, ํ›ˆ๋ จ ์ค‘ ํ™œ์„ฑํ™” ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ ˆ์•ฝํ•˜๊ธฐ ์œ„ํ•ด nn.LayerNorm ํ˜น์€ RMSNorm ๋ฅผ ์‹œํ€€์Šค ์ฐจ์›์œผ๋กœ ์ƒค๋”ฉ ํ•ฉ๋‹ˆ๋‹ค. ๋ชจ๋ธ์ด ์ปค์งˆ์ˆ˜๋ก, ํ™œ์„ฑํ™” ๋ฉ”๋ชจ๋ฆฌ๊ฐ€ ๋ณ‘๋ชฉ์ด ๋˜๋ฏ€๋กœ, Tensor Parallel ํ•™์Šต์—์„œ๋Š” ์ฃผ๋กœ LayerNorm ์ด๋‚˜ RMSNorm ๊ณ„์ธต์— ์‹œํ€€์Šค ๋ณ‘๋ ฌ(Sequence Parallel)์„ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.

Megatron-LM TP

๊ทธ๋ฆผ 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 )์€ ์—ฐ์‚ฐ ๋ฐ ๋ฉ”๋ชจ๋ฆฌ๋ฅผ ์ ˆ์•ฝํ•˜๊ธฐ ์œ„ํ•ด ์ƒค๋”ฉ๋œ ์—ฐ์‚ฐ์„ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

Tensor Parallel์„ ์ ์šฉํ•ด์•ผ ํ•˜๋Š” ์‹œ๊ธฐ์™€ ์ด์œ 

PyTorch์˜ Fully Sharded Data Parallel(FSDP)๋Š” ์ด๋ฏธ ๋ชจ๋ธ ํ•™์Šต์„ ํŠน์ • ์ˆ˜์˜ GPU๋กœ ์กฐ์ •ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋Šฅ์„ ๊ฐ–์ถ”๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋Ÿฌ๋‚˜, ๋ชจ๋ธ ํฌ๊ธฐ์™€ GPU ์–‘ ์ธก๋ฉด์—์„œ ๋ชจ๋ธ ํ•™์Šต์„ ๋” ํ™•์žฅํ•˜๋ ค๋ฉด, Tensor Parallel๊ณผ FSDP์˜ ๊ฒฐํ•ฉ์ด ํ•„์š”ํ•œ, ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ถ”๊ฐ€์ ์ธ ๊ณผ์ œ๊ฐ€ ๋‹ค์ˆ˜ ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

  1. GPU ์ˆ˜๊ฐ€ ์ง€๋‚˜์น˜๊ฒŒ ์ปค์ง์— ๋”ฐ๋ผ (128/256 GPU ์ดˆ๊ณผ), FSDP ์ง‘ํ•ฉ(์˜ˆ๋ฅผ ๋“ค์–ด, allgather )์€ ring latency์— ๋งŽ์€ ์˜ํ–ฅ์„ ๋ฐ›์Šต๋‹ˆ๋‹ค. TP/SP๋ฅผ FSDP ์œ„์— ๊ตฌํ˜„ํ•˜์—ฌ, FSDP๋ฅผ ํ˜ธ์ŠคํŠธ ๊ฐ„์—๋งŒ ์ ์šฉํ•˜์—ฌ FSDP์˜ ๊ทœ๋ชจ๋ฅผ 8๊ฐœ๋กœ ์ค„์ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๊ทธ์— ๋”ฐ๋ผ ์ง€์—ฐ ๋น„์šฉ๋„ ๋™์ผํ•˜๊ฒŒ ์ค„์ผ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  2. ์ˆ˜๋ ด ๋ฐ GPU ๋ฉ”๋ชจ๋ฆฌ ์ œํ•œ์œผ๋กœ ์ธํ•ด ๊ธ€๋กœ๋ฒŒ ๋ฐฐ์น˜ ํฌ๊ธฐ๋ฅผ GPU ์ˆ˜๋ณด๋‹ค ๋†’๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์—†๋Š” ๋ฐ์ดํ„ฐ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ์˜ ํ•œ๊ณ„๋ฅผ ๋‹ฌ์„ฑํ•˜๋ ค๋ฉด, Tensor/Sequence Parallel์ด ๊ธ€๋กœ๋ฒŒ ๋ฐฐ์น˜ ํฌ๊ธฐ๋ฅผ "์ถ”์ •(ballpark)"ํ•˜๊ณ , ๋” ๋งŽ์€ GPU๋กœ ํ™•์žฅํ•˜๋Š” ์œ ์ผํ•œ ๋ฐฉ๋ฒ•์ž…๋‹ˆ๋‹ค.
  3. ํŠน์ • ์œ ํ˜•์˜ ๋ชจ๋ธ์—์„œ๋Š” ๋กœ์ปฌ ๋ฐฐ์น˜ ํฌ๊ธฐ๊ฐ€ ์ž‘์•„์ง€๋ฉด, 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์—์„œ ์˜ค์ง ๋ฐ์ดํ„ฐ ๋ณ‘๋ ฌ ์ฒ˜๋ฆฌ๋งŒ์œผ๋กœ ์‚ฌ์šฉ๋  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

Tensor Parallel์„ ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•

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 ๊ณ„์ธต์„ ๊ณ„์ธต๋ณ„๋กœ ๋ณ‘๋ ฌํ™”ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

LayerNorm/RMSNorm ๊ณ„์ธต์— ์‹œํ€€์Šค ๋ณ‘๋ ฌ(Sequence Parallel) ์ ์šฉํ•˜๊ธฐ

์‹œํ€€์Šค ๋ณ‘๋ ฌ(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) ์ ์šฉํ•˜๊ธฐ

์†์‹ค ๋ณ‘๋ ฌ(Loss Parallel)์€ ์†์‹ค ํ•จ์ˆ˜๋ฅผ ๊ณ„์‚ฐํ•  ๋•Œ ๋ฉ”๋ชจ๋ฆฌ์™€ ํ†ต์‹ ์„ ์ ˆ์•ฝํ•˜๋Š” ๊ด€๋ จ ๊ธฐ์ˆ ๋กœ, ์ผ๋ฐ˜์ ์œผ๋กœ ๋ชจ๋ธ ์ถœ๋ ฅ์ด ๋งค์šฐ ํฌ๊ธฐ ๋•Œ๋ฌธ์— ์‚ฌ์šฉํ•ฉ๋‹ˆ๋‹ค. ์†์‹ค ๋ณ‘๋ ฌ์—์„œ๋Š” ๋ชจ๋ธ ์ถœ๋ ฅ์ด (์ž์ฃผ ๊ฑฐ๋Œ€ํ•œ) ์–ดํœ˜ ์ฐจ์›์—์„œ ์ƒค๋”ฉ๋  ๋•Œ, ๋ชจ๋“  ๋ชจ๋ธ ์ถœ๋ ฅ์€ ๋งค๋ฒˆ ๋‹จ์ผ GPU์— ๋ชจ์œผ์ง€ ์•Š๊ณ ๋„ ๊ต์ฐจ ์—”ํŠธ๋กœํ”ผ ์†์‹ค์„ ํšจ์œจ์ ์œผ๋กœ ๊ณ„์‚ฐํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š” ๋ฉ”๋ชจ๋ฆฌ ์†Œ๋น„๋ฅผ ์œ ์˜ํ•˜๊ฒŒ ์ค„์ผ ๋ฟ๋งŒ ์•„๋‹ˆ๋ผ, ํ†ต์‹  ์˜ค๋ฒ„ํ—ค๋“œ๋ฅผ ์ค„์ด๊ณ  ์ƒค๋”ฉ๋œ ์—ฐ์‚ฐ์„ ๋ณ‘๋ ฌ๋กœ ์ฒ˜๋ฆฌํ•˜์—ฌ ํ•™์Šต ์†๋„๋ฅผ ๊ฐœ์„ ํ•ฉ๋‹ˆ๋‹ค. ์•„๋ž˜ ๊ทธ๋ฆผ์€ ์†์‹ค ๋ณ‘๋ ฌ์ด ์ƒค๋”ฉ๋œ ์—ฐ์‚ฐ์„ ํ†ตํ•ด ๋‹จ์ผ GPU๋งˆ๋‹ค ๋ชจ๋“  ๋ชจ๋ธ์˜ ์ถœ๋ ฅ์„ ๋ชจ์œผ๋Š” ๊ฒƒ์„ ํ”ผํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๊ฐ„๋žตํžˆ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

loss parallel

๊ทธ๋ฆผ 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()

Fully Sharded Data Parallel๊ณผ Tensor Parallel์„ ํ•จ๊ป˜ ๊ฒฐํ•ฉํ•˜๊ธฐ

์ด์ œ Tensor/Sequence Parallel์„ ๋ชจ๋ธ์— ์ ์šฉํ•˜๋Š” ๋ฐฉ๋ฒ•์„ ๋ณด์—ฌ๋“œ๋ ธ์œผ๋‹ˆ, Tensor Parallel๊ณผ Fully Sharded Data Parallel์ด ์–ด๋–ป๊ฒŒ ํ•จ๊ป˜ ์ž‘๋™ํ•  ์ˆ˜ ์žˆ๋Š”์ง€๋„ ์‚ดํŽด๋ณด๊ฒ ์Šต๋‹ˆ๋‹ค. Tensor Parallelism๋Š” ์—ฐ์‚ฐ์„ ๋ฐฉํ•ดํ•˜๋Š” ํ†ต์‹ ์„ ๋ฐœ์ƒํ•˜๋ฏ€๋กœ, NVLink์™€ ๊ฐ™์€ ๋น ๋ฅธ ํ†ต์‹  ์ฑ„๋„ ๋‚ด์—์„œ ์‹คํ–‰๋˜๋„๋ก ํ•˜๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค. ์‹ค์ œ๋กœ, ์ผ๋ฐ˜์ ์œผ๋กœ ๊ฐ ํ˜ธ์ŠคํŠธ ๋‚ด์—์„œ Tensor Parallel์„ ์ ์šฉํ•˜๊ณ , ํ˜ธ์ŠคํŠธ ๊ฐ„ Fully Sharded Data Parallel๋ฅผ ์ ์šฉํ•ฉ๋‹ˆ๋‹ค.

fsdp + tp

๊ทธ๋ฆผ 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 ์˜ˆ์ œ ๋ฅผ ์ฐธ๊ณ ํ•˜์„ธ์š”.