LLM 엔지니어링2장 · 신경망과 딥러닝의 기본 원리19 / 23← 이전목차다음 →MetaContents

2장. 신경망과 딥러닝의 기본 원리

실습 5 — 학습률 바꿔 보기

같은 신경망을 학습률 세 가지(0.0001, 0.01, 0.5)로 학습해, 손실이 줄어드는 모습과 시험용 MAE 를 견줍니다. "학습률" 절의 그림이 실제로도 그런지 확인하는 실습입니다.

1단계. 실습 3과 같은 준비

Python
import pandas as pd
import torch
from torch import nn
import matplotlib.pyplot as plt
from torch.utils.data import TensorDataset, DataLoader
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
from sklearn.metrics import mean_absolute_error

plt.rcParams["font.family"] = "Malgun Gothic"
plt.rcParams["axes.unicode_minus"] = False

df = pd.read_csv("daily_orders.csv")
df["일차"] = range(len(df))
features = ["일차", "주말", "공휴일", "기온", "강수mm", "광고비만원", "할인행사"]
X_train, X_test, y_train, y_test = train_test_split(
    df[features], df["주문량"], test_size=0.2, random_state=42
)
scaler = StandardScaler().fit(X_train)
X_train_t = torch.tensor(scaler.transform(X_train), dtype=torch.float32)
X_test_t = torch.tensor(scaler.transform(X_test), dtype=torch.float32)
y_train_t = torch.tensor(y_train.to_numpy() / 100, dtype=torch.float32).view(-1, 1)
print(X_train_t.shape)
출력
torch.Size([584, 7])

이 단계의 함수는 실습 3과 같습니다. 2단계에서 쓸 TensorDataset, DataLoader, mean_absolute_error 를 미리 불러 둔 것만 다릅니다.

2단계. 학습을 함수로 묶기

Python
def train(lr, epochs=200):
    """학습률 lr 로 실습 4와 같은 신경망을 학습하고, (에포크별 손실, 시험용 MAE) 를 돌려준다."""
    torch.manual_seed(42)        # 세 학습률이 같은 출발점에서 시작하게 한다
    model = nn.Sequential(nn.Linear(7, 32), nn.ReLU(), nn.Linear(32, 16), nn.ReLU(), nn.Linear(16, 1))
    opt = torch.optim.Adam(model.parameters(), lr=lr)
    loss_fn = nn.MSELoss()
    loader = DataLoader(TensorDataset(X_train_t, y_train_t), batch_size=32, shuffle=True,
                        generator=torch.Generator().manual_seed(42))
    history = []
    for epoch in range(epochs):
        total = 0.0
        for xb, yb in loader:
            opt.zero_grad()
            loss = loss_fn(model(xb), yb)
            loss.backward()
            opt.step()
            total += loss.item() * len(xb)
        history.append(total / len(X_train_t))
    with torch.no_grad():
        pred = model(X_test_t).numpy().ravel() * 100
    return history, mean_absolute_error(y_test, pred)

print("함수 준비 완료")
출력
함수 준비 완료

이 단계의 함수입니다.

코드쉬운 뜻
def train(lr, epochs=200):실습 4의 모델 만들기부터 채점까지를 함수 하나로 묶는다. 학습률만 바꿔 여러 번 부르려는 것이다
torch.manual_seed(42) (함수 안)부를 때마다 씨앗을 다시 고정해, 세 학습률이 똑같은 처음 가중치에서 출발하게 한다
nn.Sequential(...) 한 줄실습 4와 같은 층을 한 줄로 적었다
return history, mean_absolute_error(...)에포크별 손실 리스트와 시험용 MAE 두 가지를 함께 돌려준다

3단계. 세 학습률로 학습하고 견주기

Python
results = {}
for lr in [0.0001, 0.01, 0.5]:
    history, mae = train(lr)
    results[lr] = history
    # 마지막 에포크의 손실과 시험용 MAE 를 찍는다
    print(f"학습률 {lr:<6}  마지막 손실 {history[-1]:.4f}  시험용 MAE {mae:.1f}건")

# 세 손실 곡선을 한 그림에 겹쳐 그린다
plt.figure(figsize=(8, 3.5))
for lr, history in results.items():
    plt.plot(range(1, 201), history, label=f"학습률 {lr}")
plt.yscale("log")
plt.gca().yaxis.set_major_formatter(plt.FuncFormatter(lambda v, _: f"{v:g}"))   # 눈금을 보통 숫자로
plt.xlabel("에포크")
plt.ylabel("학습 손실(로그 눈금)")
plt.legend()
plt.title("학습률에 따른 손실 곡선")
plt.show()
출력
학습률 0.0001  마지막 손실 0.7626  시험용 MAE 76.1건
학습률 0.01    마지막 손실 0.0467  시험용 MAE 25.0건
학습률 0.5     마지막 손실 1.0930  시험용 MAE 77.8건
학습률 0.0001, 0.01, 0.5 의 학습 손실 곡선을 겹쳐 그린 그래프

이 단계의 함수입니다.

코드쉬운 뜻
history, mae = train(lr)함수가 돌려준 두 값을 차례로 받는다
results[lr] = history학습률을 열쇠로 손실 리스트를 사전에 모아 둔다
f"{lr:<6}"학습률을 왼쪽 정렬로 여섯 칸에 맞춰 찍어 줄을 가지런히 한다
plt.plot(..., label=f"학습률 {lr}")선마다 이름표를 단다
plt.legend()이름표를 모아 범례(어느 색이 어느 학습률인지)를 그린다

이 실습이 뜻하는 것

이 실습은 안개 낀 산에서 걸음 폭만 바꿔 세 번 내려와 보는 일과 같습니다. 같은 산과 같은 출발점을 준비하고(1단계), 내려오는 방법을 한 가지 절차로 정해 둔 뒤(2단계), 아주 작은 걸음, 알맞은 걸음, 아주 큰 걸음으로 200걸음씩 내려와 어디까지 왔는지 견줍니다(3단계). 여기서 걸음 폭이 학습률, 산의 높이가 손실, 정해 둔 절차가 함수 train(lr) 입니다.

단계출력뜻
1. 준비torch.Size([584, 7])실습 3과 같은 재료입니다
2. 함수함수 준비 완료학습률만 바꿔 같은 학습을 되풀이할 준비가 되었습니다
3. 학습률 0.0001손실 0.7626, MAE 76.1건걸음이 너무 작아 200 에포크가 끝나도 아직 내려가는 중입니다
3. 학습률 0.01손실 0.0467, MAE 25.0건세 가지 가운데 가장 좋습니다. 실습 4와 같은 결과입니다
3. 학습률 0.5손실 1.0930, MAE 77.8건걸음이 너무 커서 흔들리다 내려가지 못했습니다. 77.8건은 실습 6의 "늘 평균을 말하는" 기준선과 같은 숫자입니다
3. 손실 곡선세 선을 겹친 그래프파랑(0.0001)은 천천히 내려가고, 주황(0.01)은 빠르게 떨어져 평평해지고, 초록(0.5)은 처음에 튀었다가 1 근처에 머뭅니다

한 줄로 줄이면, 같은 모델과 같은 출발점에서도 학습률 하나에 따라 MAE 가 25.0건에서 77.8건까지 달라진다는 것을 보인 실습입니다. 세 값만 200 에포크 동안 견준 결과라 "0.01 이 언제나 정답"이라는 뜻은 아니고, 0.0001 도 에포크를 훨씬 늘리면 더 좋아집니다. 다음 실습 6에서는 0.01 로 학습한 신경망을 다른 모델과 견줍니다.

코드 설명

  • 학습을 함수 train(lr) 로 묶어 두면 학습률만 바꿔 여러 번 부를 수 있습니다. 함수 안의 코드는 실습 4와 같습니다.
  • 세 번 모두 torch.manual_seed(42) 로 같은 처음 가중치에서 출발하므로, 결과의 차이는 학습률에서만 옵니다.
  • 학습률 0.01 이 시험용 MAE 25.0건으로 가장 좋습니다. 그래프의 주황 선처럼 빠르게 떨어져 0.1 아래에서 평평해집니다.
  • 0.0001 은 파랑 선처럼 아주 천천히 내려가 200 에포크가 끝나도 손실 0.7626, MAE 76.1건입니다. 보폭이 작아 아직 내려가는 중입니다. 에포크를 훨씬 늘리면 더 좋아집니다.
  • 0.5 는 초록 선처럼 처음에 크게 튀었다가 손실 1 근처에서 더 내려가지 못합니다. MAE 77.8건은 실습 6의 기준선(늘 평균을 말하기)과 같은 숫자로, 큰 보폭에 흔들리다 사실상 평균만 말하는 모델이 되어 버린 것입니다.
  • 그래프의 선 색은 matplotlib 의 기본 색입니다(파랑, 주황, 초록 순서).
← 이전 절2장 · 실습 4 — 주문량 예측 신경망 학습하기다음 절 →2장 · 실습 6 — 기준선, 직선 모델과 견주기