DevOps··2분 읽기·0

8. 학습: 30억 개의 숫자가 조정되는 과정

LLM의 30억 개 파라미터가 만들어지는 과정. 자기지도 학습으로 학습 데이터를 자동 생성하고, 역전파로 gradient를 구하고, 극도로 미세한 업데이트를 수조 번 반복하는 과정.

글꼴

1~7편에서 추론(inference) 과정을 전부 다뤘다. 토크나이저, 임베딩, 어텐션, FFN, 인과적 마스킹, KV 캐시, 샘플링까지. 이 모든 과정을 가능하게 하는 건 파라미터다. 3B 모델이면 30억 개, 7B면 70억 개의 숫자.

이 숫자들은 어떻게 만들어진 걸까?


학습 데이터 — 사람이 태깅하지 않는다

LLM 학습의 핵심은 "자기지도 학습"이다. 사람이 정답을 하나하나 달아주지 않는다.

원본 텍스트: "OOM killer가 nginx를 종료시켰다"
 
자동으로 학습 샘플 생성 (자기지도 학습):
 
  입력                              -> 정답
  [OOM]                             -> killer
  [OOM] [killer]                    -> 가
  [OOM] [killer] [가]               -> nginx
  [OOM] [killer] [가] [nginx]       -> 를
  [OOM] [killer] [가] [nginx] [를]  -> 종료시켰다
 
한 문장 -> 5개 학습 샘플 자동 생성.
인터넷 전체 -> 수조 개 학습 샘플.
사람 없이 대규모 학습 가능한 이유.

한 문장에서 자동으로 여러 개의 학습 샘플이 만들어진다. 인터넷 전체 텍스트를 이렇게 처리하면 수조 개의 학습 데이터가 생긴다. 사람이 라벨링할 필요가 없으니까 스케일이 가능하다.


순전파 -> 손실 계산

학습 과정은 이렇다. 입력을 넣고, 모델이 현재 파라미터(W)로 예측하고, 정답과 비교해서 얼마나 틀렸는지 측정한다.

입력: "OOM killer가 nginx"
모델이 현재 W로 예측:
 
  "를"    ->  8%
  "는"    -> 21%  <- 모델의 예측
  "서버"  -> 11%
  ...
 
정답: "를" (8%)
 
손실 = -log(정답의 확률) = -log(0.08) = 2.53  <- 꽤 틀림
 
정답 확률 95% -> 손실 0.05 (거의 맞음)
정답 확률 0.1% -> 손실 6.9 (크게 틀림)

손실(loss)은 "모델이 정답에 부여한 확률"의 -log다. 정답 확률이 높을수록 손실은 작고, 낮을수록 손실은 크다. 이 손실을 줄이는 방향으로 파라미터를 조정하는 게 학습이다.


역전파 — 어떤 숫자를 얼마나 바꿔야 하는가

손실 2.53을 줄이려면 30억 개의 W 중 어떤 걸 얼마나 바꿔야 할까? 체인 룰로 끝(손실)에서 시작(임베딩)까지 미분을 연쇄적으로 곱해나간다.

손실 2.53을 줄이려면 30억 개 W 중 어떤 걸 얼마나 바꿔야 하는가?
 
끝(손실)에서 시작(임베딩)까지 미분을 연쇄적으로 곱해나감:
 
손실
 |
출력 확률 <- 출력 행렬의 W
 |
최종 벡터 <- 레이어 36의 W_Q, W_K, W_V, W1, W2
 |
    ...
 |
레이어 1 출력 <- 레이어 1의 W_Q, W_K, W_V, W1, W2
 |
임베딩 벡터 <- 임베딩 테이블
 
결과: 30억 개 파라미터 각각의 gradient (방향 + 크기).

결과로 30억 개 파라미터 각각에 대해 "이 값을 올리면 손실이 줄어드는가, 내리면 줄어드는가, 얼마나?"라는 정보(gradient)가 나온다.


W 업데이트 — 극도로 미세하게

gradient를 구했으면 파라미터를 업데이트한다.

예: FFN W1[512][1024]
 
현재 값:  -0.017
gradient: -0.001 (음수 = 올리면 손실 감소)
학습률:    0.0001
 
새 값 = -0.017 - (0.0001 x -0.001)
       = -0.017 + 0.0000001
       = -0.0169999
 
변화량: 0.0000001 <- 극도로 미세.
이걸 수조 번 반복하면 축적되어 큰 변화.
 
학습률이 너무 크면: 기존 지식 파괴 (발산)
학습률이 적당하면: 기존 지식 보존 + 새 패턴 축적

한 번의 업데이트는 극도로 미세하다. 하지만 이걸 수조 번 반복하면 축적되어 의미 있는 변화가 된다. 학습률이 너무 크면 기존에 학습한 지식이 파괴된다.


배치 학습 — 한 문장이 아니라 수천 문장을 동시에

실제로는 문장 하나씩 업데이트하지 않는다. 1024개 문장을 동시에 처리해서(배치 학습) gradient의 평균으로 업데이트한다.

배치 크기 = 1 (문장 1개):
  "OOM killer가 nginx를" -> gradient -> W 업데이트
  -> 이 문장 하나에 과적합. 방향이 불안정.
 
배치 크기 = 1024 (문장 1024개):
  문장 1: "OOM killer가..." -> gradient_1
  문장 2: "The cat sat..."  -> gradient_2
  ...
  문장 1024: "SELECT * FROM..." -> gradient_1024
 
  평균 gradient = (gradient_1 + ... + gradient_1024) / 1024
  -> W 업데이트
 
  한 문장에 치우치지 않고 전반적으로 좋은 방향으로 이동.
  GPU의 병렬 처리를 최대로 활용 (1024개 동시 순전파).

배치가 크면 안정적이지만 메모리를 많이 먹는다. 배치가 작으면 메모리는 적지만 업데이트 방향이 불안정하다. 실무에서는 gradient accumulation이라는 기법으로 "실제 메모리는 작은 배치만큼 쓰면서 큰 배치의 효과"를 낸다.


옵티마이저 — 단순 gradient 하강이 아니다

실제로는 gradient를 그대로 쓰지 않는다. Adam이라는 옵티마이저가 gradient의 이동 평균과 분산을 추적하면서 더 효율적으로 업데이트한다.

단순 경사하강법:
  W_new = W_old - 학습률 x gradient
  -> 모든 파라미터에 같은 학습률. 비효율적.
 
Adam 옵티마이저:
  각 파라미터마다:
    m = gradient의 이동 평균 (방향의 관성)
    v = gradient^2의 이동 평균 (크기의 분산)
    W_new = W_old - 학습률 x m / sqrt(v)
 
  -> 자주 업데이트되는 파라미터: 학습률 자동 감소.
  -> 드물게 업데이트되는 파라미터: 학습률 자동 증가.
  -> 파라미터마다 적응적으로 조절.
 
  대가: m과 v를 파라미터마다 저장 -> VRAM 2배 추가 사용.
  30억 파라미터 x (m + v) x 4바이트 = ~24GB 추가.

이게 학습이 추론보다 VRAM을 4~8배 먹는 이유 중 하나다. 파라미터 자체 + gradient + 옵티마이저 상태(m, v) + 순전파 중간 결과를 전부 메모리에 들고 있어야 한다.


3단계 학습 과정

실제로 LLM은 한 번에 학습되지 않는다. 세 단계를 거친다.

[인터넷 텍스트 수조 토큰]
    |  다음 토큰 예측 x 수조 번, GPU 수천장 x 수개월
    v
[사전 학습된 모델] --- "문장 이어쓰기 기계"
    |  질문-답변 쌍 수만~수십만 개 (사람이 작성)
    v
[지시 튜닝된 모델] --- "질문에 답하는 기계"
    |  인간 선호도 피드백 (A가 B보다 낫다)
    v
[RLHF 모델] ------- "잘 답하려고 노력하는 기계"

사전 학습이 가장 비싸다. GPU 수천 장으로 수개월이 걸린다. 지시 튜닝과 RLHF는 상대적으로 적은 데이터와 자원으로 가능하다. ollama로 받아서 돌리는 모델은 이 세 단계를 전부 거친 결과물이다.


학습 vs 추론의 자원 차이

                추론              학습
-----------------------------------------
수행          순전파만             순전파 + 역전파
W             읽기만 (고정)        읽기 + gradient + 업데이트
저장          파라미터 + KV캐시    파라미터 + gradient + 중간결과 + 옵티마이저
VRAM          파라미터의 ~1.2배    파라미터의 4~8배
-----------------------------------------
3B 모델       ~8 GB              ~24 GB
7B 모델       ~16 GB             ~56 GB
70B 모델      ~160 GB            ~560 GB

학습이 추론보다 훨씬 비싼 이유가 여기 있다. 추론은 순전파만 하면 되지만, 학습은 순전파 + 역전파 + W 업데이트를 해야 하고, gradient와 중간 계산 결과까지 메모리에 들고 있어야 한다. VRAM 사용량이 4~8배다.

우리가 로컬에서 7B 모델을 돌리는 건 추론이니까 16GB 정도면 되지만, 이 모델을 학습하려면 56GB가 필요하다. 로컬에서 학습은 사실상 불가능에 가깝다. 파인튜닝(LoRA)이라는 효율적인 방법이 있는데, 이건 11편에서 다룬다.

다음 편에서는 추론을 돌리는 하드웨어를 파고든다. GPU가 왜 빠른지, 진짜 병목이 어디인지, 내 GPU에서 어떤 모델을 얼마나 빠르게 돌릴 수 있는지.

이 글이 어떠셨나요?

이 글이 도움이 되셨나요?
공유:

관련 포스트

뉴스레터 구독

새 글이 올라오면 이메일로 알려드려요.

댓글

댓글을 불러오는 중...