본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2026. 4. 13. · 0 Views
Day 1 언어모델의 목표 이해
LLM 바닥부터 만들기 코스의 첫 번째 날입니다. 언어모델이 무엇인지, next token prediction이 어떻게 작동하는지, 그리고 pretraining이 왜 확률 모델링인지를 이해합니다. 앞으로 30일간 만들게 될 작은 GPT의 기초 개념을 다집니다.
목차
- 언어모델이란 무엇인가
- next token prediction의 기본 개념
- 한 토큰씩 이어 붙이는 생성 방식
- pretraining은 확률 모델링이다
- 입력 x와 정답 y의 관계 이해
- x와 y를 한 칸 밀어 만드는 이유 설명하기
1. 언어모델이란 무엇인가
김개발 씨는 최근 챗GPT에 빠져서 매일 질문을 던지고 있습니다. 어느 날 문득 궁금해졌습니다.
"이건 도대체 어떻게 내 질문에 그렇게 자연스럽게 대답하는 걸까요?" 선배 박시니어 씨가 커피를 한 모금 마시며 말했습니다. "그 비밀이 바로 오늘 우리가 배울 언어모델이에요."
언어모델(Language Model)은 한마디로 다음에 올 단어를 예측하는 확률 모델입니다. 마치 독서 속도가 빠른 사람이 문맥을 읽고 다음 문장을 유추하는 것과 같습니다.
이 개념을 제대로 이해하면 챗GPT 같은 AI의 근본 원리를 파악할 수 있습니다.
다음 코드를 살펴봅시다.
# 언어모델의 핵심: 다음 단어 확률 예측
text = "오늘 날씨가"
# 모델이 예측하는 다음 단어 확률
# "맑습니다" -> 0.45
# "흐립니다" -> 0.30
# "좋네요" -> 0.15
# 기타 -> 0.10
# 모델은 가장 확률이 높은 "맑습니다"를 선택합니다
김개발 씨는 입사 3개월 차 주니어 개발자입니다. 최근 회사에서 AI 도입을 논의하면서, 갑자기 언어모델이라는 단어가 자주 등장하기 시작했습니다.
"언어모델이라고 하면 대체 뭘 하는 건데요?" 박시니어 씨가 화이트보드에 단어 하나를 적었습니다. 예측.
"언어모델의 전부는 이 한 단어로 요약돼요. 다음에 올 단어를 예측하는 것, 그것이 언어모델의 본질입니다." 김개발 씨가 고개를 갸웃했습니다.
"그게 전부인가요? 챗GPT는 그냥 다음 단어만 예측하는 건가요?" 그렇습니다.
놀랍게도 그것이 전부입니다. 하지만 이 단순한 원리가 수십억 개의 파라미터와 결합하면, 우리가 보는那样 자연스러운 대화가 가능해집니다.
쉽게 비유하자면, 언어모델은 마치 매일 아침 스마트폰 자동완성을 사용하는 것과 같습니다. "오늘 점심은"이라고 치면 "뭐 먹을까요"를 추천해주는 그 기능이죠.
언어모델은 이 자동완성을 훨씬 더 정교하게, 문맥을 깊이 이해하면서 수행합니다. 더 구체적으로 설명해보겠습니다.
언어모델에게 "나는 오늘"이라는 텍스트를 주면, 모델은 자신이 학습한 수많은 문서를 바탕으로 다음에 올 단어의 확률을 계산합니다. "학교에"가 40%, "회사에서"가 25%, "카페에서"가 15% 식으로요.
이 확률 분포를 계산하는 것이 바로 언어모델의 핵심 임무입니다. 그리고 이 확률을 계산하기 위해 우리가 앞으로 30일 동안 만들게 될 것이 바로 Transformer 구조입니다.
언어모델이 없던 시절에는 어떻게 했을까요? 개발자들은 규칙 기반 시스템을 직접 만들어야 했습니다.
"만약 사용자가 인사하면, 정해진 답변을 출력한다" 식으로요. 코드가 길어지고, 새로운 상황에 대응하기 어려웠습니다.
오늘날의 언어모델은 규칙을 직접 코딩하지 않습니다. 대신 방대한 텍스트 데이터에서 통계적 패턴을 학습합니다.
그래서 처음 보는 문장에도 자연스럽게 대응할 수 있습니다. 우리가 앞으로 만들 작은 GPT도 이 원리에서 출발합니다.
"다음 토큰을 예측한다"는 아주 단순한 목표에서 시작해서, 점점 더 복잡한 구조를 하나씩 쌓아 올려갈 것입니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
박시니어 씨의 설명을 들은 김개발 씨는 눈을 크게 떴습니다. "그러니까 결국 확률 문제였군요!" 맞습니다.
언어모델의 우아함은 바로 그 simplicity에 있습니다.
실전 팁
💡 - 언어모델의 핵심은 "다음에 올 단어 예측" 하나로 귀결됩니다
- 이 단순한 원리가 수십억 파라미터와 만나면 챗GPT가 됩니다
- 이 카드뉴스는 "LLM 바닥부터 만들기: 30일 완성 코스" 코스의 1/30편입니다
2. next token prediction의 기본 개념
언어모델의 본질이 "예측"이라는 것을 알게 된 김개발 씨. 그런데 또 궁금한 게 생겼습니다.
"예측이라면, 어떤 단위로 예측하는 건가요? 단어 단위인가요, 글자 단위인가요?" 박시니어 씨가 답했습니다.
"좋은 질문이에요. 그게 바로 토큰이라는 개념이 필요한 이유입니다."
next token prediction은 모델이 이전 토큰들을 보고 다음 토큰을 예측하는 학습 방식입니다. 마치 타자를 치다가 다음 글자를 자동으로 완성하는 것과 같습니다.
이 방식은 GPT 계열 모델이 학습하는 유일한 목표 함수입니다.
다음 코드를 살펴봅시다.
# next token prediction의 동작 원리
import torch
import torch.nn.functional as F
# 모델이 출력한 로짓(logits) 값
logits = torch.tensor([[2.0, 1.0, 0.1]]) # 3개 토큰에 대한 점수
# 소프트맥스로 확률 분포로 변환
probs = F.softmax(logits, dim=-1)
# 확률이 가장 높은 토큰 선택
next_token = torch.argmax(probs, dim=-1)
print(f"다음 토큰 확률: {probs}")
print(f"선택된 토큰: {next_token.item()}") # 출력: 0
어제 언어모델의 기본 원리를 배운 김개발 씨는 오늘부터 더 구체적인 내용을 파고들기로 했습니다. 가장 먼저 궁금한 것은 "예측의 단위"였습니다.
"단어 단위로 예측하는 건가요?" 김개발 씨가 물었습니다. 박시니어 씨가 고개를 저었습니다.
"단어도 아니고, 글자도 아니에요. 바로 토큰(token) 단위입니다." 토큰이란 무엇일까요?
쉽게 비유하자면, 토큰은 마치 언어의 레고 블록과 같습니다. "사랑합니다"라는 단어가 있다면, 토크나이저는 이를 "사랑", "하", "십니다"처럼 의미 있는 단위로 쪼갭니다.
때로는 "un", "believable"처럼 영어 단어의 일부가 하나의 토큰이 되기도 합니다. 이 토큰 단위가 중요한 이유는, 단어 단위로 쪼개면 너무 많은 종류가 생겨서 모델이 감당하기 어렵기 때문입니다.
반대로 글자 단위로 쪼개면 너무 짧아서 의미를 파악하기 어렵습니다. 토큰은 이 두 극단 사이의 최적의 타협점입니다.
그렇다면 next token prediction은 구체적으로 어떻게 작동할까요? 모델에게 "나는 오늘 학교에"라는 텍스트를 줍니다.
그러면 모델은 이 문맥을 바탕으로, 다음에 올 수 있는 모든 토큰에 대해 확률을 계산합니다. "갔습니다"가 35%, "가려고 합니다"가 20%, 이런 식으로 말이죠.
여기서 핵심은 모델이 "정답"을 하나만 출력하는 것이 아니라, 전체 어휘 사전에 대한 확률 분포를 출력한다는 점입니다. 어휘 사전이 5만 개라면, 모델은 5만 개의 확률 값을 동시에 계산합니다.
이 과정을 수식으로 표현하면 P(다음 토큰 | 이전 토큰들)이 됩니다. 조건부 확률이죠.
앞에 어떤 텍스트가 있느냐에 따라 다음 토큰의 확률이 달라집니다. 이것이 언어모델이 문맥을 이해하는 방식입니다.
실제 코드를 보면, 모델의 최종 출력은 로짓(logits)이라는 raw 점수입니다. 이 점수들을 소프트맥스 함수에 통과시키면 0에서 1 사이의 확률 값으로 변환됩니다.
그리고 가장 확률이 높은 토큰이 모델의 예측 결과가 됩니다. 물론 항상 가장 확률이 높은 토큰만 고르는 것은 아닙니다.
때로는 확률에 비례해서 무작위로 선택하기도 합니다. 이를 샘플링(sampling)이라고 부르며, 이것이 모델의 출력에 다양성을 부여합니다.
초보 개발자들이 흔히 하는 실수 중 하나는 토큰과 단어를 혼동하는 것입니다. "사과"는 하나의 단어이지만, 문맥에 따라 하나의 토큰이 될 수도, 두 개의 토큰이 될 수도 있습니다.
이 distinction이 중요합니다. 다시 김개발 씨에게 돌아가 봅시다.
"그러니까 모델은 항상 다음 토큰 하나만 보고 결정하는 거군요?" "맞아요. 하지만 그 '하나'가 누적되면 결국 완전한 문장이, 문단이, 글이 됩니다." 박시니어 씨가 미소를 지었습니다.
실전 팁
💡 - 토큰은 단어와 글자 사이의 중간 단위로, 모델이 처리하기 가장 적합한 크기입니다
- 모델은 정답 하나를 출력하는 것이 아니라 전체 어휘에 대한 확률 분포를 계산합니다
- 이 카드뉴스는 "LLM 바닥부터 만들기: 30일 완성 코스" 코스의 1/30편입니다
3. 한 토큰씩 이어 붙이는 생성 방식
next token prediction의 원리를 이해한 김개발 씨는 곧바로 다음 질문을 던졌습니다. "한 토큰만 예측한다면, 긴 문장은 어떻게 만드는 건가요?" 박시니어 씨가 노트북을 열며 말했습니다.
"바로 이 부분을 코드로 직접 보여드릴게요."
언어모델의 텍스트 생성은 한 토큰을 예측하고, 그 결과를 다시 입력에 이어 붙여 다음 토큰을 예측하는 자기회귀(autoregressive) 방식입니다. 마치 한 글자씩 타자를 쳐서 문장을 완성하는 것과 같습니다.
이 반복 과정이 GPT가 긴 텍스트를 생성하는 유일한 방법입니다.
다음 코드를 살펴봅시다.
# 자기회귀 텍스트 생성 루프
def generate(model, input_ids, max_new_tokens=10):
generated = input_ids.tolist()[0] # 초기 입력 토큰
for _ in range(max_new_tokens):
# 모델에 현재까지의 토큰 전달
logits = model(torch.tensor([generated]))
# 마지막 위치의 다음 토큰 예측
next_token = torch.argmax(logits[:, -1, :], dim=-1).item()
# 생성된 토큰을 시퀀스에 추가
generated.append(next_token)
# 종료 토큰이면 중단
if next_token == eos_token_id:
break
return generated
김개발 씨는 오늘 배운 next token prediction이 머릿속에 잘 정리되었습니다. 하지만 한 가지 의문이 남았습니다.
"한 번에 한 토큰만 예측한다면, 챗GPT는 어떻게 그렇게 긴 답변을 만드는 걸까요?" 박시니어 씨가 화이트보드에 간단한 다이어그램을 그렸습니다. 입력: "안녕" -> 모델: "하세요" -> 입력: "안녕하세요" -> 모델: "." -> 입력: "안녕하세요." -> 모델: "무엇을" ...
"보이시죠? 모델이 새 토큰을 하나 생성할 때마다, 그 토큰을 기존 입력 뒤에 이어 붙이고, 다시 모델에 넣습니다.
이 과정을 원하는 길이가 될 때까지 반복하는 거예요." 이 방식을 자기회귀(autoregressive) 생성이라고 부릅니다. "자기"(auto)는 스스로를 의미하고, "회귀"(regressive)는 이전 값을 기반으로 다음 값을 예측한다는 뜻입니다.
즉, 모델이 자신이 방금 만든 출력을 다시 자신의 입력으로 사용하는 구조입니다. 쉽게 비유하자면, 마치 독백으로 이야기를 구상하는 것과 같습니다.
"어제 카페에 갔는데"라고 말한 다음, 그 문맥을 머릿속에 유지한 채 "거기서 친구를 만났어요"라고 이어 붙이는 식이죠. 한 문장이 끝날 때마다 지금까지 한 말을 바탕으로 다음 말을 결정합니다.
코드를 보면 이 과정이 아주 직관적입니다. for 루프 안에서 모델을 호출하고, 예측 결과를 리스트에 append하는 것이 전부입니다.
언뜻 보면 단순해 보이지만, 이 루프가 바로 챗GPT가 여러분의 질문에 답변하는 전체 과정입니다. 한 가지 중요한 디테일이 있습니다.
모델이 매번 처음부터 모든 토큰을 다시 처리하는 것은 아닙니다. 실제 구현에서는 KV 캐시(Key-Value cache)라는 기법을 사용해서 이전에 계산한 결과를 재활용합니다.
이 최적화가 없다면 생성 속도가 기하급수적으로 느려집니다. 물론 이 루프가 영원히 돌아가는 것은 아닙니다.
보통 두 가지 방식으로 멈춥니다. 하나는 최대 길이(max tokens)에 도달했을 때이고, 다른 하나는 모델이 종료 토큰(EOS, End of Sequence)을 출력했을 때입니다.
종료 토큰은 모델이 "여기서 문장이 끝났다"고 판단했다는 신호입니다. 초보 개발자들이 자주 겪는 혼란 중 하나는 "모델이 전체 문장을 한 번에 생성하는 것"이라고 오해하는 것입니다.
하지만 실제로는 매 순간 단 하나의 토큰만 결정합니다. 다만 그 결정이 초당 수십 번 반복되기 때문에 우리 눈에는 한꺼번에 출력되는 것처럼 보일 뿐입니다.
이 자기회귀 특성 때문에, 생성 과정에서 한 번 잘못된 토큰이 선택되면 이후의 모든 토큰에 영향을 미칩니다. "오늘 날씨가 좋아서 산에" 다음에 "갔습니다"가 아니라 "비행기" 같은 말이 오면 문맥이 깨지죠.
이것이 언어모델 생성의 근본적인 한계이기도 합니다. 다시 김개발 씨의 이야기로 돌아가 봅시다.
"그러니까 결국 for 루프 하나가 챗GPT의 전부라는 건가요?" 김개발 씨가 놀란 표정으로 물었습니다. 박시니어 씨가 웃으며 대답했습니다.
"놀랍게도 그래요. 물론 그 for 루프 안에서 일어나는 일이 수십억 개의 파라미터 연산이지만 말이죠."
실전 팁
💡 - 자기회귀 생성은 "예측 -> 이어 붙이기 -> 재예측"의 단순한 루프입니다
- 종료 토큰(EOS)과 최대 길이(max tokens)가 생성을 멈추는 두 가지 조건입니다
- 이 카드뉴스는 "LLM 바닥부터 만들기: 30일 완성 코스" 코스의 1/30편입니다
4. pretraining은 확률 모델링이다
김개발 씨는 최근 논문에서 "사전학습"이라는 단어를 계속 보았습니다. "사전학습이 대체 뭘까요?
학습하기 전에 미리 학습하는 건가요?" 모순되는 것 같은 이 표현에 박시니어 씨가 명쾌하게 정의를 내려주었습니다.
사전학습(pretraining)은 방대한 텍스트 코퍼스에서 다음 토큰의 확률을 모델링하는 과정입니다. 마치 수백만 권의 책을 읽고 한국어의 통계적 패턴을 머릿속에 저장하는 것과 같습니다.
이 단계를 거친 모델은 이후 파인튜닝 없이도 기본적인 텍스트 생성 능력을 갖춥니다.
다음 코드를 살펴봅시다.
# 사전학습의 핵심: 교차 엔트로피 손실
import torch
import torch.nn as nn
# 모델이 예측한 확률 분포 (5개 토큰 어휘)
predicted = torch.tensor([[0.1, 0.7, 0.1, 0.05, 0.05]])
# 실제 정답 토큰의 인덱스 (두 번째 토큰이 정답)
target = torch.tensor([1])
# 교차 엔트로피로 예측과 정답 사이의 차이 계산
loss = nn.CrossEntropyLoss()(predicted, target)
print(f"손실값: {loss.item():.4f}")
# 정답 확률이 1에 가까울수록 손실은 0에 수렴합니다
김개발 씨는 LLM 논문을 읽다가 "pretraining"이라는 단어가 계속 등장하는 것을 발견했습니다. "이게 뭔가요?
학습하기 전에 학습하는 건가요? 말이 안 되는데요." 박시니어 씨가 자리에서 일어나 화이트보드 앞으로 걸어갔습니다.
"Pretraining은 번역하면 '사전학습'인데, 말이 좀 아쉽죠. 실제로는 본 학습이라고 부르는 게 더 맞아요.
모델의 능력을 결정하는 가장 중요한 단계거든요." 사전학습의 본질은 아주 간단합니다. 수십억 개의 토큰이 포함된 방대한 텍스트 데이터를 모델에게 보여주면서, "다음에 올 토큰을 맞춰봐"라고 계속 요청하는 것입니다.
위키피디아, 뉴스 기사, 블로그 글, 소스 코드, 책 등 거의 모든 텍스트가 학습 데이터로 사용됩니다. 쉽게 비유하자면, 사전학습은 마치 한 아이가 수백만 권의 책을 통째로 읽으며 언어의 규칙을 자연스럽게 습득하는 과정과 같습니다.
누군가 문법을 일일이 가르쳐주는 것이 아니라, 수많은 예시를 통해 "이 단어 다음에는 보통 이런 단어가 온다"는 패턴을 스스로 발견합니다. 이 과정에서 모델이 학습하는 것은 확률 분포입니다.
"어제" 다음에 "밥을"이 올 확률, "회의가" 다음에 "시작되었습니다"가 올 확률, 수백만 가지의 토큰 조합에 대한 확률을 파라미터에 압축해서 저장합니다. 그렇다면 모델은 이 확률을 어떻게 평가할까요?
바로 교차 엔트로피 손실(Cross-Entropy Loss)이라는 함수를 사용합니다. 모델이 예측한 확률 분포와 실제 정답 토큰 사이의 차이를 계산해서, 그 차이가 줄어들도록 파라미터를 업데이트합니다.
예를 들어 "오늘 날씨가 좋아서 산에" 다음에 "갔습니다"가 실제 정답이라고 해봅시다. 모델이 처음에는 "갔습니다"에 5%밖에 확률을 주지 않는다면 손실값이 큽니다.
하지만 학습이 진행될수록 이 확률을 80%, 90%로 점점 높여갑니다. 손실값이 0에 가까워지는 것이죠.
여기서 중요한 점은, 모델이 의미를 "이해"하는 것이 아니라 통계적 패턴을 모델링한다는 것입니다. "사과는 맛있다"와 "사과는 과일이다"에서 "사과"가 같은 토큰이라는 것도, "전자"와 "후자"가 서로 다른 문맥에서 쓰인다는 것도 모두 확률 패턴에서 학습됩니다.
초보 개발자들이 흔히 오해하는 것이 있습니다. "모델이 정답을 외우는 거 아닌가요?" 사전학습의 목적은 특정 텍스트를 암기하는 것이 아닙니다.
오히려 데이터에서 일반적인 패턴을 추출해서, 처음 보는 문장에서도 다음 토큰을 잘 예측할 수 있도록 하는 것이 목표입니다. GPT-3의 경우 약 3,000억 개의 토큰으로 사전학습을 수행했습니다.
우리가 만들 작은 GPT는 훨씬 작은 데이터로 시작하겠지만, 원리는 완전히 동일합니다. 데이터의 양이 다를 뿐, 학습 방식은 같습니다.
다시 김개발 씨에게 돌아가 봅시다. "그러니까 사전학습은 모델이 한국어(또는 영어)의 확률 분포를 파라미터에 '압축'해서 저장하는 과정이군요?" "정확합니다." 박시니어 씨가 엄지를 치켜세웠습니다.
"이 개념을 확실히 잡았으면 앞으로 나가는 일은 순조로울 거예요."
실전 팁
💡 - 사전학습의 목표는 교차 엔트로피 손실을 최소화하여 다음 토큰의 확률을 정확히 예측하는 것입니다
- 모델은 의미를 이해하는 것이 아니라 통계적 패턴을 모델링합니다
- 이 카드뉴스는 "LLM 바닥부터 만들기: 30일 완성 코스" 코스의 1/30편입니다
5. 입력 x와 정답 y의 관계 이해
사전학습이 확률 모델링이라는 것을 이해한 김개발 씨. 그런데 데이터를 준비하다가 또 막혔습니다.
"입력 데이터와 정답 데이터를 따로 만들어야 하나요?" 박시니어 씨가 코드를 보여주며 말했습니다. "놀랍게도, 하나의 텍스트에서 입력과 정답이 모두 나옵니다."
언어모델 학습에서 입력 x와 정답 y는 같은 텍스트에서 파생됩니다. 입력은 "지금까지의 토큰들"이고, 정답은 "바로 다음 토큰"입니다.
마치 독서 중 다음 페이지를 가려놓고 내용을 추측하는 것과 같습니다. 이 구조가 next token prediction 학습의 데이터 준비 방식입니다.
다음 코드를 살펴봅시다.
# 하나의 텍스트에서 입력(x)과 정답(y) 만들기
text = "나는 학교에 갔습니다"
tokens = ["나는", "학교에", "갔습니다"]
# 입력(x): 마지막 토큰을 제외한 시퀀스
x = ["나는", "학교에"]
# 정답(y): 각 위치에서 다음 토큰
y = ["학교에", "갔습니다"]
# x[0]의 정답은 y[0], x[1]의 정답은 y[1]
# "나는" -> 예측: "학교에"
# "학교에" -> 예측: "갔습니다"
김개발 씨는 딥러닝을 공부할 때 항상 했던 방식대로, 입력 데이터 x와 정답 레이블 y를 따로 준비하려고 했습니다. "이미지 분류는 사진이 x고, 레이블이 y잖아요.
언어모델도 텍스트가 x고, 뭐 정답 토큰이 y인가요?" 박시니어 씨가 고개를 끄덕이며 말했습니다. "방향은 맞아요.
하지만 훨씬 더 우아한 방식으로 데이터가 만들어져요." 일반적인 딥러닝에서는 입력과 정답이 별도의 데이터입니다. 고양이 사진이 입력이면 "고양이"라는 레이블이 정답이죠.
하지만 언어모델에서는 입력과 정답이 하나의 텍스트 안에 모두 존재합니다. 예를 들어 "나는 오늘 카페에 갔습니다"라는 문장이 있다고 해봅시다.
이 하나의 문장에서 입력과 정답이 동시에 만들어집니다. "나는"이라는 입력이 주어지면, 정답은 "오늘"입니다.
"나는 오늘"이라는 입력이 주어지면, 정답은 "카페에"입니다. "나는 오늘 카페에"라는 입력이 주어지면, 정답은 "갔습니다"입니다.
보이시나요? 입력 x는 시퀀스의 앞부분이고, 정답 y는 각 위치에서의 다음 토큰입니다.
이 구조를 수식으로 표현하면 아주 깔끔합니다. x = tokens[:-1], y = tokens[1:]입니다.
마지막 토큰을 제외한 것이 입력, 첫 토큰을 제외한 것이 정답이 됩니다. 쉽게 비유하자면, 마치 빈칸 뚫린 문제와 같습니다.
"오늘 ( )이 맑습니다"에서 빈칸에 들어갈 단어를 맞추는 것과 같은 원리입니다. 다만 언어모델은 빈칸 하나가 아니라, 시퀀스의 모든 위치에서 동시에 빈칸을 맞춥니다.
이 방식의 아름다움은 별도의 정답 데이터가 필요 없다는 점입니다. 인터넷에서 텍스트를 수집하기만 하면, 그것이 곧 학습 데이터가 됩니다.
누군가 수동으로 정답을 달아줄 필요가 없습니다. 이것이 LLM이 수조 개의 토큰으로 학습할 수 있는 근본적인 이유 중 하나입니다.
코드로 보면 이 과정이 정말 직관적입니다. 토큰 리스트에서 마지막을 하나 빼면 입력이 되고, 첫 번째를 하나 빼면 정답이 됩니다.
이 "한 칸 어긋남"이 바로 언어모델 학습 데이터의 핵심 구조입니다. 초보 개발자들이 흔히 하는 실수는 정답 y를 하나의 토큰으로 생각하는 것입니다.
하지만 실제로 y는 입력과 같은 길이의 시퀀스입니다. 입력이 10개의 토큰이면 정답도 10개의 토큰입니다.
각 위치에서 모델이 예측해야 할 다음 토큰이 하나씩 있기 때문입니다. 다시 김개발 씨에게 돌아가 봅시다.
"그러니까 정답을 따로 만들 필요가 없다는 게 정말 놀랍네요. 그냥 텍스트를 시프트하면 끝이라니요." "맞아요.
이런 단순함이야말로 스케일업을 가능하게 한 핵심 설계입니다."
실전 팁
💡 - 입력 x와 정답 y는 하나의 텍스트에서 tokens[:-1]과 tokens[1:]로 간단히 분리됩니다
- 정답 y는 단일 토큰이 아니라 입력과 같은 길이의 시퀀스입니다
- 이 카드뉴스는 "LLM 바닥부터 만들기: 30일 완성 코스" 코스의 1/30편입니다
6. x와 y를 한 칸 밀어 만드는 이유 설명하기
김개발 씨는 드디어 핵심을 이해했습니다. 입력과 정답이 같은 텍스트에서 나온다는 것, 그리고 한 칸씩 어긋나 있다는 것을요.
하지만 마지막 의문이 남았습니다. "왜 하필 한 칸이지요?
두 칸 밀면 안 되나요?" 박시니어 씨가 진지한 표정으로 답했습니다.
입력 x와 정답 y를 한 칸 어긋나게(offset by one) 만드는 것은 next token prediction의 구조적 요구사항입니다. 마치 독서에서 한 문장을 읽고 다음 문장을 예측하는 것처럼, 모델은 현재 위치의 정보로 바로 다음 위치를 예측해야 합니다.
이 한 칸의 어긋남이 언어모델 학습의 기본 전제입니다.
다음 코드를 살펴봅시다.
# 한 칸 어긋남(offset)의 구조적 이유
tokens = [t0, t1, t2, t3, t4] # 전체 시퀀스
# 학습 데이터 생성
x = [t0, t1, t2, t3] # 입력: i번째까지의 토큰
y = [t1, t2, t3, t4] # 정답: i+1번째 토큰
# 모델이 각 위치에서 병렬로 학습합니다
# timestep 0: x=[t0] -> 예측 y=t1
# timestep 1: x=[t0, t1] -> 예측 y=t2
# timestep 2: x=[t0,t1,t2]-> 예측 y=t3
# timestep 3: x=[t0,t1,t2,t3]-> 예측 y=t4
김개발 씨는 마지막 남은 질문을 던졌습니다. "입력과 정답이 한 칸 어긋나 있다는 건 이해했어요.
하지만 왜 하필 한 칸인가요? 이유가 궁금합니다." 박시니어 씨가 천천히 설명을 시작했습니다.
"이 질문을 이해하려면, 모델이 학습에서 정확히 무엇을 해야 하는지를 다시 한번 명확히 해야 해요." 모델의 임무는 "다음 토큰 예측"입니다. 즉, t0, t1, t2를 보고 t3를 예측해야 합니다.
이때 모델에게 주어야 할 입력은 t0, t1, t2이고, 기대하는 정답은 t3입니다. 만약 두 칸을 어긋나게 만들면 어떻게 될까요?
입력이 t0, t1, t2이고 정답이 t4가 됩니다. 그러면 모델은 t3를 건너뛰고 t4를 예측하도록 학습하게 됩니다.
하지만 우리의 목표는 "바로 다음" 토큰을 예측하는 것이지, 하나를 건너뛰고 예측하는 것이 아닙니다. 쉽게 비유하자면, 마치 피아노 연주와 같습니다.
현재 친 음을 들으면 바로 다음 음을 예측해야 합니다. 두 음을 건너뛰고 예측하면 멜로디를 만들 수 없죠.
언어도 마찬가지입니다. 토큰 사이의 간격이 벌어지면 문맥 연결이 끊어집니다.
더 깊이 들어가 보겠습니다. 이 한 칸 어긋남은 Transformer의 병렬 학습과도 깊은 관련이 있습니다.
시퀀스 길이가 5라면, 모델은 한 번의 forward pass에서 5개 위치 모두에 대해 동시에 예측을 수행합니다. timestep 0에서는 t0으로 t1을 예측하고, timestep 1에서는 t0, t1로 t2를 예측하는 식입니다.
하지만 여기에는 중요한 제약이 있습니다. 모델은 timestep 1에서 t2를 예측할 때, 미래의 토큰 t2를 보면 안 됩니다.
그래야 실제 생성 시와 동일한 조건에서 학습할 수 있습니다. 이것이 바로 인과적 마스킹(causal masking)의 역할이며, 한 칸 어긋남과 밀접하게 연결되어 있습니다.
초보 개발자들이 놓치기 쉬운 포인트가 있습니다. 학습 시에는 정답 y를 이미 알고 있습니다.
하지만 모델에게는 y를 "미래 정보"로 취급해서 가려줘야 합니다. 마치 시험에서 정답지를 보지 않고 풀어야 하는 것과 같습니다.
이 원칙이 지켜지지 않으면 모델은 "학습은 잘 하지만 실제로는 쓸모없는" 상태가 됩니다. 이 한 칸 어긋남은 또한 학습의 효율성과도 관련이 있습니다.
하나의 시퀀스에서 N개의 학습 예시를 동시에 만들어낼 수 있습니다. 길이 100의 시퀀스 하나가 99개의 (입력, 정답) 쌍을 제공합니다.
데이터 활용도가 극대화되는 셈입니다. 지금까지 배운 내용을 종합해봅시다.
언어모델은 텍스트에서 입력 x와 정답 y를 한 칸 어긋나게 만들고, 모델은 x를 보고 y를 예측하도록 학습합니다. 교차 엔트로피 손실을 최소화하면서 파라미터를 업데이트하고, 학습이 끝나면 자기회귀 방식으로 새로운 텍스트를 생성합니다.
이것이 LLM 바닥부터 만들기: 30일 완성 코스의 첫 번째 날입니다. 오늘 배운 개념들은 앞으로 30일간 만들게 될 모든 코드의 기초가 됩니다.
내일부터는 본격적으로 PyTorch를 활용해 이 개념들을 코드로 구현하기 시작합니다. 다시 김개발 씨에게 돌아가 봅시다.
"드디어 전체 그림이 보이기 시작해요! 내일은 PyTorch로 이걸 직접 구현해보는 건가요?" 김개발 씨의 눈이 반짝였습니다.
박시니어 씨가 고개를 끄덕였습니다. "그래요.
오늘 이론을 확실히 잡았으니, 내일은 코드로 직접 만져볼 거예요."
실전 팁
💡 - 한 칸 어긋남은 "바로 다음 토큰"을 예측하게 만드는 구조적 요구사항입니다
- 인과적 마스킹은 학습 시 모델이 미래 정보를 peeking하지 못하게 막는 장치입니다
- 내일 "Day 2: PyTorch 기본기 정리"에서는 오늘 배운 개념을 실제 코드로 구현하기 위한 PyTorch 기초를 다집니다
- 이 카드뉴스는 "LLM 바닥부터 만들기: 30일 완성 코스" 코스의 1/30편입니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
LLM 기본 사항 토큰 컨텍스트 프롬프트 설계 완벽 가이드
LLM을 다루는 데 필수적인 토큰, 컨텍스트 윈도우, 프롬프트 설계의 핵심 개념을 배웁니다. 에이전트 AI 엔지니어로 성장하기 위해 반드시 알아야 할 기초를 다집니다.
Python 기본 사항 프로젝트 구조와 타이핑 완벽 가이드
AI 에이전트 엔지니어를 위한 Python 프로젝트 구조 설계부터 타입 힌팅까지, 초보자가 반드시 알아야 할 핵심 기초를 다룹니다. 깔끔한 프로젝트 구조와 타입 안전성으로 생산성을 높여보세요.
에이전트 AI 엔지니어 로드맵 소개 및 학습 방법
2026년 에이전트 AI 엔지니어가 되기 위한 완벽 로드맵을 소개합니다. Python 기초부터 고급 에이전트 아키텍처, RAG 시스템, 다중 에이전트까지 16개 소주제로 구성된 코스의 전체 흐름과 학습 방법을 안내합니다.
Python 고급 테스트와 프로덕션 실전 가이드
AI 에이전트 개발자가 알아야 할 Python 고급 테스트 전략, 재현성 보장, 프로덕션 배포 시 흔히 겪는 함정을 다룹니다. 초급 개발자가 실무에서 바로 적용할 수 있는 실전 노하우를 전달합니다.
Day 3 문자 단위 토크나이저 만들기
LLM이 텍스트를 이해하려면 먼저 문자를 숫자로 변환해야 합니다. 텍스트를 쪼개고, 각 조각에 번호를 매기고, 다시 원래 텍스트로 복원하는 토크나이저를 직접 만들어봅니다.