본문으로 바로가기

5-2 과대적합, 과소 적합

category AI 2020. 11. 25. 13:17
728x90

학습 곡선을 통해 과대 적합과 과소 적합을 본다

  • 과대 적합
    • 모델이 훈련 세트에서는 좋은 성능을 내나 검증 세트에서는 낮은 성능을 내는 경우
    • 훈련 세트의 정확도가 99%일때 검증 세트의 정확도가 80%라면 의심할 수 있다.
  • 과소 적합
    • 훈련 세트와 검증 세트의 성능 차이가 크지 않으나 모두 낮은 성능을 내는 경우

 

  • 훈련 세트의 크기와 과대적합, 과소 적합 분석

학습 곡선

  • 첫 번째 학습 곡선
    • 과대 적합의 전형적인 모습
    • 훈련 세트와 검증 세트의 성능의 간격이 크다
    • 분산이 크다(high variance)
    • 원인으로는 훈련 세트에 충분히 다양한 패턴의 샘플이 포함되지 않은 경우
    • 해결 방안
      • 더 많은 훈련 샘플로 검증 세트의 성능 향상
      • 훈련 샘플을 모을 수 없는 경우 가중치 제한으로 조정
      • 가중치 제한을 하는 방법 == 모델의 복잡도를 낮추는 것
  • 두 번째 학습 곡선
    • 과소적합의 전형적인 모습
    • 훈련 세트와 검증 세트의 간격은 점점 가까워지나 성능이 낮음
    • 편향이 크다(high bias)
    • 원인으로는 모델이 충분히 복잡하지 않아 훈련 데이터에 있는 패턴을 모두 잡아내지 못함
    • 해결방안
      • 복잡도가 더 높은 모델을 사용
      • 가중치의 규제를 완화
  • 세번째 학습 곡선
    • 과대 적합과 과소 적합의 절충선을 찾음

 

  • 에포크와 손실 함수의 그래프로 과대 적합과 과소 적합 분석

  • 왼쪽 그래프
    • 검증 세트, 훈련 세트의 손실을 나타낸 것
    • 훈련 세트의 손실을 에포크가 진행될 수록 감소, 검증 세트의 손실은 증가
    • 이유는 최적점 이후에 계속 훈련 세트로 모델을 학습할 경우 모델이 훈련 세트의 샘플에 더 밀착하기 때문
    • 과대 적합의 방향으로 이동
    • 그러나 최적점 이전에 손실이 비슷할 경우 학습 중단시 과소 적합 모델의 완성
  • 오른쪽 그래프
    • 왼쪽은 손실, 오른쪽은 정확도에 비교
    • 그래프의 모습만 뒤집힐 뿐 해석은 동일

 

  • 모델의 복잡도와 손실 함수의 그래프로 과대적합과 과소 적합 분석

- 모델의 복잡도 : 모델이 가진 학습 가능한 가중치의 개수

- 층의 개수나 유닛의 개수가 많을 경우 복잡도가 높아진다

- 복잡도가 높다 - 과대 적합 위험

- 복잡도가 낮다 - 과소 적합 위험

 


적절한 편향-분산 트레이드오프 선택

- 과소적합 모델(편향), 과대 적합 모델(분산) 사이의 관계를 편향 - 분산 트레이드 오프(bias-variance tradeoff)

  • 트레이드오프의 의미
    • 편향을 줄이면 (훈련 세트의 성능을 높이면)
    • 분산이 커지고 (검증 세트와 차이가 커짐)
    • 분산을 줄이면 (검증 세트와 성능 차이를 줄이면)
    • 편향이 커짐 (훈련 세트의 성능이 낮아짐)

- 목표 : 분산이나 편향이 너무 심해지지 않는 적절한 중간지점 선택

 

  • 검증 손실을 기록하기 위한 변수 추가
 def __init__(self, learning_rate=0.1) :
        self.w = None
        self.b = None
        self.losses = []
        self.val_losses = []
        self.w_history = []
        self.lr = learning_rate

- 이전에 사용한 Singlelayer 클래스에 __init__() 메서드에 self.val_losses를 추가

 

  • fit() 메서드에 검증 세트 전달을 위한 매개변수 추가 (x_val, y_val)
def fit(self, x, y, epochs=100, x_val=None, y_val = None) :
        self.w = np.ones(x.shape[1])        # 가중치 초기화
        self.b = 0                          # 절편 포기화
        self.w_history.append(self.w.copy())    # 가중치 기록
        np.random.seed(42)                      # 무작위 시드 지정

        for i in range(epochs) :            # 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.backprop(x[i], err)   # 역방향 계산
                self.w -= self.lr * w_grad  # 가중치 업데이트(학습률 적용)
                self.b -= b_grad            # 절편 업데이트
                # 가중치를 기록
                self.w_history.append(self.w.copy())
                # 안전한 로그 계산을 위해 클리핑한 후 손실을 누적
                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(;en(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))

- 검증 세트 샘플 정방향 계산

- 활성화 함수 통과

- 그 결과를 이용한 로지스틱 손실 함수 값 계산을 위한 fit()에서 1 에포크마다 update_val_loss() 호출

 

  • 모델 훈련(단일 신경망)
layer3 = SingleLayer()
layer3.fit(x_train_scaled, y_train, x_val = x_val_scaled, y_val=y_val)

 

  • 손실 값으로 그래프그래 에포크 횟수 지정
plt.ylim(0, 0.3)
plt.plot(layer3.losses)
plt.plot(layer3.val_losses)
plt.ylabel('loss')
plt.xlabel('epoch')
plt.legend(['train_loss', 'val_loss'])
plt.show()

- 약 20번째 이후로 검증 손실이 훈련 세트보다 높아진다

 

  • 훈련 조기 종료

- 훈련 조기 종료방식은 조기종료(early stoppping)이라 한다

- 20번째 에포크 까지만 진후 성능 확인

layer4 = SingleLayer()
layer4.fit(x_train_scaled, y_train, epochs=20)
layer4.score(x_val_scaled, y_val)

- 약 97%의 정확도를 가진다

728x90