모델저장 학습중단 과적합

2024. 7. 1. 22:38Deep Learning

 

✅ 학습 목표

  • 베스트 모델 저장하기 / 불러오기
  • 학습 중단 기능
  • 과적합 방지 - Dropout

 

✅ 베스트 모델 저장하기 / 학습 중단

  • 📌 손글씨 이미지 데이터셋
    • 훈련 데이터 6만개, 테스트 데이터 1만개
    • 0 ~ 9까지 숫자 이미지에 대한 라벨링

from tensorflow.keras.datasets import mnist

(X_train, y_train), (X_test, y_test) = mnist.load_data()

X_train.shape, X_test.shape

  • 📌 데이터 확인
import matplotlib.pyplot as plt

print(y_train[10])

plt.imshow(X_train[10], cmap='gray')
plt.show()

  • 📌 이미지(2차원) -> Dense(1차원) 변환
X_train = X_train.reshape(-1, 28*28)
X_test = X_test.reshape(-1, 28*28)

X_train.shape, X_test.shape

  • 📌 스케일링 : 0 ~ 255 -> 0.0 ~ 1.0
X_train = X_train / 255.0
X_test = X_test / 255.0
X_train

  • 📌 라벨 데이터는 원핫 인코딩(다진 분류)
from keras.utils import to_categorical

y_train_en = to_categorical(y_train)
y_test_en = to_categorical(y_test)

y_train_en.shape, y_test_en.shape

  • 📌 신경망 설계
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense

model1 = Sequential()

# input_dim : 입력 데이터의 크기

model1.add(Dense(512, activation='relu', input_dim=28*28))

# 10 -> 라벨 데이터의 크기

model1.add(Dense(10, activation='softmax'))

model1.summary()

model1.compile(optimizer='adam', loss='categorical_crossentropy', metrics=['accuracy']) # categorical_crossentropy -> 다중분류
# validation_data : 테스트 데이터가 있는 경우
# validation_split : 테스트 데이터가 없는 경우 -> 훈련 데이터에서 비율만큼 가져온다

h1 = model1.fit(X_train, y_train_en, epochs=5, batch_size=128, validation_data=(X_test, y_test_en))

  • 📌 베스트 모델 저장, 학습 중단 설정
    • 베스트 모델 : 학습 중에서 설정한 기준 값이 가장 좋은 모델을 저장 (ModelCheckPoint())
    • 학습 중단 : 학습 중에 설정한 기준 값이 만족하는 경우에 학습을 중지 시키는 기능 (EaryStopping())
from google.colab import drive

drive.mount('/content/drive')

%cd /content/drive/MyDrive/Colab Notebooks/Deep Learning

from keras.callbacks import ModelCheckpoint, EarlyStopping

import os

# 모델을 저장할 폴더

model_dir = './model/'

# 만약 해당 폴더가 없으면 생성

if not os.path.exists(model_dir):
    os.mkdir(model_dir)

# {epoch:02d} : epoch 변수의 값을 2자리 정수로 설정
# {loss:.4f} : loss 변수의 값을 소수점 4째 자리까지로 설정
# {val_loss:.4f} : val_loss 변수의 값을 소수점 4째 자리까지로 설정
# 파일명 예시 : model1_20_0.526_0.406.hdf5

file_name = model_dir + "model1_{epoch:02d}_{loss:.4f}_{val_loss:.4f}.hdf5"

# 베스트 모델 저장 설정
# monitor : 베스트 모델을 결정하는 기준값
# save_best_only=True : monitor에서 설정한 기준값이 더 나아지는 경우에만 저장

mc = ModelCheckpoint(file_name, monitor='val_loss', save_best_only=True) # val_loss -> 과대적합이 안걸리는 가장 바람직한 방법

# 학습 중단 기능 : 얼마만큼 학습 횟수를 설정할지 알 수 없기 때문에 학습이 더 나아지지 않는 경우에 자동으로 중지
# monitor : 학습 중단을 결정하는 기준값 (가능하면 ModelCheckpoint와 동일한 값을 권장)
# patience : 학습이 더 나아지지 않더라도 기다려주는 횟수

es = EarlyStopping(monitor='val_loss', patience=5)

# validation_data : 테스트 데이터가 있는 경우
# validation_split : 테스트 데이터가 없는 경우 -> 훈련 데이터에서 비율만큼 가져온다
# callbacks : 반복 시 마다 호출되어 실행

h1 = model1.fit(X_train, y_train_en, epochs=20, batch_size=128, validation_data=(X_test, y_test_en), callbacks=[mc, es])

import matplotlib.pyplot as plt

plt.plot(h1.history['accuracy'], label="train")
plt.plot(h1.history['val_accuracy'], label="test")

plt.legend()
plt.show()

plt.plot(h1.history['loss'], label="train")
plt.plot(h1.history['val_loss'], label="test")

plt.legend()
plt.show()

  • 📌 모델 불러오기
from keras.models import load_model

# model_dir = './model/'

file_name = model_dir + "modelmodel1_01_0.0004_0.0666.hdf5"

model2 = load_model(file_name)

model2.evaluate(X_train, y_train_en)
model2.evaluate(X_test, y_test_en)

  • 📌 예측하기
idx = 200

pred = model2.predict(X_test[idx:idx+1])

print(pred)

# 가장 큰 값을 갖는 인덱스를 반환

print(pred.argmax())

# 실제 값

print(y_test[idx])

import matplotlib.pyplot as plt

plt.imshow(X_test[idx].reshape(28, 28), cmap='gray')
plt.show()

# 잘못 예측한 데이터 출력

pred = model2.predict(X_test)

co = 0
failed = 0

for i in pred :
    if pred[co].argmax() != y_test[co] :
        failed += 1
        print(co)
    co += 1

print("잘못 예측한 데이터 수 : ", failed)

  • 📌 내 손글씨 인식하기
    • 모델을 만들 때 수행했던 전처리를 그대로 해주어야 한다

# 이미지 불러오기

import PIL.Image as pimg
import numpy as np
import matplotlib.pyplot as plt

img = pimg.open('./data/2.png').convert('L')
# convert('L') : 컬러 -> 흑백 이미지로 변환

plt.imshow(img, cmap = "gray")
plt.show()

  • 📌 데이터의 형태 : (1,784)
  • 📌 데이터 값 : 0.0 ~ 1.0
img = np.array(img)

img.shape

testimg = img.reshape(-1, 28 * 28)

testimg.shape

testimg = testimg / 255.0
testimg

pred = model2.predict(testimg)

print(pred)
print(pred.argmax())

  • 📌 과적합 방지
    • Dropout()
      • 각 층의 퍼셉트론의 수를 설정한 비율만큼 제한 -> 각 반복마다 적용되는 퍼셉트론은 랜덤으로 선택
      • 제한 비율을 0.5 이하로 설정 -> 0.5 이상이면 해당 층의 신경망이 가지는 특성이 효과적으로 적용되지 못하기 때문
      • 퍼셉트론의 수가 감소 -> 파라미터의 수가 감소 -> 복잡도 감소 -> 과적합 감소
import pandas as pd

# 특성 60개로 구성
# 암석에 음파를 쏴서 반사되는 파를 확인해서 금속을 탐지
# header = None : 원본 파일에 열 이름이 없는 데이터

sonar = pd.read_csv('./data/sonar.csv', header = None)
sonar.head()

# 라벨 데이터 확인

sonar[60].value_counts()

import tensorflow as tf

# 다른 컴퓨터에서 작업을 하더라도 w와 b 값이 같은 값으로 초기화
# 모델을 개선했을 때 모델의 성능을 판별

seed = 0

tf.random.set_seed(seed)
np.random.seed(seed)
# 특성 / 라벨 데이터 분리

X_train = sonar.iloc[:, :60]
y_train = sonar.iloc[:, 60]

X_train.shape, y_train.shape

  • 📌 라벨 데이터 인코딩
    • M, R의 문자 형태로 되어 있는 라벨을 숫자로 변환 -> 라벨 인코딩
    • 0부터 숫자가 알파벳 순으로 부여
from sklearn.preprocessing import LabelEncoder

encoder = LabelEncoder()

encoder.fit(y_train)

y_train_en = encoder.transform(y_train)
y_train_en

# M -> 0, R -> 1

# 훈련, 검증 데이터

from sklearn.model_selection import train_test_split

X_train, X_val, y_train, y_val = train_test_split(X_train, y_train_en, test_size=0.2, random_state=seed)

X_train.shape, y_train.shape, X_val.shape, y_val.shape

  • 📌 모델 설계
  • 📌 컴파일
  • 📌 학습 (베스트 모델 저장, 학습 중단)
  • 📌 저장된 모델 불러오기
  • 📌 불러온 모델로 예측하기 (X_test)
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import Dense, Dropout

model3 = Sequential()

# 입력층

model3.add(Dense(512, activation='relu', input_dim=60))

# 은닉층

model3.add(Dense(256, activation='relu'))
model3.add(Dense(128, activation='relu'))
model3.add(Dense(64, activation='relu'))

# 인코딩 : 퍼셉트론 수 (특성 수)를 감소 시켜가는 방식 (압축, 정보 요약, 중요 특성 추출 / 선택)
# 디코딩 : 퍼셉트론 수 (특성 수)를 증가 시켜가는 방식 (복원)

# 출력층
# 원핫 인코딩 하지 않았음 -> 퍼셉트론 수 1, 활성화 함수 sigmoid
# 원핫 인코딩 했다면 -> 퍼셉트론 수 2, 활성화 함수 softmax

model3.add(Dense(1, activation='sigmoid'))

model3.summary()

model3.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
from keras.callbacks import ModelCheckpoint, EarlyStopping

mc = ModelCheckpoint('./model/model2_{epoch:02d}_{loss:.4f}_{val_loss:.4f}.hdf5', monitor='val_loss', save_best_only=True)

es = EarlyStopping(monitor='val_loss', patience=10)
# h2 = model3.fit(X_train, y_train, epochs=200, batch_size=16, validation_data=(X_val, y_val), callbacks=[mc, es])

h2 = model3.fit(X_train, y_train, epochs=200, batch_size=16, validation_data=(X_val, y_val))

import matplotlib.pyplot as plt

plt.plot(h2.history['accuracy'], label="train")
plt.plot(h2.history['val_accuracy'], label="test")

plt.legend()
plt.show()

plt.plot(h2.history['loss'], label="train")
plt.plot(h2.history['val_loss'], label="test")

plt.legend()
plt.show()

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

model4 = Sequential()

model4.add(Dense(512, activation='relu', input_dim=60))

model4.add(Dropout(0.3))
model4.add(Dense(256, activation='relu'))
model4.add(Dropout(0.3))
model4.add(Dense(128, activation='relu'))
model4.add(Dropout(0.3))
model4.add(Dense(64, activation='relu'))

model4.add(Dense(1, activation='sigmoid'))

model4.summary()

model4.compile(optimizer='adam', loss='binary_crossentropy', metrics=['accuracy'])
h3 = model4.fit(X_train, y_train, epochs=200, batch_size=16, validation_data=(X_val, y_val))

import matplotlib.pyplot as plt

plt.plot(h3.history['accuracy'], label="train")
plt.plot(h3.history['val_accuracy'], label="test")

plt.legend()
plt.show()

plt.plot(h3.history['loss'], label="train")
plt.plot(h3.history['val_loss'], label="test")

plt.legend()
plt.show()