자료를 공개한 저자 오렐리앙 제롱에게 깊은 감사를 드립니다. 이와 더불어 한빛미디어로부터 강의준비에 필요한 자료를 지원받았음을 밝히며, 이에 대해 진심어린 감사를 전합니다.
import numpy as np
from sklearn.datasets import load_iris
from sklearn.linear_model import Perceptron
iris = load_iris()
X = iris.data[:, (2, 3)] # petal length, petal width
y = (iris.target == 0).astype(np.int)
per_clf = Perceptron(max_iter=1000, tol=1e-3, random_state=42)
per_clf.fit(X, y)
아래 옵션을 사용할 경우 SGDClassifier 와 동일하게 작동
loss="perceptron"
learning_rate="constant"
eta0=1, penalty=None
구성은 다음과 같음.
<그림 출처: netclipart>
<그림 출처: medium>
<그림 출처: 위키피디아)>
하이퍼파라미터 | 일반적으로 사용되는 값 |
---|---|
입력뉴런 수 | 샘플의 특성마다 하나 |
은닉층 수 | 문제에 따라 다름. 보통 1-5개 |
은닉층의 뉴런 수 | 문제에 따라 다름. 보통 10-100개 |
출력뉴런 수 | 예측 차원마다 하나 |
은닉층의 활성화 함수 | ReLU 또는 SELU(11장 참조) |
출력층의 활성화 함수 | 보통 없음. 상황에 따라 ReLU/softplus 또는 logistic/tanh 사용 |
손실함수 | MSE 또는 MAE/Huber(이상치 많은 경우) |
하이퍼파라미터 | 이진 분류 | 다중레이블 분류 | 다중클래스 분류 |
---|---|---|---|
입력층과 은닉층 | 회귀와 동일 | 회귀와 동일 | 회귀와 동일 |
출력뉴런 수 | 1개 | 레이블 당 1개 | 클래스 당 1개 |
출력층의 활성화 함수 | 로지스틱 함수 | 로지스틱 함수 | 소프트맥스 함수 |
손실함수 | 크로스 엔트로피 | 크로스 엔트로피 | 크로스 엔트로피 |
10개의 클래스로 이루어짐.
데이터 셋: 28x28 픽셀 크기의 흑백 패션 이미지 샘플 70,000개
Sequential
클래스 내에 층을 쌓아 순차적 학습 지원model = keras.models.Sequential()
model.add(keras.layers.Flatten(input_shape=[28, 28]))
model.add(keras.layers.Dense(300, activation="relu"))
model.add(keras.layers.Dense(100, activation="relu"))
model.add(keras.layers.Dense(10, activation="softmax"))
model = keras.models.Sequential([
keras.layers.Flatten(input_shape=[28, 28]),
keras.layers.Dense(300, activation="relu"),
keras.layers.Dense(100, activation="relu"),
keras.layers.Dense(10, activation="softmax")
])
keras.utils.plot_model(model, "my_fashion_mnist_model.png", show_shapes=True)
model.compile(loss="sparse_categorical_crossentropy",
optimizer="sgd",
metrics=["accuracy"])
history = model.fit(X_train, y_train, epochs=30,
validation_data=(X_valid, y_valid))
import pandas as pd
pd.DataFrame(history.history).plot(figsize=(8, 5))
plt.grid(True)
plt.gca().set_ylim(0, 1)
save_fig("keras_learning_curves_plot")
plt.show()
evaluate
메서드 활용model.evaluate(X_test, y_test)
predict
또는 predict_class
메서드 활용.predict
메서드: 각 클래스에 속할 확률 계산predict_class
: 가장 높은 확률의 클래스 지정Sequential
클래스를 이용한 회귀용 MLP 구축은 분류용과 기본적으로 동일.model = keras.models.Sequential([
keras.layers.Dense(30, activation="relu", input_shape=X_train.shape[1:]),
keras.layers.Dense(1)
])
model.compile(loss="mean_squared_error", optimizer=keras.optimizers.SGD(lr=1e-3))
history = model.fit(X_train, y_train, epochs=20, validation_data=(X_valid, y_valid))
mse_test = model.evaluate(X_test, y_test)
Sequential
클래스 대신에 함수형 API, 하위클래스(subclassing) API 등을 사용하여 보다 복잡하며, 보다 강력한 딥러닝 모델 구축 가능.input_
: Input
객체hideen1
을 통해 hidden2
로 전달됨concat
를 통해 hidden2
의 결과와 함께 output
으로 직접 전달되기도 함.input_ = keras.layers.Input(shape=X_train.shape[1:])
hidden1 = keras.layers.Dense(30, activation="relu")(input_)
hidden2 = keras.layers.Dense(30, activation="relu")(hidden1)
concat = keras.layers.concatenate([input_, hidden2])
output = keras.layers.Dense(1)(concat)
model = keras.models.Model(inputs=[input_], outputs=[output])
input_A
: 5개의 특성 입력받을 수 있음input_B
: 6개의 특성 입력받을 수 있음evaluate()
, preict()
메서드를 호출할 때도 동일input_A = keras.layers.Input(shape=[5], name="wide_input")
input_B = keras.layers.Input(shape=[6], name="deep_input")
hidden1 = keras.layers.Dense(30, activation="relu")(input_B)
hidden2 = keras.layers.Dense(30, activation="relu")(hidden1)
concat = keras.layers.concatenate([input_A, hidden2])
output = keras.layers.Dense(1, name="output")(concat)
model = keras.models.Model(inputs=[input_A, input_B], outputs=[output])
input_A
입력값: 0-4번 인덱스 특성input_B
입력값: 2-7번 인덱스 특성model.compile(loss="mse", optimizer=keras.optimizers.SGD(lr=1e-3))
X_train_A, X_train_B = X_train[:, :5], X_train[:, 2:]
X_valid_A, X_valid_B = X_valid[:, :5], X_valid[:, 2:]
X_test_A, X_test_B = X_test[:, :5], X_test[:, 2:]
X_new_A, X_new_B = X_test_A[:3], X_test_B[:3]
history = model.fit((X_train_A, X_train_B), y_train, epochs=20,
validation_data=((X_valid_A, X_valid_B), y_valid))
mse_test = model.evaluate((X_test_A, X_test_B), y_test)
y_pred = model.predict((X_new_A, X_new_B))
output
: 주 출력aux_output
: 보조 출력input_A = keras.layers.Input(shape=[5], name="wide_input")
input_B = keras.layers.Input(shape=[6], name="deep_input")
hidden1 = keras.layers.Dense(30, activation="relu")(input_B)
hidden2 = keras.layers.Dense(30, activation="relu")(hidden1)
concat = keras.layers.concatenate([input_A, hidden2])
output = keras.layers.Dense(1, name="main_output")(concat)
aux_output = keras.layers.Dense(1, name="aux_output")(hidden2)
model = keras.models.Model(inputs=[input_A, input_B],
outputs=[output, aux_output])
model.compile(loss=["mse", "mse"], loss_weights=[0.9, 0.1],
optimizer=keras.optimizers.SGD(lr=1e-3))
history = model.fit([X_train_A, X_train_B], [y_train, y_train], epochs=20,
validation_data=([X_valid_A, X_valid_B], [y_valid, y_valid]))
Sequential
클래스와 함수형 API 방식을 사용한 모델은 모두 정적임.Model
클래스 상속__init__()
)를 이용하여 은닉층과 출력층 설정call()
메서드를 이용하여 층을 동적으로 구성 가능class WideAndDeepModel(keras.models.Model):
def __init__(self, units=30, activation="relu", **kwargs):
super().__init__(**kwargs)
self.hidden1 = keras.layers.Dense(units, activation=activation)
self.hidden2 = keras.layers.Dense(units, activation=activation)
self.main_output = keras.layers.Dense(1)
self.aux_output = keras.layers.Dense(1)
def call(self, inputs):
input_A, input_B = inputs
hidden1 = self.hidden1(input_B)
hidden2 = self.hidden2(hidden1)
concat = keras.layers.concatenate([input_A, hidden2])
main_output = self.main_output(concat)
aux_output = self.aux_output(hidden2)
return main_output, aux_output
model = WideAndDeepModel(30, activation="relu")
call()
메서드 안에 숨겨져 있어서, 케라스가 분석하기 어려움summary()
메서드 활용 제한됨: 층의 목록만 확인 가능하며, 층간의 연결정보 알 수 없음.model = keras.models.Sequential([...])
model.compile([...])
model.fit([...])
model.save("my_keras_model.ht")
load_model()
함수 활용model = keras.models.load_model("my_keras_model.ht")
save_weights()
, load_weights()
메서드를 활용하여 모델 파라미터만 저장/복원 가능pickle
모듈 활용.훈련 중에 일정 간격으로 모델의 체크포이트 저장
체크포인트: 텐서플로우에서 모델 파라미터를 저장하는 양식
# 모델 생성 후 훈련하기
checkpoint_cb = keras.callbacks.ModelCheckpoint("my_keras_model.hs")
history = model.fit(X_train, y_train, epochs=10, callbacks=[checkpoint_cb])
save_best_only=True
옵션 설정
훈련 종료 후 저장된 최적 모델 복원에 사용
checkpoint_cb = keras.callbacks.ModelCheckpoint("my_keras_model.hs",
save_best_only=True)
history = model.fit(X_train, y_train, epochs=10,
validation_data=(X_valid, y_valid),
callbacks=[checkpoint_cb])
# 최적 모델 복원
model = keras.models.load_model("my_keras_model.h5")
patience=10
: 일정 에포크(예를 들어, 10 에포크) 동안 검증세트에 대한 점수가 향상되지 않으면 자동 종료.restore_best_weights=True
: 최상의 모델 복원 기능 설정. 훈련이 끝난 후 최적 가중치 바로 복원.early_stopping_cb = keras.callbacks.EralyStopping(patience=10,
restore_best_weights=True)
history = model.fit(X_train, y_train, epochs=100,
validation_data=(X_valid, y_valid),
callbacks=[checkpoint_cb, early_stopping_cb])
class PrintValTrainRatioCallback(keras.callbacks.Callback):
def on_epoch_end(self, epoch, logs):
print("\nval/train: {:.2f}".format(logs["val_loss"] / logs["loss"]))
val_train_ratio_cb = PrintValTrainRatioCallback()
history = model.fit(X_train, y_train, epochs=1,
validation_data=(X_valid, y_valid),
callbacks=[val_train_ratio_cb])
fit()
메서드에서 활용됨)¶evaluate()
메서드에서 활용됨.¶predict()
메서드에서 활용됨.¶get-run_logdir()
함수# 루트 로그 디렉토리 지정
root_logdir = os.path.join(os.curdir, "my_logs")
def get_run_logdir():
import time
run_id = time.strftime("run_%Y_%m_%d-%H_%M_%S")
return os.path.join(root_logdir, run_id)
run_logdir = get_run_logdir()
run_logdir
# 텐서보드 콜백함수 지정
tensorboard_cb = keras.callbacks.TensorBoard(run_logdir)
history = model.fit(X_train, y_train, epochs=30,
validation_data=(X_valid, y_valid),
callbacks=[checkpoint_cb, tensorboard_cb])
$ tensorboard --logdir=./my_logs --port=6006
http://localhost:6006
열면 텐서보드 실행 확인 가능KerasRegressor
클래스를 이용하여 케라스 모델을 사이킷런 모델처럼 작동하게 만들 수 있음.KerasRegressor
클래스의 객체를 생성할 때 아래 build_model()
함수와 같이
케라스 모델을 생성하는 함수를 입력해 주어야 함.def build_model(n_hidden=1, n_neurons=30, learning_rate=3e-3, input_shape=[8]):
model = keras.models.Sequential()
model.add(keras.layers.InputLayer(input_shape=input_shape))
for layer in range(n_hidden):
model.add(keras.layers.Dense(n_neurons, activation="relu"))
model.add(keras.layers.Dense(1))
optimizer = keras.optimizers.SGD(lr=learning_rate)
model.compile(loss="mse", optimizer=optimizer)
return model
keras_reg = keras.wrappers.scikit_learn.KerasRegressor(build_model)
param_distribs = {
"n_hidden": [0, 1, 2, 3],
"n_neurons": np.arange(1, 100),
"learning_rate": reciprocal(3e-4, 3e-2),
}
rnd_search_cv = RandomizedSearchCV(keras_reg, param_distribs, n_iter=10, cv=3, verbose=2)
rnd_search_cv.fit(X_train, y_train, epochs=100,
validation_data=(X_valid, y_valid),
callbacks=[keras.callbacks.EarlyStopping(patience=10)])