인공지능 개론 (8) : 모델 성능 검증하기 (과적합, k겹 교차 검증)

STUDY_J·2024년 8월 22일
0

인공지능개론

목록 보기
9/13

1. 초음파 광물 예측 실험

데이터 확인

import pandas as pd

!git clone https://github.com/taehojo/data.git

df = pd.read_csv('./data/sonar3.csv', header = None)

df.head()

  • 마지막 열이 광물의 종류를 나타냄 (일반 암석 : 0, 광석일 경우 1)
  • 일반 암석과 광석이 각각 몇 개 포함되어 있는지 확인하기

  • 1 ~ 60 열을 X 변수에 저장하고, 광물의 종류를 y로 저장
  • 딥러닝 모델 설계 후 실행해보기
X = df.iloc[:, 0:60]
y = df.iloc[:, 60]

from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

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, y, epochs = 200, batch_size = 10)

정확도(accuracy)가 매우 높게 나타나는 것을 확인할 수 있음

2. 과적합(overfitting)이란?

과적합

  • 모델이 학습 데이터셋 안에서는 일정 수준 이상의 예측 정확도를 보이지만, 새로운 데이터에 적용하면 잘 맞지 않는 것을 의미한다

    이미지 출처 : 모두의 딥러닝
  • 과적합의 특징
    1. 훈련 데이터에 대한 높은 정확도 : 훈련 데이터에 대해 매우 높은 성능을 보임
    2. 테스트 데이터에 대한 낮은 일반화 성능 : 새로운 데이터에서는 예측이 부정확할 수 있음
  • 과적합의 원인
    1. 모델이 너무 복잡할 때
      모델이 너무 많은 파라미터나 복잡한 구조(예: 깊은 신경망)를 가지면, 훈련 데이터의 작은 세부사항이나 잡음까지 학습함
    2. 훈련 데이터가 부족할 때
      충분한 데이터를 제공하지 않으면, 모델이 데이터의 일반적인 패턴을 학습하기보다는, 제한된 데이터에 특화된 학습함
    3. 훈련 시간이 너무 길 때
      모델이 훈련 데이터에 과도하게 맞춰지면서, 실제 데이터에 대한 일반화 성능이 떨어짐

3. 과적합을 방지하는 방법

  • 과적합 방지 방법
    우선적으로, 학습을 하는 데이터 셋과 테스트할 데이터셋을 완전히 구분하여 학습과 동시에 테스트를 병행하며 진행한다

    이미지 출처 : 모두의 딥러닝
  • 지금까지 테스트셋을 만들지 않고 학습해왔지만, 매번 정확도를 계산할 수 있었음
    • 이는 데이터에 들어 있는 모든 샘플을 그대로 테스트에 활용한 결과임
    • 학습이 진행되는 상황을 파악할 수는 있었지만, 새로운 데이터에 적용했을 때 어느 정도의 성능이 나올지는 알 수 없음
  • 머신러닝 혹은 딥러닝의 최종 목적은 과거의 데이터를 토대로 새로운 데이터를 예측하는 것
  • 따라서, 새로운 데이터에 사용할 모델을 만드는 것이 최종 목적이므로 테스트셋을 만들어 정확한 평가를 병행하는 것이 매우 중요함
  • 학습데이터만 가지고 평가할 때, 층을 더하거나 에포크(epochs) 값을 높여 실행 횟수를 늘리면 정확도가 계속해서 올라갈 수 있음
  • (학습이 계속되면서 학습셋 에러는 줄어들지만, 테스트셋 에러에서는 과적합 발생)
  • 학습을 진행해도 테스트 결과가 더 이상 좋아지지 않는 지점에서 학습을 멈추어야 함

Train data와 Test data 분리하기

train_test_split() : 사이킷런의 함수로, 학습셋과 테스트셋으로 분리시키는 함수이다

from sklearn.model_selection import train_test_split
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense
import pandas as pd

df = pd.read_csv('./data/sonar3.csv', header = None)

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)
# model.evaluate() 함수는 loss와 accuracy 두 가지를 계산해 출력한다
# 이를 score에 저장하고 accuracy를 출력하도록 범위 설정

print('Test accuracy : ', score[1])

  • 학습데이터의 학습 정확도는 100%이지만, 테스트데이터의 학습 정확도는 88.8% 인 것을 확인할 수 있다

성능 향상 방법

  • 데이터를 이용해 성능을 향상시키려면 우선 충분한 데이터를 가져와 추가하면 됨

  • 하지만 데이터를 추가하는 것 자체가 어렵거나 데이터 추가만으로는 성능에 한계가 있을 수 있음

  1. 따라서 가지고 있는 데이터를 적절히 보완해 주는 방법을 사용
    예를 들어 사진의 경우 사진 크기를 확대/축소한 것을 더해 보거나 위아래로 조금씩 움직여 넣어 본다

  2. 테이블형 데이터의 경우 너무 크거나 낮은 이상치가 모델에 영향을 줄 수 없도록 크기를 적절히 조절할 수 있음
    시그모이드 함수를 사용해 전체를 0~1 사이의 값으로 변환하는 것이 좋은 예임

  3. 교차 검증 방법을 사용해 가지고 있는 데이터를 충분히 이용하는 방법도 있음

4. 모델 저장과 재사용

model.save()를 사용하여 학습결과를 저장한다

from tensorflow.keras.models import Sequential, load_model

# 모델 이름과 저장할 위치를 함께 지정합니다.
model.save('./data/model/my_model.keras')

# 모델이 저장된 위치와 이름까지 적어 줍니다.
model = load_model('./data/model/my_model.keras')

# 불러온 모델을 테스트셋에 적용해 정확도를 구합니다.
score = model.evaluate(X_test, y_test)
print('Test accuracy:', score[1])

  • 이전 실행값과 같은 결과를 나타냄

5. k겹 교차 검층(k-fold cross validation)

  • 데이터가 많을 수록 모델 성능이 향상된다

    • 하지만 실제 프로젝트에서는 데이터를 확보하는 것이 쉽지 않거나 많은 비용이 발생하는 경우가 있음
    • 학습 데이터 : 테스트 데이터 = 70 : 30으로 설정시, 30%의 테스트 데이터는 학습에 이용할 수 없음
  • 30%의 테스트 데이터를 학습에 이용할 수 없는 단점을 해결하기 위하여 k겹 교차 검증이 고안되었음

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

  • 데이터 셋을 여러개로 나누어 하나씩 테스트 세승로 사용하고 나머지를 모두 합해서 학습셋으로 사용하는 방법
  • 장점 : 데이터의 100% 를 학습셋으로 사용할 수 있는 동시에 테스트 셋으로 사용할 수 있다.
  • 예시 ( 5겹 교차 검증)

k겹 교차 검증을 사용하여 초음파 광물 예측하기

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

df = pd.read_csv('./data/sonar3.csv', header = None)

X = df.iloc[:, 0:60]
y = df.iloc[:, 60]

k = 5 # 몇 겹으로 나눌지 결정

# k-fold 함수를 불러오고, 분할 전 샘플이 치우지지 않도록 섞어준다
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번의 학습 진행
# for문을 사용하여 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)

avg_acc_score = sum(acc_score) / k

print('정확도 : ', acc_score)
print('정확도 평균 : ', avg_acc_score)

  • 정확도 평균 83.15% 로 모델이 평균 성능을 의미한다
  • cf) history에서 verbose = 0을 넣어주면 결과만 출력가능

최종 summary

  1. 초기 학습:
    처음에는 데이터를 그냥 피처(X)와 타겟(y)으로 나누어 학습시키면서 정확도를 확인했지만, 이 방식은 모든 데이터를 학습에 사용하기 때문에, 새로운 데이터에 대한 성능을 알 수 없다는 문제가 있음

  2. 과적합 인지:
    학습 데이터에서 높은 정확도를 기록하더라도, 새로운 데이터를 테스트했을 때 성능이 떨어질 수 있다는 점에서 과적합(overfitting) 문제가 발생할 수 있음

  3. Train-Test Split 도입:
    과적합을 방지하기 위해 데이터를 학습셋과 테스트셋으로 나누어, 학습셋으로 모델을 학습하고 테스트셋으로 성능을 평가할 수 있게 했음
    하지만, 여전히 데이터 부족으로 인한 과적합 가능성이 있음

  4. K겹 교차 검증 적용:
    데이터가 부족할 때, K겹 교차 검증(K-fold cross validation) 을 사용하여 데이터를 여러 번 학습셋과 테스트셋으로 나누고 각 모델의 성능을 평가했음
    이렇게 함으로써 데이터 부족 문제를 해결하고, 모델의 평균 정확도를 계산해 더 신뢰할 수 있는 평가를 할 수 있음

0개의 댓글