[혼자 공부하는 머신러닝+딥러닝] 19강. 신경망 모델 훈련 ▶️인경 신경망 모델 훈련의 모범 사례 학습하기 - 모델 재사용
https://www.youtube.com/watch?v=2by0Fz3XC84&list=PLJN246lAkhQjoU0C4v8FgtbjOIXxSs_4Q&index=20
1. 신경망 모델 훈련
- 준비 작업 및 신경망 모델 코드 함수화 하기
- 준비 작업
from tensorflow import keras
from sklearn.model_selection import train_test_split
# 데이터 로드
(train_input, train_target), (test_input, test_target) = \
keras.datasets.fashion_mnist.load_data()
# 표준화
train_scaled = train_input / 255.0
# # 훈련 테스트 분할
train_scaled, val_scaled, train_target, val_target = train_test_split(
train_scaled, train_target, test_size=0.2, random_state=42)
- 신경망 모델 코드 함수화
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
- 기본 함수 테스트
model = model_fn()
model.summary()
Model: "sequential"
_________________________________________________________________
Layer (type) Output Shape Param #
=================================================================
flatten (Flatten) (None, 784) 0
dense (Dense) (None, 100) 78500
dense_1 (Dense) (None, 10) 1010
=================================================================
Total params: 79510 (310.59 KB)
Trainable params: 79510 (310.59 KB)
Non-trainable params: 0 (0.00 Byte)
- compile과 fit 그리고 시각화
model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')
history = model.fit(train_scaled, train_target, epochs=5, verbose=0)
- keras의 .fit() 에는 훈련측정값을 가지고 있는 History 딕셔너리 객체가 있다. 기본적으로 loss만 반환되며 metrics에 선언된 값이 있으면 이에 대한 값도 같이 반환된다.
print(history.history.keys())
dict_keys(['loss', 'accuracy'])
- 그래프로 그리기
import matplotlib.pyplot as plt
plt.plot(history.history['loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()
plt.plot(history.history['accuracy'])
plt.xlabel('epoch')
plt.ylabel('accuracy')
plt.show()
- 에포크 늘리기
- 에포크를 더 늘려보면 손실이 점차 감소하는 것을 확인할 수 있다.
model = model_fn()
model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')
history = model.fit(train_scaled, train_target, epochs=20, verbose=0)
plt.plot(history.history['loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.show()
- 검증손실과 과대적합
- 훈련세트의 손실만 확인하게 되면 다른 데이터에 대한 정확도에 대해 정확히 판단하기 어렵다. 위에서 분리한 검증세트의 손실도 확인해 보자
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))
- 반환 결과 확인
print(history.history.keys())
# 반환 값에 추가 키 생성
dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])
- 그래프 확인
- 훈련세트와 검증세트의 손실률을 확인하면 훈련세트에만 너무 잘 맞게 학습된 과대적합 상태인 것을 알 수 있다.
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['train', 'val'])
plt.show()
- 옵티마이저 추가
- adam을 추가하면 좀 더 완화된 그래프를 확인할 수 있다.
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))
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['train', 'val'])
plt.show()
2. 드롭아웃
- 신경망 모델에만 있는 귲제 방법이다.
- 층에 있는 유닛 일부를 랜덤하게 동작하지 않도록 하여 훈련 성능을 낮춘다.
- Dropout() : 얼마나 drop을 할 것인지에 대한 비율을 지정해야 한다.
model = model_fn(keras.layers.Dropout(0.3))
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: 79510 (310.59 KB)
Trainable params: 79510 (310.59 KB)
Non-trainable params: 0 (0.00 Byte)
- 드롭아웃 처리를 한 모델의 검증손실을 출력해 보면 과대적합이 완화된 결과를 확인할 수 있다.
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))
- 그래프 결과를 보면 에포크 10 정도에서 최적화가 이루어지는 것을 확인할 수 있다.
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['train', 'val'])
plt.show()
3. 모델 저장과 복원
- 최적의 값인 에포크 10으로 설정된 모델을 만든다
model = model_fn(keras.layers.Dropout(0.3))
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy',
metrics='accuracy')
history = model.fit(train_scaled, train_target, epochs=10, verbose=0,
validation_data=(val_scaled, val_target))
- 모델 저장
- .save_weights() : 훈련된 모델의 가중치를 저장한다.
model.save_weights('model-weights.h5')
- .save() : 훈련된 모델의 구조와 가중치를 통째로 저장한다.
model.save('model-whole.h5')
- 가중치 모델 복원
- .load_weights() : 이전에 저장한 모델의 가중치를 불러온다.
- 모델 구조가 정확히 같아야 불러올 수 있다.
- .load_model() : 이전에 저장한 모델 전체를 불러온다.
model = model_fn(keras.layers.Dropout(0.3))
model.load_weights('model-weights.h5')
- 검증세트의 정확도 계산
- evaluate()를 사용해도 되지만, 복원한 모델의 다시 compile()을 실행해야 한다. 때문에 이하 강의에서는 새로운 데이터에 대해 정확도만 계산하는 것으로 가정한다.
- 예측클래스를 직접 구하고, 타깃이랑 비교하여 동일한 비율을 구할 것이다.
- .predict() : 샘플마다 각 클래스일 확률을 반환해 준다. == 사이킷런 predict_proba
- 모든 클래스별 확률을 제공하는데 그 중 가장 높은 것을 다시 선택하는 과정을 사용자가 직접 해줘야 한다.
import numpy as np
# predict_classes 함수가 제거됨으로 이렇게 수동으로 사용자가 수행해줘야 한다.
val_labels = np.argmax(model.predict(val_scaled), axis=-1)
# 정답을 비교하여 맞춘 비율 확인
print(np.mean(val_labels == val_target))
37/375 [=>............................] - ETA: 0s
375/375 [==============================] - 1s 1ms/step
0.8765
- .argmax() : predict가 출력한 확률들 중 가장 큰 값을 뽑기 위해 넘파이를 활용한다.
- axis = -1 : 배열의 마지막 차원, 축을 선택한다 이 코드에서는 axis = 1이 선택된다.
- 반환된 최대값의 인덱스 val_labels와 val_target을 비교하여 일치하는 비율이 검증세트의 정확도가 된다.
import numpy as np
val_labels = np.argmax(model.predict(val_scaled), axis=-1)
print(np.mean(val_labels == val_target))
37/375 [=>............................] - ETA: 0s
375/375 [==============================] - 1s 1ms/step
0.8765
- 전체 모델 복원
- 모델의 구조와 옵티마이저까지 모두 복원이 되기 때문에 evaluate()를 바로 사용할 수 있다.
- .load_model() : 이전에 저장한 모델 전체를 불러온다.
model = keras.models.load_model('model-whole.h5')
model.evaluate(val_scaled, val_target)
375/375 [==============================] - 1s 1ms/step - loss: 0.3402 - accuracy: 0.8765
[0.34021928906440735, 0.8765000104904175]
4. 콜백
- 훈련 과정 중간 특정 작업을 수행하게 해주는 객체로 keras.callbacks 패키지에 있다.
- ModelCheckpoint 콜백
- ModelCheckpoint() : 가장 자주 사용되는 콜백으로 에포크마다 모델을 저장해 준다.
- save_best_only = True : 손실이 가장 낮은 모델만 저장하도록 설정
model = model_fn(keras.layers.Dropout(0.3))
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy',
metrics='accuracy')
# 콜백으로 체크 포인트를 객체로 만든다.
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])
- 자동으로 저장된 최적의 모델을 load 해서 사용하면 된다.
# 콜백해둔 모델을 불러온다
model = keras.models.load_model('best-model.h5')
# 정확도를 확인한다. (다시 모델을 만들 필요가 없다)
model.evaluate(val_scaled, val_target)
375/375 [==============================] - 1s 1ms/step - loss: 0.3197 - accuracy: 0.8857
[0.3197357654571533, 0.8856666684150696]
- 조기종료 : EarlyStopping 콜백
- 최적의 모델을 찾을 때 에포크를 일단 높게 설정하고 찾게 된다. 이럴 경우 불필요하게 오랫동안 훈련을 하게 된다.
- 학습을 하는 과정에 성능이 좋아졌다가 나빠졌다가를 반복한다 이 과정들을 제한하여 최적의 위치를 찾는다.
- EarlyStopping() : 과대적합이 시작되면 정의된 조건 범위에서 훈련을 조기종료 해주는 콜백
- patience : 검증세트 성능이 떨어지더라도 넘어가는 유효한 에포크 제한 횟수 설정
- restore_best_weights = True : 훈련동안 가장 손실이 낮았던 최적 가중치로 돌리는 설정
model = model_fn(keras.layers.Dropout(0.3)) # 모델 만들기
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy',
metrics='accuracy')
# 체크포인트 콜백 설정
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])
- .stopped_epoch : 몇 번째 에포크에서 조기종료 했는지 저장되어 있는 변수
print(early_stopping_cb.stopped_epoch)
10
- 그래프 그리기
- 2번의 손실 발생 후 종료가 되었다. 최적의 에포크는 8이라 할 수 있다.
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['train', 'val'])
plt.show()
- 최종 모델 검증
model.evaluate(val_scaled, val_target)
375/375 [==============================] - 0s 1ms/step - loss: 0.3253 - accuracy: 0.8790
[0.32525375485420227, 0.8790000081062317]
- fit의 매개변수: verbose
- 훈련과정의 출력되는 log의 format을 조절한다.
- 1 : 진행 막대와 측정값 출력 ( 기본 )
- 2 : 진행막대 빼고 출력
- 0 : 훈련과정을 출력하지 않는다.
- reference :
댓글