Yet Never Lose Faith

- Good to Great , Jim Collins

How To Preprocess Image Data 자세히보기

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

[모델 튜닝] K-폴드 교차검증

Kellyyyy 2020. 10. 4. 08:00

 

 

이번 포스팅에서는 전체 샘플 데이터의 개수가 많지 않을 때 데이터를 부풀리는 방법인 교차검증(Cross Validation)에 대해서 다룬다.


Why?

 

훈련시킬 데이터의 개수가 부족하면 머신러닝 모델이 다양한 패턴을 학습하지 못하기 때문에 성능 높은 모델을 만들기 어렵다. 현실에서는 원하는 데이터를 충분하게 확보하기 어려운 경우가 많기 때문에 데이터의 특성은 유지하면서 데이터의 양을 늘리는 기법이 필수적이다. 교차검증도 그러한 방법 중 하나이다. 

 


How?

기존방식

기존 데이터 분할 방식

이전 포스팅까지 사용했던 방식은 전체 데이터를 8:2로 나눠 훈련세트를 얻은 후, 이 훈련세트를 다시 8:2로 분할해 검증세트로 사용했다. 전체 데이터가 100개라고 가정하면 60개의 데이터만 훈련에 사용할 수 있던 셈이다.

 

K-폴드 교차검증 방식

K-폴드 교차검증 방식

교차검증은 전체 데이터 세트를 8:2로 나눈 다음 8에 해당하는 훈련세트를 다시 k개의 작은 덩어리로 나누다. 그런 다음 작은 덩어리 1번씩 검증에 사용하고 나머지 덩어리를 훈련에 사용한다. 이때 한 덩어리를 폴드라고 하고, k개의 폴드로 나눈다고 하여 k-폴드 교차검증이라고도 한다. 전체 데이터 개수가 100개, K가 10이라고 가정하면 10개의 폴드가 생기므로 90개의 샘플을 훈련할 수 있다. 

원리

1. 훈련세트를 K개의 폴드로 나눈다.
2. 첫 번째 폴드를 검증 세트로 사용하고 나머지 폴드(K-1)를 훈련세트로 사용한다.
3. 모델을 훈련한 후 검증세트로 평가한다.
4. 차례대로 다음 폴드를 검증세트로 사용하여 반복한다.
5. K개의 검증세트로 K번 성능을 평가한 후, 계산된 성능의 평균을 내어 최종 성능을 계산한다.

Practice.

validation_scores = []

k = 10
bins = len(x_train_all) // k # (1) bins : 한 폴드에 들어갈 샘플의 개수

for i in range(k) :

  # (2) 검증 폴드 생성
  start = i*bins
  end = (i+1)*bins
  val_fold = x_train_all[start:end]
  val_target = y_train_all[start:end]

  # (3) 훈련 폴드 생성
  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]

  # (4) 훈련폴드 및 검증폴드 전처리
  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.001)
  lyr.fit(train_fold_scaled, train_target,epochs=100)
  score = lyr.score(val_fold_scaled, val_target)
  
  #(5) 폴드별 성능 기록
  validation_scores.append(score)


print(np.mean(validation_scores))
 # 결과 : 0.9800000000000001

 

(1) bins는 한 폴드의 들어갈 샘플의 개수로, 전체 훈련 데이터의 개수를 k(폴드 개수)로 나눈 몫이다.

(2) start, end는 각각 검증 폴드의 시작과 끝 인덱스이다.

(3) 검증폴드를 제외한 나머지 부분이 훈련폴드의 인덱스(train_index)이다. list함수와 range함수를 사용하여 새로운 리스트 형식으로 만들었다.

(4) 훈련폴드와 검증폴드로 분리한 후 전처리를 수행한다. 만약, 폴드를 나누기 전에 저체 훈련 데이터 전처리를 한다면 검증 폴드의 정보를 누설하게 되는 셈이므로 꼭! 폴드를 나눈 후 전처리를 수행해야한다.

(5) 폴드별 검증성능을 validation_scores라는 배열에 기록한 후, K번 성능을 계산한 후 평균을 내어 최종 성능을 구한다.

훈련폴드와 검증폴드의 인덱스


Conclusion.

 

결과를 보면 검증성능이 약 0.98로 교차검증을 사용하지 않았을 때보다 성능이 다소 향샹된 것을 볼 수 있다. 하지만 랜덤변수의 영향이 컸을 수도 있다. (실제로 몇번 더 수행해봤을 때는 0.96까지 나왔었다.) 정리해보면 교차검증 방식이 성능 향상에 기여할 수 있지만 무조건적으로 신뢰하면 안 된다는 점과 교차검증 방식으로 검증신뢰도를 올릴 수 있다는 점을 알 수 있었다. 추가적으로 데이터 세트의 크기에 따라 적절한 K를 정하는 법도 공부해봐야겠다. 

 


Reference.

도서 <Do it! 코딩으로 배우는 딥러닝 입문> 이지스 퍼블리싱, 박해선 지음

끝.