오늘 끝나면
나만의 미니 LLM 만들기
- ✓나만의 미니 LLM 만들기의 핵심 문제를 한 문장으로 설명한다
- ✓오른쪽 실습에서 나만의이 어떻게 움직이는지 관찰한다
- ✓다음 강의와 이어지는 한계를 말할 수 있다
실습 미션
nanoGPT 스타일 — 셰익스피어로 직접 학습시킨다 이 문장이 실제로 무슨 뜻인지 실습에서 한 번 손으로 확인한다.
성공 조건
- □실습의 기본값을 먼저 관찰
- □입력값이나 모드를 한 번 이상 바꿔 결과 비교
- □왜 결과가 바뀌었는지 한 문장으로 설명
AI · Day 12 / 지도학습 · 생성 DL
나만의
미니 LLM
12일의 종착점임. GPT를 한 줄씩 직접 짜고, 학습시키고, 문장을 뽑음.나만의 작은 AI를 노트북에서 만듦. 300줄짜리 nanoGPT면 됨.
왜 굳이 직접 만드나
API를 1만 번 호출해도 "왜 이렇게 답하지?"는 안 풀림. 소비만 하면 내부가 안 보임.
논문만 읽어도 부족함. loss.backward()를 직접 안 돌려보면 "학습"이 감이 안 옴.
학습률을 1e-3에서 1e-4로 낮추면 loss 곡선이 어떻게 휘는지,block_size를 늘리면 메모리가 왜 O(n²)로 터지는지. 이건 만들어본 사람만 아는 감각임.
Karpathy 왈, "LLM을 이해하는 유일한 길은 직접 만들어보는 것". 오늘은 그의 영상 "Let's build GPT from scratch"의 한국어 졸업 버전임.
직접 만들어야 꼭대기 칸 — 진짜 직관이 생김
토큰은 그냥 숫자다
첫 번째 아하 모먼트임. 토크나이저는 거창한 게 아님.문자열을 정수 수열로 바꾸는 딕셔너리 하나임.
셰익스피어 텍스트 1.1MB를 씀. 등장한 문자를 모으니 딱 65개.
stoi는 문자를 숫자로 / itos는 숫자를 문자로 되돌림. 그게 전부임. character-level이라 한국어 소설을 넣어도 코드 안 고치고 그대로 돎.
파이썬 코드 보기
chars = sorted(set(text)) # 65개 문자
stoi = {ch: i for i, ch in enumerate(chars)}
itos = {i: ch for i, ch in enumerate(chars)}
def encode(s): return [stoi[c] for c in s]
def decode(ids): return "".join(itos[i] for i in ids)
print(encode("Hi")) # [20, 47]
print(decode([20, 47])) # "Hi"GPT-4의 cl100k_base도 본질은 똑같음. vocab이 65개냐 10만 개냐 차이뿐임. 숫자에서 의미를 배우는 건 다음 단계 Embedding의 몫임.
문자 ↔ 정수 양방향 매핑 — 토크나이저의 본질임
GPT는 블록 N개의 반복이다
오늘의 하이라이트임. 두 번째 아하 모먼트는 "Attention이 사실 행렬 곱 한 번이구나". 세 번째는 "GPT가 똑같은 블록의 반복이구나"임.
입력 토큰에 Token Embedding과 Positional Embedding을 더함. 블록 하나는 LayerNorm → Causal Attention → Residual, 이어서 LayerNorm → FeedForward → Residual임. 이 블록을 N번 쌓고, 마지막에 Linear Head로 vocab 크기 logits을 뽑으면 끝남.
핵심은 causal mask임. 하삼각 행렬로 미래 토큰을 -inf처리함. 각 위치가 자기 이전만 보게 됨. 이게 "다음 글자 맞히기"라는 언어모델 정의 그 자체임.
파이썬 코드 보기
wei = q @ k.transpose(-2, -1) * C ** -0.5
wei = wei.masked_fill(tril == 0, float("-inf"))
wei = softmax(wei, dim=-1) # 미래는 가린 채
out = wei @ v # 과거를 가중 평균n_layer=6이면 nanoGPT / n_layer=96이면 GPT-3임. 아키텍처는 같음. 확장의 문제일 뿐임.
파란 블록 하나를 N번 쌓으면 GPT — n_layer=96이면 GPT-3임
학습은 loss가 떨어지는 현상
모델을 만들었으면 가르칠 차례임. "학습"이 막연하면 한마디. 학습은 결국 loss라는 숫자가 떨어지는 현상임.
매 스텝마다 get_batch로 임의 구간을 뽑음. 입력 x와 한 칸 민 정답 y를 만듦. 예측과 정답의 cross-entropy를 잼.loss.backward()로 기울기를 흘리고 / optimizer.step()으로 가중치를 살짝 고침. 이 반복이 전부임.
파이썬 코드 보기
for step in range(max_steps):
xb, yb = get_batch("train")
_, loss = model(xb, yb)
optimizer.zero_grad()
loss.backward() # 기울기
optimizer.step() # 한 걸음warmup으로 학습률을 완만히 올렸다가 cosine으로 부드럽게 내림. 그러면 train·val loss가 4.2 → 2.1 → 1.5로 우하향함. 이 곡선을 직접 본 사람이 "LLM 학습"을 몸으로 아는 사람임.
loss 4.2 → 2.1 → 1.5 우하향 — 이게 "학습"의 전부임
Temperature는 모델의 성격
학습이 끝나면 모델이 처음으로 "뭔가"를 말함. 마지막 아하 모먼트. "Temperature 하나 바꿨을 뿐인데 성격이 달라지네?"임.
같은 모델, 같은 프롬프트 ROMEO:인데 디코딩 전략이 결과를 바꿈.
Greedy는 항상 argmax라 지루함.Temperature는 logits을 T로 나눔 / T가 낮으면 엄격, 높으면 자유로움.Top-k는 상위 k개만 / Top-p는 누적확률 p까지만 두고 샘플링함.
여기까지가 12일의 결론임. 사내 문서 전용 소형 LLM / 엣지용 경량 모델 / 데이터가 밖으로 못 나가는 on-premise 보안 LLM / 브랜드 보이스 페르소나 LLM까지. 출발점은 모두 오늘 손으로 만든 이 구조임. 차이는 파라미터·데이터·컴퓨트뿐, 근본은 같음.