Updated:

다양한 워크플로

 케라스는 매우 간단한 것부터 매우 유연한 것까지 다양한 워크플로를 제공한다. 케라스 모델을 만드는 방법은 여러 가지고, 모델을 훈련하는 방법도 여러가지이다.

케라스 모델을 만드는 여러 방법

 케라스에서 모델을 만드는 API는 세가지 이다.

  • Sequential 모델
    • 시작하기 쉬운 API
    • 기본적으로 하나의 파이썬 리스트
    • 단순히 층을 쌓을 수만 있음
  • 함수형 API(Functional API)
    • 그래프 같은 모델 구조를 주로 다룸
    • 사용성과 유연성 사이의 적절한 중간 지점에 해당
    • 가장 널리 사용되는 모델 구축 API
  • Model 서브클래싱(subclassing)
    • 모든 것을 밑바닥부터 직접 만들 수 있는 저수준 방법
    • 모든 상세한 내용을 완전히 제어하고 싶은 경우에 적합
    • 여러 가지 케라스 내장 기능을 사용하지 못하기 때문에 실수가 발생할 위험이 많음

Sequential 모델

from tensorflow import keras
from tensorflow.keras import layers

model = keras.Sequential([
    layers.Dense(64, activation="relu"),
    layers.Dense(10, activation="softmax")
])

# 동일한 모델을 add() 메서드를 통해 점진적으로 만들 수 있음
model = keras.Sequential()
model.add(layers.Dense(64, activation="relu"))
model.add(layers.Dense(10, activation="softmax"))

 층의 가중치 크기가 입력 크기에 따라 달라지기 때문에 층은 처음 호출될 때 만들어진다. 즉, 입력 크기를 알기 전까지 가중치를 만들 수 없다. 따라서 위 Sequential 모델은 어떤 가중치도 가지고 있지 않다.

가중치를 생성하려면 어떤 데이터로 호출하거나 입력 크기를 지정하여 build() 메서드를 호출해야 한다.

 build() 메서드가 호출된 후 디버깅에 유용한 summary() 메서드를 사용하여 모델 구조를 출력할 수 있다(build() 메서드를 호출하기 전까지는 summary() 메서드를 호출할 수 없다).

 케라스에서는 모델과 층을 포함해서 모든 것에 이름을 지정할 수 있다.

 Sequential 모델의 입력 크기를 미리 지정하면 모델의 가중치를 바로 생성할 수 있다. 이를 위해 Input 클래스를 사용한다.

model = keras.Sequential()
model.add(keras.Input(shape=(3,))) # input 클래스를 사용해 입력 크기 지정
model.add(layers.Dense(64, activation="relu"))

함수형 API

 Sequential 모델은 사용하기 쉽지만 적용할 수 있는 곳이 극히 제한적이다. 하나의 입력과 하나의 출력을 가지며 순서대로 층을 쌓은 모델만 표현할 수 있다. 실제로 다중 입력, 다중 출력 또는 비선형적인 구조를 가진 모델을 자주 만날 수 있다. 이런 경우에는 함수형 API를 사용한 모델을 만든다.

간단한 예제

inputs = keras.Input(shape=(3,), name="my_input")
features = layers.Dense(64, activation="relu")(inputs)
outputs = layers.Dense(10, activation="softmax")(features)
model = keras.Model(inputs=inputs, outputs=outputs)
  • inputs = keras.Input(shape=(3,), name=”my_input”)
    • Input 클래스 객체를 정의, 모델이 처리할 데이터의 크기와 dtype에 대한 정보를 가지고 있음
    • 심볼릭 텐서(symbolic tensor): 실제 데이터를 가지고 있지 않지만 사용할 때 모델이 보게 될 데이터 텐서의 사양이 인코딩되어 있음
  • features = layers.Dense(64, activation=”relu”)(inputs)
    • 그다음 층을 만듬
    • 모든 케라스의 층은 실제 데이터 텐서나 심볼릭 텐서로 호출할 수 있음
  • outputs = layers.Dense(10, activation=”softmax”)(features), model = keras.Model(inputs=inputs, outputs=outputs)
    • 최종 출력을 얻은 후 입력과 출력을 Model 클래스에 전달하여 모델 객체를 생성

다중 입력, 다중 출력 모델
 대부분 딥러닝 모델은 리스트와 같은 형태가 아니라 그래프를 닮았다. 예를 들어 입력이 여러 개이거나 출력이 여러 개이다.
 고객 이슈 티켓에 우선순위를 지정하고 적절한 부서로 전달하는 시스템을 만들어 본다. 이 모델은 3개의 입력을 사용한다.

  • 이슈 티켓의 제목(텍스트 입력)
  • 이슈 티켓의 텍스트 본문(텍스트 입력)
  • 사용자가 추가한 태그(범주형 입력으로 여기에서는 원-핫 인코딩되었다고 가정)

 텍스스 입력을 크기가 vocabulary_size인 0과 1로 이루어진 배열로 인코딩할 수 있다. 이 모델의 출력도 2개이다.

  • 이슈 티켓의 우선순위를 점수로 0과 1사이의 스칼라(시그모이드 출력)
  • 이슈 티켓을 처리해야 할 부서(전체 부서 집합에 대한 소프트맥스 출력)
vocabulary_size = 10000
num_tags = 100
num_departments = 4

### 모델의 입력을 정의
title = keras.Input(shape=(vocabulary_size,), name="title")
text_input = keras.Input(shape=(vocabulary_size,), name="text_body")
tags = keras.Input(shape=(num_tags,), name="tags")

# 입력 특성을 하나의 텐서 features로 연결
features = layers.Concatenate()([title, text_input, tags])

# 중간층을 적용하여 입력 특성을 더 풍부한 표현으로 재결합
features = layers.Dense(64, activation="relu")(features)

### 모델의 출력을 정의
priority = layers.Dense(1, activation="sigmoid", name="priority")(features)
department = layers.Dense(num_departments, activation="softmax" ,name="department")(features)

# 입력과 출력을 지정하여 모델을 만듬
model = keras.Model(inputs=[title, text_input, tags], outputs=[priority, department])

 함수형 API는 간단하지만 층으로 구성된 어떤 그래프도 정의할 수 있는 매우 유연한 방법이다.
 Sequential 모델을 훈련하는 것과 거의 같은 방법으로 이 모델을 훈련할 수 있다. 입력과 출력 데이터의 리스트로 fit() 메서드를 호출하면 된다. 데이터의 리스트는 Model 클래스에 전달한 순서와 같아야 한다.

import numpy as np

num_samples = 1280

### 더미(dummy) 입력 데이터
title_data = np.random.randint(0, 2, size=(num_samples, vocabulary_size))
text_body_data = np.random.randint(0, 2, size=(num_samples, vocabulary_size))
tags_data = np.random.randint(0, 2, size=(num_samples, num_tags))

### 더미 타깃 데이터
priority_data = np.random.random(size=(num_samples, 1))
department_data = np.random.randint(0, 2, size=(num_samples, num_departments))

model.compile(optimizer="rmsprop",
              loss=["mean_squared_error", "categorical_crossentropy"],
              metrics=[["mean_absolute_error"], ["accuracy"]])
model.fit([title_data, text_body_data, tags_data],
          [priority_data, department_data], epochs=1)
model.evaluate([title_data, text_body_data, tags_data],
               [priority_data, department_data])
priority_preds, department_preds = model.predict([title_data, text_body_data, tags_data])

 입력 순서에 신경 쓰고 싶지 않다면, Input 객체와 출력 층에 부여한 이름을 활용해서 데이터를 딕셔너리로 전달할 수 있다.

model.compile(optimizer="rmsprop",
              loss={"priority": "mean_squared_error", "department": "categorical_crossentropy"},
              metrics={"priority": ["mean_absolute_error"], "department": ["accuracy"]})
model.fit({"title": title_data, "text_body": text_body_data,"tags": tags_data},
          {"priority": priority_data, "department": department_data}, epochs=1)
model.evaluate({"title": title_data, "text_body": text_body_data, "tags": tags_data},
               {"priority": priority_data, "department": department_data})
priority_preds, department_preds = model.predict({"title": title_data, "text_body": text_body_data, "tags": tags_data})

함수형 API의 장점: 층 연결 구조 활용하기
 함수형 모델은 명시적인 그래프 데이터 구조이다. 층이 어떻게 연결되어 있는지 조사하고 이전 그래프 노드를 새 모델의 일부로 재사용할 수 있다. 이를 통해 모델 시각화와 특성 추출이라는 두 가지 중요한 기능이 가능하다.
 방금 정의한 모델의 연결 구조(모델의 토폴로지(topology))를 시각화해본다. plot_model() 함수를 사용하여 함수형 모델을 그래프로 그릴 수 있다.

  • keras.utils.plot_model(model, “ticket_classifier.png”)

 모델에 있는 각 층의 입출력 크기를 추가하면 디버깅에 도움이 될 수 있다.

  • keras.utils.plot_model(model, “ticket_classifier_with_shape_info.png”, show_shapes=True)

 텐서 크기에 None은 배치 크기를 나타낸다. 즉, 이 모델은 어떤 크기의 배치에서도 가능하다.
 층 연결 구조를 참조하여 그래프에 있는 개별 노드를 조사하고 재사용(층 호출)할 수 있다. model.layers 속성은 모델에 있는 모든 층의 리스트를 가지고 있다. 각 층에 대해 layer.input과 layer.output을 출력해 볼 수 있다.

 이를 통해 특성 추출(feature extraction)을 수행하여 다른 모델에서 중간 특성을 재사용하는 모델을 만들 수 있다.
 이전 모델에 또 다른 출력을 추가해본다. 이슈 티켓이 해결되는 데 걸리는 시간, 즉 일종의 난의도를 추정하려고 한다. 이를 위해 ‘quick’, ‘medium’, ‘difficulty’ 3개의 범주에 대한 분류 층을 추가한다. 모델을 처음부터 다시 만들고 재훈련할 필요가 없다. 다음과 같이 중간층을 참조할 수 있기 때문에 이전 모델의 중간 특성에서 시작할 수 있다.

 새로운 모델을 그래프로 출력해본다.

  • keras.utils.plot_model(new_model, “updated_ticket_classifier.png”, show_shapes=True)

Model 서브클래싱

 마지막으로 알아야 할 모델 구축 패턴은 가장 고급 방법인 Model 서브클래싱이다.

  • __init__() 메서드에서 모델이 사용할 층을 정의
  • call() 메서드에서 앞서 만든 층을 사용하여 모델의 정방향 패스를 정의
  • 서브클래스의 객체를 만들고 데이터와 함께 호출하여 가중치를 만듬

이전 예제를 서브클래싱 모델로 다시 만들기
 Model 클래스를 상속하여 고객 이슈 티켓 관리 모델을 다시 구현해본다.

class CustomerTickerModel(keras.Model):
  def __init__(self,num_departments):
    super().__init__()  # 부모 클래스의 생성자를 호출
    ### 생성자에서 층을 정의
    self.concat_layer = layers.Concatenate()
    self.mixing_layer = layers.Dense(64, activation="relu")
    self.priority_scorer = layers.Dense(1, activation="sigmoid")
    self.department_classifier = layers.Dense(num_departments, activation="softmax")
  
  def call(self, inputs): # call() 메서드에서 정의한 패스를 정의
    title = inputs["title"]
    text_body = inputs["text_body"]
    tags = inputs["tags"]
    features = self.concat_layer([title, text_body, tags])
    features = self.mixing_layer(features)
    features = self.priority_scorer(features)
    priority = self.priority_scorer(features)
    department = self.department_classifier(features)
    return priority, department

 모델을 정의하고 나면 이 클래스의 객체를 만들 수 있다. Layer 클래스와 마찬가지로 어떤 데이터로 처음 호출할 때 가중치를 만든다.

 지금까지는 Layer 클래스 상속과 비슷하다. Layer 클래스 상속과 Model 클래스 상속의 차이점은 “층은 모델을 만드는 데 사용하는 구성요소고 모델은 실제로 훈련하고 추론에 사용하는 최상위 객체”이다. 간단히 말해서 Model 클래스는 fit(), evaluate(), predict() 메서드를 가지고 있다. Layer 클래스에는 이런 메서드가 없다. 그 외에는 두 클래스가 거의 동일하다.
 Sequential이나 함수형 모델과 마찬가지로 Model을 상속하여 만든 모델을 컴파일하고 훈련할 수 있다.

 Model 서브 클래싱 워크플로는 모델을 만드는 가장 유연한 방법이다. 층의 유향 비순환 그래프(directed acyclic hraph)로 표현할 수 없는 모델을 만들 수 있다. 예를 들어 call() 메서드가 for 루프 안에서 층을 사용하거나 재귀적으로 호출하는 모델이다.

주의: 서브클래싱된 모델이 지원하지 않는 것
 서브클래싱 모델에서는 모델 로직을 많이 책임져야 하며 잠재적인 오류 가능성이 훨씬 크다. 결과적으로 더 많은 디버깅 작업을 해야 한다.

여러 방식을 혼합하여 사용하기

 중요한 것은 Sequential 모델, 함수형 API, Model 서브클래싱 패턴 중 하나를 선택한다고 다른 패턴의 사용을 제한하지 않는다는 점이다. 케라스 API로 만든 모델은 서로 상호 운영할 수 있다. 예를 들어 함수형 모델에서 서브클래싱 층이나 모델을 사용할 수 있다.

class Classifier(keras.Model):
  def __init__(self, num_classes=10):
    super().__init__()
    if num_classes == 2:
      num_units = 1
      activation = "sigmiod"
    else:
      num_units = num_classes
      activation = "softmax"
    self.dense = layers.Dense(num_units, activation=activation)
  
  def call(self, inputs):
    return self.dense(inputs)

inputs = keras.Input(shape=(3,))
features = layers.Dense(64, activation="relu")(inputs)
outputs = Classifier(num_classes=10)(features)
model = keras.Model(inputs=inputs, outputs=outputs)

 반대로 서브클래싱 층이나 모델의 일부로 함수형 모델을 사용할 수 있다.

inputs = keras.Input(shape=(3,))
outputs = layers.Dense(1, activation="sigmoid")(inputs)
binary_classifier = keras.Model(inputs=inputs, outputs=outputs)

class MyModel(keras.Model):
  def __init__(self, num_classes=2):
    super().__init__()
    self.dense = layers.Dense(64, activation="softmax")
    self.classifier = binary_classifier
  
  def call(self, inputs):
    features = self.dense(inputs)
    return self.classifier(features)

model = MyModel()

작업에 적합한 도구 사용하기

 각 방법은 장단점이 있으므로 현재 작업에 가장 잘 맞는 것을 선택해야한다. 일반적으로 함수형 API가 쉬운 사용성과 유연성 사이에 적정한 절충점이다. 층 연결 구조를 활용하여 모델 출력이나 특성 추출과 같은 용도에 잘 맞는다. 함수형 API를 사용할 수 있다면, 즉 모델을 층의 유향 비순환 그래프로 표현할 수 있다면 Model 서브클래싱보다 이 방식을 사용할 것을 권장한다.

내장된 훈련 루프와 평가 방법

 케라스는 모델 훈련을 위해 다양한 워크플로를 제공한다. 간단하게 데이터로 fit() 메서드를 호출하거나 새로운 훈련 알고리즘을 작성할 수 있는 고급 방법도 제공한다.

from tensorflow import keras
from tensorflow.keras import layers
from tensorflow.keras.datasets import mnist

def get_mnist_model():  # 모델을 만듬
  inputs = keras.Input(shape=(28 * 28,))
  features = layers.Dense(512, activation="relu")(inputs)
  features = layers.Dropout(0.5)(features)
  outputs = layers.Dense(10, activation="softmax")(features)
  model = keras.Model(inputs, outputs)
  return model

# 데이터를 로드하고 일부를 떼어 놓는다
(images, labels), (test_images, test_labels) = mnist.load_data()
images = images.reshape((60000, 28 * 28)).astype("float32") / 255
test_images = test_images.reshape((10000, 28 * 28)).astype("float32") / 255
train_images, val_images = images[10000:],images[:10000]
train_labels, val_labels = labels[10000:], labels[:10000]

model = get_mnist_model()
model.compile(optimizer="rmsprop",
              loss="sparse_categorical_crossentropy",
              metrics=["accuracy"]) # 모델 컴파일
model.fit(train_images, train_labels,
          epochs=3,
          validation_data=(val_images, val_labels)) # 모델 훈련
test_metrics = model.evaluate(test_images, val_labels) # 새로운 데이터에 대한 손실과 측정 지표 계산
predictions = model.predict(test_images)  # 새로운 데이터에 대한 분류 확률을 계산

 이 간단한 워크플로를 커스터마이징할 수 있는 몇 가지 방법이 있다.

  • 사용자 정의 지표를 전달
  • fit() 메서드에 콜백(callback)을 전달하여 훈련하는 동안 특정 시점에 수행될 행동을 예약

사용자 정의 지표 만들기

 지표(metric)는 모델의 성능을 측정하는 열쇠이다. 특히 훈련 데이터 성능과 테스트 데이터 성능 사이의 차이를 측정하는 것이 중요하다. 분류와 회귀에 일반적으로 사용되는 지표는 keras.metrics 모듈에 포함되어 있다. 대부분의 경우 여기에 포함된 지표를 사용할 것이지만, 일반적이지 않은 작업을 한다면 사용자 정의 지표를 만들 수 있어야 한다.
 케라스 지표는 keras.metrics.Metric 클래스를 상속한 클래스이다. 층과 마찬가지로 지표는 텐서플로 변수에 내부 상태를 저장한다. 층과 다른 점은 이 변수가 역전파로 업데이트되지 않는다는 것이다. 따라서 상태 업데이트 로직을 update_state() 메서드 안에 직접 작성해야 한다.
 다음은 평균 제곱 오차(Root Mean Squared Error, RMSE)를 계산하는 간단한 사용하 정의 지표이다.

import tensorflow as tf

class RootMeanSquaredError(keras.metrics.Metric): # metric 클래스를 상속
  def __init__(self, name="rmse", **kwargs):  # 생성자에서 상태 변수를 정의, add_weight() 메서드 사용
    super().__init__(name=name, **kwargs)
    self.mse_sum = self.add_weight(name="mse_sum", initializer="zeros")
    self.total_samples = self.add_weight(name="total_samples", initializer="zeros", dtype="int32")

  def update_state(self, y_true, y_pred, sample_weight=None): # 상태 업데이트 로직을 구현
    # y_true는 배치의 타깃, y_pred는 모델의 예측
    y_true = tf.one_hot(y_true, depth=tf.shape(y_pred)[1]) # 정수 레이블인 y_true를 원-핫 인코딩으로 변환
    mse = tf.reduce_sum(tf.square(y_true - y_pred))
    self.mse_sum.assign_add(mse)
    num_samples = tf.shape(y_pred)[0]
    self.total_samples.assign_add(num_samples)
  
  def result(self): # 현재 지펴 값을 반환
    return tf.sqrt(self.mse_sum / tf.cast(self.total_samples, tf.float32))
  
  # 객체를 다시 생성하지 않고 상태를 초기화 하는 방법
  # 이렇게 함으로써 지표 객체 하나를 서로 다른 훈련 반복에 사용하거나 훈련과 평가에 모두 사용할 수 있음
  def result_state(self):
    self.mse_sum.assign(0.)
    slef.total_samples.assign(0)

 사용자 정의 지표는 내장 지표와 동일한 방식으로 사용할 수 있다.

model = get_mnist_model()
model.compile(optimizer="rmsprop",
              loss="sparse_categorical_crossentropy",
              metrics=["accuracy", RootMeanSquaredError()])
model.fit(train_images, train_labels,
          epochs=3,
          validation_data=(val_images, val_labels))
test_metrics = model.evaluate(test_images, test_labels)

 fit() 메서드가 출력하는 진행 표시줄에 RMSE 값이 표시되는 것을 볼 수 있다.

콜백 사용하기

 케라스 콜백(callback)은 fit() 메서드 호출 시 모델에 전달되는 객체이다. 훈련하는 동안 모델은 여러 지점에서 콜백을 호출한다. 콜백은 모델의 상태와 성능에 대한 모든 정보레 접근하고 훈련 중지, 모델 저장, 가중치 적재 또는 모델 상태 변경 등을 처리할 수 있다.
 다음은 콜백을 사용하는 몇 가지 사례이다.

  • 모델 체크포인트(checkpoint) 저장: 훈련하는 동안 어떤 지점에서 모델의 현재 가중치를 저장
  • 조기 종료(early stopping): 검증 손실이 더 이상 향상되지 않을 때 훈련을 중지, 훈련하는 동안 얻은 가장 좋은 모델을 저장
  • 훈련하는 동안 하이퍼파라미터 값을 동적으로 조정
  • 훈련과 검증 지표를 로그에 기록하거나 모델이 학습한 표현이 업데이트될 때마다 시각화

 keras.callbacks 모듈에는 여러 가지 내장 콜백이 포함되어 있다.

  • keras.callback.ModelChekpoint
  • keras.callback.EarlyStopping
  • keras.callback.LearningRateScheduler
  • keras.callback.ReduceLR0nPlateau
  • keras.callback.CSVLogger

ModelChekpoint와 EarlyStopping 콜백
 모델을 훈련할 때는 미리 예상할 수 없는 것이 많다. 특히 최적의 검증 손실을 얻기 위해 얼마나 많은 에포크가 필요한지 알지 못한다. 이를 알기 위해 검증 손실이 더 이상 향상되지 않을 때 훈련을 멈추는 것이다. EarlyStopping 콜백을 사용하여 이를 구현할 수 있다.
 EarlyStopping 콜백은 정해진 에포크 동안 모니터링 지표가 향상되지 않을 때 훈련을 중지한다. 따라서 에포크 횟수를 줄여 다시 모델을 훈련할 필요가 없다. 일반적으로 이 콜백은 훈련하는 동안 모델을 계속 저장해 주는 ModelCheckpoint 콜백과 함께 사용한다. 선택적으로 지금까지 가장 좋은 모델만 저장할 수 있다. 즉, 에포크 끝에서 최고의 성능을 낸 모델이다.

callbacks_list = [
    keras.callbacks.EarlyStopping(  # 성능 향상이 멈추면 훈련을 중지
        monitor="val_accuracy", # 모델의 검증 정확도를 모니터링
        patience=2, # 두 번의 에포크 동안 정확도가 향상되지 않으면 훈련을 중지
    ),
    keras.callbacks.ModelCheckpoint(  # 매 에포크 끝에서 현재 가중치를 저장
        filepath="checkpoint_path.h5",  # 저장 경로
        ### val_loss가 좋아지지 않으면 모델 파일을 덮어쓰지 않는다.
        monitor="val_loss", 
        save_best_only=True,
        ###
    )
]
model = get_mnist_model()
model.compile(optimizer="rmsprop",
              loss="sparse_categorical_crossentropy",
              metrics=["accuracy"]) # 정확도를 모니터링
model.fit(train_images, train_labels,
          epochs=10,
          callbacks=callbacks_list,
          validation_data=(val_images, val_labels))

 model.save(“my_checkpoint_path”)를 호출하면 된다. 저장된 모델은 “model = keras.models.load_model(“checkpoint_path.keras”)”와 같이 로드할 수 있다.

사용자 정의 콜백 만들기

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

 이 메서드들은 모두 logs 매개변수와 함께 호출된다. 다음은 훈련 도중 배치 손실 값을 리스트에 추가하고 에포크 끝에서 이 값을 그래프로 저장하는 예이다.

from matplotlib import pyplot as plt

class LossHistory(keras.callbacks.Callback):
  def on_train_begin(self, logs):
    self.per_batch_losses = []
  
  def on_batch_end(self, batch, logs):
    self.per_batch_losses.append(logs.get("loss"))
  
  def on_epoch_end(self, epoch, logs):
    plt.clf()
    plt.plot(range(len(self.per_batch_losses)), self.per_batch_losses, label="Training loss for each batch")
    plt.xlabel(f"Batch (epoch {epoch})")
    plt.ylabel("Loss")
    plt.legend()
    plt.savefig(f"plot_at_epoch_{epoch}")
    self.per_batch_losses = []

 이 콜백을 테스트해 본다.

model = get_mnist_model()
model.compile(optimizer="rmsprop",
              loss="sparse_categorical_crossentropy",
              metrics=["accuracy"])
model.fit(train_images, train_labels,
          epochs=10,
          callbacks=[LossHistory()],
          validation_data=(val_images, val_labels))

 저장된 손실 그래프는 다음과 같다.

텐서보드를 사용한 모니터링과 시각화

 좋은 연구를 하거나 좋은 모델을 개발하려면 실험하는 모델 내부에서 어떤 일이 일어나는지 자주 그리고 많은 피드백을 받아야 한다. 모델이 얼마나 잘 작동하는지 가능한 많은 정보를 얻는 것이 실험을 하는 목적이다. 케라스는 이를 도와준다. 이를 위해 텐서보드(TesnsorBoard)가 필요하다.
 텐서보드는 로컬에서 실행할 수 있는 브라우저 기반 애플리케이션이다. 훈련하는 동안 모델 안에서 일어나는 모든 것을 모니터링하기 위한 가장 좋은 방법이다. 탠서보드를 사용하여 다음과 같은 일을 수행할 수 있다.

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

 케라스 모델의 fit() 메서드와 함께 텐서보드를 사용하는 가장 쉬운 방법은 keras.callbacks.TensorBoard 콜백이다. 간단한 예로는 이 콜백에 로그를 저장할 위치를 저장하기만 하면 된다.

model = get_mnist_model()
model.compile(optimizer="rmsprop",
              loss="sparse_categorical_crossentropy",
              metrics=["accuracy"])
tensorboard = keras.callbacks.TensorBoard(
    log_dir="/full_path_to_your_log_dir",
)
model.fit(train_images, train_labels,
          epochs=10,
          validation_data=(val_images, val_labels),
          callbacks=[tensorboard()])

 모델이 실행되고 나면 지정한 위치에 로그를 기록한다. 로컬 컴퓨터에서 파이썬 스크립트를 실행한다면 텐서보드를 실행할 수 있다.

댓글남기기