제2부 사전학습(Pretraining)
2.3 학습 목표·루프·옵티마이저·LR 스케줄
사전학습의 전부는 하나의 for 루프다. 그 루프가 수천 개 GPU 위에서 몇 주 동안 실행된다. 그리고 그 안에 내재된 몇 개의 스칼라 결정 — 손실을 무엇으로 나누는가, 그래디언트를 여러 마이크로배치에 걸쳐 어떻게 세는가, 배치를 바꿀 때 학습률을 어떻게 함께 옮기는가 — 이 루프가 좋은 모델로 수렴할지, NaN으로 발산할지, 아니면 조용히 컴퓨트의 3분의 1을 버릴지를 가른다. 2.2이 "얼마나 큰 모델을 얼마나 많은 데이터로"를 정했고 1.3가 역전파·AdamW·웜업의 원리를 복습했다면, 이 장은 그 결정들을 실제로 실행하는 루프 자체다 — 수조 토큰 규모에서 무엇이 실전으로 달라지는가.
되풀이하지 않을 것부터 긋자. 교차엔트로피가 무엇인지, Adam이 SGD에서 어떻게 진화했는지, 웜업이 대략 왜 필요한지는 1.3에 있다. 여기서 무게를 싣는 것은 대규모 특유의 결정들이다 — 손실을 토큰 단위로 평균한다는 것의 정확한 의미, 문서를 낭비 없이 텐서에 채워 넣는 패킹, 그래디언트 누적으로 만드는 실효 배치, 임계 배치 크기를 정하는 그래디언트 잡음 규모, 코사인의 경직성을 푸는 WSD, 로짓 폭주를 막는 z-loss, 작은 모델에서 튜닝한 하이퍼파라미터를 큰 모델로 옮기는 muP까지. 등장하는 하이퍼파라미터 값은 공개 레시피에서 흔히 보이는 대표값일 뿐 정답이 아니다 — 값이 무엇을 조절하는지에 무게를 두고, 특정 숫자는 개략 규모로만 받아들이면 된다.
2.3.1 손실이 무엇을 세는가
큰 그림은 1.1·1.3 그대로다 — 다음 토큰을 맞힌다. 달라지는 것은 이제 손실을 하나의 시퀀스가 아니라 한 배치의 수백만 토큰에서 잰다는 것이고, 그 "잰다"의 세부에 함정이 하나 숨어 있다. 배치 $\mathcal{B}$ 가 여러 시퀀스로 이루어지고 시퀀스 $b$ 의 길이가 $T_b$ 라 하자. 인과 언어모델 손실은 배치 안 모든 (시퀀스, 위치) 쌍의 음의 로그가능도를 토큰 총수로 나눈 평균이다.
$$\mathcal{L}(\theta) = -\frac{1}{\sum_{b\in\mathcal{B}} T_b}\ \sum_{b\in\mathcal{B}}\ \sum_{t=1}^{T_b} \log p_\theta\!\left(x^{(b)}_t \mid x^{(b)}_{<t}\right)$$
시선을 둘 곳은 분모다. 분모가 시퀀스 개수가 아니라 토큰 총수라는 것 — 손실은 토큰당 평균이고, 예측 하나가 손실에 동등하게 기여한다. 자연로그를 쓰므로 단위는 nat이며, 지수를 씌우면 1.1의 퍼플렉서티 $\text{PPL}=e^{\mathcal{L}}$ 가 된다.
왜 토큰 평균이어야 하는지는 대안을 실제로 미분해 보면 분명해진다. 만약 시퀀스별로 먼저 평균한 뒤 그 시퀀스 평균들을 다시 평균한다고 하자. 길이 $T_b$ 인 시퀀스는 자기 안의 $T_b$ 개 토큰을 $1/T_b$ 로 가중하므로, 짧은 시퀀스의 토큰 하나는 $1/T_b$ 가 커서 큰 가중을, 긴 시퀀스의 토큰 하나는 작은 가중을 받는다. 그래디언트도 같은 가중으로 섞인다 — 학습 신호가 시퀀스 길이에 반비례해 편향되는 것이다. 웹 코퍼스처럼 문서 길이가 수십에서 수만 토큰까지 세 자릿수로 흩어진 데이터에서 이 편향은 사소하지 않다. 토큰 평균은 이 편향을 없앤다. 예측 하나 = 가중치 하나.
여기서 인과 마스크(1.4)가 손실 밀도를 추가 비용 없이 준다는 점을 다시 다룰 값어치가 있다. 길이 $T$ 시퀀스를 한 번의 순전파에 넣으면 위치 $1..T$ 각각의 다음-토큰 예측이 동시에 나온다 — 토큰이 $T$개면 학습 예제도 사실상 $T$개다. 구현은 입력을 한 칸 이동해 라벨을 만든다.
$$\text{입력}=(x_1,\dots,x_{T-1}),\qquad \text{라벨}=(x_2,\dots,x_{T})$$
각 위치의 로짓(어휘 크기 $V$)과 라벨 토큰으로 교차엔트로피를 구해 전부 더한다. 이 신호 밀도가 디코더-온리 인과 LM이 빈칸의 15%만 학습에 쓰는 마스크드 LM보다 데이터 효율이 좋은 이유의 절반이다.
사전학습에서 손실을 적용하는 대상은 "패딩만 빼고 전부"다. 이는 사후학습과 다르다 — SFT(3.2)에서는 프롬프트 부분의 손실을 마스킹하고 응답 토큰에만 손실을 적용한다. 목표가 "이어 쓰기"가 아니라 "지시에 답하기"이기 때문이다. 지금은 사전학습이므로 실토큰 전부가 대상이고, ignore_index로 패딩만 제외한다.
한 가지 통념을 조용히 깨 두자. "우리 모델은 손실 1.9, 저 모델은 2.1이니 우리가 낫다"는 비교는 두 모델의 토크나이저가 다르면 무의미하다. 토큰당 손실은 토큰이 담는 바이트 수에 의존하기 때문이다. 더 공격적으로 병합해 토큰이 길고 적은 토크나이저는 같은 텍스트를 더 세게 압축하므로, 같은 실력이라도 토큰당 손실이 더 높게 나온다 — 한 토큰이 예측하기 더 어려운 큰 묶음을 담아서다. 토크나이저에 무관한 척도는 바이트당 비트(bits-per-byte, BPB)다.
$$\text{BPB} = \frac{\mathcal{L}}{\ln 2}\times\frac{N_{\text{tok}}}{N_{\text{byte}}}$$
여기서 $\mathcal{L}/\ln 2$ 가 토큰당 비트, $N_{\text{tok}}/N_{\text{byte}}$ 가 토큰-바이트 비(보통 1보다 작다 — 토큰 하나가 여러 바이트). 한 토큰이 평균 4바이트면 이 비가 $0.25$ 이므로, 토큰당 손실이 커 보여도 BPB로 환산하면 비교가 공정해진다. 서로 다른 토크나이저의 모델을 비교하려면 BPB를 쓰고, 퍼플렉서티 숫자만 들이대는 벤치마크 주장은 토크나이저가 같은지부터 의심하라(평가·해석의 세부는 4.1).
2.3.2 시퀀스 패킹 — 토큰을 한 톨도 버리지 않기
원 데이터는 문서(웹페이지·책·코드 파일)의 길이가 제각각이다 — 수십 토큰 길이의도, 수만 토큰 길이의도 있다. 그런데 학습은 고정 길이 컨텍스트 $L$(예: 4096)의 텐서로 실행된다. 문서 하나를 시퀀스 하나에 넣고 $L$까지 패딩하면, 짧은 문서에서 대부분이 패딩이 되어 GPU가 허공을 계산한다.
숫자로 확정하자. 평균 문서가 $L$의 20%, 즉 약 820토큰이라면, 문서당 컨텍스트의 80%가 패딩이다. 순전파·역전파의 FLOP은 패딩 토큰에도 똑같이 든다(어텐션과 FFN이 자리마다 실행된다). 즉 컴퓨트의 80%가 아무것도 배우지 않는 자리에 낭비된다 — 유효 처리량이 5분의 1이다. 사전학습이 컴퓨트로 결정되는(2.2) 작업임을 생각하면 이것은 학습 예산의 80%를 소모해 버리는 것과 같다.
시퀀스 패킹(sequence packing)이 답이다. 토큰화된 문서들을 문서 구분자(보통 EOS)로 이어 붙여 하나의 긴 스트림으로 만들고, 이를 정확히 길이 $L$인 블록으로 잘라 배치를 채운다. 패딩이 (스트림 맨 끝 마지막 블록을 빼면) 거의 0이 되어 토큰 활용률이 100%에 수렴한다. 위의 예에서 유효 처리량이 5분의 1에서 사실상 1로 회복된다.
2.3.2.1 문서 경계 오염과 인트라-도큐먼트 마스킹
패킹에는 대가가 하나 따른다. 한 블록 $L=4096$ 안에 평균 512토큰 길이의 문서가 여덟 개가량 섞여 들어가면, 셀프어텐션이 문서 경계를 넘어 이전 문서를 볼 수 있다 — 블록 뒷부분 문서의 토큰이 같은 블록 앞부분의 무관한 문서를 참조하는 것이다. 아무 의미 없는 두 텍스트를 억지로 잇는 잡음이다. 대응은 두 갈래다.
첫째는 그대로 두는 것이다. 초기 여러 모델은 이어 붙이고 EOS를 약한 경계로만 뒀다. 대규모 데이터에서 이 오염의 평균 영향은 작다고 보고 커널을 단순하게 유지하는 선택이다. 둘째는 인트라-도큐먼트 마스킹(document masking)이다 — 어텐션 마스크를 블록 대각(block-diagonal)으로 만들어 각 토큰이 자기 문서 안만 보게 하고, RoPE 등 위치 인덱스(1.5)도 문서마다 0으로 리셋한다. FlashAttention의 가변 길이(varlen) API가 이 블록 대각 어텐션을 지원한다.
원리적으로는 둘째가 깨끗하고, 부수적으로 어텐션 연산도 준다 — 블록 대각은 전 범위 인과 어텐션보다 계산 쌍이 적기 때문이다. 다만 커널·데이터 파이프라인이 복잡해지고, 실제 성능 이득은 연구마다 엇갈린다(작지만 있다는 보고와 무시할 만하다는 보고가 공존하며 데이터·길이에 의존한다). 경계가 의미를 강하게 담는 도메인일수록 이득이 커지는 경향이 관찰된다 — 짧은 웹 문서 여럿을 섞을 때보다, 롱컨텍스트 학습이나 코드·수학처럼 한 문서 안의 구조가 답에 직결되는 경우에 그렇다.
패킹은 손실 정규화에도 미묘한 영향을 준다. 문서 마스킹으로 일부 위치를 무효화하거나 마지막 블록에 패딩이 남으면, 블록마다 실토큰 수가 조금씩 달라진다. 그러면 2.3.1의 토큰 평균 분모가 블록마다 달라지고, 다음에 볼 그래디언트 누적에서 이 실토큰 수를 정확히 세지 않으면 손실 스케일이 조용히 틀어진다. "손실이 이론값과 살짝 안 맞는다"는 버그의 상당수가 여기서 온다.
2.3.3 학습 루프 한 스텝의 해부
한 최적화 스텝(optimizer step)에서 실제로 무엇이 일어나는지 조립하자. 골격은 1.3의 "순전파→손실→역전파→갱신"이지만, 대규모에서는 그래디언트 누적·클리핑·스케줄·체크포인트가 매 스텝에 개입한다.
의사코드로 옮기면(단일 노드 관점 — 다중 GPU 데이터 병렬은 2.4):
model.train()
optimizer = AdamW(param_groups, # weight decay 대상 분리 (2.3.14)
lr=peak_lr, betas=(0.9, 0.95),
eps=1e-8, weight_decay=0.1)
scheduler = warmup_cosine(optimizer, warmup=2_000,
total=119_000, min_lr_ratio=0.1)
expected_tokens = grad_accum * micro_bsz * L # 완전 패킹 시 스텝당 실토큰 수
for step in range(total_steps):
optimizer.zero_grad(set_to_none=True)
loss_sum, tok_total = 0.0, 0
for _ in range(grad_accum): # K개 마이크로배치 누적
batch = next(data_iter) # 패킹 블록 [micro_bsz, L]
logits = model(batch.inputs) # 순전파
loss = cross_entropy(logits.view(-1, V), batch.labels.view(-1),
ignore_index=PAD, reduction="sum") # 토큰합
(loss / expected_tokens).backward() # 토큰평균 후 역전파(누적)
loss_sum += loss.item(); tok_total += batch.n_real_tokens
grad_norm = clip_grad_norm_(model.parameters(), max_norm=1.0)
optimizer.step()
scheduler.step()
if step % log_every == 0:
log(loss=loss_sum / tok_total, # 실제 토큰평균 손실
lr=scheduler.get_last_lr()[0], grad_norm=grad_norm)
if step % ckpt_every == 0:
save_checkpoint(model, optimizer, scheduler, data_iter, rng, step)
세 곳이 초심자가 미끄러지는 지점이다.
reduction="sum" 후 토큰 수로 나누는 순서. 프레임워크 기본 mean은 "이 텐서의 유효 원소 평균"이라, 마이크로배치마다 실토큰 수가 다르면 누적 시 평균의 평균이 되어 편향된다. 토큰합을 낸 뒤 스텝 전체의 토큰 수로 나눠야 2.3.1의 정의와 정확히 일치한다.
역전파의 누적성. backward()는 그래디언트를 파라미터의 .grad에 더한다(덮어쓰지 않는다). 그래서 zero_grad 없이 $K$번 부르면 $K$개 마이크로배치의 그래디언트가 그대로 쌓인다 — 이 성질이 다음 절 실효 배치의 기계다. 그리고 마이크로배치로 분할하는 근본 이유는 활성값 메모리에 있다. 순전파는 역전파에 쓸 중간 활성값을 층마다 유지하고 있어야 하는데, 이 양이 배치 크기에 비례해 급증한다. 큰 배치 전체를 넣으면 활성값이 GPU를 넘치므로, 작은 마이크로배치로 나눠 활성값을 한 조각씩만 보유하고 그래디언트만 누적한다(활성값을 버리고 역전파 때 다시 계산하는 재계산 기법은 2.4·2.6).
클리핑은 옵티마이저 스텝 앞. $K$개 누적이 끝난 전체 그래디언트에 대해 노름을 재고 자른 뒤에 갱신한다 — 마이크로배치마다 자르면 누적의 의미가 깨진다. 로깅은 세 개면 대부분의 사고를 조기에 검출한다. 손실(내려가는가), 학습률(스케줄이 맞는가), 그래디언트 노름(발산 전조 — 스파이크 감지, 2.6).
2.3.3.1 체크포인트 — 무엇을, 얼마나 자주
수 주에 걸친 학습은 반드시 중단된다 — 하드웨어 고장, 스케줄러의 프리엠션, 발산. 체크포인트는 재개(resume) 가능성의 보험이다. 재현 가능한 재개를 위해 저장할 것은 모델 가중치만이 아니다.
| 저장 대상 | 왜 필요한가 | 크기(개략) |
|---|---|---|
| 모델 파라미터 | 당연 | $N$ |
| 옵티마이저 상태 $\mathbf{m},\mathbf{v}$ | 없으면 Adam이 냉시동(모멘텀 소실) | $2N$(+FP32 마스터 $N$) |
| LR 스케줄러 상태 | 스텝 카운터·현재 LR 복원 | 극소 |
| 데이터로더 위치 | 같은 토큰을 두 번/건너뛰지 않게 | 소 |
| RNG 상태 | dropout·셔플 재현 | 소 |
크기를 실제로 재 보면 주기 결정이 왜 문제가 되는지 보인다. 7B 모델을 FP32로 완전 저장하면 마스터 가중치 $4N=28$ GB에 Adam 상태 $\mathbf{m},\mathbf{v}$ 각 28 GB를 더해 약 84 GB다(연산용 BF16 사본까지 담으면 100 GB에 근접). 이것을 오브젝트 스토리지에 2 GB/s로 쓴다면 스텝을 멈추고 42초가 걸린다. 1000스텝마다 저장하면 42초의 정지가 반복되는데, 7B에선 견딜 만해도 70B로 가면 완전 체크포인트가 약 840 GB, 동기 저장이 7분씩 걸려 못 쓴다. 그래서 실무는 두 가지로 푼다. 완전 체크포인트는 드물게(수천 스텝) 남기고 가중치만은 자주 남기는 절충, 그리고 저장을 백그라운드로 실행하는 비동기·그 상태를 데이터 병렬 랭크 $W$개에 분할해 각자 자기 몫만 병렬로 쓰는 샤딩(벽시계가 $W$로 나뉜다). 분산 샤딩 저장의 세부는 2.4·2.5다. 스토리지 총량도 무시 못 한다 — 1000스텝마다 84 GB를 남기고 119개를 보관하면 10 TB이므로, 오래된 체크포인트는 몇 개만 남기고 지우는 회전 정책이 필요하다.
2.3.4 그래디언트 누적과 실효 배치
대규모 학습이 원하는 배치는 수백만 토큰인데, 그만한 텐서의 활성값은 GPU에 한 번에 안 들어간다. 해법이 그래디언트 누적(gradient accumulation)이다 — 큰 배치를 작은 마이크로배치 $K$개로 분할해, 각각 순전파·역전파해 그래디언트를 누적하고, $K$번째 뒤에 옵티마이저 스텝을 정확히 한 번 밟는다. 수학적으로 이것이 큰 배치 하나로 잰 그래디언트와 (거의) 같은 이유는 그래디언트가 합에 대해 선형이기 때문이다. 손실이 토큰합의 평균이고 미분이 선형 연산이므로,
$$\nabla_\theta \mathcal{L}_{\text{big}} = \frac{1}{K}\sum_{k=1}^{K}\nabla_\theta \mathcal{L}_{\text{micro}}^{(k)}$$
가 정확히 성립한다(정규화 상수만 맞으면). 여기에 데이터 병렬(2.4)까지 곱하면 실효 배치(effective batch)는 세 인자의 곱이다.
$$\underbrace{B_{\text{eff}}}_{\text{시퀀스}} = \underbrace{b_\mu}_{\text{마이크로배치}} \times \underbrace{K}_{\text{누적 횟수}} \times \underbrace{W}_{\text{데이터 병렬 수}},\qquad \text{스텝당 토큰} = B_{\text{eff}} \times L$$
같은 실효 배치를 만드는 조합은 여럿이다. $b_\mu{=}4,\ K{=}8,\ W{=}64$ 와 $b_\mu{=}2,\ K{=}16,\ W{=}64$ 는 둘 다 실효 배치 2048로 같다. 메모리가 부족하면 $b_\mu$를 줄이고 $K$를 늘리면 되며, 결과는 재현성 근사 안에서 동일하다 — 작은 GPU로 큰 배치를 흉내 내는 표준 기법이다. 유일한 대가는 시간이다. $K$를 늘리면 옵티마이저 스텝 하나를 위해 순전파·역전파를 $K$번 직렬로 밟아야 하므로 스텝당 벽시계가 길어진다.
여기 미묘한 버그가 있다. 마이크로배치마다 실토큰 수가 다른데(패킹 잔여·문서 마스킹, 2.3.2) 각 마이크로배치에서 mean 손실을 내어 $K$로 나눠 더하면, 토큰이 많은 마이크로배치가 과소 반영되는 틀린 가중이 된다. 정답은 2.3.3 코드처럼 토큰합을 누적하고 스텝 전체 토큰 수로 한 번에 나누는 것이다. 완전 패킹으로 모든 마이크로배치의 실토큰이 같으면 두 방식이 일치하지만, 그렇지 않으면 손실 곡선이 미세하게 어긋나고 그래디언트도 편향된다.
2.3.5 임계 배치 크기와 그래디언트 잡음 규모
"배치를 얼마나 크게?"는 단순한 튜닝 변수가 아니라 컴퓨트 효율의 핵심 결정이다. 큰 배치의 이점은 셋이다. 그래디언트가 더 많은 표본의 평균이라 잡음이 줄어 더 큰 학습률을 감당하고, 하드웨어를 꽉 채워 행렬곱 효율(MFU)이 오르며, 같은 토큰 예산을 더 적은 옵티마이저 스텝으로 소화해 통신·동기화 오버헤드(2.5)를 줄이고 벽시계를 단축한다.
한계는 이렇다. 배치를 두 배로 키운다고 목표 손실까지의 스텝 수가 절반이 되지는 않는다. 어느 지점까지는 거의 절반이 되지만(잡음 감소가 실질적), 그 지점을 넘으면 그래디언트가 이미 충분히 정확해서 표본을 더 넣어도 방향이 거의 안 바뀐다 — 스텝은 안 줄고 토큰(=컴퓨트)만 더 쓴다.
이 전환점을 정량화한 것이 그래디언트 잡음 규모(gradient noise scale)이고, 그로부터 임계 배치 크기(critical batch size, CBS)가 나온다(McCandlish 등의 경험 모형 — 조건 의존적 경험 법칙이다). 직관은 신호 대 잡음이다. 참 그래디언트 $G$ 와, 표본 하나에서 잰 그래디언트의 공분산 $\Sigma$ 를 생각하면, 잡음 규모는 대략
$$B_{\text{noise}} = \frac{\operatorname{tr}(\Sigma)}{|G|^2}$$
로 정의된다 — 표본 간 분산의 총량을 참 그래디언트 크기의 제곱으로 나눈 것이다. 배치가 $B_{\text{noise}}$ 보다 작으면 잡음이 신호를 압도해, 표본을 늘릴수록 잡음이 줄어 스텝 효율이 거의 비례로 오른다(컴퓨트 효율 구간). 배치가 $B_{\text{noise}}$ 를 넘으면 잡음이 이미 신호에 비해 작아 더 넣어도 이득이 미미하다(데이터 비효율 구간). CBS는 이 둘이 맞먹는 지점이다.
이 그림을 정확한 곡선으로 만들면 실무 관점이 단단해진다. 목표 손실에 도달하는 데 든 옵티마이저 스텝 수 $S$ 와 처리한 예제 수 $E$($=B\cdot S$)를 각각의 극한 $S_{\min}$(무한 배치), $E_{\min}$(무한소 배치)으로 나누면, 경험 모형은 이 둘이 쌍곡선을 그린다고 말한다.
$$\left(\frac{S}{S_{\min}}-1\right)\left(\frac{E}{E_{\min}}-1\right) = 1,\qquad \frac{S}{S_{\min}} = 1 + \frac{B_{\text{crit}}}{B},\quad \frac{E}{E_{\min}} = 1 + \frac{B}{B_{\text{crit}}}$$
여기서 $B_{\text{crit}} = E_{\min}/S_{\min}$ 이 임계 배치 크기다. 정확히 $B=B_{\text{crit}}$ 에서 $S=2S_{\min}$ 이고 $E=2E_{\min}$ — 최소 스텝의 두 배와 최소 데이터의 두 배를 동시에 치르는 균형점이다. 이 관계를 숫자로 실행해 보면 배치 선택이 무엇을 사고파는지 명확해진다. $B_{\text{crit}}$ 가 100만 토큰이라 하자. 배치를 균형점에 두면 스텝은 이상값의 2배, 토큰도 2배다. 배치를 $B=4\,B_{\text{crit}}$(400만 토큰)로 키우면
$$\frac{S}{S_{\min}} = 1+\tfrac14 = 1.25,\qquad \frac{E}{E_{\min}} = 1+4 = 5$$
이 된다 — 스텝은 이상값보다 25%만 더 들지만 토큰(컴퓨트)은 5배가 든다. 배치를 크게 설정하면 벽시계(적은 스텝)를 사는 대신 컴퓨트(토큰)를 지불하는 것이다. 그래서 실무 배치는 보통 CBS 부근에서 약간 위에 둔다 — 시간을 조금 사려고 토큰을 조금 더 쓰는 셈이고, 사전학습의 전형은 수백만 토큰/스텝(대략 2~8M) 규모다.
한 가지 더. $B_{\text{crit}}$ 는 상수가 아니라 학습 중 커진다. 손실이 내려갈수록 참 그래디언트 $|G|$ 가 작아지고 분자 $\operatorname{tr}(\Sigma)$ 는 상대적으로 덜 줄어, 잡음 규모가 후반으로 갈수록 커진다. 그래서 후반에는 더 큰 배치가 정당화되고, 배치를 학습 중 점진적으로 키우는(batch ramp) 레시피가 이 관찰에 근거한다(구현·데이터에 의존).
곡선은 파레토 전선이다. 왼쪽 위(작은 배치·많은 스텝)에서 오른쪽 아래(큰 배치·많은 토큰)로 갈 때, 무릎 근처가 CBS이고 "스텝 수와 토큰 수를 함께 적당히 줄이는" 균형점이다.
2.3.6 배치와 학습률의 결합
배치가 커지면 그래디언트 잡음이 줄어 더 큰 학습률을 감당한다. 두 가지 경험 규칙이 회자되는데, 둘 다 물리 법칙이 아니라 휴리스틱이다. 선형 스케일링 $\eta \propto B$ 는 SGD·비전에서 자주 쓰였고, 제곱근 스케일링 $\eta \propto \sqrt{B}$ 는 Adam 계열·대규모 LM에서 더 자주 인용된다.
왜 Adam에서 제곱근인지는 잡음이 배치로 어떻게 줄어드는지에서 나온다. 표본 $B$개를 평균한 그래디언트 추정의 표준편차는 $1/\sqrt{B}$ 로 준다. Adam은 스텝을 2차 모멘트의 제곱근, 즉 그래디언트의 RMS로 나눠 정규화하므로, 갱신의 신호 대 잡음비가 대략 $\sqrt{B}$ 에 비례해 좋아진다. 같은 안정성을 유지하면서 학습률을 이 개선분만큼 키울 수 있으니 $\eta \propto \sqrt{B}$ 가 나온다. SGD는 갱신이 그래디언트에 선형이라 잡음 억제 방식이 달라 선형 규칙이 더 맞는다.
어느 규칙도 맹신하면 다친다. 배치를 크게 바꾸면 학습률만이 아니라 웜업도 함께 다시 튜닝해야 하고, CBS를 넘어선 영역에서는 배치를 키워도 최적 LR이 더는 오르지 않는다. "배치만 키우고 LR은 그대로"와 "LR을 배치에 선형 비례로 무작정" 둘 다 발산이나 정체의 흔한 원인이다(2.6). 배치·모델·LR을 함께 옮기는 원리적 방법이 이 장 끝의 muP다.
2.3.7 왜 AdamW인가 — 이질적 그래디언트를 길들이기
거의 모든 현대 LLM 사전학습은 AdamW를 쓴다. 이유를 트랜스포머를 순수 SGD로 학습해 보면 뼈저리게 알게 된다 — 매우 어렵다. 원인은 파라미터마다 그래디언트 스케일이 극단적으로 다르다는 데 있다. 임베딩, LayerNorm/RMSNorm 게인, 어텐션 투영, FFN의 큰 행렬이 서로 자릿수가 다른 크기의 그래디언트를 낸다. 단일 학습률의 SGD로는 큰 그래디언트를 내는 파라미터에 맞추면 작은 쪽이 안 움직이고, 작은 쪽에 맞추면 큰 쪽이 발산한다.
Adam은 2차 모멘트 $\mathbf{v}$ 로 각 파라미터의 스텝을 자기 그래디언트 크기로 정규화해, 하나의 학습률로도 이질적인 지형을 함께 내려간다. 결과적으로 갱신의 크기가 그래디언트의 절대 크기와 거의 무관해진다 — 이 성질은 다음 절에서 정확히 지적한다. 임베딩처럼 드물게 갱신되는(희소 그래디언트) 파라미터에도 강하다. 이 적응성이 "트랜스포머 = AdamW"를 사실상 표준으로 만들었다.
2.3.8 AdamW 하이퍼파라미터 읽기
갱신식부터 세우자. 그래디언트 $\mathbf{g}_t$ 에 대해 1차·2차 모멘트를 지수이동평균으로 갱신하고, 편향 보정을 거쳐 갱신한다.
$$\mathbf{m}_t = \beta_1\mathbf{m}_{t-1} + (1-\beta_1)\mathbf{g}_t,\qquad \mathbf{v}_t = \beta_2\mathbf{v}_{t-1} + (1-\beta_2)\mathbf{g}_t^2$$ $$\hat{\mathbf{m}}_t = \frac{\mathbf{m}_t}{1-\beta_1^t},\quad \hat{\mathbf{v}}_t = \frac{\mathbf{v}_t}{1-\beta_2^t},\qquad \theta_t = \theta_{t-1} - \eta\!\left(\frac{\hat{\mathbf{m}}_t}{\sqrt{\hat{\mathbf{v}}_t}+\epsilon} + \lambda\,\theta_{t-1}\right)$$
편향 보정 $1/(1-\beta^t)$ 이 왜 필요한지부터. $\mathbf{m}_t$ 는 0에서 시작하는 가중합이라 초기에는 참 평균을 과소평가한다 — $t=1$ 이면 $\mathbf{m}_1=(1-\beta_1)\mathbf{g}_1$ 로 참값의 $(1-\beta_1)$ 배밖에 안 된다. $1-\beta_1^t$ 로 나누면 이 초기 축소가 정확히 상쇄되어, 첫 스텝부터 추정이 편향 없이 시작한다. $\mathbf{v}$ 도 마찬가지다.
이 갱신의 핵심 성질 하나를 명시하자. 안정 상태에서 $\hat{\mathbf{m}}/\sqrt{\hat{\mathbf{v}}}$ 는 그래디언트가 일관되면 대략 $\pm 1$, 잡음이 크면 그보다 작은 크기다 — 그래디언트의 절대 크기가 분자·분모에서 상쇄되기 때문이다. 그래서 파라미터당 갱신의 크기가 대략 $\eta$ 로 상한이 정해진다. 그래디언트가 갑자기 100배 커져도 스텝은 폭발하지 않는다는 뜻이고, 이 자기 정규화가 Adam이 SGD보다 안정적인 이유의 절반이다(나머지 절반은 클리핑, 2.3.14).
| 하이퍼파라미터 | 흔한 값 | 의미·조율 능력 |
|---|---|---|
| $\beta_1$ | $0.9$ | 1차 모멘트(모멘텀)의 기억 길이. 거의 조정하지 않는다. |
| $\beta_2$ | $0.95$ (LLM), $0.999$(일반) | 2차 모멘트의 기억 길이. LLM은 흔히 0.95로 낮춘다. |
| $\epsilon$ | $10^{-8}$ (때로 $10^{-5}$) | 0 나눗셈 방지. BF16·FP8에서 안정성 위해 키우기도. |
| $\lambda$ (weight decay) | $0.1$ | AdamW의 분리형 감쇠. 대상 선정이 중요(2.3.14). |
| $\eta$ (peak LR) | 모델 크기 의존 | 최중요 조정 변수. 스케줄·배치와 함께 결정(2.3.6·2.3.11). |
$\beta_2$ 를 0.95로 낮추는 이유가 손실 스파이크(2.6)와 직결되므로 풀어 두자. $\mathbf{v}$ 는 최근 그래디언트 제곱의 평균, 즉 스텝 크기를 조절하는 분모다. $\beta_2$ 가 클수록(0.999) $\mathbf{v}$ 가 긴 과거를 기억해 천천히 변한다. 그런데 어느 순간 나쁜 배치가 큰 그래디언트를 내면, $\mathbf{v}$ 는 아직 과거의 작은 값에 머물러 있어 분모가 작고, $\hat{\mathbf{m}}/\sqrt{\hat{\mathbf{v}}}$ 가 순간적으로 급등해 파라미터를 크게 갱신해 손실 스파이크가 난다. $\beta_2$ 를 0.95로 낮추면 $\mathbf{v}$ 가 최근 그래디언트를 더 빨리 반영해 이 지연이 줄고, 큰 그래디언트가 오면 분모도 곧바로 커져 스텝이 덜 급등한다. 대가는 $\mathbf{v}$ 추정이 더 시끄러워지는 것이라, 안정성과 잡음 사이의 절충이다. 그래서 짧은 학습이나 큰 배치처럼 스파이크가 걱정되는 설정에서 특히 0.95를 쓴다.
이 값들이 관습이지 보편 최적은 아니라는 점을 문장 안에서 지키자. 어떤 공개 레시피는 $\beta_2{=}0.98$ 을, 또는 $\epsilon{=}10^{-15}$ 처럼 전혀 다른 값을 쓴다. 무게는 "이 파라미터가 무엇을 조절하는가"에 있고, 특정 값은 자기 모델·데이터·정밀도에서 재튜닝할 출발점일 뿐이다.
이름의 W, 즉 분리형(decoupled) weight decay가 왜 중요한지도 한 번 살펴보자. 순정 Adam에 L2 정규화를 넣으면 감쇠 항이 그래디언트에 섞여 들어가 $\sqrt{\mathbf{v}}$ 로 나뉜다 — 그러면 그래디언트가 큰(따라서 $\mathbf{v}$ 가 큰) 파라미터는 감쇠가 약해지고, 작은 파라미터는 세진다. 정규화의 세기가 파라미터마다 제멋대로가 되는 것이다. AdamW는 감쇠를 적응적 분모 바깥에 두어($\lambda\theta_{t-1}$ 를 갱신식에 직접 더함) 모든 파라미터가 $\eta\lambda$ 라는 같은 비율로 줄어들게 한다. "Adam + L2"와 "AdamW"가 다른 모델을 낸다는 사실이 여기서 온다.
2.3.9 옵티마이저 상태 메모리 — 파라미터보다 큰 비용
AdamW의 대가는 메모리다. 파라미터마다 $\mathbf{m},\mathbf{v}$ 두 상태를 추가로 들고, 혼합정밀도(2.6)에서는 보통 이 상태들과 FP32 마스터 가중치를 FP32로 유지한다. 7B 모델의 정적 메모리(활성값 제외)를 바이트로 다 세어 보자.
| 항목 | 정밀도 | 크기 |
|---|---|---|
| 파라미터(연산용) | BF16 | $2N=14$ GB |
| 그래디언트 | BF16 | $2N=14$ GB |
| FP32 마스터 가중치 | FP32 | $4N=28$ GB |
| Adam $\mathbf{m}$ | FP32 | $4N=28$ GB |
| Adam $\mathbf{v}$ | FP32 | $4N=28$ GB |
| 합계 | ≈ 112 GB |
파라미터당 16바이트, 총 $16N$ 이다. 옵티마이저 상태($\mathbf{m}+\mathbf{v}$)만 56 GB로 파라미터 자체($2N$)의 네 배다. 비교하자면 같은 7B를 BF16으로 추론만 하면 가중치 14 GB면 된다 — 학습의 정적 메모리는 그 8배다. 그러니 80 GB GPU 한 장으로는 7B조차 이 정적 메모리로 부족하고, 거기에 마이크로배치의 활성값이 더해진다. 이 상태를 여러 GPU로 샤딩하는 것이 ZeRO/FSDP의 1차 동기다(2.4). 그래디언트를 FP32 버퍼에 누적하는 변형은 여기에 $2N$ 을 더 추가한다. 정밀도·마스터 가중치의 세부는 2.6.
2.3.10 대안 옵티마이저
AdamW의 메모리나 계산을 줄이거나 성능을 노린 대안들이 있다. 다만 AdamW가 여전히 검증된 기본값이고, 아래는 대체로 연구·신흥이라는 점을 전제로 읽어야 한다.
| 옵티마이저 | 아이디어 | 장점 | 유의 |
|---|---|---|---|
| Lion | 부호(sign) 기반 모멘텀 업데이트, 상태 1개 | 옵티마이저 메모리 절반($\mathbf{m}$만) | LR·wd를 다르게 튜닝해야, 안정성 보고 엇갈림 |
| Adafactor | 2차 모멘트를 행·열로 인수분해 | 큰 임베딩·행렬 메모리 절감 | 순정 Adam보다 불안정할 수 있음 |
| Sophia | 대각 헤시안 근사(준2차) | 스텝 수 절감 주장 | 재현·범용성 미확립 |
| Shampoo/Muon 계열 | 행렬 전처리(preconditioner) | 수렴 빠르다는 보고 | 계산·구현 비용, 검증 진행 중 |
큰 배치·큰 모델에서 이들이 AdamW를 넘는지는 재현·조건에 의존해 아직 논쟁적이다. 실전 기본은 AdamW로 두고, 대안은 메모리가 실제 병목이거나(예: 임베딩이 거대할 때 Adafactor) 특정 설정에서 명확한 이득을 재현했을 때 고른다.
2.3.11 학습률 스케줄 — 웜업, 그리고 왜 상수로 두지 않나
학습률을 상수로 두는 사전학습은 드물다. 전형은 웜업 + 감쇠의 조합이다. 웜업은 처음 수백~수천 스텝 동안 LR을 0에서 피크까지 선형으로 높인다. 이유가 셋 겹친다.
초기 그래디언트가 크고 거칠다. 파라미터가 무작위라 첫 순전파부터 손실과 그래디언트가 크게 변동하는데, 처음부터 큰 LR이면 이 변동에 실려 발산하기 쉽다. 둘째, Adam의 2차 모멘트가 냉시동이다. 몇 스텝 안 지난 $\mathbf{v}$ 는 소수 표본의 추정이라 분산이 크고, 편향 보정이 평균의 축소는 고쳐도 이 높은 분산까지 없애지는 못한다 — 운 나쁘게 작게 추정된 $\mathbf{v}$ 가 분모에 들어가면 초기 스텝이 과하게 커진다. 웜업이 LR을 낮게 유지하는 동안 $\mathbf{v}$ 가 데워져 신뢰할 만해진다. 셋째, 큰 배치일수록 웜업이 더 중요하다 — 큰 배치·큰 LR 조합은 초기 불안정이 크기 때문이다. 웜업 길이는 흔히 총 스텝의 0.5~4% 수준이다.
2.3.11.1 코사인 감쇠와 그 경직성
피크에 도달한 뒤 LR을 코사인 곡선으로 최소값까지 부드럽게 낮춘다. 총 스텝 $T$, 웜업 $t_w$, 피크 $\eta_{\max}$, 최소 $\eta_{\min}$ 일 때,
$$\eta_t = \eta_{\min} + \tfrac{1}{2}\left(\eta_{\max}-\eta_{\min}\right)\left(1 + \cos\!\left(\pi\,\frac{t - t_w}{T - t_w}\right)\right)$$
$\eta_{\min}$ 은 흔히 피크의 10%(또는 0)로 둔다 — 끝까지 완전히 0으로 내리기보다 소량을 남겨 후반 미세 조정이 멈추지 않게 하는 편이 흔하다. 코사인이 잘 통하는 직관은 담금질(annealing)에 가깝다. 초반의 높은 LR은 높은 "온도"로 손실 지형을 넓게 탐색하고, 서서히 식으며 좁은 골로 안착한다.
코사인의 약점은 총 스텝 $T$ 를 미리 명시해야 한다는 것이다. 이것이 단순한 불편이 아니라 실전에서 두 번 문제가 된다. 첫째, 학습을 예정보다 더 늘리고 싶어도 곡선을 매끄럽게 이어 붙이기 어렵다 — 이미 최소로 내려간 LR을 다시 높여 이어가면 손실이 급등한다. 둘째, 스케일링 법칙(2.2)을 만들려고 "이 데이터로 X스텝 학습하면 손실이 얼마"를 여러 길이에서 재려 할 때, 코사인 실행의 중간 체크포인트는 그 짧은 길이의 최적 모델이 아니다 — 그 지점의 LR은 훨씬 먼 $T$ 를 겨냥해 스케줄된 값이라 아직 높기 때문이다. 즉 코사인으로 여러 길이의 데이터점을 얻으려면 길이마다 별도 실행을 실행해야 한다. 이 두 경직성이 다음 WSD를 낳았다.
2.3.11.2 WSD — Warmup-Stable-Decay
WSD는 스케줄을 세 국면으로 나눈다 — 웜업, 긴 상수 구간(stable, 피크 LR 유지), 짧고 빠른 감쇠(decay). 코사인과 달리 상수 구간은 원하는 만큼 길게 이어갈 수 있고, "여기까지 마감하겠다" 싶을 때 막판에만 급감쇠해 손실을 크게 낮춘다.
이 구조가 코사인의 두 약점을 정확히 뒤집는다. 총 길이를 미리 명시할 필요가 없어 상수 구간의 아무 지점에서나 감쇠를 시작해 여러 크기의 최종 모델을 하나의 실행에서 뽑을 수 있다(감쇠 직전 체크포인트에서 분기). 지속학습이나 데이터 커리큘럼과도 잘 맞는다. 감쇠 구간에서 손실이 눈에 띄게 급락하는 현상이 보고되는데(MiniCPM 등 — 연구 관찰이며 조건 의존), 담금질 관점에서 보면 오래 탐색하던 상태를 마지막에 빠르게 식혀 골짜기로 수렴시키는 것으로 읽힌다. 감쇠 형태는 선형·코사인·"1−sqrt" 등을 쓰고, 감쇠 길이는 총 스텝의 10~20% 정도가 흔하다.
피크 LR과 최소 LR을 정하는 실무 기준은 이렇다. 피크는 모델 크기와 배치에 함께 스케일한다 — 폭 $d_{model}$ 이 클수록 최적 피크 LR이 작아지는 경향이라 대략 $\eta \propto 1/\sqrt{d_{model}}$ 로 줄인다는 경험칙이 흔하고(다음 절 muP가 이를 원리적으로 만든다), 배치 쪽은 2.3.6의 $\eta \propto \sqrt{B}$ 이되 CBS를 넘으면 더 높여도 이득이 없다. 최소 LR은 피크의 0~10%. 스케줄을 고를 때는, 총 예산이 확정되고 산출물이 하나면 코사인이 검증된 단순한 기본이고, 지속학습이거나 여러 크기를 뽑아야 하거나 언제 멈출지 미정이면 WSD의 유연성이 값어치를 하며, 안정성이 극도로 걱정되면 웜업을 길게 설정하고 $\beta_2$·$\epsilon$·클리핑을 함께 강화한다(2.3.14, 2.6).
2.3.12 안정 장치 — 클리핑, 감쇠 대상, z-loss
대규모 학습은 드물지만 치명적인 사고(손실 스파이크·발산)와 늘 싸운다. 세 가지 저비용 안정 장치가 표준이다.
간헐적으로 나타나는 거대한 그래디언트(나쁜 배치·수치 이상)가 한 방에 파라미터를 튕겨 발산시킨다. 그래디언트 클리핑(global norm clipping)은 전체 그래디언트 벡터의 노름이 임계 $c$ 를 넘으면 전부 줄인다.
$$\mathbf{g} \leftarrow \mathbf{g}\cdot\min\!\left(1,\ \frac{c}{\lVert \mathbf{g}\rVert_2}\right)$$
전체(global) 노름을 쓰는 것이 핵심이다 — 파라미터별로 따로 자르면 각 파라미터가 다른 비율로 줄어 그래디언트 방향이 왜곡된다. global norm은 모든 파라미터를 같은 스칼라로 곱하므로 방향을 보존한 채 크기만 줄인다. 임계값은 흔히 $c=1.0$ 이다. 평상시엔 노름이 $c$ 아래라 클리핑이 발동 안 하고, 스파이크 순간에만 개입한다. 그래서 로깅한 그래디언트 노름이 자주 $c$ 에 붙어 있으면 LR이 너무 크거나 데이터에 문제가 있다는 신호로 읽는다.
AdamW의 weight decay $\lambda$ 는 모든 파라미터에 거는 것이 아니다. 2D 가중치 행렬(어텐션 투영·FFN의 $W$)에는 걸고, 편향(bias), LayerNorm/RMSNorm의 게인·시프트, 그리고 종종 임베딩에는 빼는 편이다. 이들에 감쇠를 적용하면 정규화 스케일이 0으로 끌려가 표현이 망가지거나 학습이 나빠진다 — 정규화 게인이 0이 되면 그 층의 출력이 소멸한다. 구현은 파라미터 그룹을 둘로 나눠 한쪽만 $\lambda>0$ 을 준다. "전부에 wd"는 흔한 미묘 버그다.
decay, no_decay = [], []
for name, p in model.named_parameters():
if p.ndim >= 2 and "embed" not in name: # 2D 가중치만 감쇠
decay.append(p)
else: # bias·norm·임베딩은 제외
no_decay.append(p)
param_groups = [{"params": decay, "weight_decay": 0.1},
{"params": no_decay, "weight_decay": 0.0}]
세 번째가 z-loss다. 학습이 길어지면 로짓의 절대 크기가 서서히 커져, softmax 정규화자 $Z=\sum_j e^{z_j}$ 의 로그가 표류한다. 이는 특히 BF16에서 수치 불안정과 손실 스파이크로 이어진다 — 큰 로짓은 $\exp$ 에서 표현 범위를 압박하고, $\log Z$ 가 커지면 반올림 오차가 손실에 실린다. z-loss는 이 정규화자가 1 근처(즉 $\log Z \approx 0$)에 머물도록 작은 보조 손실을 더한다.
$$\mathcal{L}_{\text{total}} = \mathcal{L}_{\text{CE}} + \alpha\,(\log Z)^2,\qquad \alpha \approx 10^{-4}$$
$\log Z$ 가 커지려는 압력에 이차식으로 제동을 걸어 로짓 폭주를 억제한다(PaLM 등에서 사용 보고 — 실무 관행). 비슷한 목적의 다른 장치로 어텐션 로짓을 정규화하는 QK-norm 등이 있는데, 셋 다 "어딘가의 크기가 조용히 부풀어 수치를 깨는" 같은 병에 대한 다른 처방이다. 여기서는 무엇을 막는지까지만 두고, 정밀도·발산과 얽힌 본격 동작은 2.6에서 다룬다.
2.3.13 muP — 하이퍼파라미터를 큰 모델로 옮기기
문제는 돈이다. 학습률·초기화·각종 배수는 성능을 크게 가르는데, 목표 크기(수백억~수천억 파라미터) 모델에서 직접 튜닝하는 것은 불가능하다 — 한 번 실행하는 데 수십만 달러가 든다. 작은 모델에서 튜닝해 큰 모델로 옮길 수 있다면?
muP(Maximal Update Parametrization, Tensor Programs V·Yang 등)가 이를 노린다(연구 주장). 아이디어는 초기화 분산·학습률·층별 배수를 폭(width)에 따라 특정 방식으로 스케일하도록 재매개변수화하면, 최적 하이퍼파라미터가 폭에 근사적으로 불변해진다는 것이다. 그러면 작은 프록시 모델에서 LR 등을 튜닝하고, 그 값을 큰 모델로 그대로 전이(μTransfer)한다.
스케일 규칙의 골자는 폭 $d$ 가 커질 때 각 층이 기여하는 활성값 변화를 $O(1)$ 로 유지하는 것이다. 은닉층 가중치는 초기화 분산을 팬인에 반비례($\propto 1/d$)로 두고, Adam에서는 그 층의 학습률을 폭에 반비례($\propto 1/d$)로 줄이며, 출력(언임베딩) 로짓에는 $1/d$ 배수를 곱해 폭이 커져도 로짓이 커지지 않게 한다. 이렇게 맞추면 폭을 키워도 최적 피크 LR이 거의 그 자리에 머문다 — 2.3.11에서 본 "$\eta \propto 1/\sqrt{d}$" 같은 민간 규칙은 이 원리를 대략 흉내 낸 근사일 뿐이고, 정확한 지수는 어느 파라미터를 어떻게 스케일하느냐에 달렸다. 구현이 제대로 됐는지는 폭을 바꿔 가며 각 층 활성값의 크기가 유지되는지 보는 좌표 점검(coordinate check)으로 확인한다.
muP는 강력하지만 범용 해법이 아니고, 그 한계를 정직하게 두는 편이 실전에 낫다. 이론이 명료한 것은 주로 폭 전이다 — 깊이(depth) 전이는 더 취약하고 별도 처방이 필요하며 연구가 진행 중이다. 실제 이득은 구현 정확도에 민감해서, 배수·초기화·옵티마이저 상호작용을 정확히 맞추지 못하면 오히려 손실을 본다. 그리고 "완전한 무재튜닝 전이"가 항상 성립한다는 보장은 없다 — 근사이며 데이터·배치·스케줄과도 얽힌다. 대안이나 보완으로, 여러 작은 크기에서 최적 HP를 재고 스케일링 법칙으로 외삽하는 접근(2.2)도 쓰인다. 어느 쪽이든 메시지는 같다 — 큰 모델의 하이퍼파라미터는 큰 모델에서 찾지 말고, 작은 모델과 원리적 스케일 규칙으로 옮겨라.
2.3.14 수계산 — 실효 배치부터 총 스텝까지
숫자로 끝까지 실행해 이 장의 결정들을 한자리에 모으자(모두 설명용 개략값이다). 목표는 1조(1T) 토큰으로 사전학습하는 것이고, 설정은 다음과 같다.
| 항목 | 값 |
|---|---|
| 컨텍스트 길이 $L$ | 4096 토큰 |
| 마이크로배치 $b_\mu$ (GPU당 시퀀스) | 4 |
| 그래디언트 누적 $K$ | 8 |
| 데이터 병렬 GPU 수 $W$ | 64 |
| 토큰 예산 $D$ | $1\times10^{12}$ |
실효 배치는 세 인자의 곱이다.
$$B_{\text{eff}} = b_\mu \times K \times W = 4 \times 8 \times 64 = 2048\ \text{시퀀스}$$
스텝당 토큰은 여기에 컨텍스트를 곱한다.
$$\text{tokens/step} = B_{\text{eff}} \times L = 2048 \times 4096 = 8{,}388{,}608 \approx 8.39\text{M 토큰}$$
배치가 약 8.4M 토큰으로 사전학습의 전형 범위(수 M) 안이고, 2.3.5의 CBS 논의에 비추면 대개 임계 부근~약간 위다. 총 옵티마이저 스텝은 예산을 스텝당 토큰으로 나눈다.
$$T = \frac{D}{\text{tokens/step}} = \frac{1\times10^{12}}{8.39\times10^{6}} \approx 119{,}210 \approx 119\text{k 스텝}$$
웜업을 2000스텝으로 두면 총의 약 1.7%로 0.5~4% 범위 안이다. 체크포인트를 1000스텝마다 남기면 약 119개의 완전 체크포인트가 되는데, 각각 7B·FP32 상태 기준 약 84 GB이므로(2.3.3.1) 그대로 보관하면 10 TB이고, 동기 저장이면 스텝을 42초씩 세우므로 비동기·샤딩·회전 정책이 필요하다.
이제 메모리가 부족할 때를 보자. GPU가 $b_\mu{=}4$ 를 못 담으면 $b_\mu{=}2,\ K{=}16$ 으로 바꿔도 실효 배치·토큰/스텝·총 스텝이 그대로 2048 / 8.39M / 119k다 — 마이크로배치는 메모리에 맞추고 실효 배치는 누적·병렬로 지킨다(2.3.4). 다만 $K$ 가 두 배가 됐으니 스텝당 순전파·역전파를 16번 직렬로 밟아 스텝당 벽시계는 길어진다.
반대로 배치를 절반(약 4.2M 토큰)으로 줄이면 스텝당 토큰이 반이 되어 총 스텝이 약 238k로 두 배가 된다. CBS 아래 구간이었다면 스텝당 진도가 좋아 전체 토큰은 비슷하게 유지되지만, CBS를 넘는 영역이었다면(2.3.5의 쌍곡선에서 오른쪽) 배치를 줄여도 최종 손실은 크게 안 바뀌고 벽시계 시간만 는다. "배치 = 스텝 수와 컴퓨트·시간의 교환"이라는 관점을 이 계산으로 확정해 두면 된다.
마지막으로 이 장의 배치·스텝이 총 컴퓨트를 정하지 않는다는 점을 명시하자. 사전학습 총 연산은 대략 $C \approx 6ND$(2.2)로 파라미터 수 $N$ 과 토큰 예산 $D$ 가 결정한다. $D{=}10^{12}$ 는 고정이므로 총 컴퓨트 $C$ 는 배치를 어떻게 설정하든 같다 — 배치·누적·병렬은 그 정해진 컴퓨트를 어떤 입자 크기로, 몇 번의 스텝에 나눠 소화하느냐, 그래서 벽시계와 안정성이 어떻게 되느냐를 정할 뿐이다.
이 루프가 단일 노드를 넘어서는 순간이 다음 장의 출발점이다. 옵티마이저 상태 112 GB와 활성값이 GPU 한 장을 넘으면, 실효 배치의 $W$ 인자였던 데이터 병렬에 더해 텐서·파이프라인·전문가 병렬과 ZeRO/FSDP로 파라미터·그래디언트·상태를 여러 GPU에 분할해야 한다(2.4). 그 인프라·인터커넥트·체크포인트 분산은 2.5가, 이 장에서 맛본 손실 스파이크·발산과 혼합정밀도의 본격 대응은 2.6가 이어 받는다.