머신러닝 & 딥러닝

언어모델 학습 시 고려사항

도갱도갱 2025. 2. 27. 11:59

1. 모델에 학습 데이터를 한 번에 학습시키면 안 되는가?

데이터를 한 번에 학습시키는 것은 메모리 한계, 일반화 문제, 최적화 어려움 등의 이유로 비효율적임.

(1) 메모리 한계

  • 대규모 데이터셋을 한 번에 모델에 입력하면 GPU/CPU 메모리를 초과할 가능성이 높음.
  • 특히 딥러닝에서는 행렬 연산을 수행하는 과정에서 메모리 사용량이 급격히 증가하기 때문에, 한 번에 모든 데이터를 처리하는 것은 현실적으로 어려움.

(2) 일반화 문제 (Overfitting)

  • 한 번에 학습하면 모델이 데이터셋 전체를 외워버리는 과적합(overfitting) 문제가 발생할 가능성이 높음.
  • 모델이 특정 데이터셋에만 최적화되면 새로운 데이터를 만났을 때 성능이 저하됨.

(3) 최적화 어려움

  • 경사하강법(Gradient Descent)에서 한 번에 모든 데이터를 사용하면, 최적의 가중치를 찾기 어려워지는 문제가 생김.
  • 특정 데이터가 전체 학습을 방해하는 경우가 있을 수 있음.
  • 따라서 데이터를 나누어 학습하면 모델이 더 빠르게 수렴하고, 최적점을 더 잘 찾을 가능성이 높아짐.

2. 데이터를 나누어 학습시키는 방법

데이터를 나누어 학습하는 방식은 크게 Batch Gradient Descent, Mini-Batch Gradient Descent, Stochastic Gradient Descent (SGD) 로 구분됨.

학습 방식 설명 장점 단점

Batch Gradient Descent (BGD) 전체 데이터셋을 사용하여 한 번의 업데이트 수행 최적해를 정확하게 찾을 가능성이 높음 연산량이 많고 속도가 느리며 메모리 부담이 큼
Stochastic Gradient Descent (SGD) 한 개의 샘플을 랜덤하게 뽑아 업데이트 빠르게 학습 가능, 국소 최적해 탈출 가능 최적해 근처에서 진동하며 안정성이 떨어짐
Mini-Batch Gradient Descent (MBGD) 일부 데이터(배치)를 사용하여 업데이트 속도와 안정성의 균형, 메모리 효율적 배치 크기에 따라 성능이 달라질 수 있음

(1) 배치 크기(Batch Size) 개념

  • 배치 크기는 한 번의 학습에서 모델이 처리하는 데이터 샘플 수를 의미함.
  • 작은 배치: 메모리 절약 가능하지만, 변동성이 커짐.
  • 큰 배치: 안정적이지만 메모리 부담이 커지고 일반화 성능이 떨어질 수 있음.

3. 학습 코드 예제

python

import torch
import torch.nn as nn
import torch.optim as optim
from torch.utils.data import DataLoader, TensorDataset

# 가상의 데이터 생성
x_data = torch.randn(1000, 10)  # 1000개의 샘플, 10개의 특성
y_data = torch.randn(1000, 1)   # 1000개의 레이블

# 데이터셋 & 데이터로더
dataset = TensorDataset(x_data, y_data)
dataloader = DataLoader(dataset, batch_size=32, shuffle=True)  # Mini-Batch 학습

# 간단한 모델 정의
model = nn.Sequential(
    nn.Linear(10, 64),
    nn.ReLU(),
    nn.Linear(64, 1)
)

# 손실 함수 및 옵티마이저 설정
criterion = nn.MSELoss()
optimizer = optim.Adam(model.parameters(), lr=0.01)

# 학습 과정
for epoch in range(10):  # 10번 반복 학습
    for batch_x, batch_y in dataloader:  # Mini-Batch 방식
        optimizer.zero_grad()
        output = model(batch_x)
        loss = criterion(output, batch_y)
        loss.backward()
        optimizer.step()

    print(f"Epoch {epoch+1}, Loss: {loss.item()}")

설명

  • DataLoader 를 사용하여 데이터를 미니배치로 나누어 학습시킴. (batch_size=32)
  • shuffle=True 를 설정하면 매 epoch마다 데이터 순서를 랜덤하게 섞어 일반화 성능을 높일 수 있음.
  • 옵티마이저로 Adam 을 사용하고, lr=0.01 로 러닝레이트 설정.
  • 학습 과정에서 loss.backward() 로 손실을 역전파하여 가중치를 업데이트함.

4. 러닝레이트 (Learning Rate) 개념

러닝레이트는 가중치를 업데이트하는 크기(스텝 크기) 를 조절하는 하이퍼파라미터임.

(1) 러닝레이트가 너무 크면?

  • 빠르게 최적값에 도달할 수도 있지만, 최적점을 지나쳐 진동하거나 발산할 가능성이 있음.
  • 학습이 불안정해지고, 최적의 가중치를 찾지 못할 수 있음.

(2) 러닝레이트가 너무 작으면?

  • 학습이 너무 느려지고, 지역 최적해(local minimum)에 갇힐 가능성이 커짐.
  • 최적점에 도달하더라도 시간이 오래 걸림.

(3) 적절한 러닝레이트를 찾는 방법

  • Step Decay: 특정 epoch마다 러닝레이트를 줄여서 학습 안정화
  • Exponential Decay: 지수 함수적으로 감소
  • Adaptive Methods (Adam, RMSprop): 학습 중 자동으로 러닝레이트 조정
python
# Step Decay 적용
scheduler = optim.lr_scheduler.StepLR(optimizer, step_size=5, gamma=0.1)

for epoch in range(20):
    for batch_x, batch_y in dataloader:
        optimizer.zero_grad()
        output = model(batch_x)
        loss = criterion(output, batch_y)
        loss.backward()
        optimizer.step()

    scheduler.step()  # 러닝레이트 감소 적용
    print(f"Epoch {epoch+1}, Loss: {loss.item()}, LR: {scheduler.get_last_lr()}")

(4) 최적의 러닝레이트 찾기

  • 러닝레이트 스케줄링을 활용해 초기에는 크게 설정하고 점점 감소시키는 것이 일반적임.
  • Adam 옵티마이저는 내부적으로 적응형 러닝레이트(adaptive learning rate)를 사용하여 따로 조정하지 않아도 됨.

5. 결론

  • 데이터를 한 번에 학습시키면 메모리 문제, 일반화 문제, 최적화 문제가 발생하므로 나누어서 학습해야 함.
  • 데이터를 나누는 방법에는 Batch Gradient Descent, Stochastic Gradient Descent(SGD), Mini-Batch Gradient Descent가 있음.
  • Mini-Batch 방식이 가장 현실적이고 많이 사용됨.
  • 러닝레이트는 학습 속도를 조절하는 핵심 요소이며, 적절한 값을 찾는 것이 중요함.
  • Step Decay, Exponential Decay, Adaptive Methods 등을 활용하면 최적의 러닝레이트를 찾을 수 있음.