본문 바로가기
데이터 과학 관련 스터디/모두의 딥러닝

[모두의 딥러닝] 13장 과적합 피하기

by inhovation97 2020. 7. 14.

13장은 제가 잠깐 언급했던 과적합(overfitting)에 대한 챕터입니다.

과적합이 무엇인지에 대해서 정확히 짚어보고 그 해결방안을 주제로 포스팅 하겠습니다.

 

이번 데이터는 이진분류로 광석과 돌을 예측하는 모델을 설계합니다.

코딩은 지난 포스팅이랑 거의 똑같아요. 간단합니다.

 

 

<과적합(overfitting) 문제>

 

from keras.models import Sequential
from keras.layers.core import Dense
from sklearn.preprocessing import LabelEncoder

# 시드값 설정
np.random.seed(3)
tf.random.set_seed(3)

# 데이터 입력
dataset = df.values
X = dataset[:,0:60]
X = X.astype(float)
Y_obj = dataset[:,60]

# 문자열 변환
e = LabelEncoder()
e.fit(Y_obj)
Y = e.transform(Y_obj)

# 모델 설정
model = Sequential()
model.add(Dense(24, input_dim=60, activation='relu'))
model.add(Dense(10, activation='relu'))
model.add(Dense(1, activation='sigmoid'))

# 모델 컴파일
model.compile(loss='mean_squared_error',
             optimizer='adam',
             metrics=['accuracy'])

# 모델 실행
model.fit(X,Y, epochs=200, batch_size=5)
print('\n Accuracy: %.4f'% (model.evaluate(X,Y)[1]))

 

 

정확도는 100%로 나옵니다. 정말 100%인 모델일까요? 앞으로 모든 돌과 광물을 오차없이 분류하는 최고의 모델을 만든 것일까요? 지금 이 모델은 과적합이 일어났다고 볼 수있습니다.

 

 

 

머신러닝은 데이터를 학습하여 나중에 새로운 데이터를 잘 예측하는게 궁극적인 목표입니다.

 

새로운 데이터를 잘 예측해야하는데, 빨간선을 보면 알듯이 모델이 학습데이터에 대해서 너무 많이 학습해서 생기는 문제점이죠.

 

사실 ML모델을 설계하는 사람들은 전부 설계하는 과정에서 과적합을 굉장히 주의하면서 모델을 설계합니다.

 

이제부터 과적합을 해결해봅시다!

 

 

 

 

<과적합 해결하기>

모델의 층을 더하거나 epoch를 높이면, 모델이 학습 데이터를 더 많이 학습하고, 그 오차를 계속 줄이는 방향으로 나아 가니 정확도가 올라갑니다. 그렇다고 학습을 필요이상으로 낮추면 위 그림의 파란선이 그려지겠죠?

가장 대표적인 방법은 train set / test set을 나누는 것입니다!

 

학습셋과 테스트셋을 나누어서 테스트셋의 정확도가 더 낮아지지 않는 지점에서 학습을 멈추도록 모델을 설계하는 겁니다. 이는 사이킷런의 라이브러리로 아주 간단하게 구현할 수 있습니다.

train_test_split 함수를 써서 학습셋을 70% 테스트셋을 30%로 나눈 뒤에, train으로 학습한 모델로 과적합이 일어났는지를 확인해봅시다.

 

from sklearn.model_selection import train_test_split

# 학습셋과 테스트셋의 구분
X_train, X_test, Y_train, Y_test = train_test_split(X,Y,test_size=0.3, random_state=3)
model.fit(X_train, Y_train, epochs=130, batch_size=5)

# 테스트셋에 모델 적용
print("\n Test Accuracy: %.4f" % (model.evaluate(X_test, Y_test)[1]))  # 다른 셀에 실행하세요

 

아래 결과를 보면 train에서는 100%였던 정확도가 test셋에서는 0.7619의 정확도를 보입니다. 과적합이 일어나고 있다는 증거입니다. 그렇다면 이제 과적합을 해결해보겠습니다!

 

 

<K겹 교차 검증 (k - fold cross validation)>

 

보통 모델을 만들 때, 과적합을 경계하는 포인트가 크게 몇 가지 있습니다.

 

1. 데이터량이 매우 적을 때

   표본이 너무 적으면 모집단을 충분히 대표할 수 있을지 의심을 할 수 있습니다. 테스트셋은 전체 데이터의 30%정도에  불과하므로 정말로 모집단을 잘 대표할 수 있을 지를 의심합니다.

 

2. 모델이 복잡할 때

   모델의 파라미터 수가 복잡하고, 인공 신경망의 경우 은닉층이 매우 많아 모델이 복잡한 경우에는 모델이 과적합 되지 않게 주의하며 설계해야 합니다.

 

3. Imbalanced Data

   데이터의 라벨이 불균형함을 의미합니다. 가령 은행의 데이터를 보면 row가 신용 불량자의 비율은 굉장히 적어서 1%라고 가정한다면, row는 1만개이지만, 신용불량자에 대한 데이터는 100개의 row밖에 없는 것이지요. 겉으로 데이터는 굉장히 많아 보이지만, 정작 아주 필요한 데이터의 양은 굉장히 적은 케이스입니다.

 

더보기

이렇게 1,3번 처럼 데이터의 양이 부족한 경우에는 과적합의 위험이 있는데, 이때 아주 간단한 방법은 데이터 양을 늘리는 방법입니다! 하지만 데이터를 더 수집하는 데에는 많은 비용과 시간이 들 수 있습니다.

이때, 바로 'K겹 교차검증'을 이용할 수 있습니다.

 

 

데이터의 양을 train, test 모두 부풀린 뒤, 검증도 k번이나 할 수 있습니다.

 

sampling은 층화 추출법인 strartified k-fold를 이용합니다. 층화 추출법은 data의 레이블의 비율을 맞춰서 샘플링을 해주는 것입니다. 돌과 광물의 비율이 본 데이터의 비율에 맞게 샘플링을 실행하도록 해주는 것 입니다.

파라미터는 shuffle=True로  샘플의 순서를 섞지만, random_state를 고정시켜 일정한 결과를 유도합니다.

 

 

# 먼저 k-fold로 데이터를 쪼개줌

from sklearn.model_selection import StratifiedKFold

n_fold = 10
skf = StratifiedKFold(n_splits=n_fold, shuffle=True, random_state=3)
accuracy = []
# k개로 쪼갠 데이터를 for문으로 k번 검증함
for train, test in skf.split(X, Y):
    model = Sequential()
    model.add(Dense(24, input_dim=60, activation='relu'))
    model.add(Dense(10, activation='relu'))
    model.add(Dense(1, activation='sigmoid'))
    model.compile(loss='mean_squared_error',
                 optimizer='adam',
                 metrics=['accuracy'])
    model.fit(X[train], Y[train], epochs=100, batch_size=5)
    k_accuracy = '%.4f' % (model.evaluate(X[test], Y[test])[1])
    accuracy.append(k_accuracy)

# 결과 출력
print('\n %.f fold accuracy:' % n_fold, accuracy)

test셋의 결과가 잘 나온 것을 보니 잘 해결했다고 볼 수 있습니다!

보통 이런 모델 10개를 평균내어 최종 결괏값으로 정하는 '앙상블' 기법을 이용합니다.

 

아무튼 과적합 해결!!

댓글