경기도 인공지능 개발 과정/Python

[Python] 텐서플로 손실곡선, 드롭아웃, 모델저장

agingcurve 2022. 7. 17. 12:44
반응형
import tensorflow as tf
# 실행마다 동일한 결과 얻기 위한 랜덤시드 적용
tf.keras.utils.set_random_seed(42)

# 텐서플로 연상을 결정적으로 만든다.
# 시작부분 입력
tf.config.experimental.enable_op_determinism()

손실곡선

In [ ]:
from tensorflow import keras
from sklearn.model_selection import train_test_split
In [ ]:
(train_input, train_target), (test_input, test_target) = keras.datasets.fashion_mnist.load_data()
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-labels-idx1-ubyte.gz
32768/29515 [=================================] - 0s 0us/step
40960/29515 [=========================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/train-images-idx3-ubyte.gz
26427392/26421880 [==============================] - 0s 0us/step
26435584/26421880 [==============================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-labels-idx1-ubyte.gz
16384/5148 [===============================================================================================] - 0s 0us/step
Downloading data from https://storage.googleapis.com/tensorflow/tf-keras-datasets/t10k-images-idx3-ubyte.gz
4423680/4422102 [==============================] - 0s 0us/step
4431872/4422102 [==============================] - 0s 0us/step
In [ ]:
# 각 픽셀 : 0~ 255 사이의 정수 값을 보유
# -> 255.0 으로 나누어 0~1 사이 값으로 정규화
train_scaled = train_input / 255.0
In [ ]:
# 훈련 데이터셋으로부터 20% 정도의 샘플 데이터를 추출하여 검증 데이터 셋 추출
# -> train_test_split()
train_scaled, val_scaled, train_target, val_target = train_test_split(
    train_scaled, train_target, test_size=0.2, random_state=42)
In [ ]:
# 모델 생성 : 사용자 정의 함수../

def model_fn(a_layer = None):
  model = keras.Sequential()
  model.add(keras.layers.Flatten(input_shape=(28, 28)))
  model.add(keras.layers.Dense(100, activation="relu"))
  if a_layer:
    model.add(a_layer)

  model.add(keras.layers.Dense(10, activation="softmax"))
  return model
In [ ]:
model = model_fn()
model.summary()
Model: "sequential_1"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 flatten_1 (Flatten)         (None, 784)               0         
                                                                 
 dense_2 (Dense)             (None, 100)               78500     
                                                                 
 dense_3 (Dense)             (None, 10)                1010      
                                                                 
=================================================================
Total params: 79,510
Trainable params: 79,510
Non-trainable params: 0
_________________________________________________________________
In [ ]:
model.compile(loss="sparse_categorical_crossentropy", metrics="accuracy")
In [ ]:
history = model.fit(train_scaled, train_target, epochs=5, verbose =0)
In [ ]:
# history : Histroy 객체가 저장
# histroy : 학습 결과 값이 학습 할 때마다 저장
# dict_keys(["loss","accuracy"])
print(history.history.keys())
dict_keys(['loss', 'accuracy'])
In [ ]:
# 손실 : histtory.history["loss"]

import matplotlib.pyplot as plt

plt.plot(history.history["loss"])
plt.xlabel("epoch")
plt.ylabel("loss")
plt.show()
In [ ]:
# 정확도 그래프
plt.plot(history.history["accuracy"])
plt.xlabel("epoch")
plt.ylabel("accuracy")
plt.show()

과적합(overfititting) : 훈련, 검증 결과 데이터가 모두 필요

  • 학습할 때마다 검증 손실을 계싼하기 위해서 fit에게 검증 데이터를 전달함
  • vaildation_data 옵션을 이용하여 전달
  • validation_data 에 전달할 경우 검증에 사용할 입력값과 타겟값을 튜플로 전달
In [ ]:
model = model_fn()
model.compile(loss="sparse_categorical_crossentropy", metrics="accuracy")

history = model.fit(train_scaled, train_target, epochs=20, verbose =0,
                    validation_data = (val_scaled, val_target))
In [ ]:
print(history.history.keys())
# dict_keys(["loss","accuracy","val_loss","val_accuracy"])
dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])
In [ ]:
# 손실 시각화
plt.plot(history.history["loss"])
plt.plot(history.history["val_loss"])
plt.xlabel("epoch")
plt.ylabel("loss")
plt.legend(["train","val"])
plt.show()
  • 과대 적합 : 훈련점수는 좋지만, 테스트 점수가 낮을 경우
  • 과소 적합 : 훈련 점수보다, 테스트 점수가 높을 경우, 또는 훈련 점수와 테스트 점수가 모두 현저히 낮을 경우
  • 그 외 : 훈련 데이터셋과 테스트 데이터셋이 너무 작을 경우 (즉, 데이터 갯수가 현저히 작을 경우)
  • 과대적합의 경우는 검증 손실이 상승하는 시점을 뒤로 늦추는 방법을 통해
  • 검증셋에 대한 손실과 정확도를 높일 수 있다.

과대적합 완화

  • 옵티마이저 하이퍼 파라미터를 조정
  • optimizer = "함수"
  • 예) optimizer = "adam" 의 형태
  • 이 옵션은 모델 컴파일 시, 미리 설정
  • adam 은 적응적 학습율을 적용하기 때문에, 에폭이 진행되면서 학습률 크기를 자동으로 조정해준다.
In [ ]:
model = model_fn()
model.compile(optimizer = "adam",loss="sparse_categorical_crossentropy", metrics="accuracy")

history = model.fit(train_scaled, train_target, epochs=20, verbose =0,
                    validation_data = (val_scaled, val_target))
In [ ]:
# 완화 되었음
plt.plot(history.history["loss"])
plt.plot(history.history["val_loss"])
plt.xlabel("epoch")
plt.ylabel("loss")
plt.legend(["train","val"])
plt.show()

드롭아웃

  • 훈련과정에서 층에 있는 일부 노드(뉴런)을 랜덤하게 꺼내어 과대적합을 막는 개념
  • 즉, 노드에 출력값을 0으로 만들어 방지
  • Dropout() 레이어를 추가 -> 모델 객체 생성 시
  • keras.layers.Dropout()
In [ ]:
model = model_fn(keras.layers.Dropout(0.3)) # 30%
model.summary()
Model: "sequential_7"
_________________________________________________________________
 Layer (type)                Output Shape              Param #   
=================================================================
 flatten_7 (Flatten)         (None, 784)               0         
                                                                 
 dense_14 (Dense)            (None, 100)               78500     
                                                                 
 dropout (Dropout)           (None, 100)               0         
                                                                 
 dense_15 (Dense)            (None, 10)                1010      
                                                                 
=================================================================
Total params: 79,510
Trainable params: 79,510
Non-trainable params: 0
_________________________________________________________________
In [ ]:
model.compile(optimizer = "adam",loss="sparse_categorical_crossentropy", metrics="accuracy")

history = model.fit(train_scaled, train_target, epochs=20, verbose =0,
                    validation_data = (val_scaled, val_target))
In [ ]:
# 완화 되었음
plt.plot(history.history["loss"])
plt.plot(history.history["val_loss"])
plt.xlabel("epoch")
plt.ylabel("loss")
plt.legend(["train","val"])
plt.show()

모델 저장과 복원

  • 모델 저장하기 : 모델 객체의 함수를 이용
  • 훈련된 모델의 파라미터만 저장 : save_weights('모델명.h5') <=> load_weights('모델명.h5')
  • 훈련된 모델의 구조 및 파라미터까지 저장 : save('모델명.h5') <=> lo
In [ ]:
model = model_fn(keras.layers.Dropout(0.3)) # 30%
model.compile(optimizer = "adam",loss="sparse_categorical_crossentropy", metrics="accuracy")

history = model.fit(train_scaled, train_target, epochs=20, verbose =0,
                    validation_data = (val_scaled, val_target))
In [ ]:
# 모델의 객체의 save_weights() : 훈련된 모델의 파라미터 저장
model.save_weights("model-weights.h5")
In [ ]:
# 모델 객체의 save() : 훈련된 모델의 구조와 파라미터 저장
model.save("model-while.h5")
In [ ]:
# 코랩에서 두 개 파일 저장 확인
!ls -al *.h5
-rw-r--r-- 1 root root 333448 Jul 14 02:22 model-weights.h5
-rw-r--r-- 1 root root 982664 Jul 14 02:22 model-while.h5
In [ ]:
# 저장될 모델을 이용하여 사용

# 1. 파라미터만 저장한 모델 로드하여 사용 : predict()
# 훈련하지 않은 새로운 모델 생성
model = model_fn(keras.layers.Dropout(0.3))

# 저장된 모델 로드하여 사용
model.load_weights("model-weights.h5")
In [ ]:
import numpy as np

# np.argmax() : predict() 의 결과 값에서 가장 큰 값을 추출하기 위한 함수
# axis 옵션 : 
# axis = -1 : 배열의 마지막 차원을 따라 최대값을 추출
#           => 검증데이터 셋은 2차원 이기 때문에 마지막 차원은 1

# axis = 0 : 행을 따라 각 열의 최대값의 인덱스
# axis = 1 : 열을 따라 각 행의 최대값의 인덱스

val_labels = np.argmax(model.predict(val_scaled), axis= -1)

# 정확도 : val_labels과 val_target을 비교하여
#     각 위치가 같으면 : 1
#     각 위치가 다르면 : 0
# 따라서 이 결과에 대한 평균이 정확도.....

print(np.mean(val_labels == val_target))
0.887
In [ ]:
# 2. 모델의 구조와 파라미터를 저장한 모델을 사용

model = keras.models.load_model("model-while.h5")
model.evaluate(val_scaled, val_target)
375/375 [==============================] - 2s 3ms/step - loss: 0.3207 - accuracy: 0.8870
Out[ ]:
[0.32070672512054443, 0.8870000243186951]

콜백

In [ ]:
# 콜백 : 훈련도중 어떠한 일을 하기 위해 설정
# 예) 가장 낮은 손실이 발생했을 때, 훈련을 멈춘다든지....

# fit() 함수의 callbacks =[체크포인트 객체] 을 이용하여 설정
# 체크포인트 객체 : keras.callbacks.ModelCheckPoint()
# ModelCheckPoint("저장모델명.h5", 체크포인트위치)
# 체크포인트 위치: 만약 훈련결과 점수가 가장 낮은 지점에서 훈련을 멈추고 해당 모델을 저장할 경우,
# save_best_only = True 로 설정
In [ ]:
# 새로운 모델 생성
model = model_fn(keras.layers.Dropout(0.3)) # 30%
model.compile(optimizer = "adam",loss="sparse_categorical_crossentropy", metrics="accuracy")

history = model.fit(train_scaled, train_target, epochs=20, verbose =0,
                    validation_data = (val_scaled, val_target))

# 체크포인트 객체 생성
checkpoint_cb = keras.callbacks.ModelCheckpoint("best-model.h5", save_best_only=True)

# fit()에 체크포인트 객체 설정
model.fit(train_scaled, train_target, epochs=20, verbose=0,
          validation_data = (val_scaled, val_target),
          callbacks=[checkpoint_cb])
Out[ ]:
<keras.callbacks.History at 0x7fc3d610cb90>
In [ ]:
# 저장된 체크포인트 모델 사용
model = keras.models.load_model("best-model.h5")

model.evaluate(val_scaled, val_target)
375/375 [==============================] - 1s 2ms/step - loss: 0.3143 - accuracy: 0.8898
Out[ ]:
[0.3142765462398529, 0.8897500038146973]
In [ ]:
# 설계한 모델의 훈련과정 중, 최상의 시점에서 훈련을 멈추고, 최상의 파라미터를 저장할 경우
# 즉 최고의 훈련 모델을 저장할 경우에는
# ModelCheckPoint 객체와 
# EarlyStopping 객체를 
# fit() 의 callbacks = []에 [ModelCheckPoint 객체, EarlyStopping 객체] 에 설정

# EarlyStopping 객체 = keras.callbacks.EarlyStopping(patience =?, restore_best_weights= True)
# patience=의 값
# patience=2 설정 했을 경우 : 점수가 두번 이상 향상되지 않으면 훈련 종료
# re
In [ ]:
# 새로운 모델 생성
model = model_fn(keras.layers.Dropout(0.3)) # 30%
model.compile(optimizer = "adam",loss="sparse_categorical_crossentropy", metrics="accuracy")

history = model.fit(train_scaled, train_target, epochs=20, verbose =0,
                    validation_data = (val_scaled, val_target))
In [ ]:
# 체크포인트 객체 생성
checkpoint_cb = keras.callbacks.ModelCheckpoint("best-model.h5", save_best_only=True)

# 얼리스탑핑 생성
early_stopping_cb = keras.callbacks.EarlyStopping(patience=2,
                                                  restore_best_weights=True)

# fit()에 체크포인트 객체 설정
history = model.fit(train_scaled, train_target, epochs=20, verbose=0,
          validation_data = (val_scaled, val_target),
          callbacks=[checkpoint_cb,early_stopping_cb])
In [ ]:
# 완화 되었음
plt.plot(history.history["loss"])
plt.plot(history.history["val_loss"])
plt.xlabel("epoch")
plt.ylabel("loss")
plt.legend(["train","val"])
plt.show()