케라스에서 모델을 만드는 API는 세가지입니다.
Sequential 모델
: 가장 시작하기 쉬운 API, 기본적으로 하나의 파이썬 리스트이며, 단순히 층을 쌓을 수만 있다.
함수형 API
: 그래프같은 모델 구조를 주로 다룬다. 사용성과 유용성 사이 적절한 중간 지점에 위치하며, 가장 널리 사용되는 모델 구축 API이다.
Model 서브클래싱
: 모든 것을 밑바닥부터 직접 만들 수 있는 저수준 방법. 모든 상세한 내용을 완전히 제어하고 싶은 경우에 적합하다. But 여러가지 케라스 내장 기능을 사용하지 못하기 때문에 실수가 발생할 위험이 많다.
함수형 API의 장점 : 층 구조 활용하기
함수형 모델은 명시적인 그래프 데이터 구조이다. 층이 어떻게 연결되어있는지 조사하고 이전 그래프 노드(node)를 새 모델의 일부로 재사용할 수 있다. 특성 추출을 통하여 다른 모델에서 중간 특성을 재사용하는 모델을 만들 수 있는데, 중간층 참조를 통해서 이전 모델의 중간 특성에서 시작할 수 있다.
Model 서브클래싱 사용해보기
Model 클래스를 상속하는 방법은
__init__()
메서드에서 모델이 사용할 층을 정의한다.call()
메서드에서 앞서 만든 층을 사용하여 모델의 정방향 패스를 정의한다.여러 방식을 혼합하여 사용하기
케라스 API로 만든 모델은 Sequential 모델, 함수형 모델 또는 밑바닥부터 만든 서브클래싱 모델인지에 상관없이 부드럽게 서로 상호 운영할 수 있다.
케라스는 모델 훈련을 위해 다양한 워크플로를 제공한다. 간단하게 데이터로 fit()메서드를 호출하거나 밑바닥부터 새로운 훈련 알고리즘을 작성할 수 있는 고급 방법도 제공한다.
표준 워크플로 : compile()
, fit()
, evaluate()
, predict()
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, test_labels)
predictions = model.predict(test_images)
이 간단한 워크 플로를 커스터마이징할 수 있는 몇가지 방법이 있다.
fit()
메서드에 콜백(callback)을 전달하여 훈련하는 동안 특정 시점에 수행될 행동을 예약한다.사용자 정의 특정 지표를 전달하기
지표(metric)
는 모델의 성능을 측정하는 열쇠이다. 특히 훈련 데이터 성능과 테스트 데이터 성능 사이의 차이를 측정하는 것이 중요하다. 케라스 지표는 keras.metrics.Metric 클래스를 상속한 클래스인데, 층과 마찬가지로 지표는 테서플로 변수에 내부 상태를 저장한다. 이 지표가 층과 다른 점은 이런 변수가 역전파로 업데이트 되지 않는다는 것인데, 따라서 상태 업데이트 로직을 update_state() 메서드 안에 직접 작성해야한다.
평균 제곱근 오차MSE를 계산하는 간단한 사용자 정의 지표를 살펴보자.
import tensorflow as tf
class RootMeanSquaredError(keras.metrics.Metric):
def __init__(self, name="rmse", **kwargs):
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 = tf.one_hot(y_true, depth=tf.shape(y_pred)[1])
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 reset_state(self):
self.mse_sum.assign(0.)
self.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()
메서드 호출 시 모델에 전달되는 객체(특정 메서드를 구현한 클래스 객체)이다. 훈련하는 동안 모델은 여러 지점에서 콜백을 호출한다. 콜백은 모델의 상태와 성능에 대한 모든 정보에 접근하고 훈련 중지, 모델 저장, 가중치 적재 또는 모델 상태 변경 등을 처리할 수 있다.
콜백을 사용하는 몇가지 예에는
사용자 정의 콜백 만들기
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))
텐서보드를 사용한 모니터링과 시각화