본 포스팅은 다음 과정을 정리 한 글입니다.
Custom Models, Layers, and Loss Functions with TensorFlow
www.coursera.org/specializations/tensorflow-advanced-techniques
지난 시간 리뷰
Custom Callbacks, Custom Callbacks code walkthrough
이전 시간에 TensorFlow의 기본 제공 콜백을 사용하는 방법에 대해 살펴보았습니다.
이번 시간에는 Custom Callbacks(사용자 지정 콜백)을 만드는 방법에 대해 알아보겠습니다.
사용자 지정 콜백을 생성하면 많은 이점이 있는데 무엇보다도 각 사용자가 원하는 콜백을 정의할 수 있습니다.
바로 프로젝트의 특정 요구에 맞는 콜백을 사용할 수 있다는 것입니다.
사용자 정의 콜백이 Keras의 기본 제공 콜백을 확장하는 경우 Keras 콜백의 모든 기능을 사용할 수 있게 됩니다.
마지막으로 표준 Keras 콜백에 아직 없는 기능을 사용자 정의 콜백을 디자인하여 사용할 수 있습니다.
코드를 사용하여 예를 드는 것이 더 쉬울 것 같아 몇 가지 시나리오를 살펴보겠습니다.
시작하기 전에 Tensorflow Keras를 사용하여 간단한 모델을 만들어 보겠습니다.
Sequential 형태의 하나의 뉴런을 가지는 Dense layer를 정의하고 RMSprop optimizer를 optimizer로 사용하고 mean_squared_error를 통해 loss를 계산하고 metrics로 mean average error를 받게 합니다.
이제 사용자 지정 콜백(custom callback)을 정의해 보겠습니다.
class에 사용자 지정 콜백의 이름을 지정합니다. (MyCustomCallback) 그리고 tf.keras.callbacks.Callback을 subclassing 합니다.
우리의 사용자 지정 콜백은 Training batch가 시작되거나 종료될 때마다 timestamp를 출력합니다.
이를 구현하기 위해 우리는 on_train_batch_begin과 on_train_batch_end 메서드를 재정의(오버 라이딩)하여 batch가 몇 번째 인지, 현재 timestamp는 몇 시인지를 출력해줍니다.
방금 정의한 사용자 지정 콜백을 사용하기 위해 MyCustomCallback의 인스턴스를 생성합니다.
my_custom_callback이라는 변수에 사용자 지정 콜백의 인스턴스를 저장하고 여태까지 했던 것과 같이 model.fit을 사용하여 모델을 훈련합니다.
mode.fit 메서드 안에는 콜백 목록을 받는 매개 변수 콜백이 있습니다.
그중 하나가 사용자 지정 콜백입니다. my_custom_callback 변수에 저장된 사용자 지정 콜백의 인스턴스를 전달하여 이를 수행할 수 있습니다.
이 콜백은 각 epoch의 시작과 끝에 대한 timestamp를 print 해줍니다.
이제 좀 더 복잡한 것을 살펴보겠습니다.
검증 손실과 훈련 손실 사이의 비율을 측정하는 콜백을 살펴봅시다.
비율이 너무 높으면 train loss(훈련 손실)이 계속 감소하는 동안에 validation loss(검증 손실)이 더 이상 감소하지 않아 검증 손실을 훈련 손실로 나눈 비율이 높아지기 때문에 과적합 시나리오가 발생할 수 있습니다.
이러한 경우 Overfitting(과적합)을 피하기 위해 훈련을 중단해야 합니다.
우리는 DetectOverfittingCallback이라는 클래스를 정의하여 이를 구현하고자 합니다.
기존과 마찬가지로 subclass로 tf.keras.callbacks.Callback을 받습니다.
__init__ 함수를 재 정의하여 threshold 값을 매개 변수로 받아 self.threshold에 저장합니다.
그런 다음 on_epoch_end를 오버 라이딩합니다.
여기서 매 epoch가 끝날 때마다 ratio를 계산하고 epoch와 ratio를 출력하는데, ratio가 threshold보다 크면 학습을 종료합니다.
이를 사용하기 위해 위에 처럼 model.fit을 수행할 때 callbacks에 우리가 정의한 클래스 DetectOverfittingCallback을 등록하고 매개변수로 threshold를 전달해 주면 됩니다.
또 하나의 예제를 살펴보겠습니다.
이 예제에서는 무한 분류기를 학습시키고 VisCallback이라는 사용자 정의 콜백을 정의했습니다.
모든 epoch가 끝날 때 사용자 지정 콜백은 분류된 출력의 시각화 이미지를 생성하고 해당 이미지를 디스크에 저장합니다.
오른쪽에 저장된 이미지 (숫자들)을 볼 수 있습니다.
예측이 잘못되었을 때 예측된 출력 아래 빨간색으로 정답 숫자가 표기되어있고 예측이 잘 된 것들은 녹색으로 표시되어 있습니다.
먼저 tf.keras.callbacks.Callback을 subclassing 하는 VisCallback이라는 사용자 정의 콜백을 정의하고 클래스 변수들 (inputs, ground_truth, images, display_freq, n_samples)을 정의합니다.
self.input은 모델에서 실행할 입력을 저장하고 self.ground_truth는 입력 이미지에 대한 ground truth 또는 True 레이블을 저장합니다. 이를 통해 각 예측을 실제 레이블과 비교할 수 있습니다.
self.images는 ground_truth와 예측의 시각화 비교를 위한 것입니다.
self.display_freq는 이미지를 plot 할 빈도를 설정하는 것입니다.
self.n_samples는 시각화가 생성될 때마다 plot 할 샘플 수를 결정합니다.
여기서 default는 display_freq가 10, n_samples가 10입니다.
epoch가 끝날 때 입력 이미지 목록(self.inputs)에서 데이터를 무작위로 샘플링 한 다음 분류합니다.
올바르게 분류되었는지 여부에 따라 라벨 예측을 녹색 또는 빨간색으로 표시합니다.
np.random.choice를 사용하여 입력 수와 원하는 샘플 크기를 전달하는 것으로 시작합니다.
우리는 np.random.choice를 사용하여 훈련 데이터에서 완전히 무작위로 이미지를 선택할 수 있습니다.
indexes에 무작위로 생성된 인덱스 목록이 있고 self.inputs[indexes], self.ground_truth[indexes]로 indexes에 해당하는 값만 가져와 X_test와 y_test에 저장합니다.
그다음 예측을 얻기 위해 model.predict에 X_test 값을 전달합니다.
np.argmax를 사용하여 가능성이 가장 높은 값을 얻습니다.
np.argmax는 목록을 가져와서 해당 목록에서 최대 값을 찾은 다음 해당 최댓값의 인덱스 위치를 반환합니다.
이제 예측을 얻었으므로 데이터를 display_digits 함수에 전달하여 plotter에 그릴 수 있습니다.
그런 다음 plot의 결과를 버퍼로 읽어서 plot 된 이미지를 목록에 저장하면 self.images라는 목록에 추가할 수 있습니다.
display_freq만큼 plot을 표시하려면 epoch을 self.display_freq으로 % 연산하여 원하는 빈도만큼 plot을 수행할 수 있습니다.
예를 들어 빈도가 10이면 10번째 epoch마다 이미지가 렌더링 됩니다.
저장된 여러 이미지로 구성된 애니메이션 GIF를 만드는 방법은 다음과 같습니다.
Python용 imageio 라이브러리에는 이미지 배열을 지정하고 애니메이션 GIF를 작성할 수 있는 mimsave 메서드가 포함되어 있습니다.
self.images에 이미지 목록을 보관했으므로 이것을 mimsave의 매개변수로 넣어줍니다.
이 gif를 얻으려면 model.fix을 호출할 때 콜백에 이 사용자 지정 클래스를 넣어줍니다. x_test와 y_test를 매개 변수로 넣어주고 시각화가 train 세트가 아닌 test 세트에서 생성되도록 합니다.
다음은 콜백에 의해 생성된 하나의 GIF입니다.
train이 끝날 때마다 매 epoch때 무작위로 이미지 세트를 선택하여 저장했던 self.images를 저장하여 GIF로 만든 것입니다.
이것으로 Tensorflow에서 callback에 대한 것들을 모두 살펴보았습니다.
감사합니다.
댓글