본 콘텐츠의 이미지 및 내용은 AI로 생성되었습니다.
본 콘텐츠의 이미지 및 내용을 무단으로 복제, 배포, 수정하여 사용할 경우 저작권법에 의해 법적 제재를 받을 수 있습니다.
이미지 로딩 중...
AI Generated
2026. 4. 13. · 0 Views
Day 2 PyTorch 기본기 정리
LLM을 직접 만들기 위해 꼭 알아야 할 PyTorch의 핵심 개념을 정리합니다. 텐서, 자동 미분, 옵티마이저까지 모델 학습의 기초를 다집니다.
목차
1. 텐서의 기본 구조
어제 김개발 씨는 언어모델이 '다음 토큰을 예측하는 확률 모델'이라는 것을 배웠습니다. 하지만 막상 코드를 열어보니 수학 기호와 배열이 빼곡했습니다.
"이걸 코드로 어떻게 구현하지?"
**텐서(Tensor)**는 PyTorch에서 데이터를 담는 가장 기본적인 그릇입니다. 쉽게 말해 NumPy 배열과 거의 똑같지만 GPU에서도 동작하는 다차원 배열입니다.
마치 엑셀의 셀들을 여러 겹으로 쌓아놓은 것과 같습니다.
다음 코드를 살펴봅시다.
import torch
# 스칼라(0차원), 벡터(1차원), 행렬(2차원)
scalar = torch.tensor(42) # 0차원: 단일 값
vector = torch.tensor([1, 2, 3]) # 1차원: 1D 배열
matrix = torch.tensor([[1, 2], # 2차원: 2D 행렬
[3, 4]])
print(scalar.shape) # torch.Size([])
print(vector.shape) # torch.Size([3])
print(matrix.shape) # torch.Size([2, 2])
"LLM 바닥부터 만들기: 30일 완성 코스" 두 번째 날입니다. 어제 우리는 언어모델이 다음 토큰을 예측하는 확률 모델이라는 것을 배웠습니다.
오늘부터는 그 예측을 코드로 직접 구현하기 위해 PyTorch라는 도구의 기본기를 익혀보겠습니다. 김개발 씨는 어제의 내용을 복습하며 노트를 펼쳤습니다.
"next token prediction, 입력 x와 정답 y를 한 칸 밀어서 만든다..." 그런데 막상 코드를 짜려고 하니 막막했습니다. 수학 공식은 이해했는데, 그걸 어떻게 컴퓨터에 입력해야 할까요?
박시니어 씨가 커피를 한 잔 가져오며 말했습니다. "먼저 PyTorch의 가장 기본이 되는 **텐서(Tensor)**부터 알아야 합니다.
모든 것은 텐서에서 시작하거든요." 텐서가 뭘까요? 어렵게 생각할 필요 없습니다.
우리가 흔히 아는 숫자 배열입니다. 엑셀의 셀 하나가 스칼라, 한 행이 벡터, 시트 하나가 행렬이라고 생각하면 됩니다.
PyTorch에서는 이런 배열을 텐서라고 부릅니다. 그런데 왜 NumPy 배열 대신 텐서를 사용할까요?
가장 큰 이유는 GPU 가속입니다. 딥러닝 모델은 수백만 개의 숫자를 동시에 계산해야 합니다.
NumPy는 CPU에서만 돌아가지만, 텐서는 GPU로 계산을 넘길 수 있어 훨씬 빠릅니다. 코드를 보면 세 가지 형태의 텐서를 만들었습니다.
scalar는 단일 값, vector는 1차원 배열, matrix는 2차원 배열입니다. .shape 속성으로 각 텐서의 크기를 확인할 수 있습니다.
실제로 언어모델에서는 주로 3차원 이상의 텐서를 사용합니다. 예를 들어 문장의 길이, 배치 크기, 임베딩 차원이 모두 합쳐진 3차원 텐서가 자주 등장합니다.
지금은 0~2차원으로 연습하고, 나중에 점차 차원을 늘려가면 됩니다. 중요한 점 하나.
텐서는 기본적으로 CPU에 생성됩니다. GPU를 사용하려면 .to('cuda')를 호출해야 합니다.
하지만 이건 나중에 모델을 만들 때 필요하니, 지금은 "텐서 = GPU도 가능한 숫자 배열" 정도로 기억해 두세요.
실전 팁
💡 - 텐서와 NumPy는 .numpy()와 torch.from_numpy()로 서로 변환할 수 있습니다
- GPU 사용 여부는
tensor.device로 확인할 수 있습니다
2. 텐서 연산과 브로드캐스팅
김개발 씨가 텐서의 기본 구조를 이해한 뒤, 박시니어 씨에게 질문했습니다. "텐서를 만들었으면 이제 계산도 해야 하지 않을까요?" 박시니어 씨가 고개를 끄덕였습니다.
"맞아요. 그런데 형태가 다른 텐서끼리도 계산이 된다는 걸 알면 진짜 편하거든요."
**브로드캐스팅(Broadcasting)**은 형태(shape)가 다른 텐서끼리 자동으로 크기를 맞춰서 연산해 주는 기능입니다. 마치 한 명의 교사가 30명의 학생에게 동시에 같은 문제를 나눠주는 것과 같습니다.
다음 코드를 살펴봅시다.
import torch
# 형태가 다른 텐서끼리 연산
scores = torch.tensor([[80, 90, 70], # 2x3 행렬
[60, 85, 95]])
bonus = torch.tensor([5, 5, 5]) # 1차원 벡터
# 브로드캐스팅으로 자동 확장 후 덧셈
result = scores + bonus
print(result)
# tensor([[85, 95, 75],
# [65, 90, 100]])
# 기본 수학 연산
print(torch.mean(result.float())) # 평균: 83.3333
print(result.sum()) # 합계: 500
어제 배운 next token prediction을 코드로 구현하려면, 텍스트를 숫자로 변환한 뒤 수많은 연산을 수행해야 합니다. 그 연산의 기초가 바로 텐서 연산입니다.
김개발 씨가 가장 먼저 떠올린 것은 덧셈이었습니다. "숫자를 더하고 빼는 건 기본이겠죠?" 맞습니다.
텐서는 +, -, *, / 같은 일반 연산자를 그대로 사용할 수 있습니다. 하지만 텐서 연산의 진짜 무기는 브로드캐스팅입니다.
브로드캐스팅이 뭘까요? 쉽게 말해 형태가 달라도 자동으로 맞춰서 계산해 주는 마법입니다.
코드를 보면 scores는 2x3 행렬인데, bonus는 길이 3짜리 벡터입니다. 일반적으로는 크기가 달라서 덧셈이 안 되어야 합니다.
하지만 PyTorch는 똑똑합니다. bonus 벡터를 자동으로 복사해서 각 행에 더해줍니다.
마치 한 장의 보너스 점수표를 모든 학생 행에 동시에 적용하는 것과 같습니다. 이게 바로 브로드캐스팅입니다.
왜 이게 중요할까요? 언어모델을 만들 때 매 토큰마다 같은 가중치를 적용해야 하는 경우가 많습니다.
브로드캐스팅이 없다면 for문으로 하나씩 곱해야 합니다. 수만 개의 토큰에 대해 for문을 돌리면 속도가 처참해집니다.
브로드캐스팅으로 한 번에 처리하면 GPU가 병렬로 계산해서 훨씬 빠릅니다. 코드의 torch.mean()과 .sum()도 자주 쓰는 연산입니다.
모델 학습에서는 **손실(loss)**이라는 값을 계산할 때 평균이나 합계를 자주 구합니다. "예측이 얼마나 틀렸는가"를 하나의 숫자로 요약해야 하니까요.
주의할 점이 있습니다. 브로드캐스팅은 편하지만, 어떻게 확장될지 머릿속으로 그려보는 습관이 필요합니다.
형태가 (3,)인 벡터와 (2, 3) 행렬은 연산이 되지만, (3,)과 (3, 2)는 호환되지 않습니다. 에러를 만나면 .shape을 찍어서 크기를 비교해 보세요.
실전 팁
💡 - torch.zeros(), torch.ones(), torch.randn()으로 특정 형태의 텐서를 빠르게 만들 수 있습니다
- 브로드캐스팅 규칙이 헷갈리면 두 텐서의 shape을 출력해서 비교해 보세요
3. 자동 미분과 requires grad
"모델을 학습시킨다"는 말을 자주 듣지만, 도대체 컴퓨터가 어떻게 '학습'하는 걸까요? 김개발 씨는 이 질문이 머릿속에서 맴돌았습니다.
박시니어 씨가 화이트보드에 사인 곡선을 그리며 설명을 시작했습니다.
**자동 미분(Autograd)**은 PyTorch가 연산 과정을 자동으로 기록하고, 각 파라미터에 대한 기울기(gradient)를 계산해 주는 시스템입니다. 마치 GPS가 내가 지나온 모든 길을 기록해서 역방향으로 경로를 안내해 주는 것과 같습니다.
다음 코드를 살펴봅시다.
import torch
# requires_grad=True로 미분 추적 시작
x = torch.tensor([2.0, 3.0], requires_grad=True)
# 연산 정의: y = x1^2 + x2^3
y = x[0] ** 2 + x[1] ** 3 # y = 4 + 27 = 31
# 역전파로 기울기 계산
y.backward()
# dy/dx1 = 2*x1 = 4, dy/dx2 = 3*x2^2 = 27
print(x.grad) # tensor([ 4., 27.])
딥러닝에서 "학습"이라는 말은 사실 **'기울기를 구해서 파라미터를 조금씩 수정하는 과정'**을 의미합니다. 이 기울기를 자동으로 계산해 주는 것이 바로 Autograd입니다.
박시니어 씨가 설명했습니다. "기울기가 뭔지 알죠?
수학 시간에 배운 도함수요. f(x) = x^2에서 x=3일 때 기울기는 6이에요.
즉, x를 살짝 키우면 y는 6배만큼 커진다는 뜻이죠." 이걸 언어모델에 적용해 봅시다. 모델이 "나는" 다음에 "사과"를 예측했는데 정답은 "학교"였습니다.
이때 모델의 파라미터들을 살짝 수정해서 다음엔 "학교"를 예측하도록 만들어야 합니다. 어느 방향으로, 얼마나 수정해야 할까? 이걸 알려주는 것이 기울기입니다.
코드를 보면 requires_grad=True를 설정한 부분이 핵심입니다. 이 플래그를 켜면 PyTorch가 이 텐서에 대한 모든 연산을 기록합니다.
마치 도서관 사서가 내가 빌린 모든 책의 목록을 적어두는 것과 같습니다. y.backward()를 호출하는 순간 기적이 일어납니다.
PyTorch가 기록해 둔 연산의 역순으로 거슬러 올라가며, 각 파라미터의 기울기를 계산합니다. 이를 **역전파(Backpropagation)**라고 합니다.
x[0]=2일 때 x[0]^2의 기울기는 22=4, x[1]=3일 때 x[1]^3의 기울기는 39=27입니다. 결과가 정확히 맞네요.
이 기울기를 사용하면 "파라미터를 늘려야 할지 줄여야 할지"를 알 수 있습니다. 기울기가 양수면 해당 파라미터를 줄이고, 음수면 늘리면 손실이 줄어듭니다.
이게 바로 **경사하강법(Gradient Descent)**의 원리입니다. 주의할 점이 있습니다.
requires_grad=True는 계산을 추적하므로 메모리를 더 사용합니다. 추론(inference) 시에는 .detach()나 torch.no_grad()로 추적을 끄면 메모리를 절약할 수 있습니다.
실전 팁
💡 - torch.no_grad() 블록 안에서는 미분 추적이 꺼지므로 메모리를 절약할 수 있습니다
- 기울기는 기본적으로 누적되므로, 다음 학습 전에
.zero_grad()로 초기화해야 합니다
4. 옵티마이저와 학습 루프
김개발 씨는 기울기를 구하는 방법을 배웠습니다. 그런데 기울기만 있으면 자동으로 모델이 좋아지는 걸까요?
박시니어 씨가 웃으며 말했습니다. "기울기는 방향을 알려줄 뿐이에요.
실제로 걸어가는 건 옵티마이저가 합니다."
**옵티마이저(Optimizer)**는 계산된 기울기를 사용해 모델의 파라미터를 업데이트하는 역할을 합니다. 가장 대표적인 SGD는 기울기 방향으로 일정한 보폭으로 걸어가듯 파라미터를 수정합니다.
마치 목적지까지 방향만 가리켜주는 내비게이션 아래에서 운전자가 직접 액셀을 밟는 것과 같습니다.
다음 코드를 살펴봅시다.
import torch
import torch.optim as optim
# 간단한 가중치와 학습률 설정
w = torch.tensor([1.0], requires_grad=True)
optimizer = optim.SGD([w], lr=0.1) # 학습률 0.1
# 3번 학습하는 루프
for step in range(3):
loss = (w - 5.0) ** 2 # w가 5가 되도록 학습
loss.backward() # 기울기 계산
optimizer.step() # 파라미터 업데이트
optimizer.zero_grad() # 기울기 초기화
print(f"Step {step}: w = {w.item():.3f}, loss = {loss.item():.3f}")
기울기를 구하는 것만으로는 모델이 학습되지 않습니다. 기울기는 "이 방향으로 가면 손실이 줄어든다"는 정보일 뿐입니다.
실제로 파라미터를 수정하는 역할을 하는 것이 바로 옵티마이저입니다. 박시니어 씨가 비유를 들었습니다.
"산 정상에서 골짜기로 내려가는 상상을 해보세요. 기울기는 '어느 방향이 아래인지' 알려주는 나침반이고, 옵티마이저는 그 방향으로 실제로 걷는 사람입니다." 코드를 보면 optim.SGD([w], lr=0.1)로 옵티마이저를 만듭니다.
여기서 **lr(학습률)**이 매우 중요합니다. 학습률은 한 걸음의 크기입니다.
너무 크면 골짜기를 그냥 지나쳐 버리고, 너무 무리면 산 밖으로 튕겨 나갑니다. 반대로 너무 작으면 한 걸음씩 한 걸음씩이라 영원히 도착하지 못합니다.
학습 루프는 항상 세 단계로 구성됩니다. 첫째, loss.backward()로 기울기를 계산합니다.
둘째, optimizer.step()으로 파라미터를 업데이트합니다. 셋째, optimizer.zero_grad()로 기울기를 초기화합니다.
이 세 단계를 반복하는 것이 학습 루프입니다. 코드에서는 w=1.0에서 시작해서 w=5.0에 도달하도록 학습합니다.
손실 함수 (w - 5.0) ** 2는 w가 5에서 멀수록 큰 값을 반환합니다. 즉, w를 5로 만들어야 손실이 0이 됩니다.
실행해 보면 w가 1.0에서 점점 5.0에 가까워지는 것을 볼 수 있습니다. Step 0에서 w=1.800, Step 1에서 w=2.440, Step 2에서 w=2.952로 변합니다.
매번 학습률(0.1)만큼씩 5에 다가가는 것입니다. 실제 언어모델에서는 이 학습 루프가 수만 번에서 수십만 번 반복됩니다.
그만큼 많은 데이터를 보면서 파라미터를 조금씩 조정하는 것이죠. 어제 배운 next token prediction을 이 학습 루프로 구현하게 될 것입니다.
옵티마이저에는 SGD 외에도 Adam, AdamW 같은 변종이 있습니다. Adam은 "한 걸음의 크기를 자동으로 조절"하는 스마트 옵티마이저입니다.
나중에 실제 모델을 학습할 때는 주로 AdamW를 사용할 예정입니다.
실전 팁
💡 - 학습률은 보통 0.001에서 0.0001 사이를 많이 사용합니다
- 기울기를 초기화(
.zero_grad())하는 것을 잊으면 기울기가 누적되어 학습이 망가집니다
5. 선형 변환과 nn.Module
"파라미터를 업데이트하는 건 이해했어요. 그런데 실제 모델은 파라미터를 어떻게 가지고 있죠?" 김개발 씨의 질문에 박시니어 씨가 노트북을 열며 말했습니다.
"바로 이번에 배울 nn.Module이 그 답입니다."
nn.Module은 PyTorch에서 모델을 정의하는 기본 클래스입니다. 모델의 파라미터(가중치, 편향)를 자동으로 관리하고, 학습 가능한 상태를 유지합니다.
마치 하나의 기계 장치를 조립하는 설계도와 같습니다.
다음 코드를 살펴봅시다.
import torch
import torch.nn as nn
# 간단한 선형 회귀 모델 정의
class SimpleModel(nn.Module):
def __init__(self):
super().__init__()
# 입력 3차원 -> 출력 2차원
self.linear = nn.Linear(3, 2)
def forward(self, x):
return self.linear(x)
# 모델 생성과 사용
model = SimpleModel()
inputs = torch.randn(4, 3) # 배치 4개, 입력 3차원
outputs = model(inputs) # 자동으로 forward 호출
print(outputs.shape) # torch.Size([4, 2])
지금까지 텐서, 기울기, 옵티마이저를 배웠습니다. 이 세 가지를 하나로 묶어서 "학습 가능한 모델"로 만들어주는 것이 바로 nn.Module입니다.
박시니어 씨가 설명했습니다. "nn.Module은 모델의 뼈대예요.
이 안에 파라미터들을 넣고, 입력을 받아 출력을 내는 forward 메서드를 정의하면 끝입니다." 코드를 보면 SimpleModel 클래스가 nn.Module을 상속받습니다. __init__에서 nn.Linear(3, 2)를 정의하는데, 이는 입력 3차원을 출력 2차원으로 변환하는 선형 변환입니다.
수식으로는 y = Wx + b입니다. 가중치 W는 3x2 행렬이고, 편향 b는 길이 2인 벡터입니다.
forward 메서드는 모델이 "입력을 받았을 때 무엇을 할지"를 정의하는 곳입니다. 여기서는 단순히 self.linear(x)를 호출하지만, 나중에는 여러 층을 거치고 활성화 함수를 거치는 복잡한 변환을 넣게 됩니다.
모델을 만들고 model(inputs)를 호출하면 PyTorch가 자동으로 forward 메서드를 실행합니다. outputs.shape이 (4, 2)인 것은 배치 크기 4개의 입력이 각각 2차원 출력으로 변환되었음을 보여줍니다.
가장 중요한 점은 nn.Module이 파라미터를 자동으로 추적한다는 것입니다. model.parameters()를 호출하면 모든 학습 가능한 파라미터를 반환합니다.
옵티마이저는 이 파라미터 목록을 받아서 기울기를 계산하고 업데이트합니다. 실제 언어모델에서는 이 nn.Module 안에 여러 개의 층을 쌓습니다.
임베딩 층, Transformer 층, 출력 층 등이 모두 nn.Module 안에서 정의됩니다. 우리는 앞으로 이 구조를 점차 확장해 나갈 것입니다.
실전 팁
💡 - print(model)로 모델의 구조를 한눈에 볼 수 있습니다
model.parameters()로 모든 학습 가능한 파라미터에 접근할 수 있습니다
6. 손실 함수와 모델 평가
김개발 씨는 모델을 만들고 옵티마이저까지 설정했습니다. "이제 학습을 시키면 되나요?" 박시니어 씨가 고개를 끄덕였습니다.
"맞아요. 마지막으로 필요한 게 하나 있어요.
모델이 얼마나 틀렸는지 측정하는 손실 함수요."
**손실 함수(Loss Function)**는 모델의 예측값과 실제 정답 사이의 차이를 숫자로 계산합니다. 어제 배운 next token prediction에서는 모델이 예측한 다음 토큰과 실제 다음 토큰이 얼마나 다른지를 측정합니다.
마치 시험에서 정답과 내 답안을 비교해서 점수를 매기는 것과 같습니다.
다음 코드를 살펴봅시다.
import torch
import torch.nn as nn
# 교차 엔트로피 손실 함수 (분류 문제용)
criterion = nn.CrossEntropyLoss()
# 모델 예측과 실제 정답
predictions = torch.tensor([[0.2, 0.7, 0.1], # 배치 2개
[0.8, 0.1, 0.1]]) # 각 3개 클래스
targets = torch.tensor([1, 0]) # 정답 인덱스
loss = criterion(predictions, targets)
print(f"Loss: {loss.item():.4f}")
# 정답 예측 확인
predicted_classes = predictions.argmax(dim=1)
correct = (predicted_classes == targets).sum()
print(f"Accuracy: {correct.item()}/{len(targets)}")
모델이 학습하려면 "얼마나 틀렸는지"를 숫자로 알아야 합니다. 이 숫자가 바로 **손실(loss)**입니다.
손실이 크면 많이 틀린 것이고, 손실이 작으면 잘 맞춘 것입니다. 학습의 목표는 이 손실을 줄이는 것입니다.
어제 배운 next token prediction을 생각해 봅시다. 모델이 "나는" 다음에 "학교에"를 예측했는데 정답은 "밥을"이었다면 손실이 큽니다.
반대로 정답과 일치하면 손실이 작습니다. 언어모델에서 가장 많이 사용하는 손실 함수는 **CrossEntropyLoss(교차 엔트로피 손실)**입니다.
이 함수는 모델이 각 토큰에 할당한 확률과 실제 정답 토큰을 비교합니다. 모델이 정답 토큰에 높은 확률을 부여하면 손실이 작아지고, 틀린 토큰에 높은 확률을 부여하면 손실이 커집니다.
코드를 보면 predictions는 모델의 출력입니다. 각 행은 하나의 입력에 대한 3개 클래스의 확률입니다.
첫 번째 입력에서 모델은 두 번째 클래스(인덱스 1)에 가장 높은 확률 0.7을 주었고, 정답도 1입니다. 두 번째 입력에서는 첫 번째 클래스(인덱스 0)에 0.8을 주었고 정답도 0입니다.
.argmax(dim=1)은 가장 확률이 높은 클래스의 인덱스를 반환합니다. 이를 정답과 비교하면 정확도(accuracy)를 계산할 수 있습니다.
하지만 학습에서는 정확도보다 손실 값을 사용합니다. 손실은 연속적인 숫자라 미분이 가능하지만, 정확도는 이산적이라 기울기를 구할 수 없기 때문입니다.
학습 루프는 이렇게 완성됩니다. 전진 계산(foward)으로 예측을 하고, 손실 함수로 얼마나 틀렸는지 계산하고, 역전파(backward)로 기울기를 구하고, 옵티마이저로 파라미터를 업데이트합니다.
이 네 단계가 딥러닝 학습의 전부입니다.
실전 팁
💡 - 손실이 줄어들지 않고 튀어오르면 학습률이 너무 큰 것이니 줄여보세요
CrossEntropyLoss는 내부적으로 softmax를 포함하므로 모델 출력에 별도로 softmax를 적용하지 않아도 됩니다
7. 전체 학습 파이프라인
지금까지 배운 모든 것을 하나로 합쳐봅시다. 텐서, 자동 미분, 옵티마이저, nn.Module, 손실 함수.
이 다섯 가지가 만나면 비로소 완전한 학습 파이프라인이 완성됩니다. 김개발 씨의 눈이 반짝였습니다.
"드디어 모델을 학습시켜볼 수 있겠네요!"
학습 파이프라인은 데이터 준비, 모델 정의, 손실 함수 설정, 옵티마이저 설정, 학습 루프 실행의 다섯 단계로 구성됩니다. 이 파이프라인은 어떤 딥러닝 모델을 만들든 동일한 구조를 가집니다.
마치 요리 레시피의 기본 단계가 항상 재료 준비, 조리, 플레이팅으로 같은 것과 같습니다.
다음 코드를 살펴봅시다.
import torch
import torch.nn as nn
import torch.optim as optim
# 1단계: 데이터 준비
X = torch.randn(100, 3) # 학습 데이터 100개
y = (X[:, 0] + X[:, 1] > 0).long() # 이진 분류 정답
# 2단계: 모델 정의
model = nn.Linear(3, 2) # 입력 3 -> 출력 2
# 3단계: 손실 함수와 옵티마이저
criterion = nn.CrossEntropyLoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)
# 4단계: 학습 루프
for epoch in range(20):
loss = criterion(model(X), y) # 전진 + 손실 계산
loss.backward() # 역전파
optimizer.step() # 파라미터 업데이트
optimizer.zero_grad() # 기울기 초기화
if epoch % 5 == 0:
print(f"Epoch {epoch}: loss = {loss.item():.4f}")
드디어 모든 퍼즐 조각이 맞춰집니다. 오늘 배운 텐서, Autograd, 옵티마이저, nn.Module, 손실 함수가 하나의 파이프라인으로 연결되면 비로소 모델이 학습됩니다.
코드를 보면 네 가지 단계가 명확히 구분되어 있습니다. 먼저 데이터를 준비합니다.
여기서는 100개의 3차원 입력과 이진 분류 정답을 만들었습니다. 실제 언어모델에서는 텍스트 데이터를 토큰으로 변환한 텐서가 여기에 들어갑니다.
다음으로 모델을 정의합니다. 지금은 간단한 nn.Linear 하나지만, 나중에는 Transformer 기반의 복잡한 모델이 여기에 들어갑니다.
중요한 것은 모델의 구조만 바뀔 뿐 파이프라인은 같다는 점입니다. 손실 함수와 옵티마이저를 설정합니다.
여기서는 CrossEntropyLoss와 Adam을 사용했습니다. Adam은 학습률을 자동으로 조절하는 옵티마이저로, 처음에는 큰 보폭으로 이동하다가 목적지에 가까워지면 보폭을 줄입니다.
학습 루프를 실행합니다. 20번의 epoch 동안 손실을 계산하고 기울기를 구하고 파라미터를 업데이트합니다.
출력을 보면 손실이 점점 줄어드는 것을 확인할 수 있습니다. 이것이 바로 모델이 학습하고 있다는 증거입니다.
이 파이프라인이 왜 중요할까요? 앞으로 우리가 만들 GPT 스타일 언어모델도 이 똑같은 구조로 학습됩니다.
모델이 Transformer로 바뀌고, 데이터가 텍스트로 바뀌고, 손실 함수가 조금 복잡해질 뿐, 근본적인 학습 과정은 변하지 않습니다. 지금은 간단한 선형 모델이지만, 이 기초가 확실히 잡혀 있어야 나중에 복잡한 모델을 만들 때 당황하지 않습니다.
박시니어 씨가 말했듯 "기초가 탄탄하면 응용은 저절로 따라옵니다."
실전 팁
💡 - 이 다섯 단계의 파이프라인은 어떤 딥러닝 프로젝트에서든 동일합니다
- 학습 중 손실이 0에 수렴하면 과적합(overfitting)을 의심해 보세요
- 배치 크기를 조절하면 학습 속도와 안정성에 영향을 줍니다
- 다음 카드뉴스에서는 텍스트를 숫자로 변환하는 "문자 단위 토크나이저 만들기"를 다룹니다. 지금 배운 텐서가 그때 핵심 역할을 합니다
- 이 카드뉴스는 "LLM 바닥부터 만들기: 30일 완성 코스" 코스의 2/30편입니다
이상으로 학습을 마칩니다. 위 내용을 직접 코드로 작성해보면서 익혀보세요!
댓글 (0)
함께 보면 좋은 카드 뉴스
프레임워크 선택 LangGraph vs CrewAI vs AutoGen 완벽 가이드
AI 에이전트 개발을 위한 세 가지 핵심 프레임워크를 비교 분석합니다. 각 프레임워크의 특징, 장단점, 실무 선택 기준을 초급 개발자도 이해할 수 있도록 설명합니다.
Day 6 학습 루프 이해하기
LLM이 실제로 어떻게 학습하는지 학습 루프의 핵심 원리를 단계별로 살펴봅니다. Forward Pass, Loss 계산, Backward Pass, 파라미터 업데이트까지 한 사이클의 전 과정을 이해합니다.
Day 5 Baseline 모델 만들기
복잡한 모델에 앞서 가장 단순한 Baseline 모델을 직접 만들어봅니다. 아무런 기교 없이 순수하게 다음 토큰을 예측하는 모델을 구현하면서, 언어모델의 가장 기본 구조를 이해합니다.
Day 4 학습용 샘플 데이터 만들기
LLM을 학습시키기 위한 샘플 데이터를 직접 만들어봅니다. 작은 텍스트 말뭉치를 준비하고, 토크나이저로 변환한 뒤 PyTorch 텐서로 만드는 전체 과정을 단계별로 배웁니다.
LLM 핵심 원리 함수 호출 환각 임베딩 완벽 가이드
LLM의 세 가지 핵심 개념인 함수 호출(Function Calling), 환각(Hallucination), 임베딩(Embedding)을 중급 개발자 관점에서 실무 중심으로 설명합니다. 에이전트 AI 엔지니어가 반드시 알아야 할 원리와 실전 팁을 담았습니다.