logo

조기 종료와 모델 체크포인트

조기 종료 early stopping

  • 검증 성능이 더 이상 개선되지 않을 때 최대 에포크 전에 훈련을 끝내는 방법
  • 훈련 시간을 줄이고 과대적합이 심해지기 전의 파라미터를 선택하는 정칙화 효과
  • 훈련 손실은 계속 감소해도 검증 손실은 어느 시점부터 다시 증가 가능
  • 훈련 손실 대신 검증 손실이나 검증 정확도처럼 일반화 성능을 나타내는 값을 관찰

검증 손실이 다시 증가하기 전에 훈련을 멈추는 조기 종료

  • 파라미터는 초기값에서 시작해 에포크마다 갱신
  • 훈련을 일찍 끝내면 파라미터가 초기값에서 지나치게 멀어지는 정도를 제한

훈련 에포크를 제한해 파라미터가 초기값에서 멀어지는 정도를 줄이는 효과

테스트 데이터는 마지막 평가에 사용

  • 조기 종료 기준은 검증 데이터에서 계산
  • 테스트 데이터를 매 에포크 확인해 중단 시점을 고르면 테스트 성능이 모델 선택에 반영
  • 모델 선택에 사용한 테스트 데이터는 최종 평가의 독립성을 상실

중단 기준 설정

  • keras.callbacks.EarlyStopping은 에포크가 끝날 때 관찰값의 개선 여부를 확인
인자역할예시
monitor관찰할 값"val_loss"
mode개선 방향손실은 "min", 정확도는 "max"
min_delta개선으로 인정할 최소 변화량0.001
patience개선 없이 기다릴 에포크 수3
restore_best_weights종료 후 가장 좋았던 에포크의 가중치 복원True
  • 가장 작은 검증 손실이 나온 시점은 2번째 에포크
  • patience=3이면 3~5번째 에포크의 개선 여부를 확인
  • 세 에포크 동안 개선이 없으면 5번째 에포크가 끝난 뒤 중단
에포크검증 손실처리
10.40현재 최적
20.31최적값 갱신
30.331회 대기
40.322회 대기
50.343회 대기 후 중단
  • restore_best_weights의 기본값은 False
  • True로 설정하면 가장 좋았던 에포크의 가중치를 현재 model 객체에 복원
  • False이면 중단 직전 에포크의 가중치를 유지

모델 체크포인트 model checkpoint

  • keras.callbacks.ModelCheckpoint는 훈련 중 모델이나 가중치를 파일로 저장
  • save_best_only=True이면 관찰값이 개선될 때만 저장
  • 같은 파일 경로를 사용하면 이전 최적 파일을 새 최적 파일로 교체
  • 조기 종료와 체크포인트는 서로 다른 역할
기능EarlyStoppingModelCheckpoint
훈련 중단가능불가
최적 가중치를 현재 모델에 복원restore_best_weights=True자동 복원하지 않음
런타임 종료 후 복구할 파일 생성생성하지 않음생성
  • 전체 모델 저장: 파일명을 .keras로 끝내고 keras.models.load_model()로 불러오기

  • 가중치만 저장: save_weights_only=True, 파일명을 .weights.h5로 끝내고 같은 구조의 모델에서 load_weights() 호출

  • 두 콜백을 함께 사용하면 불필요한 훈련을 멈추고 가장 좋았던 모델을 파일로 보존 가능

콜백 실습

  • MNIST 훈련 데이터 60,000개를 불러오기
  • validation_split=0.2로 훈련 데이터의 20%를 검증 데이터로 분리
  • 테스트 데이터는 훈련이 끝난 뒤 체크포인트의 예측을 확인할 때만 사용
import os

os.environ["KERAS_BACKEND"] = "torch"

import keras
import numpy as np

(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
  • keras.utils.set_random_seed(812)로 모델의 초기값을 고정
  • 학습률은 검증 손실의 변화를 빠르게 확인하기 위해 큰 값인 0.1로 지정
keras.utils.set_random_seed(812)

model = keras.models.Sequential(
    [
        keras.layers.Rescaling(1 / 255),
        keras.layers.Flatten(),
        keras.layers.Dense(128, activation="relu"),
        keras.layers.Dense(10),
    ]
)
model.compile(
    optimizer=keras.optimizers.Adam(learning_rate=0.1),
    loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
    metrics=["accuracy"],
)
  • 두 콜백은 같은 val_loss를 관찰
  • EarlyStopping의 나머지 인자는 기본값인 min_delta=0, patience=0, restore_best_weights=False를 사용
  • 검증 손실이 한 에포크라도 개선되지 않으면 훈련을 종료
  • 현재 model을 최적 가중치로 되돌리지는 않음
early_stopping = keras.callbacks.EarlyStopping(
    monitor="val_loss",
)

model_checkpoint = keras.callbacks.ModelCheckpoint(
    filepath="best_model.keras",
    monitor="val_loss",
    save_best_only=True,
)

history = model.fit(
    x_train,
    y_train,
    batch_size=128,
    epochs=50,  # 조기 종료가 없을 때의 최대 에포크
    validation_split=0.2,
    callbacks=[early_stopping, model_checkpoint],
)
실행 결과
Epoch 1/50
375/375 ━━━━━━━━━━━━━━━━━━━━ 3s 8ms/step - accuracy: 0.8344 - loss: 0.7997 - val_accuracy: 0.9007 - val_loss: 0.4072
Epoch 2/50
375/375 ━━━━━━━━━━━━━━━━━━━━ 3s 8ms/step - accuracy: 0.8813 - loss: 0.4965 - val_accuracy: 0.8980 - val_loss: 0.5471
  • 1번째 에포크의 검증 손실은 0.4072, 2번째 에포크는 0.5471
  • 검증 손실이 개선되지 않았고 patience=0이므로 2번째 에포크가 끝난 뒤 즉시 종료
  • restore_best_weights=False이므로 메모리의 model에는 마지막인 2번째 에포크의 가중치가 남음
  • save_best_only=TrueModelCheckpoint는 검증 손실이 더 작았던 1번째 에포크의 모델을 best_model.keras에 저장
  • 난수 연산과 실행 장치에 따라 구체적인 손실값과 중단 에포크는 달라질 수 있음
  • 확인할 핵심은 검증 손실이 개선되지 않은 에포크 뒤 기본 설정의 조기 종료가 작동한다는 점

저장한 모델 불러오기

  • ModelCheckpoint가 저장한 전체 모델은 새 객체로 불러오기 가능
best_model = keras.models.load_model("best_model.keras")
best_model.predict(x_test[[0]])
실행 결과
array([[-18.8172   ,  -3.5413115,  19.47736  ,  14.68325  ,  -6.1147866,
        -12.530763 , -12.839593 ,  39.227615 , -18.692066 ,   1.3114679]],
      dtype=float32)
  • 테스트 이미지 1개에 대해 숫자 0~9의 로짓 10개를 출력
  • 가장 큰 값은 인덱스 7의 39.227615이므로 예측 클래스는 숫자 7.
  • load_model()로 검증 손실이 가장 작았던 체크포인트를 별도 모델로 복원한 결과.
Previous
정칙화