#캘리포니아 주택 가격 데이터 셋을 통해 예시를 살펴본다.
from sklearn.datasets import fetch_california_housing
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler
housing = fetch_california_housing()
X_train_full , X_test , y_train_full , y_test = train_test_split(
housing.data, housing.target
)
X_train, X_valid, y_train, y_valid = train_test_split(
X_train_full , y_train_full
)
scaler = StandardScaler()
X_train = scaler.fit_transform(X_train)
X_valid = scaler.transform(X_valid)
X_test = scaler.transform(X_test)
import tensorflow as tf
from tensorflow import keras
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.Model(inputs=[input_],outputs=[output])
input -> hidden1 -> hidden2 -> concat -> output
intput - - - - - - - - - - - - - - - - - - -> concat
이후 모델을 훈련 , 평가 , 검증 , test 하는 과정은 다른 경우과 같게 일반적인 방식으로 구현된다.
이외에 모델을 만드는 방식에서 feature를 나누어 입력층을 다수 만드려면 다음과 같이도 만들 수 있다.
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.Model(inputs=[input_a,input_b],outputs=[output])
다음과 같은 모델의 경우 구조는 다음과 같을 것이다.
input_a - - - - - - - - - - - - - - - - - - - > concat => output
input_b -> hidden1 -> hidden2 -> concat => output
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))
#위의 코드에서 볼 수 있듯이 , 2개로 나누어진 입력에 대해서
#fit , evalutae , predict 모두 2개로 이루어진 튜플로 입력받고 있다.
/usr/local/lib/python3.7/dist-packages/keras/optimizer_v2/gradient_descent.py:102: UserWarning: The `lr` argument is deprecated, use `learning_rate` instead. super(SGD, self).__init__(name, **kwargs)
Epoch 1/20 363/363 [==============================] - 1s 2ms/step - loss: 2.0211 - val_loss: 0.9457 Epoch 2/20 363/363 [==============================] - 1s 2ms/step - loss: 0.8167 - val_loss: 0.7193 Epoch 3/20 363/363 [==============================] - 1s 2ms/step - loss: 0.6834 - val_loss: 0.6501 Epoch 4/20 363/363 [==============================] - 1s 2ms/step - loss: 0.6291 - val_loss: 0.6134 Epoch 5/20 363/363 [==============================] - 1s 2ms/step - loss: 0.5939 - val_loss: 0.5856 Epoch 6/20 363/363 [==============================] - 1s 2ms/step - loss: 0.5682 - val_loss: 0.5634 Epoch 7/20 363/363 [==============================] - 1s 2ms/step - loss: 0.5466 - val_loss: 0.5471 Epoch 8/20 363/363 [==============================] - 1s 2ms/step - loss: 0.5298 - val_loss: 0.5307 Epoch 9/20 363/363 [==============================] - 1s 2ms/step - loss: 0.5154 - val_loss: 0.5195 Epoch 10/20 363/363 [==============================] - 1s 2ms/step - loss: 0.5034 - val_loss: 0.5075 Epoch 11/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4926 - val_loss: 0.4974 Epoch 12/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4827 - val_loss: 0.4897 Epoch 13/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4748 - val_loss: 0.4807 Epoch 14/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4675 - val_loss: 0.4742 Epoch 15/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4607 - val_loss: 0.4683 Epoch 16/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4548 - val_loss: 0.4625 Epoch 17/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4498 - val_loss: 0.4582 Epoch 18/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4454 - val_loss: 0.4528 Epoch 19/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4408 - val_loss: 0.4500 Epoch 20/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4372 - val_loss: 0.4464 162/162 [==============================] - 0s 1ms/step - loss: 0.4404
#보조출력 추가
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.Model(inputs=[input_a,input_b],outputs=[output,aux_output])
#위의 코드와 같이 적절하게 output 층을 추가하는 것으로 쉽게 다중 출력을 구현할 수 있다.
model.compile(loss=["mse","mse"],loss_weights=[0.9,0.1], optimizer="sgd")
#이처럼 각각의 출력에 대해 loss function list를 전달하고 이에 대해
#가중치를 두어 중요도를 달리 적용할 수 있다.
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])
)
Epoch 1/20 363/363 [==============================] - 2s 3ms/step - loss: 0.9955 - main_output_loss: 0.8358 - aux_output_loss: 2.4326 - val_loss: 0.5942 - val_main_output_loss: 0.5227 - val_aux_output_loss: 1.2377 Epoch 2/20 363/363 [==============================] - 1s 2ms/step - loss: 0.5485 - main_output_loss: 0.4836 - aux_output_loss: 1.1326 - val_loss: 0.5185 - val_main_output_loss: 0.4626 - val_aux_output_loss: 1.0219 Epoch 3/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4967 - main_output_loss: 0.4460 - aux_output_loss: 0.9527 - val_loss: 0.4865 - val_main_output_loss: 0.4434 - val_aux_output_loss: 0.8747 Epoch 4/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4638 - main_output_loss: 0.4236 - aux_output_loss: 0.8260 - val_loss: 0.4562 - val_main_output_loss: 0.4215 - val_aux_output_loss: 0.7686 Epoch 5/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4563 - main_output_loss: 0.4255 - aux_output_loss: 0.7334 - val_loss: 0.4561 - val_main_output_loss: 0.4286 - val_aux_output_loss: 0.7029 Epoch 6/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4442 - main_output_loss: 0.4191 - aux_output_loss: 0.6700 - val_loss: 0.4310 - val_main_output_loss: 0.4080 - val_aux_output_loss: 0.6383 Epoch 7/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4220 - main_output_loss: 0.3995 - aux_output_loss: 0.6251 - val_loss: 0.4224 - val_main_output_loss: 0.4020 - val_aux_output_loss: 0.6062 Epoch 8/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4105 - main_output_loss: 0.3899 - aux_output_loss: 0.5957 - val_loss: 0.4174 - val_main_output_loss: 0.3993 - val_aux_output_loss: 0.5802 Epoch 9/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4005 - main_output_loss: 0.3813 - aux_output_loss: 0.5730 - val_loss: 0.4043 - val_main_output_loss: 0.3869 - val_aux_output_loss: 0.5614 Epoch 10/20 363/363 [==============================] - 1s 2ms/step - loss: 0.4284 - main_output_loss: 0.4135 - aux_output_loss: 0.5622 - val_loss: 0.4036 - val_main_output_loss: 0.3876 - val_aux_output_loss: 0.5478 Epoch 11/20 363/363 [==============================] - 1s 2ms/step - loss: 0.3911 - main_output_loss: 0.3741 - aux_output_loss: 0.5447 - val_loss: 0.3926 - val_main_output_loss: 0.3770 - val_aux_output_loss: 0.5331 Epoch 12/20 363/363 [==============================] - 1s 2ms/step - loss: 0.3810 - main_output_loss: 0.3642 - aux_output_loss: 0.5314 - val_loss: 0.3873 - val_main_output_loss: 0.3719 - val_aux_output_loss: 0.5260 Epoch 13/20 363/363 [==============================] - 1s 2ms/step - loss: 0.3745 - main_output_loss: 0.3580 - aux_output_loss: 0.5224 - val_loss: 0.3872 - val_main_output_loss: 0.3726 - val_aux_output_loss: 0.5180 Epoch 14/20 363/363 [==============================] - 1s 2ms/step - loss: 0.3692 - main_output_loss: 0.3530 - aux_output_loss: 0.5142 - val_loss: 0.3800 - val_main_output_loss: 0.3658 - val_aux_output_loss: 0.5080 Epoch 15/20 363/363 [==============================] - 1s 2ms/step - loss: 0.3824 - main_output_loss: 0.3674 - aux_output_loss: 0.5168 - val_loss: 0.3881 - val_main_output_loss: 0.3736 - val_aux_output_loss: 0.5185 Epoch 16/20 363/363 [==============================] - 1s 2ms/step - loss: 0.3669 - main_output_loss: 0.3516 - aux_output_loss: 0.5047 - val_loss: 0.3720 - val_main_output_loss: 0.3585 - val_aux_output_loss: 0.4936 Epoch 17/20 363/363 [==============================] - 1s 2ms/step - loss: 0.3617 - main_output_loss: 0.3468 - aux_output_loss: 0.4952 - val_loss: 0.3761 - val_main_output_loss: 0.3629 - val_aux_output_loss: 0.4948 Epoch 18/20 363/363 [==============================] - 1s 2ms/step - loss: 0.3608 - main_output_loss: 0.3467 - aux_output_loss: 0.4876 - val_loss: 0.3643 - val_main_output_loss: 0.3515 - val_aux_output_loss: 0.4791 Epoch 19/20 363/363 [==============================] - 1s 2ms/step - loss: 0.3527 - main_output_loss: 0.3384 - aux_output_loss: 0.4810 - val_loss: 0.3625 - val_main_output_loss: 0.3498 - val_aux_output_loss: 0.4769 Epoch 20/20 363/363 [==============================] - 1s 2ms/step - loss: 0.3646 - main_output_loss: 0.3521 - aux_output_loss: 0.4777 - val_loss: 0.3672 - val_main_output_loss: 0.3552 - val_aux_output_loss: 0.4752
total_loss , main_loss , aux_loss = model.evaluate(
[X_test_a,X_test_b],[y_test,y_test]
)
#전체 loss값과 main , aux에 대한 loss값을 따로 구할 수 있다.
#즉 evaluate 단계에서 개별손실과 총손실 모두 return 한다는 것이다.
y_pred_main , y_pred_aux = model.predict([X_new_a,X_new_b])
#prediction의 경우도 각각 주 출력과 보조출력에 대하여 각각 예측한다.
162/162 [==============================] - 0s 1ms/step - loss: 0.3498 - main_output_loss: 0.3361 - aux_output_loss: 0.4729