손실 곡선
신경망 모델 훈련 시 fit() 메서드를 활용하는데 이 메서드의 반환 결과로 손실과 정확도가 포함된 딕셔너리가 반환된다. 이를 통해 손실 곡선과 정확도 곡선을 그리면 아래와 같다.
import matplotlib.pyplot as plt
history = model.fit(train_scaled,train_target,epochs=5)
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()
위 결과를 보면 에포크마다 손실이 감소하고 정확도가 증가한다. 에포크를 늘리면 늘릴수록 모델이 좋아지는 것 같지만 사실 과대/과소적합을 평가해야 그를 판단할 수 잇다.
참고로, 신경망 모델이 최적화하는 대상은 정확도가 아닌 손실 함수이다. 손실 감소에 비례하여 정확도가 높아지지 않는 경우도 있으니 손실 함수의 값을 주로 확인해야 한다.
과대/과소적합을 평가하기 위해 검증 값에 대한 손실/정확도를 전달받아야 한다. 이는 아래 코드에서 해당 방법과 함께 그래프를 그린다.
...
# 훈련 과정에서 validation_data를 설정해주면
# 반환결과로 훈련/검증 세트에 대한 손실, 정확도가 출력된다.
# ['loss','accuracy','val_los','val_accuracy']
history = model.fit(train_scaled,train_target,epochs=20,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.5 에포크까지는 공통적으로 손실이 감소한다. 손실이 감소하는 시점을 최대한 늦추어야 훈련 세트에만 손실이 낮은 과대적합 모델을 개선할 수 있다. 가장 손쉽게 사용 가능한 규제는 'adam' 옵티마이저를 활용하는 방법이다. 'adam'은 앞선 포스팅에서 말한 듯 적응적 학습률을 사용한다.
...
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics='accuracy')
...
확실히 앞선 방법보다 검증 세트의 손실이 꾸준히 감소하는 것으로 보인다.
드롭아웃(Dropout)
드롭아웃은 신경망 훈련에서 사용하는 대표적인 규제 방법이다. 훈련 과정에서 층에 있는 일부 뉴런을 랜덤하게 0으로 만들어서 과대적합을 만든다. 일부 뉴런을 랜덤하게 0으로 만들면 출력이 나오지 않게 된다. 이렇게 되면 특정 뉴런에 대해 과대하게 의존하는 것을 줄일 수 있게 된다. 그리고, 드롭아웃을 한다면 한 에포크마다 사실 서로 다른 층을 훈련하게 된다. 이런 앙상블 학습은 과대적합을 막는 좋은 방법이다.
케라스는 아래와 같이 Dropout 층을 제공하며 어떤 층 뒤에 해당 Dropout 층을 두면 해당 층을 랜덤하게 Dropout 한다.
...
model.add(keras.layers.Flatten(input_shape=(28,28)))
model.add(keras.layers.Dense(100,activation='relu'))
model.add(keras.layers.Dropout(0.3))
model.add(keras.layers.Dense(10,activation='softmax'))
...
확실히 검증세트에 대한 손실이 줄어들어 모델이 대폭 개선되었다.
모델 저장과 복원
위에서 작성한 모델을 저장하기 위해서는 save() 메서드를 활용한다. 만약 모델 파라미터만 저장하고 싶다면 save_weights() 메서드를 사용한다. 모델을 불러올때는 load_model()/load_weights() 메서드를 활용한다.
아래는 에포크를 10으로 바꾸고 save_weight()와 save()를 수행하는 코드이다.
model.compile(optimizer='adam', loss='sparse_categorical_crossentropy', metrics='accuracy')
history = model.fit(train_scaled,train_target,epochs=10,validation_data=(val_scaled,val_target))
model.save_weights('model-weights.h5')
model.save('model-whole.h5')
코랩 드라이브에 저장된다.
아래 코드는 가장 큰 값의 인덱스를 골라 타깃 레이블과 비교하여 정확도를 계산하는 코드이다.
import numpy as np
val_labels = np.argmax(model.predict(val_scaled),axis=1)
print(np.mean(val_labels==val_target))
# 0.8774166666666666
다음으로는 전체 모델을 읽어서 검증 세트의 정확도를 출력해본다.
model = keras.models.load_model('model-whole.h5')
model.evaluate(val_scaled,val_target)
# [0.33862680196762085, 0.8774166703224182]
콜백(Callback)
앞선 과정에서 20번의 에포크 동안 모델을 훈련하여 검증 세트의 손실이 상승하는 지점을 찾았고, 이후 과대적합 되지 않는 만큼 다시 훈련을 한다. 이렇게 모델을 두번씩 훈련하는 대신 한번의 절차로 끝내기 위해 콜백을 활용할 수 있다.
ModelCheckPoint 콜백의 사용
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')
history = model.fit(train_scaled,train_target,epochs=10,validation_data=(val_scaled,val_target),callbacks=[checkpoint_cb])
해당 콜백을 통해 최상의 검증 점수를 만드는 모델을 저장할 수 있다. 콜백을 통해 저장된 모델을 아래와 같이 불러와 사용할 수 있다.
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')
history = model.fit(train_scaled,train_target,epochs=10,validation_data=(val_scaled,val_target),callbacks=[checkpoint_cb])
model = keras.models.load_model('best-model.h5')
model.evaluate(val_scaled,val_target)
사실, 검증 점수가 상승하기 시작하면 과대적합이 더 커지기 때문에 더 훈련을 진행할 필요가 없다. 이때 자동으로 종료하는 것을 조기 종료라고 부른다. 조기 종료는 훈련 에포크를 제한하는 역할이지만 과대적합되는 것을 막아주기 때문에 규제로 볼 수 있다. 이를 위해 EarlyStopping 콜백을 케라스에서 제공한다.
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')
early_stopping_cb = keras.callbacks.EarlyStopping(patience=2, restore_best_weights=True)
history = model.fit(train_scaled,train_target,epochs=20,
validation_data=(val_scaled,val_target),callbacks=[checkpoint_cb,early_stopping_cb])
print(early_stopping_cb.stopped_epoch) # 9
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) # [0.32994160056114197, 0.8790000081062317
위 EarlyStopping 클래스에서 patience 파라미터를 지정해주는데 이는 n회 이상 손실이 상승하면 조기종료한다는 것을 의미한다. 위는 두번 이상 상승하면 종료하고 restore_best_weight=True 파라미터를 통해 최상의 모델을 저장한다.
위를 보면 val_loss 값이 8회차에 최저점을 찍고 연속해서 상승하는 것을 볼 수 있다. 훈련은 10회까지 진행되었지만 최상의 지점이 9회차에 모델이 저장되게 된다.
요약
- 규제를 통해 손실이 증가하는 시점을 늦추어야 한다.
- 'adam' 옵티마이저는 적응적 학습률을 사용하여 규제에 좋다.
- 드랍아웃 층을 추가하여 해당 층의 뉴런을 랜덤하게 0으로 만들어 규제한다. (앙상블 학습, 특정 뉴런 과의존 방지)
- save_weights()는 층의 가중치와 절편을 저장하고 save()는 모델 구조까지 저장한다.
- ModelCheckpoint 콜백을 통해 최상의 검증 점수를 만드는 모델을 저장한다.
- EarlyStopping 콜백을 통해 일정 구간 손실이 감소하지 않으면 조기 종료한다.
참고
- 혼자 공부하는 머신러닝+딥러닝(박해선 저)
'AI: ML,DL' 카테고리의 다른 글
[인공지능] 합성곱 신경망을 활용한 이미지 분류 (0) | 2021.03.22 |
---|---|
[인공지능] 합성곱 신경망(CNN, Convolutional Neural Network) (0) | 2021.03.21 |
[인공지능] 심층 신경망 (0) | 2021.03.20 |
[인공지능] 인공 신경망(딥러닝, DNN) (0) | 2021.03.20 |
[인공지능] 확률적 경사 하강법 (0) | 2021.03.15 |