머신러닝 & 딥러닝
언어모델 학습 시 고려사항
도갱도갱
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 등을 활용하면 최적의 러닝레이트를 찾을 수 있음.