7.2 케라스 콜백과 텐서보드를 사용한 딥러닝 모델 검사와 모니터링

이 절에서 훈련하는 동안 모델 내부에서 일어나는 일을 조사하고 제어하는 방법을 살펴보겠습니다. 대규모 데이터셋에서 model.fit()이나 model.fit_generator()로 수십 번의 에포크를 실행하고 나면 제어할 방법이 없습니다. 앞으로 소개할 기법은 model.fit() 호출을 스스로 판단하고 동적으로 제어하는 방법을 살펴 보겠습니다.

7.2.1 콜백을 사용하여 모델의 훈련 과정 제어하기

모델을 훈련할 때 미리 예상할 수 없는 것들이 많습니다. 특히 최적의 검증 손실을 얻기 위해 얼마나 많은 에포크가 필요한지 알지 못합니다. 앞의 예제들은 적절한 훈련 에포크를 알아내기 위해 첫 번째 실행에서 과대적합이 시작될 때까지 충분한 에포크로 훈련했습니다. 그런 다음 최적의 에포크 횟수로 처음부터 새로운 훈련을 시작했습니다. 이런 방식은 낭비가 많습니다.

더 좋은 처리 방법은 검증 손실이 더 이상 향상되지 않을 때 훈련을 멈추는 것입니다. 이런 기법은 케라스의 콜백을 사용하여 구현할 수 있습니다. 콜백은 모델의 fit() 메서드가 호출될 때 전달되는 객체(특정 메서드1를 구현한 클래스 객체)입니다. 훈련하는 동안 모델은 여러 지점에서 콜백을 호출합니다. 콜백은 모델의 상태와 성능에 대한 모든 정보에 접근하고 훈련 중지, 모델 저장, 가중치 적재 또는 모델 상태 변경 등을 처리할 수 있습니다.

다음은 콜백을 사용하는 몇 가지 사례입니다.

  • 모델 체크포인트 저장: 훈련하는 동안 어떤 지점에서 모델의 현재 가중치를 저장합니다.
  • 조기 종료(early stopping): 검증 손실이 더 이상 향상되지 않을 때 훈련을 중지합니다(물론 훈련하는 동안 얻은 가장 좋은 모델을 저장합니다).
  • 하이퍼파라미터 값 동적 조정: 훈련하는 동안 하이퍼파라미터 값을 동적으로 조정합니다. 옵티마이저의 학습률 같은 경우입니다.
  • 로그 기록 및 시각화: 훈련과 검증 지표를 로그에 기록하거나 모델이 학습한 표현이 업데이트될 때마다 시각화합니다: 앞서 보았던 케라스의 진행 표시줄(progress bar)이 하나의 콜백입니다.

keras.callbacks 모듈은 많은 내장 콜백을 포함하고 있습니다.2 다음은 내장 콜백의 일부입니다.

  • keras.callbacks.ModelCheckpoint
  • keras.callbacks.EarlyStopping
  • keras.callbacks.LearningRateScheduler
  • keras.callbacks.ReduceLROnPlateau
  • keras.callbacks.CSVLogger

콜백 사용법을 익히기 위해 ModelCheckpoint, EarlyStopping, ReduceLROnPlateau를 사용한 예를 살펴봅시다.

ModelCheckpoint와 EarlyStopping 콜백

EarlyStopping 콜백을 사용하면 정해진 에포크 동안 모니터링 지표가 향상되지 않을 때 훈련을 중지할 수 있습니다. 예를 들어 과대적합이 시작되자마자 훈련을 중지할 수 있습니다. 따라서 에포크 횟수를 줄여 다시 모델을 훈련할 필요가 없습니다. 일반적으로 이 콜백은 훈련하는 동안 모델을 계속 저장해 주는 ModelCheckpoint와 함께 사용합니다. (선택적으로 지금까지 가장 좋은 모델만 저장할 수 있습니다.)

import keras

# fit() 메서드의 callbacks 매개변수를 사용하여 콜백의 리스트를 모델로 전달합니다. 몇 개의 콜백이라도 전달할 수 있습니다.
callbacks_list = [
  # 성능 향상이 멈추면 훈련을 중지합니다.
  keras.callbacks.EarlyStopping(
    # 모델의 검증 정확도를 모니터링합니다.
    monitor='val_acc',
    # 1 에포크보다 더 길게 (즉 2 에포크 동안) 정확도가 향상되지 않으면 훈련이 중지됩니다. ),
    patience=1,
  ),
  # 에포크마다 현재 가중치를 저장합니다.
  keras.callbacks.ModelCheckpoint(
    # 모델 파일의 경로
    filepath='my_model.h5',
    # 이 두 매개변수는 val_loss가 좋아지지 않으면 모델 파일을 덮어쓰지 않는다는 뜻입니다. 훈련하는 동안 가장 좋은 모델이 저장됩니다.
    monitor='val_loss',
    save_best_only=True,
  )
]

# 정확도를 모니터링하므로 모델 지표에 포함되어야 합니다.
model.compile(optimizer='rmsprop',
              loss='binary_crossentropy', metrics=['acc'])

# 콜백이 검증 손실과 검증 정확도를 모니터링하기 때문에 validation_data 매개변수에 검증 데이터를 전달해야 합니다.
model.fit(x, y, echo=10, batch_size=32, callbacks=callbacks_list,
          validation_data=(x_val, y_val))

3 4

ReduceLROnPlateau 콜백

이 콜백을 사용하면 검증 손실이 향상되지 않을 때 학습률을 작게 할 수 있습니다. 손실 곡선이 평탄할 때 학습률을 작게 하거나 크게 하면 훈련 도중 지역 최솟값에서 효과적으로 빠져나올 수 있습니다. 다음은 ReduceLROnPlateau 콜백을 사용하는 예입니다.

callbacks_list = [
  keras.callbacks.ReduceLROnPlateau(
    # 모델의 검증 손실을 모니터링합니다.
    monitor='val_loss'
    # 콜백이 호출될 때 학습률을 1/10으로 줄입니다.
    factor=0.1,
    # 검증 손실이 10 에포크 동안 좋아지지 않으면 콜백이 호출됩니다.
    patience=10,
  )
]

자신만의 콜백 만들기

내장 콜백에서 제공하지 않는 특수한 행동이 훈련 도중 필요하면 자신만의 콜백을 만들 수 있습니다. 콜백은 keras.callbacks.Callback 클래스를 상속받아 구현합니다. 그다음 훈련하는 동안 호출될 여러 지점을 나타내기 위해 약속된 다음 메서드를 구현합니다.

  • on_epoch_begin: 각 에포크가 시작할 때 호출합니다.
  • on_epoch_end: 각 에포크가 끝날 때 호출합니다.

  • on_batch_begin: 각 배치 처리가 시작되기 전에 호출합니다.
  • on_batch_end: 각 배치 처리가 끝난 후에 호출합니다.

  • on_train_begin: 훈련이 시작될 때 호출합니다.
  • on_train_end: 훈련이 끝날 때 호출합니다.

이 메서드들은 모두 logs 매개변수와 함께 호출됩니다. 이 매개변수에는 이전 배치, 에포크에 대한 훈련과 검증 측정값이 담겨 있는 딕셔너리가 전달됩니다. 또 콜백은 다음 속성을 참조할 수 있습니다.

  • self.model: 콜백을 호출하는 모델 객체
  • self.validation_data: fit() 메서드에 전달된 검증 데이터

다음은 매 에포크의 끝에서 검증 세트의 첫 번째 샘플로 모델에 있는 모든 층의 활성화 출력을 계산하여 (넘파이 배열로) 디스크에 저장하는 자작 콜백의 예입니다.

import keras
import numpy as np

# 호출하는 모델에 대한 정보를 전달하기 위해 훈련하기 전에 호출됩니다.
class ActivationLogger(keras.callbacks.Callback):
  def set_model(self, model):
    self.model = model
    layer_outputs = [layer.output for layer in model.layers]
    # 각 층의 활성화 출력을 반환하는 Model 객체입니다.
    self.activations_model = keras.models.Model(model.input, layer_outputs)

  def on_epoch_end(self, epoch, logs=None):
    if self.validation_data is None:
      raise RuntimeError('Requires validation_data.')

    # 검증 데이터의 첫 번째 샘플을 가져옵니다.
    validation_sample = self.validation_data[0][0:1]
    activations = self.activations_model.predict(validation_sample)

    # 배열을 디스크에 저장합니다.
    f = open('activations_at_epoch_' + str(epoch) + '.npz', 'wb')
    np.savez(f, activations)
    f.close()

5

이것이 콜백에 대해 알아야 할 전부입니다. 기술적인 세부 사항은 쉽게 찾아볼 수 있습니다. 이제 훈련하는 동안 케라스 모델에 어떤 종류의 로깅이나 프로그래밍된 간섭을 수행할 수 있을 것입니다.

7.2.2 텐서보드 소개: 텐서플로의 시각화 프레임워크

좋은 연구를 하거나 좋은 모델을 개발하려면 실험하는 모델 내부에서 어떤 일이 일어나는지 자주 그리고 많은 피드백을 받아야 합니다. 그것이 실험을 하는 목적입니다. 모델이 얼마나 잘 작동하는지 가능한 많은 정보를 얻는 것입니다. 발전은 반복되는 프로세스 또는 루프를 통해 일어납니다. 한 아이디어가 떠오르면 이 아이디어를 검증할 실험을 계획합니다. 실험을 수행하고 생성된 정보를 가공합니다. 이 정보는 다음 아이디어에 영감을 줍니다. 이 루프를 더 많이 실행할수록 아이디어는 더 정제되고 강력해질 것입니다. 케라스는 가능한 최단 시간에 아이디어를 실험으로 구현하도록 도와줍니다. 고속의 GPU가 가능한 빠르게 실험의 결과를 얻도록 도와줄 것입니다. 그렇다면 실험 결과는 어떻게 처리할까요? 바로 텐서보드가 하는 일입니다.

나타낼 수 없음
그림 7-9. 발전 루프

이 절에서는 텐서플로와 함께 제공되는 브라우저 기반 시각화 도구인 텐서보드를 소개합니다. 텐서플로 백엔드로 케라스를 설정한 경우에만 케라스 모델에서 사용할 수 있습니다.

텐서보드의 핵심 목적은 훈련 모델의 내부에서 일어나는 모든 것을 시각적으로 모니터링할 수 있도록 돕는 것입니다. 모델의 최종 손실 외에 더 많은 정보를 모니터링하면 모델 작동에 대한 명확한 그림을 그릴 수 있습니다. 결국 모델을 더 빠르게 개선할 수 있습니다. 텐서보드는 여러 가지 멋진 기능을 제공합니다. 모두 브라우저에서 작동합니다.

  • 훈련하는 동안 측정 지표를 시각적으로 모니터링합니다.
  • 모델 구조를 시각화합니다.
  • 활성화 출력과 그래디언트의 히스토그램을 그립니다.
  • 3D로 임베딩을 표현합니다.

간단한 예를 사용하여 이 기능들을 실습해 보죠. IMDB 감성 분석 문제를 위해 1D 컨브넷을 훈련하겠습니다.

이 모델은 6장 마지막 절에서 보았던 것과 비슷합니다. IMDB 어휘 사전에서 빈도가 높은 2,000개 단어만 사용하겠습니다. 이렇게 하면 단어 임베딩을 시각화하기가 조금 더 쉽습니다.

# 코드 7-7. 텐서보드를 사용한 텍스트 분류 모델
#import keras
#from keras import layers
#from keras.datasets import imdb
#from keras.preprocessing import sequence

import tensorflow.keras as keras
from tensorflow.keras import layers
from tensorflow.keras.datasets import imdb
from tensorflow.keras.preprocessing import sequence
from tensorflow.keras.models import Sequential


# 특성으로 사용할 단어의 수
max_features = 2000
# 사용할 텍스트의 길이(가장 빈번한 max_features개의 단어만 사용합니다.)
max_len = 500

(x_train, y_train), (x_test, y_test) = imdb.load_data(num_words=max_features)
x_train = sequence.pad_sequences(x_train, maxlen=max_len)
x_test = sequence.pad_sequences(x_test, maxlen=max_len)

model = keras.models.Sequential()
model.add(layers.Embedding(max_features, 128,
                           input_length=max_len,
                           name='embed'))
model.add(layers.Conv1D(32, 7, activation='relu'))
model.add(layers.MaxPooling1D(5))
model.add(layers.Conv1D(32, 7, activation='relu'))
model.add(layers.GlobalMaxPooling1D())
model.add(layers.Dense(1))
model.summary()

model.compile(optimizer='rmsprop',
              loss='binary_crossentropy',
              metrics=['acc'])

텐서보드를 시작하기 전에 로그 파일이 저장될 디렉터리를 만들어야 합니다.

# 코드 7-8 텐서보드 로그 파일을 위한 디렉터리 생성하기
import os
os.mkdir('my_log_dir')

TensorBoard 콜백 객체와 함께 훈련을 시작해 보죠. 이 콜백은 지정된 디스크 위치에 로그 이벤트를 기록할 것입니다.

# 코드 7-9 텐서보드 콜백과 함께 모델 훈련하기
callbacks = [
  keras.callbacks.TensorBoard(
    # 로그 파일이 기록될 위치입니다.
    log_dir='my_log_dir',
    # 1 에포크마다 활성화 출력의 히스토그램을 기록합니다.
    histogram_freq=1,
    # 1 에포크마다 임베딩 데이터를 기록합니다.
    embeddings_freq=1,
  )
]
history = model.fit(x_train, y_train, epochs=20,
                    batch_size=128,
                    validation_split=0.2,
                    callbacks=callbacks)

이제 명령행에서 콜백이 사용하는 로그 디렉터리를 지정하여 텐서보드 서버를 실행합니다. 텐서플로를 설치했다면 (예를 들어 pip 명령으로 설치했다면) 텐서보드 유틸리티는 자동으로 설치되었을 것입니다.

$ tensorboard --logdir=my_log_dir

그다음 브라우저에서 http://localhost:6006 주소에 접속하면 모델의 훈련 결과를 확인할 수 있습니다(그림 7-10 참고). 훈련 지표와 검증 지표를 실시간 그래프로 볼 수 있고 Histograms 탭에서 층의 활성화 출력을 멋진 히스토그램 그래프로 볼 수 있습니다(그림 7-11 참고).

나타낼 수 없음
그림 7-10. 텐서보드: 측정 지표 모니터링

나타낼 수 없음
그림 7-11. 텐서보드: 활성화 출력 히스토그램

Embeddings 탭에서 입력 어휘 사전에 있는 단어 2,000개의 임베딩 위치와 공간상 관계를 조사할 수 있습니다. 이 임베딩은 첫 번째 Embedding 층이 학습한 것입니다. 임베딩 공간이 128차원이기 때문에 텐서보드는 우리가 선택한 차원 축소 알고리즘을 사용하여 자동으로 2D 또는 3D로 축소합니다. 주성분 분석(Principal Component Analysis, PCA) 또는 t-SNE(t-distributed Stochastic Neighbor Embedding)입니다.6 그림 7-12의 점 구름(point cloud) 그래프에서 2개의 클러스터가 뚜렷하게 구분됩니다. 긍정적인 의미의 단어와 부정적인 의미의 단어입니다. 이 그래프는 주어진 문제에 완전히 특화된 모델의 목적에 맞게 임베딩이 훈련되었다는 것을 확실하게 보여 줍니다. 이것이 사전 훈련된 보편적인 단어 임베딩이 드물게 사용되는 이유입니다.

나타낼 수 없음
그림 7-12. 텐서보드: 반응형 3D 단어 임베딩의 시각화

Graphs 탭은 케라스 모델을 구성하는 저수준 텐서플로 연산의 그래프를 시각화합니다(그림 7-13 참고). 여기서 볼 수 있듯이 예상보다 훨씬 복잡합니다. 케라스에서 만든 모델은 간단해 보이지만 (기본 층을 몇 개 쌓았습니다) 무대 뒤에서는 상당히 복잡한 그래프 구조가 만들어집니다. 그래프의 많은 부분은 경사 하강법과 관련이 있습니다. 보이는 것과 만들어야 하는 것 사이의 이런 복잡도 차이 때문에 모든 것을 밑바닥부터 텐서플로를 사용하여 만드는 대신 케라스를 사용하여 모델을 만듭니다. 케라스는 작업 흐름을 극적으로 간단하게 만들어 줍니다.

나타낼 수 없음
그림 7-13. 텐서보드: 텐서플로 그래프 시각화

텐서플로 연산의 그래프 외에 케라스의 keras.utils.plot_model 유틸리티는 모델의 층 그래프를 깔끔하게 그려 주는 기능을 제공합니다. 이를 사용하려면 파이썬의 pydotpydot-ng, graphviz 라이브러리가 필요합니다. 간단하게 살펴봅시다.

from keras.utils import plot_model

plot_model(model, to_file='model.png')

이 코드는 그림 7-14에 나온 PNG 이미지를 만듭니다.

나타낼 수 없음
그림 7-14 plot_model 함수가 만든 모델의 층 그래프

층 그래프에 크기 정보를 추가할 수 있습니다. 다음은 plot_model 함수와 show_shapes 매개변수를 사용하여 모델의 그래프를 그립니다(그림 7-15 참고).7

from keras.utils import plot_model

plot_model(model, show_shapes=True, to_file='model.png')

나타낼 수 없음
그림 7-15. 크기 정보가 포함된 모델 그래프

7.2.3 정리

  • 케라스 콜백은 훈련하는 동안 모델을 모니터링하고 모델 상태를 바탕으로 자동으로 작업을 수행하는 손쉬운 방법입니다.
  • 텐서플로를 사용하면 텐서보드를 이용하여 모델 상황을 브라우저에서 시각화할 수 있습니다. 케라스 모델에서는 TensorBoard 콜백을 통해 사용합니다.
  1. ‘자신만의 콜백 만들기’에서 소개된 6개의 메서드를 말합니다. 

  2. 케라스 모델은 fit() 메서드가 반환하는 history 객체를 위한 History 콜백, 측정 지표의 평균을 계산하는 BaseLogger 콜백, fit() 메서드에 verbose=0을 지정하지 않았다면 진행 표시줄을 위한 ProgbarLogger 콜백이 자동으로 추가됩니다. 

  3. monitor 매개변수의 기본값은 ‘val_loss’입니다. 

  4. 검증 정확도를 측정하려면 compile() 메서드의 metrics 매개변수에 ‘acc’를 포함하고 fit() 메서드의 validation_data 매개변수에 검증 데이터를 전달해야 합니다. 

  5. validation_data의 첫 번째 원소는 입력 데이터고, 두 번째 원소는 레이블입니다. 

  6. Embeddings 탭의 왼쪽 아래 패널에서 t-SNE와 PCA를 선택할 수 있습니다. t-SNE 그래프는 2D, 3D를 선택할 수 있고 PCA는 3개의 주성분을 추출합니다. t-SNE와 PCA에 대한 자세한 설명은 <파이썬 라이브러리를="" 활용한="" 머신러닝="">(한빛미디어, 2017)의 3장을 참고하세요. 

  7. plot_model() 함수에는 2개의 매개변수가 더 있습니다. show_layer_names=True로 지정하면 층 이름을 포함합니다. rankdir=‘TB’는 수직으로 그래프를 그리고(기본값입니다), ‘LR’은 수평 그래프를 만듭니다. 

댓글남기기