18. AI Training 단계별 학습 문서
원문 경로
/Users/keumky/Documents/New project 3/sources/mlsysbook/18-training/source.md
짧은 소개
이 장은 AI 모델을 학습시키는 일이 단순히 학습 버튼을 누르는 작업이 아니라는 점을 보여줘요. 모델은 데이터를 보고, 예측하고, 틀린 정도를 계산하고, 내부 숫자를 조금씩 고치면서 좋아집니다. 그런데 현대 AI에서는 이 과정이 너무 커져서 데이터 공급, GPU/TPU 계산, 메모리 관리, optimizer, 분산 학습, 하드웨어 선택이 모두 함께 맞물려야 해요.
원문은 GPT-2 규모의 모델을 예시로 삼아, 학습이라는 개념을 수학적 최적화이면서 동시에 거대한 시스템 엔지니어링 문제로 설명합니다.
읽는 방법
처음부터 모든 수식과 숫자를 붙잡고 읽기보다, 세 번에 나누어 읽는 방식이 좋아요.
| 읽기 순서 | 목표 | 집중할 내용 |
|---|---|---|
| 1회차 | 큰 그림 잡기 | 학습이 왜 반복적인 수정 과정인지 이해해요 |
| 2회차 | 흐름 잡기 | 데이터가 들어와서 예측, 오차 계산, 수정으로 이어지는 순서를 봐요 |
| 3회차 | 시스템 관점 파고들기 | 메모리, 연산량, 통신, 하드웨어 제약이 왜 중요한지 분석해요 |
학습 흐름은 이렇게 잡으면 됩니다.
데이터 준비
↓
모델이 예측
↓
정답과 비교해서 loss 계산
↓
backward pass로 gradient 계산
↓
optimizer가 parameter 업데이트
↓
평가와 모니터링
↓
이 과정을 반복
이 장의 한 줄 요약
AI training은 loss를 줄이도록 parameter를 반복 수정하는 과정이지만, 실제로는 데이터 파이프라인, 행렬 연산, 메모리, 분산 통신, 하드웨어 가속을 함께 설계해야 하는 종합 시스템 문제예요.
1단계: 중학교 수준
학습은 문제를 풀고 채점하고 고치는 과정이에요
AI 학습을 학생의 문제 풀이에 비유해볼게요.
학생이 처음부터 문제를 잘 푸는 것은 아니에요. 문제를 풀고, 정답과 비교하고, 어디가 틀렸는지 확인한 뒤, 다음에는 조금 더 나은 방식으로 풀어봅니다. AI도 비슷해요. 데이터를 보고 답을 예측한 다음, 정답과 비교해서 틀린 정도를 확인하고, 내부 숫자를 조금씩 고쳐요.
여기서 중요한 점은 사람이 모든 규칙을 하나하나 알려주지 않는다는 거예요. 대신 많은 예시를 보여주고, 틀렸는지 맞았는지를 알려주면서 AI가 스스로 내부 기준을 조정하게 해요.
Training system은 거대한 공부 공장 같아요
작은 문제 몇 개를 푸는 정도라면 노트 한 권과 계산기 하나면 충분해요. 하지만 수억, 수십억 개의 숫자를 다루는 AI 모델은 혼자 계산하기 어렵습니다. 그래서 학습 시스템은 거대한 공부 공장처럼 움직여요.
| 비유 | AI 학습에서의 의미 |
|---|---|
| 문제집 | 학습 데이터 |
| 학생 | 모델 |
| 채점 | loss 계산 |
| 틀린 방향 표시 | gradient |
| 공부 방법 조정 | optimizer |
| 넓은 책상 | 메모리 |
| 많은 계산기 | GPU나 TPU |
| 여러 사람이 나눠 푸는 방식 | 분산 학습 |
이 공장이 잘 돌아가려면 문제집이 끊기지 않고 도착해야 하고, 학생이 계산할 공간도 충분해야 하며, 여러 사람이 함께 풀 때 답을 맞춰보는 시간도 필요해요.
한 번의 학습은 작은 한 바퀴예요
학습은 아주 많은 작은 반복으로 이루어집니다.
- 데이터를 조금 가져와요.
- 모델이 답을 예측해요.
- 정답과 비교해 얼마나 틀렸는지 봐요.
- 틀린 방향을 참고해 내부 숫자를 고쳐요.
- 검사용 데이터로 잘하고 있는지 확인해요.
이 한 바퀴를 수천 번, 수만 번, 큰 모델에서는 훨씬 더 많이 반복해요.
왜 GPU와 TPU가 필요할까요?
AI 학습은 숫자를 아주 많이 곱하고 더하는 일입니다. 일반 계산기 하나로도 계산은 할 수 있지만, 너무 오래 걸려요. GPU와 TPU는 많은 계산을 동시에 처리하도록 만들어진 장치예요.
하지만 계산 장치만 빠르면 끝나는 것은 아니에요. 데이터를 가져오는 속도가 느리면 계산 장치가 기다리게 됩니다. 책상이 너무 작으면 중간 계산 결과를 놓을 곳이 없어요. 여러 장치가 함께 일하면 서로 결과를 맞추는 시간도 필요합니다.
그래서 AI 학습에서는 “계산을 빠르게 하자”뿐 아니라 “데이터를 끊기지 않게 보내자”, “책상 공간을 아끼자”, “여러 장치가 기다리지 않게 하자”가 모두 중요해요.
핵심 최적화는 생활 속 요령과 비슷해요
| 학습 최적화 | 쉬운 비유 | 핵심 의미 |
|---|---|---|
| Prefetching | 다음 수업 자료를 미리 책상에 올려두기 | GPU가 기다리지 않도록 다음 데이터를 미리 준비해요 |
| Mixed precision | 아주 정밀한 자 대신 적당히 충분한 자를 쓰기 | 숫자 표현을 줄여 메모리와 시간을 아껴요 |
| Gradient accumulation | 작은 묶음을 여러 번 모아 큰 묶음처럼 채점하기 | 메모리가 부족해도 큰 batch처럼 학습해요 |
| Checkpointing | 모든 풀이 과정을 저장하지 않고 중간 표시만 남기기 | 메모리를 아끼고 필요할 때 다시 계산해요 |
| Distributed training | 여러 사람이 문제를 나눠 풀고 답을 맞추기 | 큰 데이터나 큰 모델을 여러 장치가 함께 학습해요 |
분산 학습은 나눠서 공부하는 방식이에요
분산 학습에는 대표적인 방식이 있어요.
| 방식 | 쉬운 설명 |
|---|---|
| Data parallelism | 같은 교재를 가진 여러 사람이 서로 다른 문제를 풀고 결과를 평균내요 |
| Model parallelism | 교재 자체가 너무 커서 여러 사람이 서로 다른 단원을 맡아요 |
| Pipeline parallelism | 앞 사람이 1단원을 끝내면 다음 사람이 2단원을 이어서 처리해요 |
| Hybrid parallelism | 문제도 나누고 교재도 나누는 혼합 방식이에요 |
분산 학습은 강력하지만, 항상 빠른 것은 아니에요. 여러 사람이 모이면 회의 시간이 생기듯이, 여러 GPU가 함께 학습하면 서로 결과를 주고받는 시간이 생깁니다. 이 통신 시간이 너무 커지면 오히려 비효율적일 수 있어요.
1단계 중간 정리
AI 학습은 “예측하고, 틀린 정도를 보고, 조금 고치고, 다시 반복하는 과정”이에요. 큰 모델을 학습하려면 계산 장치, 데이터 공급, 메모리, 여러 장치 간 협력이 모두 중요합니다. 이 장은 바로 그 전체 공부 공장을 어떻게 효율적으로 운영할지 설명하는 장이에요.
2단계: 고등학교 수준
학습을 함수 찾기로 볼 수 있어요
모델은 입력 (x)를 받아 예측값 (\hat{y})를 만드는 함수라고 볼 수 있어요.
[ \hat{y} = f_\theta(x) ]
여기서 (\theta)는 모델 안에 들어 있는 parameter예요. 학습은 좋은 (\theta)를 찾는 과정입니다. 예측값 (\hat{y})와 정답 (y)가 다르면 loss가 커져요.
[ loss = L(\hat{y}, y) ]
결국 학습의 목표는 loss를 작게 만드는 parameter를 찾는 거예요.
Gradient descent는 언덕을 내려가는 방법이에요
loss를 산의 높이라고 생각해볼게요. 우리는 가장 낮은 곳으로 내려가고 싶어요. gradient는 어느 방향으로 가면 높이가 빨리 커지는지 알려줍니다. 그러면 반대 방향으로 조금 이동하면 loss를 줄일 수 있어요.
[ \theta_{\text{new}} = \theta_{\text{old}} - \alpha \nabla L(\theta) ]
이 식에서 각 항의 의미는 다음과 같아요.
| 기호 | 뜻 |
|---|---|
| (\theta) | 모델 parameter |
| (\alpha) | learning rate, 한 번에 움직이는 크기 |
| (\nabla L(\theta)) | loss가 커지는 방향 |
learning rate가 너무 크면 낮은 지점을 지나쳐 튈 수 있고, 너무 작으면 학습이 너무 느려져요.
전체 데이터 대신 mini-batch를 써요
모든 데이터를 한 번에 보고 parameter를 업데이트하면 정확한 방향을 알 수 있지만, 메모리가 너무 많이 필요해요. 반대로 데이터 하나씩만 보면 메모리는 적게 쓰지만 GPU를 충분히 활용하지 못합니다.
그래서 실제 학습에서는 mini-batch를 많이 써요.
| 방식 | 장점 | 단점 |
|---|---|---|
| Full-batch | 전체 데이터를 보므로 gradient가 안정적이에요 | 메모리와 시간이 너무 많이 들어요 |
| Single-example SGD | 메모리를 적게 써요 | GPU 활용률이 낮고 업데이트가 흔들릴 수 있어요 |
| Mini-batch | 병렬 계산과 메모리 사이 균형이 좋아요 | batch size를 잘 골라야 해요 |
mini-batch에서 gradient는 대략 이렇게 평균으로 계산돼요.
[ g = \frac{1}{B}\sum_{i=1}^{B}\nabla L(\theta; x_i, y_i) ]
여기서 (B)는 batch size예요.
Training pipeline은 세 부분이 맞물려 돌아가요
| 구성 요소 | 하는 일 | 병목이 생기면 |
|---|---|---|
| Data pipeline | 데이터를 읽고 전처리하고 batch로 만들어요 | GPU가 데이터를 기다려요 |
| Training loop | forward, loss, backward, update를 반복해요 | 계산 시간이 길어져요 |
| Evaluation pipeline | validation 데이터로 성능을 확인해요 | 과적합이나 학습 실패를 늦게 발견해요 |
시스템 전체 속도는 가장 느린 부분에 의해 결정돼요.
[ T_{\text{system}} = \min(T_{\text{pipeline}}, T_{\text{compute}}) ]
데이터 파이프라인이 초당 200개만 공급하는데 GPU가 초당 1000개를 처리할 수 있다면, 실제 시스템은 초당 200개 수준으로만 움직여요. 나머지 시간에는 GPU가 기다립니다.
Forward pass와 backward pass는 서로 다른 부담을 만들어요
Forward pass는 입력을 모델에 통과시켜 예측을 만드는 단계예요.
[ A^{(l)} = f(W^{(l)}A^{(l-1)} + b^{(l)}) ]
이 식은 이전 층의 결과에 weight를 곱하고 bias를 더한 뒤 activation function을 적용한다는 뜻이에요.
Backward pass는 loss를 줄이기 위해 각 parameter를 얼마나 고쳐야 하는지 계산하는 단계예요. 이때 forward pass에서 만든 중간 결과가 필요합니다. 그래서 학습은 추론보다 메모리를 훨씬 많이 써요.
메모리 부담은 대략 batch size와 layer 수에 비례해 커집니다.
[ \text{Activation Memory} \sim B \times \sum_{l=1}^{L} A_l ]
batch size를 키우면 GPU 활용률은 좋아질 수 있지만, 메모리도 같이 커져요.
Optimizer마다 메모리 사용량이 달라요
SGD는 단순하지만 수렴이 느릴 수 있어요. Momentum은 이전 이동 방향을 기억해서 더 안정적으로 움직이고, Adam은 gradient의 평균과 제곱 평균을 함께 저장해서 parameter마다 조정된 업데이트를 해요.
| Optimizer | 추가로 기억하는 것 | 시스템 관점 |
|---|---|---|
| SGD | 거의 없음 | 메모리는 적지만 수렴이 느릴 수 있어요 |
| Momentum | 이동 속도 벡터 | 메모리가 parameter 크기의 약 2배 수준으로 늘어요 |
| Adam | 1차 moment와 2차 moment | 수렴은 빠를 수 있지만 메모리가 크게 늘어요 |
원문은 Adam의 상태 저장이 큰 모델에서 매우 중요하다고 강조해요. parameter가 15억 개라면 optimizer state만으로도 수십 GB가 필요할 수 있어요.
병목을 보고 최적화를 골라야 해요
원문은 무작정 최적화 기법을 적용하지 말고, 먼저 병목을 찾아야 한다고 설명해요.
Profile
↓
Select
↓
Compose
| 병목 | 대표 증상 | 어울리는 기법 |
|---|---|---|
| 데이터 이동 지연 | GPU가 데이터를 기다려요 | Prefetching, pipeline overlapping |
| 계산 처리량 부족 | 연산이 하드웨어 성능을 못 끌어내요 | Mixed precision, fused kernel |
| 메모리 부족 | batch나 모델이 GPU에 안 들어가요 | Gradient accumulation, checkpointing |
| 통신 지연 | 여러 GPU가 서로 기다려요 | 효율적인 AllReduce, gradient accumulation, hybrid parallelism |
분산 학습의 기본 논리는 gradient 평균이에요
Data parallelism에서는 여러 장치가 같은 모델을 가지고 서로 다른 데이터를 처리해요. 각 장치가 자기 batch에서 gradient를 계산한 뒤, 그 gradient를 평균내면 전체 batch를 본 것과 비슷한 효과를 얻습니다.
[ g_{\text{global}} = \frac{1}{N}\sum_{k=1}^{N}g_k ]
이 수식은 장치 (N)개가 각자 계산한 gradient (g_k)를 평균내는 뜻이에요. 이 원리 덕분에 데이터 병렬 학습이 가능합니다. 하지만 평균을 내려면 서로 통신해야 하므로, 모델이 크고 장치가 많아질수록 통신 시간이 커져요.
2단계 중간 정리
고등학교 수준에서는 AI 학습을 “loss라는 값을 줄이는 함수 최적화”로 보면 됩니다. 하지만 실제 시스템에서는 수식만으로 끝나지 않아요. batch size, activation memory, optimizer state, 데이터 공급 속도, GPU 통신 시간이 모두 학습 속도와 비용을 결정합니다.
3단계: 대학교 수준
3.1 목적: 왜 새로운 training system이 필요한가요?
원문은 현대 머신러닝 학습이 단일 머신의 한계를 넘어섰다고 설명해요. 큰 모델은 수십억 개 이상의 parameter를 가지고, 데이터셋은 메모리에 한 번에 올릴 수 없을 만큼 큽니다. 또한 gradient 기반 학습은 한 번 계산하고 끝나는 작업이 아니라, forward pass, backward pass, parameter update를 계속 반복해야 해요.
이 반복 구조 때문에 training system은 네 가지 부담을 동시에 다룹니다.
| 부담 | 의미 |
|---|---|
| 연산량 | 행렬 곱과 gradient 계산이 막대한 FLOPS를 요구해요 |
| 메모리 | parameter, activation, gradient, optimizer state를 동시에 관리해야 해요 |
| 통신 | 여러 장치가 gradient와 parameter 정보를 맞춰야 해요 |
| 운영 | 실패 복구, 스케줄링, 비용, 재현성을 관리해야 해요 |
원문은 GPT-2를 장 전체의 기준 예시로 사용해요. GPT-2는 약 15억 개 parameter, 48개 transformer layer, hidden dimension 1280, attention head 20개를 가진 모델로 소개됩니다. 너무 작아서 시스템 문제가 사라지는 모델도 아니고, 너무 커서 설명이 현실과 동떨어지는 모델도 아니기 때문에 좋은 기준점이에요.
3.2 Training systems의 진화와 구조
Computing architecture의 진화
원문은 AI training system이 갑자기 등장한 것이 아니라, 컴퓨팅 아키텍처의 역사적 흐름 위에서 발전했다고 설명해요.
| 시대 | 잘한 일 | AI training 관점의 한계 |
|---|---|---|
| Mainframe | 표준화된 명령어, 메모리 계층 같은 기본 개념을 만들었어요 | 현대 신경망 학습 규모를 다루기에는 부족해요 |
| HPC | 과학 계산, 부동소수점, 조밀한 행렬 연산에 강했어요 | 신경망의 동적 메모리와 반복적 gradient 동기화에는 완전히 맞지 않았어요 |
| Warehouse-scale computing | 대규모 데이터 처리와 장애 복구에 강했어요 | 독립 작업 중심이라 synchronized gradient update와 다릅니다 |
| AI hypercomputing | GPU, TPU, 고속 interconnect로 AI 학습에 특화됐어요 | 성능을 얻으려면 소프트웨어와 운영까지 함께 설계해야 해요 |
AI training은 HPC처럼 조밀한 FP16/FP32 계산을 많이 하지만, warehouse-scale computing처럼 엄청난 데이터 규모도 필요해요. 여기에 반복적이고 동기화된 parameter update가 추가됩니다. 이 조합 때문에 일반적인 컴퓨팅 시스템만으로는 충분하지 않고, AI 전용 가속기와 분산 학습 프레임워크가 필요해진 거예요.
ML 개발 생명주기 안에서의 training system
Training system은 모델 개발의 중심 인프라예요. 데이터 전처리와 연결되고, 모델 검증과 배포 전 단계에 영향을 줍니다. 학습이 느리거나 불안정하면 실험 주기가 길어지고, 모델 개선도 늦어져요.
현대 training system은 다음 일을 처리해야 합니다.
- 대규모 데이터를 계속 공급해요.
- 모델 parameter를 반복적으로 최적화해요.
- 수치 안정성을 유지해요.
- GPU, TPU 같은 accelerator를 효율적으로 사용해요.
- 여러 장치나 여러 노드의 동기화를 관리해요.
- 비용, 에너지, 재현성, 실패 복구를 고려해요.
Training infrastructure 설계 원칙
원문은 training을 순수한 수학 문제가 아니라 시스템 설계 문제로 봐야 한다고 강조해요. 데이터 preprocessing, forward pass, backward pass, parameter update는 각각 다른 리소스를 압박합니다.
| 단계 | 주로 압박하는 리소스 |
|---|---|
| Data preprocessing | 저장장치, CPU, 네트워크, I/O |
| Forward pass | matrix compute, activation memory |
| Backward pass | activation 재사용, gradient 계산, memory bandwidth |
| Parameter update | optimizer state, memory bandwidth |
| Distributed synchronization | interconnect, collective communication |
따라서 좋은 training system은 “빠른 GPU를 많이 사는 것”만으로 만들어지지 않아요. 데이터가 끊기지 않고 공급되고, 메모리가 예측 가능하게 쓰이며, 통신이 계산을 지나치게 막지 않도록 설계해야 합니다.
3.3 Mathematical foundations
Neural network computation
신경망의 한 layer는 보통 다음 형태로 계산됩니다.
[ A^{(l)} = f(W^{(l)}A^{(l-1)} + b^{(l)}) ]
여기서 (A^{(l-1)})는 이전 layer의 activation, (W^{(l)})는 weight matrix, (b^{(l)})는 bias, (f)는 activation function이에요.
이 식은 단순해 보이지만, 시스템 관점에서는 매우 중요한 정보를 줍니다.
- (W^{(l)}A^{(l-1)})는 대규모 행렬 곱이에요.
- activation function은 element-wise 연산이지만 메모리 대역폭을 압박할 수 있어요.
- backward pass를 위해 (A^{(l-1)}), 중간값, 출력 activation을 저장해야 해요.
- layer가 깊고 batch가 커질수록 activation memory가 크게 늘어요.
Matrix operations
원문은 neural network training에서 matrix-matrix multiplication이 대부분의 시간을 차지한다고 설명해요. forward pass와 backward pass의 60-90%가 행렬 곱에 집중될 수 있어요. 그래서 GPU Tensor Core나 TPU systolic array처럼 행렬 곱에 특화된 하드웨어가 중요해졌습니다.
GPT-2 attention 계산 예시는 규모감을 잘 보여줘요.
| 항목 | 원문 예시 규모 |
|---|---|
| Q, K, V projection | batch 32, sequence 1024, hidden 1280 기준 약 160B FLOPS |
| Attention score 계산 | 20 heads 기준 약 42.9B FLOPS |
| Attention layer 1개 | forward pass만 약 204B FLOPS |
| 48 layers | 학습 step당 약 9.8T FLOPS |
| 50K steps | 전체 약 490 petaFLOPS |
여기서 중요한 점은 “수식이 크다”가 아니라, 이 연산 패턴이 하드웨어 설계를 결정한다는 거예요. 행렬 곱은 독립적인 곱셈과 덧셈을 많이 포함하므로 GPU의 수천 개 코어와 잘 맞습니다. 반면 matrix-vector 연산이나 element-wise 연산은 병렬화가 덜 효율적일 수 있어요.
Batching도 이 맥락에서 중요합니다. 데이터를 하나씩 처리하면 matrix-vector에 가까운 작은 연산이 많아져 GPU 활용률이 낮아질 수 있어요. 여러 예시를 batch로 묶으면 더 큰 matrix-matrix 연산으로 바뀌어 하드웨어를 더 잘 사용할 수 있습니다.
Activation functions
Activation function은 비선형성을 제공하지만, 시스템 관점에서는 계산 비용과 메모리 접근 패턴도 중요합니다.
| 함수 | 수학적 특징 | 시스템 관점 |
|---|---|---|
| Sigmoid | 0과 1 사이 출력 | exponential 계산이 비싸고 gradient 문제가 있어요 |
| Tanh | -1과 1 사이 출력 | sigmoid와 비슷하게 계산 비용이 커요 |
| ReLU | 음수는 0, 양수는 그대로 | 비교 연산 중심이라 매우 빠르고 sparse activation을 만들어요 |
| Softmax | 전체 값을 확률 분포로 정규화 | 각 값이 전체 입력에 의존해서 메모리와 reduction 비용이 커요 |
| GELU | 부드러운 확률적 gating 성격 | GPT-2에서 사용되며 ReLU보다 비싸지만 품질 이점이 있어요 |
원문은 GPT-2가 GELU를 사용한다고 설명해요.
[ \text{GELU}(x) = x \cdot \Phi(x) ]
GELU는 ReLU보다 gradient가 부드럽고 언어 모델링에서 성능이 좋지만, erf 계산 때문에 더 비쌉니다. 현대 프레임워크는 근사식을 사용해 비용을 낮춰요. 원문은 GELU가 GPT-2의 48개 layer에서 forward pass 시간을 몇 퍼센트 늘릴 수 있지만, 모델 품질 개선이 그 비용을 정당화한다고 설명합니다.
중요한 시스템 원칙도 나와요. Activation function은 항상 compute-bound가 아닙니다. element-wise 연산은 계산 자체는 적지만 메모리에서 값을 읽고 쓰는 시간이 더 중요해질 수 있어요. 그래서 ReLU와 sigmoid의 이론적 계산 비용 차이가 실제 GPU 전체 학습 시간에서는 생각보다 작게 보일 수 있습니다.
Optimization algorithms
Optimization algorithm은 loss를 줄이도록 parameter를 업데이트합니다.
기본 gradient descent는 다음과 같아요.
[ \theta_{t+1} = \theta_t - \alpha \nabla L(\theta_t) ]
전체 데이터를 한 번에 쓰는 full-batch gradient descent는 수학적으로 깔끔하지만, 시스템적으로는 너무 무겁습니다. 예시가 100만 개라면 모든 예시에 대한 activation과 gradient를 계산하고 저장해야 하므로 메모리가 폭발해요.
SGD는 데이터 하나 또는 작은 묶음으로 gradient를 추정합니다.
[ \theta_{t+1} = \theta_t - \alpha \nabla L(\theta_t; x_i, y_i) ]
Mini-batch gradient descent는 실제 시스템에서 많이 쓰이는 절충안이에요.
[ \theta_{t+1} = \theta_t - \alpha \frac{1}{B}\sum_{i=1}^{B}\nabla L(\theta_t; x_i, y_i) ]
batch size (B)를 키우면 GPU 활용률이 좋아질 수 있지만, activation memory가 선형으로 늘어납니다. 원문은 batch size가 하드웨어 효율과 메모리 한계를 동시에 결정하는 핵심 system parameter라고 봐요.
Momentum, RMSprop, Adam의 시스템 비용
Momentum은 이전 update 방향을 velocity로 저장합니다.
[ v_{t+1} = \beta v_t + \nabla L(\theta_t) ]
[ \theta_{t+1} = \theta_t - \alpha v_{t+1} ]
RMSprop은 squared gradient의 이동 평균을 저장해 parameter별로 update 크기를 조정합니다.
Adam은 momentum과 RMSprop의 아이디어를 결합해 1차 moment (m_t)와 2차 moment (v_t)를 모두 저장합니다.
[ m_t = \beta_1 m_{t-1} + (1-\beta_1)\nabla L(\theta_t) ]
[ v_t = \beta_2 v_{t-1} + (1-\beta_2)(\nabla L(\theta_t))^2 ]
[ \theta_{t+1} = \theta_t - \alpha \frac{m_t}{\sqrt{v_t + \epsilon}} ]
시스템 관점의 메모리 비용은 다음처럼 증가합니다.
| Optimizer | 대략적인 optimizer 관련 메모리 |
|---|---|
| SGD | parameter 크기 수준 |
| Momentum | parameter 크기의 약 2배 |
| Adam | parameter 크기의 약 3배 |
GPT-2 예시에서 Adam은 매우 큰 메모리 부담을 만듭니다. 15억 parameter를 FP32로 저장하면 parameter, gradient, Adam의 1차 moment, 2차 moment가 각각 약 6GB씩 필요해 총 24GB 수준이 됩니다. 여기에 activation memory가 더해지므로 단일 GPU에 넣기 어렵습니다.
원문은 그래도 Adam이 유용하다고 설명해요. GPT-2 예시에서는 Adam이 SGD+Momentum보다 훨씬 적은 step으로 수렴할 수 있어, per-step 비용이 크더라도 전체 학습 시간을 줄일 수 있습니다.
Optimizer 구현의 시스템 세부 사항
Optimizer는 수학식만 구현하면 끝나는 것이 아니에요. parameter와 gradient, optimizer state를 계속 읽고 써야 하므로 memory bandwidth가 병목이 됩니다.
원문은 Adam 연산을 따로 실행하면 memory access가 parameter 크기의 약 5배 수준까지 커질 수 있지만, fused kernel로 묶으면 약 2배 수준으로 줄일 수 있다고 설명해요.
| 구현 방식 | 의미 |
|---|---|
| Separate operations | 여러 kernel이 따로 실행되어 메모리를 반복해서 읽고 써요 |
| Fused operations | 여러 update 연산을 하나의 kernel로 묶어 memory traffic을 줄여요 |
| Sequential access layout | cache hit와 memory bandwidth 활용을 개선해요 |
| Mixed precision state | 일부 state를 낮은 정밀도로 저장해 메모리를 줄여요 |
프레임워크의 optimizer API는 gradient 계산과 parameter update를 분리합니다. 일반적인 흐름은 gradient 초기화, forward, backward, optimizer step, learning rate scheduler step으로 이어져요. 이 분리 덕분에 gradient accumulation이나 learning rate schedule을 조합하기 쉬워집니다.
Backpropagation mechanics
Backpropagation은 computational graph를 거꾸로 따라가며 gradient를 계산하는 알고리즘이에요.
Forward pass에서는 layer마다 다음 값을 계산합니다.
[ z^{(l)} = W^{(l)}a^{(l-1)} + b^{(l)} ]
[ a^{(l)} = f(z^{(l)}) ]
Backward pass에서는 chain rule을 이용합니다.
[ \frac{\partial L}{\partial z^{(l)}} = \frac{\partial L}{\partial a^{(l)}} \odot f’(z^{(l)}) ]
[ \frac{\partial L}{\partial W^{(l)}} = \frac{\partial L}{\partial z^{(l)}}(a^{(l-1)})^T ]
이 식이 시스템에 주는 의미는 분명합니다. 앞쪽 layer의 gradient를 계산하려면 뒤쪽 layer에서 온 gradient 신호와 forward pass 때 저장한 activation이 필요해요. 따라서 training system은 forward pass의 중간 결과를 보관해야 합니다.
Activation memory
원문은 activation memory가 학습 메모리의 핵심 병목이라고 설명해요. 각 layer에서 저장해야 할 것은 보통 다음과 같습니다.
- forward pass의 입력 activation
- layer 연산 후 출력 activation
- layer parameter
- parameter update에 필요한 gradient
GPT-2 예시를 보면 batch size 32, sequence length 1024, hidden dimension 1280, 48 layers에서 activation memory가 매우 커져요.
| 항목 | 원문 예시 |
|---|---|
| Attention activation | layer당 약 335MB |
| FFN activation | layer당 약 335MB |
| Layer norm state | layer당 약 10MB |
| 총 layer당 activation | 약 680MB |
| 48 layers activation | 약 32.6GB |
| parameter FP16 | 약 3GB |
| gradient | 약 3GB |
| Adam FP32 state | 약 12GB |
| peak memory | 약 51GB |
이 수치는 32GB V100 한 장에 들어가지 않아요. 그래서 원문은 gradient checkpointing, CPU offloading, mixed precision, batch size 축소, gradient accumulation 같은 해법을 설명합니다.
전체 메모리 관계는 다음처럼 볼 수 있어요.
[ \text{Memory per batch} = B \times \sum_{l=1}^{L}(s_l + a_l) ]
[ \text{Total Memory} = \text{Memory per batch} + \text{Memory}_{\text{optimizer}} ]
여기서 (s_l)은 중간 계산 크기, (a_l)은 activation 크기예요. 이 식은 batch size와 layer 수가 왜 학습 메모리를 크게 만드는지 보여줍니다.
3.4 Pipeline architecture
전체 구조
Training pipeline은 세 부분으로 나뉩니다.
| 구성 | 역할 |
|---|---|
| Data pipeline | raw data를 읽고 전처리해서 batch로 만들어요 |
| Training loop | forward, loss, backward, update를 반복해요 |
| Evaluation pipeline | validation data로 성능과 과적합을 확인해요 |
이 세 부분은 독립적으로 보이지만 실제로는 겹쳐서 움직여야 합니다. GPU가 현재 batch를 계산하는 동안 CPU는 다음 batch를 전처리하고, storage는 그다음 데이터를 읽어야 해요. 이렇게 겹치지 않으면 GPU가 기다리며 비용이 낭비됩니다.
Data pipeline
Data pipeline은 storage, CPU preprocessing, GPU training zone으로 나눌 수 있어요.
Storage에서 데이터를 읽는 이론적 최대 throughput은 disk bandwidth와 network bandwidth 중 작은 값에 의해 제한됩니다.
[ T_{\text{storage}} = \min(B_{\text{disk}}, B_{\text{network}}) ]
하지만 실제 학습은 데이터를 섞고 random access를 많이 하므로 효과적인 throughput은 더 낮아져요.
[ T_{\text{effective}} = T_{\text{storage}} \times F_{\text{access}} ]
원문은 typical training에서 (F_{\text{access}})가 약 0.1일 수 있다고 설명합니다. 이론적으로 빠른 저장장치라도 random access와 shuffling 때문에 실제 속도는 크게 줄 수 있어요.
Preprocessing throughput은 다음과 같이 표현됩니다.
[ T_{\text{preprocessing}} = \frac{N_{\text{workers}}}{t_{\text{transform}}} ]
worker 수를 늘리면 처리량이 늘 수 있지만, CPU contention이나 메모리 부담이 생길 수 있으므로 무조건 늘리는 것이 답은 아닙니다.
최종 training throughput은 다음 중 가장 느린 것에 의해 결정됩니다.
[ T_{\text{training}} = \min(T_{\text{preprocessing}}, B_{\text{GPU_transfer}}, B_{\text{GPU_compute}}) ]
이 식은 training system의 핵심 원칙을 보여줘요. 전체 성능은 가장 느린 단계가 결정합니다.
GPT-2 text pipeline 예시
원문은 GPT-2 학습용 OpenWebText 데이터 파이프라인도 설명해요.
| 단계 | 원문 예시 |
|---|---|
| Raw data | 약 40GB text |
| Storage | NVMe SSD, sequential read 약 3.5GB/s |
| Random access effective | 약 0.35GB/s |
| Tokenizer | BPE, vocabulary 50,257 |
| Tokenization 속도 | CPU core당 약 500K tokens/s |
| Batch | batch 32, sequence 1024, 총 32K tokens |
| 단일 core tokenization | batch당 약 64ms |
| GPU forward pass | 약 80ms |
| 8 workers 적용 | tokenization이 약 8ms 수준으로 감소 |
이 예시의 핵심은 NLP에서는 tokenization이 CPU-bound 병목이 될 수 있다는 점이에요. vision task에서는 image I/O나 augmentation이 병목일 수 있지만, language model에서는 text를 token ID로 바꾸는 과정이 중요할 수 있습니다.
Data flow와 memory hierarchy
Training data는 storage, system memory, accelerator memory를 거쳐 이동합니다.
| 계층 | 대략적 특징 |
|---|---|
| Storage | 용량은 크지만 bandwidth가 낮아요 |
| System RAM | storage보다 빠르지만 GPU memory보다 느려요 |
| Accelerator memory | 매우 빠르지만 용량이 제한돼요 |
원문은 데이터 이동률이 다음의 최솟값에 의해 제한된다고 설명해요.
[ T_{\text{memory}} = \min(B_{\text{storage}}, B_{\text{system}}, B_{\text{accelerator}}) ]
한 iteration의 시간은 fetch, process, transfer 중 가장 긴 시간으로 볼 수 있어요.
[ t_{\text{iteration}} = \max(t_{\text{fetch}}, t_{\text{process}}, t_{\text{transfer}}) ]
그래서 현대 pipeline은 이 세 작업을 겹치게 만듭니다. 한 batch를 GPU가 계산하는 동안 다음 batch는 CPU가 전처리하고, 그다음 batch는 storage에서 읽는 방식이에요.
Forward pass
Forward pass는 원문 앞부분의 layer 계산식을 실제 하드웨어에서 실행하는 단계예요. Dense layer는 큰 matrix multiplication을 수행하고, convolutional network는 kernel을 공간적으로 적용하며, transformer는 attention score와 softmax를 계산합니다.
시스템 관점에서 forward pass의 핵심은 세 가지예요.
- 큰 행렬 곱을 GPU/TPU에 맞는 크기로 잘 실행해야 해요.
- activation을 backward pass를 위해 저장해야 해요.
- memory bandwidth가 element-wise 연산의 병목이 될 수 있어요.
원문은 GPU가 warp나 wavefront 같은 고정 크기 thread 묶음으로 일하기 때문에, matrix dimension이 하드웨어에 잘 맞을 때 효율이 좋아진다고 설명합니다. cuDNN 같은 라이브러리는 input dimension과 hardware 특성에 맞춰 최적 알고리즘을 선택해요.
Forward pass의 activation memory는 대략 다음과 같이 커집니다.
[ \text{Total Memory} \sim B \times \sum_{l=1}^{L}A_l ]
ResNet-50 예시에서는 batch size 32에서 forward activation이 약 8GB, gradient가 약 4GB, parameter가 약 200MB로 총 12.2GB 수준까지 갈 수 있다고 설명합니다. batch size를 64로 키우면 activation과 gradient memory도 거의 두 배가 됩니다.
Backward pass
Backward pass는 gradient를 거꾸로 계산하는 단계입니다. 핵심 계산은 다음과 같아요.
[ \frac{\partial L}{\partial W^{(l)}} = \delta^{(l)}(a^{(l-1)})^T ]
여기서 (\delta^{(l)})는 뒤쪽 layer에서 온 gradient signal이에요. 이 계산을 하려면 forward pass 때 저장한 activation을 다시 읽어야 합니다.
Backward pass는 memory operation이 복잡합니다.
- 저장된 activation을 읽어요.
- 뒤쪽 layer에서 온 gradient signal을 읽어요.
- weight gradient를 계산해요.
- 계산 결과를 다시 memory에 씁니다.
또한 backward pass는 순서 의존성이 강해요. 앞쪽 layer의 gradient를 계산하려면 뒤쪽 layer의 gradient가 먼저 와야 합니다. 이 의존성 때문에 무작정 모든 layer를 동시에 계산할 수 없고, memory lifetime 관리가 중요해집니다.
Parameter updates and optimizers
Backward pass가 gradient를 만들면 optimizer가 parameter를 업데이트합니다. 이 단계는 보통 단순해 보이지만, 큰 모델에서는 memory bandwidth가 큰 부담이에요.
한 parameter update에는 보통 다음 일이 필요합니다.
- 현재 parameter를 memory에서 읽어요.
- gradient를 읽어요.
- optimizer state를 읽거나 갱신해요.
- 새 parameter를 계산해요.
- 결과를 다시 memory에 씁니다.
SGD는 상대적으로 단순하지만, Adam은 1차 moment와 2차 moment를 유지해야 하므로 메모리가 2-3배 늘 수 있어요. 또한 batch size는 update 빈도, gradient noise, GPU 활용률, 분산 학습의 data parallelism 정도에 영향을 줍니다.
3.5 Pipeline optimizations
Systematic optimization framework
원문은 최적화를 세 단계로 설명합니다.
| 단계 | 설명 |
|---|---|
| Profile | PyTorch Profiler, TensorFlow Profiler, NVIDIA Nsight 등으로 병목을 찾아요 |
| Select | 병목에 맞는 기법을 고릅니다 |
| Compose | 여러 기법을 조합하되 서로 충돌하지 않게 해요 |
예를 들어 data loading이 40%를 차지한다면 prefetching이 우선이고, memory가 부족하다면 checkpointing이나 mixed precision이 우선입니다. 생산 환경에서는 성능 개선뿐 아니라 구현 복잡도, 모니터링 비용, 안정성, 재현성도 함께 고려해야 해요.
Data prefetching and pipeline overlapping
Prefetching은 다음 batch를 미리 준비하는 기법이에요. GPU가 현재 batch를 계산하는 동안 CPU worker가 다음 batch를 로드하고 전처리합니다.
Overlapping은 여기서 한 걸음 더 나아가 storage fetch, CPU preprocessing, GPU computation을 동시에 굴리는 방식이에요.
시간 t
GPU: batch n 계산
CPU: batch n+1 전처리
Storage: batch n+2 읽기
장점은 GPU idle time을 줄이는 것입니다. 특히 image augmentation이 무겁거나, text tokenization이 CPU-bound이거나, remote storage latency가 큰 경우 효과가 큽니다.
하지만 trade-off도 있어요.
| 장점 | 비용과 위험 |
|---|---|
| GPU utilization 증가 | prefetch buffer가 메모리를 더 씁니다 |
| iteration 사이 대기 시간 감소 | worker 수와 buffer 크기 튜닝이 필요해요 |
| 대규모 데이터에 효과적 | 비동기 로딩으로 debugging이 어려워질 수 있어요 |
| remote storage latency 완화 | 병목이 compute 쪽이면 효과가 작을 수 있어요 |
Mixed-precision training
Mixed precision은 FP32, FP16, bfloat16을 적절히 섞어 쓰는 기법입니다.
| 형식 | 특징 |
|---|---|
| FP32 | 4 bytes, 넓은 범위와 높은 정밀도 |
| FP16 | 2 bytes, 빠르고 작지만 표현 범위가 좁아요 |
| bfloat16 | 2 bytes, FP32와 비슷한 dynamic range를 유지하지만 정밀도는 낮아요 |
Mixed precision의 기본 흐름은 다음과 같아요.
- Forward pass의 큰 matrix multiplication은 FP16이나 bfloat16으로 빠르게 계산해요.
- Backward pass도 많은 연산을 reduced precision으로 처리해요.
- Weight update나 gradient accumulation처럼 민감한 부분은 FP32를 유지해요.
- FP16에서 작은 gradient가 0이 되는 문제를 막기 위해 loss scaling을 사용해요.
Loss scaling은 loss에 큰 값을 곱해 gradient를 표현 가능한 범위로 키운 뒤, update 전에 다시 원래 크기로 되돌리는 방식이에요.
GPT-2 예시에서 mixed precision은 결정적입니다.
| 구성 | 메모리 예시 |
|---|---|
| FP32 baseline | parameter 6GB, activation 약 65GB, gradient 6GB로 총 약 77GB |
| FP16 mixed precision | parameter 3GB, activation 약 32.6GB, gradient 3GB, optimizer state 12GB로 총 약 51GB |
| Mixed precision + checkpointing | activation이 약 8GB로 줄어 총 약 26GB 수준 |
원문은 V100에서 FP16 사용 시 throughput이 크게 증가하고, cost와 iteration 시간을 줄일 수 있다고 설명합니다. 다만 LayerNorm과 Softmax처럼 수치적으로 민감한 연산은 FP32로 처리하는 것이 안정적일 수 있어요.
Mixed precision의 한계도 분명합니다.
- FP16은 dynamic range가 좁아 underflow와 overflow가 생길 수 있어요.
- NaN이나 infinity가 더 자주 나타날 수 있어 debugging이 필요해요.
- Tensor Core 같은 특화 하드웨어가 없으면 효과가 작을 수 있어요.
- 작은 모델에서는 구현 복잡도가 이득보다 클 수 있어요.
Gradient accumulation and activation checkpointing
Gradient accumulation은 큰 batch를 한 번에 올릴 수 없을 때 micro-batch 여러 개의 gradient를 모아 한 번에 update하는 방법이에요.
micro-batch 1 forward/backward
micro-batch 2 forward/backward
micro-batch 3 forward/backward
micro-batch 4 forward/backward
↓
누적 gradient로 parameter update
수학적으로는 gradient가 더해질 수 있기 때문에 큰 batch와 비슷한 효과를 냅니다.
[ \nabla L_{\text{batch}} = \frac{1}{N}\sum_{i=1}^{N}\nabla L(x_i) ]
Activation checkpointing은 모든 activation을 저장하지 않고 일부 지점만 저장한 뒤, backward pass 때 필요한 구간을 다시 forward 계산하는 방법이에요. 메모리를 줄이는 대신 계산량이 늘어납니다.
| 기법 | 줄이는 것 | 늘어나는 것 |
|---|---|---|
| Gradient accumulation | 한 번에 필요한 batch memory | update까지 걸리는 계산 반복 |
| Activation checkpointing | activation memory | recomputation 비용 |
GPT-2 예시에서 per-GPU micro-batch 16, accumulation steps 4, 8 GPUs를 사용하면 global effective batch 512를 만들 수 있어요.
| 항목 | 원문 예시 |
|---|---|
| Per-GPU micro-batch | 16 |
| Accumulation steps | 4 |
| Effective batch per GPU | 64 |
| GPU 수 | 8 |
| Global effective batch | 512 |
이 방식은 32 GPUs를 단순히 쓰는 것보다 통신 횟수를 줄이고 비용도 크게 줄일 수 있다고 설명합니다. 단, accumulation은 update 빈도를 낮추므로 learning rate 조정과 gradient reset 관리가 중요해요.
Checkpointing의 challenge도 있어요. 모델을 어느 구간으로 나눌지 잘못 정하면 recomputation 비용이 커지고, 오류가 backward recomputation 중에 나타나 debugging이 어려워질 수 있습니다.
Single-machine에서 distributed로 넘어가는 조건
원문은 분산 학습이 “있으면 좋은 것”이 아니라 필요한 순간이 있다고 설명해요.
| 신호 | 의미 |
|---|---|
| Memory exhaustion | mixed precision과 checkpointing을 써도 모델, optimizer state, activation이 한 장치에 안 들어가요 |
| Training duration too long | 단일 장치로는 수주, 수개월, 수백 년이 걸릴 수 있어요 |
| Dataset scale too large | 데이터가 단일 머신 storage나 I/O로 감당되지 않아요 |
분산 학습은 새로운 복잡도를 만듭니다. gradient synchronization의 communication overhead, node failure에 대한 fault tolerance, 큰 batch로 인한 optimization dynamics 변화가 생겨요. 원문은 (D)개 device와 (N) parameter가 있을 때 AllReduce가 step마다 대략 (2N(D-1)/D) bytes 수준의 통신을 요구할 수 있다고 설명합니다.
3.6 Distributed systems
Distributed training efficiency metrics
분산 학습에서는 계산만큼 통신이 중요합니다. 원문은 AllReduce가 data parallel training에서 전체 시간의 10-40%를 차지할 수 있고, 더 큰 모델과 더 많은 GPU에서는 overhead가 훨씬 커질 수 있다고 설명해요.
| 지표 | 의미 |
|---|---|
| Communication overhead | gradient 동기화에 쓰는 시간 |
| Bandwidth requirement | 충분한 속도로 tensor를 주고받기 위한 네트워크 요구량 |
| Synchronization frequency | 얼마나 자주 gradient를 맞추는지 |
| Scaling efficiency | GPU를 늘렸을 때 실제 속도가 얼마나 늘었는지 |
| Hardware topology | NVLink, PCIe, InfiniBand 같은 연결 구조 |
보통 2-32 GPUs 구간에서는 높은 효율을 얻기 쉽지만, 64-256 GPUs부터는 communication-bound가 되기 쉽고, 512 GPUs 이상에서는 coordination overhead가 큰 문제가 될 수 있어요.
Data parallelism
Data parallelism은 가장 직관적인 분산 학습 방식이에요. 모든 device가 같은 모델 복사본을 가지고, 서로 다른 data subset을 처리합니다.
각 device (k)가 local gradient (g_k)를 계산하면 global gradient는 다음처럼 평균냅니다.
[ g_{\text{global}} = \frac{1}{N}\sum_{k=1}^{N}g_k ]
이 방식은 mini-batch gradient의 평균 성질 덕분에 single-device training과 수학적으로 연결됩니다.
구현 단계는 다음과 같아요.
- Dataset을 device별로 겹치지 않게 나눠요.
- 각 device가 자기 batch로 forward pass를 수행해요.
- 각 device가 backward pass로 local gradient를 계산해요.
- AllReduce로 gradient를 평균내요.
- 모든 device가 같은 global gradient로 parameter를 업데이트해요.
Data parallelism의 장점은 구현이 상대적으로 쉽고, dataset이 클 때 잘 확장된다는 점이에요. PyTorch DistributedDataParallel 같은 프레임워크가 gradient bucketing, AllReduce, communication overlap을 상당 부분 처리해줍니다.
하지만 한계도 큽니다.
| 한계 | 설명 |
|---|---|
| Communication overhead | 모델이 클수록 gradient 동기화 비용이 커져요 |
| Model memory limit | 각 device가 전체 모델 복사본을 가져야 해요 |
| Scaling efficiency 감소 | device 수가 늘수록 동기화 장벽이 커져요 |
| Heterogeneous hardware 문제 | 느린 device가 전체를 기다리게 만들 수 있어요 |
| Fault tolerance | node failure가 전체 training run을 중단시킬 수 있어요 |
원문의 GPT-2 scaling 예시는 중요한 교훈을 줍니다. single node 안에서 NVLink로 연결된 8 GPUs는 효율적일 수 있지만, 32 GPUs를 여러 node에 걸쳐 단순 data parallel로 확장하면 inter-node communication이 병목이 되어 효율이 크게 떨어질 수 있어요. 이때 gradient accumulation을 함께 쓰는 8 GPU 전략이 더 비용 효율적일 수 있습니다.
Model parallelism
Model parallelism은 모델 자체가 한 device에 들어가지 않을 때 사용합니다. data parallelism처럼 모델 전체를 복사하는 대신, 모델의 layer나 tensor dimension을 여러 device에 나눠요.
| 방식 | 설명 |
|---|---|
| Layer-wise partitioning | 연속된 layer 묶음을 device별로 나눠요 |
| Operator-level partitioning | 한 layer 안의 matrix multiplication이나 attention head를 나눠요 |
| Pipeline parallelism | layer partition 위에 micro-batch를 흘려 device idle time을 줄여요 |
Layer-wise partitioning은 이해하기 쉽지만 device idle time이 생길 수 있어요. 예를 들어 device 1이 앞 layer를 처리하는 동안 device 4는 기다립니다. Pipeline parallelism은 micro-batch를 사용해 device들이 서로 다른 micro-batch를 동시에 처리하게 해서 이 idle time을 줄입니다.
Operator-level parallelism은 transformer에서 attention head를 나누거나 feed-forward layer의 intermediate dimension을 나누는 방식이에요. 메모리 압박을 줄이고 큰 tensor 연산을 분산할 수 있지만, device 간 tensor transfer가 많아질 수 있습니다.
Model parallelism의 가장 큰 장점은 거대한 모델을 학습 가능하게 만든다는 점이에요. 하지만 data dependency와 device 간 activation transfer가 많아서 구현과 debugging이 어렵습니다. Pipeline parallelism에서는 pipeline bubble도 생겨요. (m)개 stage가 있으면 pipeline이 채워지는 동안 앞뒤 device 일부가 놀게 됩니다.
Hybrid parallelism
Hybrid parallelism은 data parallelism과 model parallelism을 조합합니다. 모델도 크고 데이터도 큰 상황에서 필요해요.
예를 들어 거대한 transformer 모델은 layer를 여러 GPU에 나누고, 그런 GPU 그룹을 여러 벌 만들어 서로 다른 data batch를 처리하게 할 수 있습니다.
| 형태 | 설명 |
|---|---|
| Hierarchical hybrid | 먼저 모델을 나누고, 그 partition 묶음을 data parallel로 복제해요 |
| Intra-layer hybrid | attention이나 feed-forward 같은 layer 내부에서 model/data parallel을 섞어요 |
| Inter-layer hybrid | layer마다 다른 parallelism 전략을 적용해요 |
Hybrid parallelism은 가장 큰 모델과 데이터셋을 다룰 수 있는 강력한 방법이지만, 통신 경로가 복잡해지고 workload balancing, memory balancing, fault tolerance, debugging이 모두 어려워집니다.
Parallelism 전략 비교
| 전략 | 가장 잘 맞는 상황 | 주요 병목 | 구현 난이도 |
|---|---|---|---|
| Data parallelism | 모델은 한 device에 들어가고 데이터가 큰 경우 | gradient synchronization | 낮음-중간 |
| Model parallelism | 모델이 한 device에 안 들어가는 경우 | activation transfer, dependency | 높음 |
| Pipeline parallelism | layer를 나눌 수 있고 throughput이 중요한 경우 | pipeline bubble, scheduling | 높음 |
| Hybrid parallelism | 모델과 데이터가 모두 매우 큰 경우 | 복합 통신, balancing | 매우 높음 |
Framework integration
원문은 프레임워크가 분산 학습의 복잡도를 API로 감싸준다고 설명해요.
PyTorch의 단순 data parallel API는 사용이 쉽지만 큰 규모에서 bottleneck이 생길 수 있습니다. DistributedDataParallel은 process group 초기화가 필요하지만 AllReduce 기반으로 더 높은 성능을 냅니다.
Model parallelism은 tensor placement와 device 간 이동을 더 명시적으로 관리해야 해요. Pipeline parallel API나 manual device placement를 통해 구현할 수 있지만, tensor가 장치 사이를 오갈 때 생기는 latency를 고려해야 합니다.
분산 학습 primitive로는 AllReduce, Broadcast, ReduceScatter 같은 collective operation이 중요합니다. NCCL 같은 라이브러리는 이러한 통신을 하드웨어 topology에 맞게 최적화해요.
3.7 Performance optimization
Bottleneck analysis
성능 최적화는 병목 분석에서 시작합니다.
| 병목 유형 | 예시 |
|---|---|
| Computational bottleneck | GPU/TPU가 충분히 활용되지 않거나 병렬화가 비효율적이에요 |
| Memory bottleneck | activation이나 optimizer state가 device memory를 초과해요 |
| Data handling bottleneck | data loading과 preprocessing이 느려 GPU가 기다려요 |
| Communication bottleneck | distributed training에서 gradient sync가 오래 걸려요 |
Profiler는 어디에서 시간이 쓰이는지 보여줍니다. PyTorch Profiler, TensorFlow Profiler, NVIDIA Nsight Systems 같은 도구는 GPU utilization, memory usage, kernel time, communication overhead를 분석하는 데 쓰입니다.
System-level techniques
System-level optimization은 하드웨어와 데이터 흐름을 조정합니다.
- profiling으로 실제 병목을 측정해요.
- Tensor Core, bfloat16, NVLink 같은 hardware feature를 활용해요.
- caching, prefetching, 효율적인 storage format으로 data pipeline을 개선해요.
- accelerator가 기다리지 않도록 CPU, storage, GPU 작업을 겹쳐요.
Software-level techniques
Software-level optimization은 프레임워크와 알고리즘 구현을 개선합니다.
| 기법 | 효과 |
|---|---|
| Fused kernels | 여러 연산을 합쳐 kernel launch와 memory traffic을 줄여요 |
| Dynamic graph execution | 입력에 따라 계산 graph를 유연하게 구성해요 |
| Gradient accumulation | memory limit 안에서 큰 effective batch를 만들어요 |
| Optimized libraries | cuBLAS, cuDNN 같은 라이브러리로 하드웨어 성능을 끌어내요 |
Scale-up strategies
Batch size scaling은 training throughput을 높일 수 있지만, convergence와 generalization에 영향을 줄 수 있어요. 큰 batch를 쓸 때는 learning rate scaling과 warmup schedule이 중요합니다.
Layer freezing은 transfer learning에서 하위 layer를 고정해 메모리와 계산량을 줄이는 전략이에요. 모든 parameter를 매번 업데이트하지 않아도 되는 상황에서는 효율적입니다.
3.8 Hardware acceleration
GPUs
GPU는 현대 AI training의 핵심 장치입니다. 수천 개의 코어로 matrix multiplication을 병렬 처리하고, Tensor Core로 FP16/bfloat16 연산을 빠르게 수행해요.
GPU 기반 학습에서 중요한 요소는 다음과 같습니다.
- dense linear algebra에 강해 forward/backward pass를 가속해요.
- Tensor Core가 mixed precision training을 크게 빠르게 해요.
- NCCL, NVLink 같은 생태계가 multi-GPU gradient synchronization을 돕습니다.
- CUDA, cuDNN, cuBLAS 같은 소프트웨어 스택이 성능을 좌우해요.
원문의 GPT-2 hardware 비교는 최신 GPU가 시간뿐 아니라 전체 비용도 줄일 수 있음을 보여줘요. H100은 시간당 비용이 높더라도 학습 시간이 크게 줄어 총비용이 낮아질 수 있습니다. 긴 학습 run에서는 새로운 GPU가 더 나은 총소유비용을 제공할 가능성이 큽니다.
TPUs
TPU는 deep learning workload에 맞게 설계된 custom accelerator예요. 특히 systolic array 구조를 통해 matrix multiplication의 data movement를 줄이고 throughput을 높입니다.
TPU의 특징은 다음과 같아요.
| 특징 | 의미 |
|---|---|
| Systolic array | processing element 사이로 데이터를 흐르게 하며 행렬 곱을 효율적으로 처리해요 |
| bfloat16 중심 | deep learning gradient의 넓은 dynamic range에 적합해요 |
| TPU pod | 여러 TPU를 묶어 대규모 distributed training을 수행해요 |
| Framework integration | TensorFlow 생태계와 강하게 연결돼요 |
TPU는 BERT, T5 같은 큰 모델 학습에 유용하지만, 생태계 의존성과 접근성, 초기 비용이 한계가 될 수 있습니다. 원문은 AWS Trainium, Intel Gaudi 같은 다른 custom accelerator도 함께 언급해요.
FPGAs
FPGA는 고정된 GPU나 TPU와 달리 하드웨어 구성을 재프로그래밍할 수 있는 장치예요. 특정 workload에 맞춘 dataflow, preprocessing, sparse matrix operation, custom communication pattern을 구현할 수 있습니다.
장점은 유연성과 낮은 latency예요. 하지만 Verilog, VHDL 같은 hardware description language나 특수 도구에 대한 지식이 필요해 진입 장벽이 큽니다. 그래서 원문은 FPGA가 강력하지만 GPU/TPU 생태계만큼 일반 ML practitioner에게 쉽지는 않다고 설명합니다.
ASICs
ASIC은 특정 작업에 맞춰 설계된 전용 칩이에요. 원문은 Cerebras Wafer-Scale Engine을 예시로 설명합니다. 하나의 거대한 wafer-scale chip에 많은 core와 on-chip memory를 배치해, 여러 GPU 사이를 오가는 통신 병목을 줄이려는 접근이에요.
ASIC의 장점은 특정 workload에서 매우 높은 효율과 낮은 data movement입니다. 하지만 범용성이 낮고, 비용과 통합 난이도가 높으며, 다양한 workload를 모두 잘 처리하기는 어렵습니다.
3.9 Fallacies and pitfalls
원문은 training system에서 흔히 생기는 오해도 정리합니다.
| 오해 또는 함정 | 왜 문제인가요? |
|---|---|
| 큰 모델은 항상 더 좋다 | 데이터와 compute가 충분하지 않으면 overfitting, diminishing returns, 비용 폭증이 생겨요 |
| 분산 학습은 자동으로 빨라진다 | 통신과 동기화 비용 때문에 작은 모델은 오히려 느려질 수 있어요 |
| 작은 모델의 learning rate schedule을 큰 학습에 그대로 써도 된다 | 큰 batch와 분산 환경에서는 optimization dynamics가 달라져요 |
| 재현성과 실험 추적은 나중 문제다 | seed, hyperparameter, data order, software version 차이가 결과를 바꿀 수 있어요 |
| 분산 인프라는 단순한 확장이다 | node failure, network partition, synchronization deadlock, heterogeneity를 관리해야 해요 |
3.10 3단계 최종 정리
이 장의 핵심은 training을 수학과 시스템의 결합으로 보는 것입니다.
수학적으로는 loss를 줄이는 parameter optimization이에요. 하지만 시스템적으로는 다음 네 가지를 계속 조율해야 합니다.
- Matrix multiplication 중심의 연산을 accelerator에 맞게 실행해요.
- Activation, gradient, optimizer state가 만드는 메모리 압박을 관리해요.
- Data pipeline이 compute를 굶기지 않도록 throughput을 맞춰요.
- 분산 학습에서는 계산 이득과 통신 비용의 균형을 잡아요.
결국 좋은 training system은 algorithm, framework, hardware가 함께 설계될 때 만들어집니다. 이 장의 모든 기법은 같은 질문으로 돌아와요.
지금 학습을 막고 있는 진짜 병목은 계산인가요, 메모리인가요, 데이터 이동인가요, 통신인가요?
이 질문에 답할 수 있어야 올바른 최적화 기법을 고를 수 있습니다.
복습 질문
1단계 확인 질문
- AI 학습을 “문제를 풀고 채점하고 고치는 과정”에 비유할 수 있는 이유는 무엇인가요?
- GPU가 빠른데도 데이터 파이프라인이 느리면 왜 전체 학습이 느려질까요?
- checkpointing을 “중간 표시만 남기고 필요하면 다시 계산하기”라고 볼 수 있는 이유는 무엇인가요?
- data parallelism과 model parallelism을 일상적인 협업 상황에 비유해 설명해보세요.
2단계 확인 질문
- (\hat{y} = f_\theta(x))에서 (\theta)는 무엇을 의미하나요?
- Gradient descent에서 learning rate가 너무 크거나 너무 작으면 어떤 문제가 생기나요?
- 전체 throughput이 (\min(T_{\text{pipeline}}, T_{\text{compute}}))로 표현되는 이유는 무엇인가요?
- Adam이 SGD보다 더 많은 메모리를 쓰는 이유는 무엇인가요?
- Mini-batch size를 키우면 어떤 장점과 단점이 동시에 생기나요?
3단계 확인 질문
- Matrix-matrix multiplication이 training hardware 설계에 큰 영향을 준 이유는 무엇인가요?
- Activation function은 계산량이 작아 보여도 왜 memory-bandwidth-bound 병목이 될 수 있나요?
- GPT-2 예시에서 activation memory와 optimizer state가 단일 GPU 학습을 어렵게 만드는 과정을 설명해보세요.
- Prefetching과 pipeline overlapping은 각각 어떤 병목을 줄이나요?
- Mixed precision에서 FP16만 쓰지 않고 FP32 master weight나 FP32 accumulation을 유지하는 이유는 무엇인가요?
- Gradient accumulation이 큰 batch와 수학적으로 비슷한 효과를 내는 이유는 무엇인가요?
- Data parallelism에서 AllReduce가 필요한 이유와, 이것이 병목이 되는 이유를 설명해보세요.
- Model parallelism에서 pipeline bubble이 생기는 이유는 무엇인가요?
- Hybrid parallelism이 강력하지만 구현이 어려운 이유를 communication, memory, debugging 관점에서 설명해보세요.
- “분산 학습은 자동으로 빠르다”라는 생각이 왜 위험한 오해인지 원문 내용을 바탕으로 설명해보세요.