
과적합(overfitting)이란 모델이 학습 데이터셋 안에서는 일정 수준 이상의 예측 정확도를 보이지만, 새로운 데이터에 적용하면 잘 맞지 않는 것을 의미한다.
과적합은 층이 너무 많거나 변수가 복잡해서 발생하기도 하고 테스트셋과 학습셋이 중복될 때 생기기도 한다. 특히 딥러닝은 학습 단계에서 입력층, 은닉층, 출력층의 노드들에 상당히 많은 변수가 투입되기에 과적합에 빠지지 않도록 주의해야 한다.

또한 epoch가 너무 많을 시에도 학습셋 내부에서만의 정확도가 높아져 실제 환경에선 제대로 된 결과를 내지 못할 수 있다.

과적합 문제를 방지하기 위해선 테스트 데이터셋과 학습 데이터셋을 완전히 분리한 후 학습과 동시에 테스트를 진행하는 것이 한 방법이다.
보통 학습 데이터셋과 테스트 데이터셋은 7 : 3으로 분리한다. 그 후 7의 데이터로 학습을 진행하며 모델을 만들고 3의 데이터로 모델을 실험해 정확도를 확인하면 얼마나 학습이 잘 되었는지 알 수 있는 것이다.
손실 함수(Loss Function) 평가: 모델이 예측한 결과와 실제 결과의 차이를 측정하는 지표다. 손실 함수가 낮을수록 모델의 예측이 정확하다는 것을 의미한다.
정확도(Accuracy) 평가: 모델이 예측한 결과와 실제 결과가 일치한 비율을 측정하는 지표다. 모델의 예측이 맞을수록 정확도가 높아진다.
혼동 행렬(Confusion Matrix) 평가: 이진 분류 문제에서 많이 사용되는 평가 방법으로, 실제 클래스와 모델이 예측한 클래스를 비교하여 TP(True Positive), TN(True Negative), FP(False Positive), FN(False Negative) 값을 계산한다. 이를 기반으로 정밀도(Precision), 재현율(Recall), F1-Score 등을 계산할 수 있다.
ROC 커브(ROC Curve) 평가: 이진 분류 문제에서 사용되는 평가 방법으로, 모델의 성능을 TPR(True Positive Rate)과 FPR(False Positive Rate)을 나타내는 곡선으로 표현한다. AUC(Area Under the Curve) 값이 높을수록 모델의 분류 성능이 높다는 것을 의미한다.
교차 검증(Cross Validation) 평가: 모델의 일반화 성능을 평가하기 위해 사용되는 방법으로, 데이터를 여러 개의 폴드로 나누어 각 폴드를 순서대로 검증 데이터로 사용하고, 나머지 폴드를 학습 데이터로 사용하여 모델을 학습시키는 방법이다.
Early Stopping 평가: 모델이 학습 데이터에 과적합(Overfitting)되는 것을 방지하기 위해 사용되는 방법으로, 검증 데이터 손실이 더 이상 개선되지 않을 때 학습을 중지하는 방법이다. 이를 통해 모델의 일반화 성능을 높일 수 있다.
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from sklearn.model_selection import train_test_split
import pandas as pd
!git clone https://github.com/taehojo/data.git
# 광물 데이터를 불러온다.
df = pd.read_csv('./data/sonar3.csv', header=None)
# 음파 관련 속성을 X로, 광물의 종류를 y로 저장한다.
X = df.iloc[:,0:60]
y = df.iloc[:,60]
# 학습셋과 테스트셋을 구분한다.
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3, shuffle=True)
# 모델을 설정한다.
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='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
# 모델을 실행한다.
history=model.fit(X_train, y_train, epochs=200, batch_size=10)
# 모델을 테스트셋에 적용해 정확도를 구한다.
score=model.evaluate(X_test, y_test)
print('Test accuracy:', score[1])
# 학습셋
Epoch 200/200
15/15 [==============================] - 0s 2ms/step - loss: 0.0163 - accuracy: 1.0000
# 테스트셋
2/2 [==============================] - 0s 8ms/step - loss: 0.7675 - accuracy: 0.7778
Test accuracy: 0.7777777910232544
학습 데이터에선 100%의 정확도를 보이지만 테스트 데이터에선 약 78%의 정확도를 보인다.
기존처럼 7 : 3 비율로 학습셋과 테스트셋을 분류하면 테스트셋은 학습셋에 이용할 수 없다는 단점이 있다. 이를 해결하기 위해 K겹 교차 검증(K-fold cross validation)이란 방법이 고안되었다.
K겹 교차 검증이란 데이터셋을 여러 개로 나누어 하나씩 테스트셋으로 사용하고 나머지를 모두 합해서 학습셋으로 이용하는 방법이다. 이렇게 하면 가지고 있는 데이터를 모두 학습셋으로 사용할 수 있고, 동시에 테스트셋으로 활용할 수 있다.

위의 그림이 5겹 교차 검증의 예가 된다.
데이터를 원하는 수만큼 나누어 각각 학습셋과 테스트셋으로 사용하게 하는 함수는 사이킷런 라이브러리의 KFold() 함수다.
# 예제
from sklearn.model_selection import KFold
# 몇 개의 파일로 나눌것인지
k = 5
kfold = KFold(n_splits=k, shuffle=True)
# 정확도가 채워질 리스트
acc_score = []
# split에 의해 테스트와 학습으로 분리
for train_index , test_index in kfold.split(X):
X_train , X_test = X.iloc[train_index,:], X.iloc[test_index,:]
y_train , y_test = y.iloc[train_index], y.iloc[test_index]
# 정확도를 리스트에 저장
accuracy = model.evaluate(X_test, y_test)[1]
acc_score.append(accuracy)
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
from sklearn.model_selection import KFold
from sklearn.metrics import accuracy_score
import pandas as pd
!git clone https://github.com/taehojo/data.git
# 광물 데이터를 불러온다.
df = pd.read_csv('./data/sonar3.csv', header=None)
# 음파 관련 속성을 X로, 광물의 종류를 y로 저장한다.
X = df.iloc[:,0:60]
y = df.iloc[:,60]
# 몇 겹으로 나눌 것인지를 정한다.
k=5
# KFold 함수를 불러온다. 분할하기 전에 샘플이 치우치지 않도록 섞어 준다.
kfold = KFold(n_splits=k, shuffle=True)
# 정확도가 채워질 빈 리스트를 준비한다.
acc_score = []
def model_fn():
model = Sequential() # 딥러닝 모델의 구조 시작.
model.add(Dense(24, input_dim=60, activation='relu'))
model.add(Dense(10, activation='relu'))
model.add(Dense(1, activation='sigmoid'))
return model
# K겹 교차 검증을 이용해 k번의 학습을 실행한다.
# split에 의해 k개의 테스트셋과 학습셋으로 분리된다.
for train_index , test_index in kfold.split(X):
X_train , X_test = X.iloc[train_index,:], X.iloc[test_index,:]
y_train , y_test = y.iloc[train_index], y.iloc[test_index]
model = model_fn()
model.compile(loss='binary_crossentropy', optimizer='adam', metrics=['accuracy'])
history=model.fit(X_train, y_train, epochs=200, batch_size=10, verbose=0)
accuracy = model.evaluate(X_test, y_test)[1] # 정확도를 구한다.
acc_score.append(accuracy) # 정확도 리스트에 저장한다.
# k번 실시된 정확도의 평균을 구한다.
avg_acc_score = sum(acc_score)/k
# 결과를 출력한다.
print('정확도:', acc_score)
print('정확도 평균:', avg_acc_score)
정확도: [0.9047619104385376, 0.7857142686843872, 0.7857142686843872,
0.7560975551605225, 0.8536585569381714]
정확도 평균: 0.8171893119812011
위와 같은 결과가 나왔다.