chae._.chae

03. 과대적합, 과소적합과 규제 방법 본문

ML/딥러닝 입문

03. 과대적합, 과소적합과 규제 방법

walbe0528 2022. 1. 31. 14:16
728x90
반응형

✔ 과대적합

  • 과대적합이란 모델이 훈련세트에서는 좋은 성능을 내지만 검증 세트에서는 낮은 성능을 내는 경우이다.
  • 과대적합 모델 = 분산이 크다. 
  • 원인 : 훈련세트에 다양한 패턴의 샘플이 포함되지 않아서 검증세트에 적응하지 못해 성능이 낮음
  • 해결 : 더 많은 훈련 샘플을 모아 훈련시킨다. 

 

최적점 이후에도 훈련세트로 모델을 학습시키면 모델이 훈련세트에 밀착하여 학습하기에, 모델이 과대적합된다. 

과대적합의 경우, 모델이 훈련세트에 집착하지 않도록 가중치를 제한할 수 있다.

(= 모델의 복잡도를 낮춘다)

 

 

✔ 과소적합

  • 과소적합이란 훈련세트와 검증세트의 성능에는 차이가 크지 않지만, 모두 낮은 성능을 내는 경우
  • 측정한 성능의 간격은 점점 가까워지지만, 성능 자체가 낮음
  • 과소적합 모델 = 편향이 크다.
  • 원인 : 모델이 충분이 복잡하지 않아 훈련 데이터에 있는 패턴을 모두 잡아내지 못함
  • 해결 : 복잡도가 더 높은 모델을 사용하거나, 가중치의 규제를 완화.

* 모델복잡도 : 모델이 가진 학습 가능한 가중치의 갯수. 

 

 

✔ 편향-분산 트레이드오프 

 

  • 편향을 줄이면(훈련세트의 성능 up), 분산이 커짐(검증세트와의 성능 차이 up)
  • 분산을 줄이면 편향이 커짐
  • 즉, 하나를 줄이면 하나가 커지는 관계이다. -> 분산/편향이 적절하도록 중간지점을 선택해야함

 

📖 규제방법

  • 가중치 규제(regulation) : 가중치의 값이 커지지 않도록 제한하는 기법이다. 

그래프의 성능을 평가할 때는, 경사가 급한 그래프보다는 경사가 완만한 그래프가 성능이 좋다고 말한다. 

오른쪽 그래프는 샘플 데이터에 너무 집착한 모습임.

  • 새로운 데이터에 적응하지 못하므로 좋은 성능을 가졌다고 할 수 X
  • 모델이 일반화되지 않았다.
  • L1 규제, L2 규제 기법

 

 

⚡ L1 규제

  • L1 규제는 손실함수에 가중치의 절댓값인 L1 norm을 추가한 것이다.

L1 norm의 정의

  • norm에서의 n은 가중치의 갯수이므로, L1 규제는 가중치의 절댓값을 손실함수에 더한 것

손실함수에 L1규제를 적용

  • alpha : L1 규제의 양을 조절하는 파라미터
  • alpha값이 크면 규제가 강하다 => 전체 손실함수의 값이 커지지 않아지도록 w값의 합이 작아지게 됨
  • alpha값이 작으면 규제가 약하다 => w의 합이 커져도 손실함수의 값이 큰 폭으로 변하지 않음

L1규제를 적용한 손실함수의 도함수

  • w_grad += alpha * np.sign(w)로 나타낼 수 있다.  // np.sign() : 부호를 반환
  • 라쏘(Lasso)모델 : 선형회귀에 L1규제를 적용한 모델 (일부 가중치를 0으로 만들 수도 있음)

 

L1 규제는 규제 하이퍼파라미터 alpha에 많이 의존한다. 

가중치의 크기에 따라 규제의 양이 변하지 않으므로 규제 효과가 좋다고 할 수 없다.

 

 

⚡ L2 규제

  • L2 규제는 손실함수에 가중치에 대한 L2 norm의 제곱을 더한 것이다.

L2 노름

 

L2 규제

  • alpha : 가중치의 양을 조절하는 하이퍼파라미터

L2 규제를 적용한 손실함수의 도함수

  • w_grad += alpha * w 로 나타낼 수 있다.
  • L2 규제는 그래디언트 계산에 가중치의 값 자체가 포함되므로, 가중치의 부호만으로 계산하는 L1 규제보다 더 효과적이다. 
  • L2 규제는 가중치를 완전히 0으로 만드는 경우는 없다. 가중치를 0으로 제외하면 특성을 제외하는 효과는 있지만 모델의 복잡도가 떨어진다. => L2 규제가 더 많이 쓰인다.
  • 릿지(ridge)모델 : 회귀모델에 L2 규제를 적용한 모델

L1 규제와 L2 규제를 동시에 수행하는 경우도 있다.

 

 

L1 규제의 강도에 따라 모델의 학습 곡선과 가중치가 어떻게 변할까 ?

규제강도는 0.0001, 0.001, 0.01 세가지로 해보자. 

 

l1_list = [0,0001, 0.001. 0,01]

for l1 in l1_list:
	lyr = SingleLayer(l1=l1)
    lyr.fit(x_train_scaled, y_train, x_va=x_val_scaled, y_val = y_val)
    
    plt.plot(lyr.losses)
    plt.plot(lyr.val_losses)
    plt.title('Learning Curve (l1={}'.format(l1))
    plt.ylabel('loss')
    plt.xlabel('epoch')
    plt.legend(['train_loss', 'val_loss'])
    plt.ylim(0, 0.3)
    plt.show()
    
    plt.plot(lyr.w, 'bo')
    plt.title('Weight (l1={}'.format(l1))
    plt.ylabel('value')
    plt.xlabel('weight')
    plt.ylim(-4, 4)
    plt.show()

 

규제강도가 0.0001, 0.001, 0.01일때

  • 규제가 더 커질수록 훈련세트의 손실과 검증세트의 손실이 더 커진다.  즉, 과소적합 현상이 일어난다. 
  • 규제 강도가 커질수록 가중치 그래프의 값이 점점 0에 가까워진다. 
  • L2 규제도 L1규제와 비슷한 양상을 보이지만, L2 규제는 규제강도가 강해져도 L1만큼 과소적합이 심해지지는 않는다. 

 


⚡교차검증(cross validation, k-폴드 교차 검증)

 

  • 검증세트를 훈련세트에서 분리하느랴 훈련세트의 샘플 갯수가 줄어들어 모델을 훈련시킬 데이터가 부족해지는 경우 사용한다.
  • 기존에는 전체 데이터세트를 8:2로 나누어 훈련세트와 데이터 세트를 얻고, 다시 훈련세트를 8:2로 나누어 훈련세트와 검증세트를 얻는 방법을 사용하였다.
  • 교차 검증에서는 검증세트가 훈련세트에 포함된다. 

 

  • 교차 검증 방법
  1. 훈련세트를 모두 동일한 크기의 k개의 폴드로 나눈다. 
  2. 첫 번째 폴드를 검증세트로 사용하고, 나머지 폴드를(k-1개) 훈련세트로 사용한다. 
  3. 모델을 훈련시키고, 검증세트로 평가한다. 그 다음 폴드를 검증세트로 사용하며 모델훈련과 평가를 반복해준다. 
  4. k개의 검증세트로 k번의 성능을 평가한 후, 성능의 평균을 내어 최종 성능을 구한다. 
  • k-폴드 교차 검증은 기존 방법보다 더 많은 데이터로 훈련할 수 있다. 

k-폴드 교차 검증을 위한 반복문 코드

validation_scores = []  # 각 폴드의 검증 점수를 저장하기 위한 리스트
k = 10
bins = len(x_train_all) // k  # bins갯수만큼 건너뛰며 폴드를 구분한다. 

for i in range(k):
    start = i*bins  # 검증폴드 샘플의 시작과 끝 인덱스, 나머지가 훈련폴드 샘플의 인덱스임
    end = (i+1)*bins
    val_fold = x_train_all[start:end]  # 검증폴드 
    val_target = y_train_all[start:end]
    
    train_index = list(range(0, start))+list(range(end, len(x_train_all)))  # 훈련폴드의 인덱스
    train_fold = x_train_all[train_index]  # 훈련폴드 
    train_target = y_train_all[train_index]
    
    train_mean = np.mean(train_fold, axis=0)  # 평균, 표준편차를 구해줌 
    train_std = np.std(train_fold, axis=0)
    train_fold_scaled = (train_fold - train_mean) / train_std  # 표준화 작업
    val_fold_scaled = (val_fold - train_mean) / train_std
    
    lyr = SingleLayer(l2=0.01)
    lyr.fit(train_fold_scaled, train_target, epochs=50)  # 훈련
    score = lyr.score(val_fold_scaled, val_target)  # 성능 검증
    validation_scores.append(score)

print(np.mean(validation_scores))  # 평균값을 구해 최종성능을 계산한다.

 

  • 훈련데이터의 표준화 전처리 작업을 폴드를 나눈 뒤에 수행 -> 폴드를 나누기 전에 표준화 전처리 작업을 한다면, 검증폴드의 정보가 새어나가기에 뒤에 해준다.
  • 주로 직접 구현하기보다, 사이킷런의 model_selection 모듈에 교차검증하는 cross_validate()함수를 사용한다. 
  • 인자로 교차검증하고 싶은 모델의 객체, 훈련데이터, 타깃데이터를 전달하고, cv매개변수에 폴드 수를 지정하고 사용하면 된다. cross_validation()함수는 파이썬 딕셔너리를 반환한다. 

 

⚡ Pipeline 클래스

 

  • cross_validate()함수를 사용할 때에도 동일하게, 검증 폴더가 누설되면 안된다. 이때, 데이터를 전처리하는 과정에 Pipeline클래스가 사용된다. 
  • 사이킷런은 검증 폴더가 전처리 단계에서 누설되지 않도록 전처리 과정과 모델클래스를 연결해주는 Pipeline클래스를 제공한다. 
  • cross_validate()함수로 인자를 넘길때, Pipeline클래스로 감싸 전달해준다. 

1. cross_validate()함수는 훈련세트를 훈련폴드와 검증폴드로 나누는 작업만 수행한다.

2. 전처리 단계와 SGDClassifie 클래스 객체의 호출은 Pipeline클래스에서 이루어진다. 

3. 검증폴드가 전처리 단계에서 누설되지 않게 된다. 

4. 사이킷런은 Pipeline함수를 만들어주는 make_pipeline()함수를 제공한다. 

 

728x90

'ML > 딥러닝 입문' 카테고리의 다른 글

04. 다층 신경망  (0) 2022.02.04
02. [로지스틱 회귀] 이진분류  (0) 2022.01.13
01. [선형회귀] 수치 예측  (0) 2022.01.10