HuggingFace에서의 조기 종료(early stopping) – 예시
서론
이번 리포트에서는 조기 종료 정규화(early stopping regularization)을 사용해 HuggingFace Transformer를 미세 조정하는 예를 살펴보겠습니다. HuggingFace의 Trainer API
와 함께 네이티브 PyTorch 및 TensorFlow 워크 플로를 통해 조기 종료 사용에 대해서 다루겠습니다.
네이티브 TensorFlow
Colab에서 TF를 사용하여 HuggingFace Transformer 미세 조정하기 →\rightarrow
TensorFlow(Keras)를 사용하여 HuggingFace Transformer를 미세 조정하는 경우, tf.keras.callbacks.EarlyStopping
콜백을 통해 조기 종료를 간단하게 추가할 수 있습니다. 여기에는 모니터링할 메트릭의 이름과 개선이 없는 경우 훈련을 중지할 epoch(에포크) 수가 필요합니다.
early_stopper = tf.keras.callbacks.EarlyStopping(monitor='val_loss',
patience=5,
restore_best_weights=True)
여기서 early_stopper
는 model.fit
과 함께 사용할 수 있는 콜백입니다.
model.fit(trainloader,
epochs=10,
validation_data=validloader,
callbacks=[early_stopper])
관측
-
모델은 검증 손실(validation loss)에서 분명히 알 수 있는 훈련 데이터세트에서 빠르게 오버핏(overfit) 되었습니다.
-
조기 종료(early stopping)를 포함한 훈련 모델은 훈련 프로세스의 조기 종료(early termination)으로 이어집니다. 이를 통해 계산상 비용(computational cost)과 시간을 절약할 수 있습니다.
-
모델의 최적 인스턴스(가장 낮은 검증 손실)는
EarlyStopping
콜백을 사용하여 저장되었으므로, 실험 정확도 결과는 보다 일반화된 모델을 나타냅니다.
네이티브 PyTorch
Colab에서 PyTorch를 사용하여 HuggingFace Transformer 미세 조정하기 →\rightarrow
네이티브 PyTorch는 기성의(off-the-shelf) 조기 종료(early stopping) 방법이 없습니다. 그러나 네이티브 PyTorch를 사용하여 HuggingFace Transformer를 미세 조정할 경우, 여기 조기 정지 후크(early stopping hook)를 제공하는 GitHub Gist가 있습니다.
class EarlyStopping(object):
def __init__(self, mode='min', min_delta=0, patience=10, percentage=False):
self.mode = mode
self.min_delta = min_delta
self.patience = patience
self.best = None
self.num_bad_epochs = 0
self.is_better = None
self._init_is_better(mode, min_delta, percentage)
if patience == 0:
self.is_better = lambda a, b: True
self.step = lambda a: False
def step(self, metrics):
if self.best is None:
self.best = metrics
return False
if np.isnan(metrics):
return True
if self.is_better(metrics, self.best):
self.num_bad_epochs = 0
self.best = metrics
else:
self.num_bad_epochs += 1
if self.num_bad_epochs >= self.patience:
print('terminating because of early stopping!')
return True
return False
def _init_is_better(self, mode, min_delta, percentage):
if mode not in {'min', 'max'}:
raise ValueError('mode ' + mode + ' is unknown!')
if not percentage:
if mode == 'min':
self.is_better = lambda a, best: a < best - min_delta
if mode == 'max':
self.is_better = lambda a, best: a > best + min_delta
else:
if mode == 'min':
self.is_better = lambda a, best: a < best - (
best * min_delta / 100)
if mode == 'max':
self.is_better = lambda a, best: a > best + (
best * min_delta / 100)
훈련 루프(training loop)에서 조기 종료(early stopping)를 사용하시려면 위에 링크된 Colab notebook 을 확인하시기 바랍니다.
es = EarlyStopping(patience=5)
num_epochs = 100
for epoch in range(num_epochs):
train_one_epoch(model, data_loader) # train the model for one epoch.
metric = eval(model, data_loader_dev) # evalution on dev set.
if es.step(metric):
break # early stop criterion is met, we can stop now
PyTorch Lightning을 사용하여 PyTorch 코드를 재구성하기를 적극적으로 추천합니다. 이는 조기 종료(early stopping) 및 그 외 많은 테크닉을 즉시 사용할 수 있습니다. PyTorch Lightning에 대해 잘 모르는 경우, 다음과 같은 리포트를 참조하여 시작할 수 있습니다: