1. 손실 곡선
- 케라스의 fit() 메서드는 History 클래스 객체를 반환
- History 객체에는 훈련 과정에서 계산한 지표, 즉 손실과 정확도 값이 저장되어 있다.
- 패션 MNIST 데이터셋을 적재하고 훈련 세트와 검증 세트로 나눈다.
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
- if 구문은 model_fn() 함수에 (a_layer 매개변수로) 케라스 층을 추가하면 은닉층 뒤에 또 하나의 층을 추가하는 것이다.
- a_layer 매개변수로 층을 추가하지 않고 단순하게 model_fn() 함수를 호출한다.
model = model_fn()
model.summary()
- fit() 메서드의 결과를 history 변수에 담기
model.compile(loss='sparse_categorical_crossentropy', metrics='accuracy')
history = model.fit(train_scaled, train_target, epochs=5, verbose=0)
- history 객체에는 훈련 측정값이 담겨 있는 history 딕셔너리가 들어있다.
print(history.history.keys())
- history 속성에 포함된 손실과 정확도는 에포크마다 계산한 값이 순서대로 나열된 단순한 리스트이다.
- 맷플롯립을 사용해 손실 그래프 그리기
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()
- 에포크마다 손실이 감소하고 정확도가 향상한다.
- 에포크 횟수를 20으로 늘려서 모델을 훈련하고 손실 그래프 그리기
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()
2. 검증 손실
- 에포크에 따른 과대적합과 과소적합을 파악하라면 훈련 세트에 대한 점수뿐만 아니라 검증 세트에 대한 점수도 필요하다.
- 에포크마다 검증 손실을 계산하기 위해 케라스 모델의 fit() 메서드에 검증 데이터를 전달할 수 있다.
- validation_data 매개변수에 검증에 사용할 입력과 타깃값을 튜플로 만들어 전달한다.
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))
- 반환된 histroy.history 딕셔너리에는 검증 세트에 대한 손실은 'val_loss'에 들어 있고 정확도는 'val_accuracy'에 들어있다.
print(history.history.keys())
- 과대/과소적합 문제를 조사하기 위해 훈련 손실과 검증 손실을 한 그래프에 그려서 비교
- 초기에 검증 손실이 감소하다가 다섯 번째 에포크만에 다시 상승하기 시작한다. 훈련 손실은 꾸준히 감소하기 때문에 전형적인 과대적합 모델이 만들어진다.
- 검증 손실이 상승하는 시점을 가능한 뒤로 늦추면 검증 세트에 대한 손실이 줄어들 뿐만 아니라 검증 셍트에 대한 정확도도 증가할 것 이다.
- 옵티마이저 하이퍼파라미터를 조정하여 과대적합을 완화시키기
- 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()
- 과대 적합이 훨씬 줄어들었다. 검증 손실 그래프에 여전히 요동이 남아 있지만 열 번째 에포크까지 전반적인 감소 추세가 이어지고 있다. 이는 Adam 옵티마이저가 이 데이터셋에 잘 맞는다는 것을 보여준다.
3. 드롭아웃
드롭아웃(dropout)
- 훈련 과정에서 층에 있는 일부 뉴런을 랜덤하게 꺼서(즉, 뉴런의 출력을 0으로 만들어) 과대적합을 막는다.
- 이전 층의 일부 뉴런이 랜덤하게 꺼지면 특정 뉴런에 과대하게 의존하는 것을 줄일 수 있고 모든 입력에 주의를 기울여야 한다. 일부 뉴런의 출력이 없을 수 있다는 것을 감안하면 이 신경망은 더 안정적인 예측을 만들 수 있을 것이다.
- 케라스에서는 드롭아웃을 keras.layers 패키지 아래 Dropyout 클래스를 제공한다.
- 어떤 층의 뒤에 드롭아웃을 두어 이 층의 출력을 랜덤하게 0으로 만드는 것이다.
- 드롭아웃이 층처럼 사용되지만 훈련되는 모델 파라미터는 없다.
model = model_fn(keras.layers.Dropout(0.3))
model.summary()
- 출력 결과에서 볼 수 있듯이 은닉층 뒤에 추가된 드롭아웃(Dropout) 층은 훈련되는 모델 파라미터가 없다.
- 또한 입력과 출력의 크기가 같다. 일부 뉴런의 출력을 0으로 만들지만 전체 출력 배열의 크기를 바꾸지는 않는다.
- 훈련 손실과 검증 손실의 그래프를 그려 비교
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()
- 과대적합이 줄었다. 열 번째 에포크 정도에서 검증 손실의 감소가 멈추지만 크게 상승하지 않고 어느정도 유지되고 있다.
4. 모델 저장과 복원
- 에포크 횟수를 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() 메서드를 제공한다.
- 기본적으로 이 메서드는 텐서플로의 체크포인트 포맷으로 저장하지만 파일의 확장자가 '.h5'일 경우 HDF5포맷으로 저장한다.
model.save_weights('model-weights.h5')
- 모델 구조와 모델 파라미터를 함께 저장하는 save() 메서드로 제공한다.
- 기본적으로 이 메서드는 텐서플로의 SavedModel 포맷으로 저장하지만 파일의 확장자가 '.h5'일 경우 HDF5 포맷으로 저장한다.
!ls -al *.h5
1) 훈련을 하지 않은 새로운 모델을 만들고 model-weights.h5 파일에서 훈련된 모델 파라미터를 읽어서 사용
- load_weights() 메서드를 사용하려면 save_weights() 메서드로 저장했던 모델과 정확히 같은 구조를 가져야 한다.
#훈련하지 않은 새로운 모델을 만들고 이전에 저장했던 모델 파라미터를 적재
model = model_fn(keras.layers.Dropout(0.3))
model.load_weights('model-weights.h5')
- 모델의 검증 정확도 확인.
- 패션 MNIST 데이터셋에서 덜어낸 검증 세트의 샘플 개수는 12,000개 이기 때문에 predict() 메서드는 (12000,10) 크기의 배열을 반환
import numpy as np
val_labels = np.argmax(model.predict(val_scaled), axis=-1)
print(np.mean(val_labels == val_target))
- 10개의 확률 중에 가장 큰 값의 인덱스를 골라 타깃 레이블과 비교하여 정확도를 계산
- 모델의 predict() 메서드 결과에서 가장 큰 값을 고르기 위해 넘파이 argmax() 함수를 사용
- argmax() 함수는 배열에서 가장 큰 값의 인덱스를 반환한다.
- argmax() 함수의 axis=-1은 배열의 마지막 차원을 따라 최댓값을 고른다. 검증 세트는 2차원 배열이기 때문에 마지막 차원은 1이 된다.
- axis=1이면 열을 따라 각 행의 최댓값 인덱스를 선택하고, axis=0이면 행을 따라 각 열의 최댓값의 인덱스를 선택한다.
- argmax()로 고른 인덱스 (val_labels)와 타깃(val_target)을 비교한다.
- 두 배열에서 각 위치의 값이 같으면 1이 되고 다르면 0이된다. 이를 평균하면 정확도가 된다.
2) 모델 전체를 파일에서 읽은 다음 검증 세트의 정확도를 출력
- 모델이 저장된 파일을 읽을 때는 케라스가 제공하는 load_model() 함수를 사용한다.
model = keras.models.load_model('model-whole.h5')
model.evaluate(val_scaled, val_target)
5. 콜백
콜백(callback)
- 훈련 과정 중간에 어떤 작업을 수행할 수 있게 하는 객체로, keras.callbacks 패캐지 아래에 있는 클래스들이다.
- fit() 메서드의 callbacks 매개변수에 리스트로 전달하여 사용한다
- ModelCheckpoint 콜백은 기본적으로 에포크마다 모델을 저장한다. save_best_only=True 매개변수를 지정하여 가장 낮은 점수를 만드는 모델을 저장할 수 있다.
- ModelCheckpoint 클래스의 객체 checkpoint_cb를 만든 후 fit() 메서드의 callbacks 매개변수에 리스트로 감싸서 잔달한다.
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)
model.fit(train_scaled, train_target, epochs=20, verbose=0,
validation_data=(val_scaled, val_target),
callbacks=[checkpoint_cb])
- 이 모델을 load_model() 함수로 다시 읽어서 예측을 수행
model = keras.models.load_model('best-model.h5')
model.evaluate(val_scaled, val_target)
- ModelCheckpoint 콜백이 가장 낮은 검증 점수의 모델을 자동으로 저장해 주었다,
- 사실 검증 점수가 상승하기 시작하면 그 이후에는 과대적합이 더 커지기 때문에 훈련을 계속할 필요가 없다.
- 이때 훈련을 중지하면 컴퓨터 자원과 시간을 아낄 수 있다.
- 이렇게 과대적합이 시작되기 전에 훈련을 미리 중지하는 것을 조기 종료(early stopping)이라고 부른다.
- 케라스에는 조기 종료를 위한 EarlyStopping 콜백을 제공한다. 이 콜백의 patience 매개변수는 검증 점수가 향상되지 않더라도 참을 에포크 횟수를 지정한다.
- patience = 2로 지정하면 2번 연속 검증 점수가 향상되지 않으면 훈련을 중지한다.
- 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)
history = model.fit(train_scaled, train_target, epochs=20, verbose=0,
validation_data=(val_scaled, val_target),
callbacks=[checkpoint_cb, early_stopping_cb])
- 훈련을 마치고 나면 훈련이 중지되었는지 early_stopping_cb 객체의 stopped_epoch 속성에서 확인할 수 있다.
print(early_stopping_cb.stopped_epoch)
- 11번째 에포크에서 훈련이 중지되었다는 것을 의미
- patience는 2로 지정했으므로 최상의 모델은 9번째 에포크일 것이다.
- 훈련 손실과 검증 손실을 출력해서 확인
plt.plot(history.history['loss'])
plt.plot(history.history['val_loss'])
plt.xlabel('epoch')
plt.ylabel('loss')
plt.legend(['train', 'val'])
plt.show()
- 조기 종료 기법을 사용하면 안심하고 에포크 횟수를 크게 지정해도 괜찮다. 컴퓨터 자원과 시간을 아낄 수 있고 ModelCheckpoint 콜백과 함께 사용하면 최상의 모델을 자동으로 저장해주므로 편리하다.
- 조기 종료로 얻은 모델을 사용해 검증 세트에 대한 성능을 확인
model.evaluate(val_scaled, val_target)
'데이터 > 머신러닝' 카테고리의 다른 글
[혼공] ch 8-2 합성곱 신경망을 사용한 이미지 분류 (1) | 2024.07.01 |
---|---|
[혼공] ch 8-1. 합성곱 신경망의 구성 요소 (0) | 2024.07.01 |
[혼공] ch 7-2 심층 신경망 (0) | 2024.07.01 |
[혼공] ch 7-1 인공 신경망 (1) | 2024.06.30 |
[혼공] ch 6. 비지도 학습 (0) | 2024.06.28 |