Yet Never Lose Faith

- Good to Great , Jim Collins

How To Preprocess Image Data 자세히보기

Deep Learning/[Books] Do it! 정직하게 코딩하며 배우는 딥러닝 입문

[모델 튜닝] 하는 방법 - 과대적합과 과소적합

Kellyyyy 2020. 9. 24. 08:00

 

 

 

 

이번 포스팅에서는 머신러닝/딥러닝 모델의 성능평가 이슈 2가지 과대적합(overfittiong)과 과소적합(underfitting)에 대해서 다룬다.


| Overfitting VS Underfitting

 

과대적합(Overfitting)이란 모델이 훈련세트에서는 좋은 성능을 내지만 검증세트에서는 낮은 성능을 내는 경우를 말한다. 구체적인 예로 분류 문제에서 훈련세트의 정확도가 99%이고, 검증세트의 정확도가 80% 수준이라면 과대적합을 의심할 수 있다. 반면에 과소적합(Underfitting)훈련세트와 검증 세트의 성능에는 차이가 크지 않지만 모두 낮은 성능을 내는 경우이다.

 


| 언제 발생해??

 

도서 <Do it! 정직하게 코딩하며 배우는 딥러닝 입문>에서는 과소, 과대 적합이 발생하는 원인을 3가지 관점에서 분석했다. 

 

1. 훈련세트의 크기와 과대/과소적합

훈련세트 크기와 과대/과소 적합

X축은 훈련세트의 크기, Y축은 모델의 정확도이다. 첫 번째 그래프는 과대적합된 모델이다. 훈련세트의 정확도는 높지만 검증세트의 정확도가 그에 비해 현저히 낮은 것을 볼 수 있다.  과대 적합의 주요 원인 중 하나는 훈련 세트에 충분히 다양한 패턴의 샘플이 포함되지 않은 경우이다. 훈련세트에 다양한 샘플이 없으니 검증 세트에 제대로 적응하지 못한 것이다. 이런 경우에는 더 많은 훈련 샘플을 모아 검증 세트의 성능을 향상시킬 수 있다. 현실적인 한계로 훈련 샘플을 모을 수 없는 경우에는 모델이 훈련 세트에 집착하지 않도록 가중치를 제한할 수 있다.

 

두 번째 그래프는 과소적합된 모델의 그래프다. 훈련세트와 검증세트에서 측정한 성능의 간격은 점점 가까워지지만 성능 자체가 낮다. 과소적합은 모델이 충분히 복잡하지 않아 훈련 데이터에 있는 패턴을 모두 잡아내지 못하는 현상이다. 해결하는 방법은 복잡도가 더 높은 모델을 사용하거나 가중치의 규제를 완화하는 것이다.

 

마지막 그래프과대 적합과 과소 적합 사이에서 절충점을 찾은 모습이다.

 

2. 에포크 횟수와 과대/과소적합

 

epoch 횟수와 과대/과소적합

 

X축은 에포크의 횟수, Y축은 정확도이다. 에포크 횟수가 증가하면 훈 세트의 정확도는 증가하지만 검증 세트의 정확도는 최적점을 지나면서 오히려 감소한다. 최적점 이후에도 훈련세트로 모델을 학습시키면 모델이 훈련 세트의 샘플에 더 밀착하여 학습하기 때문이다. 그래서 최적점 이후의 영역을 과대적합 영역이라고 한다. 반대로 최적점 이전에는 훈련세트와 검증세트의 정확도가 비슷한 간격을 유지하면서 함께 증가하는데 이 영역에서 학습을 중지하면 과소적합된 모델이 만들어진다.

 

3. 모델 복잡도와 과대/과소적합  

 

모델 복잡도와 과대/과소 적합

 

X축은 모델복잡도, Y축은 정확도이다. 모델복잡도란 모델이 가진 학습 가능한 가중치 개수를 말하는데 층의 개수나 유닛의 개수가 많아지면 복잡도가 높은 모델이 만들어진다. 에포크 횟수와 마찬가지로, 모델 복잡도가 높아질수록 훈련세트의 정확도는 높아지지만 최적점 이후로 검증세트의 정확도는 감소한다. 이유는 모델이 복잡해서 훈련세트에만 잘 맞는 형태로 만들어지면 훈련세트에서만 좋은 성능을 내기 때문이다. 그래서 최적점 이후의 영역을 과대적합 영역이라고 한다. 반면에 모델의 복잡도가 너무 낮아도 훈련세트의 경향을 잘 반영하지 못하기 때문에 과소적합된 모델이 만들어진다.

 


Conclusion.

 

위 분석들을 통해 알 수 있는 점은 훈련세트의 크기, 에포크 횟수와 모델 복잡도가 높다고 해서 절대적으로 성능이 높아지는 것은 아니다. 따라서 우리는 모델 튜닝 단계에서 여러가지 관점의 그래프 해석을 통해 최적점을 찾아내야 한다.

 


Practice! : 최적 epoch 횟수 찾고 튜닝하기 

class SingleLayer :
  def __init__(self, learning_rate=0.1) :
    self.w = None
    self.b = None
    self.losses = []
    self.val_losses = []
    self.lr = learning_rate

...(중략)...

  def fit(self, x, y, epochs=100, x_val=None, y_val=None) :
    self.w = np.ones(x.shape[1])
    self.b = 0
    for i in range(epochs) :
      loss = 0
      indexes = np.random.permutation(np.arange(len(x)))
      for i in indexes :
        z = self.forpass(x[i])
        a = self.activation(z)
        err = -(y[i] - a)
        w_grad, b_grad = self.backdrop(x[i], err)
        self.w -= self.lr * w_grad
        self.b -= b_grad
        a = np.clip(a, 1e-10, 1-1e-10)
        loss += -(y[i]*np.log(a) + (1-y[i])*np.log(1-a))
      self.losses.append(loss/len(y))
      self.update_val_loss(x_val, y_val)
    
...(중략)...
  
  def update_val_loss(self, x_val, y_val) :
    if x_val is None :
      return
    val_loss = 0
    for i in range(len(x_val)) :
      z = self.forpass(x_val[i])
      a = self.activation(z)
      a = np.clip(a, 1e-10, 1-1e-10)
      val_loss += -(y_val[i]*np.log(a)+(1-y_val[i])*np.log(1-a))
    self.val_losses.append(val_loss/len(y_val))
    
from sklearn.datasets import load_breast_cancer
from sklearn.model_selection import train_test_split
import numpy as np
cancer = load_breast_cancer()
x = cancer.data
y = cancer.target
x_train_all, x_test, y_train_all, y_test = train_test_split(x,y,stratify=y,test_size=0.2, random_state=42)
x_train, x_val, y_train, y_val = train_test_split(x_train_all, y_train_all, stratify=y_train_all, test_size=0.2, random_state=42)

train_mean = np.mean(x_train, axis=0)
train_std = np.std(x_train, axis=0)
x_train_scaled = (x_train - train_mean) / train_std

x_val_scaled = (x_val-train_mean) / train_std

 

우선 머신러닝 모델을 만들고, 데이터셋을 로드해 전처리했다.

 

layer = SingleLayer()
layer.fit(x_train_scaled, y_train)
layer.score(x_val_scaled,y_val)
# 정확도 : 0.967032967032967

import matplotlib.pyplot as plt
plt.ylim(0,0.3)
plt.plot(layer.losses)
plt.plot(layer.val_losses)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train_loss','val_loss'])
plt.show()

다음으로 layer라는 모델을 만든 후 에포크 횟수 조절 없이 100회 동안 모델을 학습시켰다. 정확도는 약 0.967이 나왔다.

 

 

epoch횟수와 손실함수의 관계

 

또한 모델 튜닝을 위해 epoch 횟수에 따른 훈련세트와 검증세트의 손실함수 그래프를 그려보았다. 손실함수의 값은 정확도와 반비례하므로, 검증데이터의 손실값이 훈련데이터의 손실값보다 증가하는 영역이 과대적합 영역이다. 위 그래프를 보면 약 40번째 epoch부터 검증함수의 손실값이 훈련데이터의 손실값보다 커지는 것을 볼 수 있다. 그래서 나는 이 모델은 40번의 epoch이후에는 더 이상 훈련할 필요가 없다고 판단하고 epoch 횟수를 40회로 제한해 다시 모델을 학습시켰다.

 

layer3 = SingleLayer()
layer3.fit(x_train_scaled, y_train, epochs=40)
layer3.score(x_val_scaled, y_val)
# 정확도 : 0.978021978021978

그 결과 정확도는 약 0.978 정도로 튜닝 전보다 개선된 것을 확인할 수 있었다.


Reference.

- 도서 <Do it! 정직하게 코딩하며 배우는 딥러닝 입문>, 이지스 퍼블리싱, 박해선


끝.