使用 Keras 函数的多输入多输出模型 API
Multi-input Multi-output Model with Keras Functional API
如图 1 中所述,我有 3 个模型,每个模型都适用于特定领域。
这 3 个模型分别使用不同的数据集进行训练。
并且推理是连续的:
由于 python 的多进程库,我尝试并行调用这 3 个模型,但它非常不稳定,不建议这样做。
这是我必须确保一次完成所有操作的想法:
由于这 3 个模型共享一个共同的预训练模型,我想制作一个具有多个输入和多个输出的模型。
如下图所示:
就像在推理过程中那样,我将调用一个模型,该模型将同时执行所有 3 个操作。
我看到使用 KERAS 的函数 API,这是可能的,但我不知道该怎么做。
数据集的输入具有相同的维度。这些是 (200,200,3) 的照片。
如果有人有一个共享共同结构的多输入多输出模型的例子,我没问题。
更新
这是我的代码示例,但它 returns 是一个错误,因为 layers. concatenate (...)
线传播的形状未被 EfficientNet
模型考虑。
age_inputs = layers.Input(shape=(IMG_SIZE, IMG_SIZE, 3), name="age_inputs")
gender_inputs = layers.Input(shape=(IMG_SIZE, IMG_SIZE, 3)
, name="gender_inputs")
emotion_inputs = layers.Input(shape=(IMG_SIZE, IMG_SIZE, 3),
name="emotion_inputs")
inputs = layers.concatenate([age_inputs, gender_inputs, emotion_inputs])
inputs = layers.Conv2D(3, (3, 3), activation="relu")(inputs)
model = EfficientNetB0(include_top=False,
input_tensor=inputs, weights="imagenet")
model.trainable = False
inputs = layers.GlobalAveragePooling2D(name="avg_pool")(model.output)
inputs = layers.BatchNormalization()(inputs)
top_dropout_rate = 0.2
inputs = layers.Dropout(top_dropout_rate, name="top_dropout")(inputs)
age_outputs = layers.Dense(1, activation="linear",
name="age_pred")(inputs)
gender_outputs = layers.Dense(GENDER_NUM_CLASSES,
activation="softmax",
name="gender_pred")(inputs)
emotion_outputs = layers.Dense(EMOTION_NUM_CLASSES, activation="softmax",
name="emotion_pred")(inputs)
model = keras.Model(inputs=[age_inputs, gender_inputs, emotion_inputs],
outputs =[age_outputs, gender_outputs, emotion_outputs],
name="EfficientNet")
optimizer = keras.optimizers.Adam(learning_rate=1e-2)
model.compile(loss={"age_pred" : "mse",
"gender_pred":"categorical_crossentropy",
"emotion_pred":"categorical_crossentropy"},
optimizer=optimizer, metrics=["accuracy"])
(age_train_images, age_train_labels), (age_test_images, age_test_labels) = reg_data_loader.load_data(...)
(gender_train_images, gender_train_labels), (gender_test_images, gender_test_labels) = cat_data_loader.load_data(...)
(emotion_train_images, emotion_train_labels), (emotion_test_images, emotion_test_labels) = cat_data_loader.load_data(...)
model.fit({'age_inputs':age_train_images, 'gender_inputs':gender_train_images, 'emotion_inputs':emotion_train_images},
{'age_pred':age_train_labels, 'gender_pred':gender_train_labels, 'emotion_pred':emotion_train_labels},
validation_split=0.2,
epochs=5,
batch_size=16)
我们可以在 tf. keras
中使用其出色的函数 API 轻松做到这一点。在这里,我们将带您了解如何使用函数 API.
构建具有不同类型(classification
和 regression
)的 multi-out
根据你上一张图,你需要一个输入模型和三个不同类型的输出。为了演示,我们将使用 MNIST
这是一个手写数据集。它通常是 10 class class化问题数据集。从中,我们将创建一个额外的 2 class classifier(无论数字是 even
还是 odd
)以及1回归部分(预测一个数字的平方,即对于输入9的图像,应该给出近似的平方)。
数据集
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
(xtrain, ytrain), (_, _) = keras.datasets.mnist.load_data()
# 10 class classifier
y_out_a = keras.utils.to_categorical(ytrain, num_classes=10)
# 2 class classifier, even or odd
y_out_b = keras.utils.to_categorical((ytrain % 2 == 0).astype(int), num_classes=2)
# regression, predict square of an input digit image
y_out_c = tf.square(tf.cast(ytrain, tf.float32))
因此,我们的训练对将是 xtrain
和 [y_out_a, y_out_b, y_out_c]
,与您上一张图相同。
模型建筑
让我们使用 tf. keras
的函数 API 相应地构建模型。请参阅下面的模型定义。 MNIST
个样本是 28 x 28
个灰度图像。所以我们的输入就是这样设置的。我猜你的数据集可能是 RGB,所以相应地改变输入维度。
input = keras.Input(shape=(28, 28, 1), name="original_img")
x = layers.Conv2D(16, 3, activation="relu")(input)
x = layers.Conv2D(32, 3, activation="relu")(x)
x = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(32, 3, activation="relu")(x)
x = layers.Conv2D(16, 3, activation="relu")(x)
x = layers.GlobalMaxPooling2D()(x)
out_a = keras.layers.Dense(10, activation='softmax', name='10cls')(x)
out_b = keras.layers.Dense(2, activation='softmax', name='2cls')(x)
out_c = keras.layers.Dense(1, activation='linear', name='1rg')(x)
encoder = keras.Model( inputs = input, outputs = [out_a, out_b, out_c], name="encoder")
# Let's plot
keras.utils.plot_model(
encoder
)
需要注意的一点是,在模型定义期间定义 out_a
、out_b
和 out_c
时,我们设置了非常重要的 name
变量。他们的名字分别设置为'10cls'
、'2cls'
和'1rg'
。您也可以从上图(最后 3 个尾巴)中看到这一点。
编译并运行
现在,我们可以明白为什么 name
变量很重要了。为了 运行 模型,我们需要先使用适当的 loss
函数、metrics
和 optimizer
对其进行编译。现在,如果你知道,对于 classification
和 regression
问题,optimizer
可以相同,但对于 loss
函数和 metrics
应该改变.在我们的模型中,它有一个 multi-type 输出模型(2 个 class 化和 1 个回归),我们需要为每种类型设置适当的 loss
和 metrics
。请看下面是如何完成的。
encoder.compile(
loss = {
"10cls": tf.keras.losses.CategoricalCrossentropy(),
"2cls": tf.keras.losses.CategoricalCrossentropy(),
"1rg": tf.keras.losses.MeanSquaredError()
},
metrics = {
"10cls": 'accuracy',
"2cls": 'accuracy',
"1rg": 'mse'
},
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
)
看,我们上述模型的每个最后输出,在这里由它们的 name
变量表示。我们为它们设置了适当的编译。希望你能理解这部分。现在,是时候训练模型了。
encoder.fit(xtrain, [y_out_a, y_out_b, y_out_c], epochs=30, verbose=2)
Epoch 1/30
1875/1875 - 6s - loss: 117.7318 - 10cls_loss: 3.2642 - 4cls_loss: 0.9040 - 1rg_loss: 113.5637 - 10cls_accuracy: 0.6057 - 4cls_accuracy: 0.8671 - 1rg_mse: 113.5637
Epoch 2/30
1875/1875 - 5s - loss: 62.1696 - 10cls_loss: 0.5151 - 4cls_loss: 0.2437 - 1rg_loss: 61.4109 - 10cls_accuracy: 0.8845 - 4cls_accuracy: 0.9480 - 1rg_mse: 61.4109
Epoch 3/30
1875/1875 - 5s - loss: 50.3159 - 10cls_loss: 0.2804 - 4cls_loss: 0.1371 - 1rg_loss: 49.8985 - 10cls_accuracy: 0.9295 - 4cls_accuracy: 0.9641 - 1rg_mse: 49.8985
Epoch 28/30
1875/1875 - 5s - loss: 15.5841 - 10cls_loss: 0.1066 - 4cls_loss: 0.0891 - 1rg_loss: 15.3884 - 10cls_accuracy: 0.9726 - 4cls_accuracy: 0.9715 - 1rg_mse: 15.3884
Epoch 29/30
1875/1875 - 5s - loss: 15.2199 - 10cls_loss: 0.1058 - 4cls_loss: 0.0859 - 1rg_loss: 15.0281 - 10cls_accuracy: 0.9736 - 4cls_accuracy: 0.9727 - 1rg_mse: 15.0281
Epoch 30/30
1875/1875 - 5s - loss: 15.2178 - 10cls_loss: 0.1136 - 4cls_loss: 0.0854 - 1rg_loss: 15.0188 - 10cls_accuracy: 0.9722 - 4cls_accuracy: 0.9736 - 1rg_mse: 15.0188
<tensorflow.python.keras.callbacks.History at 0x7ff42c18e110>
这就是最后一层的每个输出如何通过他们关注的 loss
函数进行优化。仅供参考,有一件事需要提及,.compile
您可能需要的模型有一个基本参数:loss_weights
- to weight the loss contributions of different model outputs. See my other answer here 在此。
预测/推断
让我们看看一些输出。我们现在希望这个模型能够预测 3 件事:(1) 数字是什么,(2) 它是偶数还是奇数,以及 (3) 它的平方值。
import matplotlib.pyplot as plt
plt.imshow(xtrain[0])
如果我们想快速检查模型的输出层
encoder.output
[<KerasTensor: shape=(None, 10) dtype=float32 (created by layer '10cls')>,
<KerasTensor: shape=(None, 2) dtype=float32 (created by layer '4cls')>,
<KerasTensor: shape=(None, 1) dtype=float32 (created by layer '1rg')>]
将此 xtrain[0]
(我们知道 5)传递给模型进行预测。
# we expand for a batch dimension: (1, 28, 28, 1)
pred10, pred2, pred1 = encoder.predict(tf.expand_dims(xtrain[0], 0))
# regression: square of the input dgit image
pred1
array([[22.098022]], dtype=float32)
# even or odd, surely odd
pred2.argmax()
0
# which number, surely 5
pred10.argmax()
5
更新
根据您的评论,我们也可以扩展上述模型以采用 multi-input。我们需要改变一些事情。为了演示,我们将使用 mnist
数据集的 train
和 test
个样本作为 multi-input.
模型
(xtrain, ytrain), (xtest, _) = keras.datasets.mnist.load_data()
xtrain = xtrain[:10000] # both input sample should be same number
ytrain = ytrain[:10000] # both input sample should be same number
y_out_a = keras.utils.to_categorical(ytrain, num_classes=10)
y_out_b = keras.utils.to_categorical((ytrain % 2 == 0).astype(int), num_classes=2)
y_out_c = tf.square(tf.cast(ytrain, tf.float32))
print(xtrain.shape, xtest.shape)
print(y_out_a.shape, y_out_b.shape, y_out_c.shape)
# (10000, 28, 28) (10000, 28, 28)
# (10000, 10) (10000, 2) (10000,)
接下来,我们需要修改上面模型的一些部分,取multi-input。接下来,如果您现在绘图,您将看到新图表。
input0 = keras.Input(shape=(28, 28, 1), name="img2")
input1 = keras.Input(shape=(28, 28, 1), name="img1")
concate_input = layers.Concatenate()([input0, input1])
x = layers.Conv2D(16, 3, activation="relu")(concate_input)
...
...
...
# multi-input , multi-output
encoder = keras.Model( inputs = [input0, input1],
outputs = [out_a, out_b, out_c], name="encoder")
现在,我们可以按如下方式训练模型
# multi-input, multi-output
encoder.fit([xtrain, xtest], [y_out_a, y_out_b, y_out_c],
epochs=30, batch_size = 256, verbose=2)
Epoch 1/30
40/40 - 1s - loss: 66.9731 - 10cls_loss: 0.9619 - 2cls_loss: 0.4412 - 1rg_loss: 65.5699 - 10cls_accuracy: 0.7627 - 2cls_accuracy: 0.8815 - 1rg_mse: 65.5699
Epoch 2/30
40/40 - 0s - loss: 60.5408 - 10cls_loss: 0.8959 - 2cls_loss: 0.3850 - 1rg_loss: 59.2598 - 10cls_accuracy: 0.7794 - 2cls_accuracy: 0.8928 - 1rg_mse: 59.2598
Epoch 3/30
40/40 - 0s - loss: 57.3067 - 10cls_loss: 0.8586 - 2cls_loss: 0.3669 - 1rg_loss: 56.0813 - 10cls_accuracy: 0.7856 - 2cls_accuracy: 0.8951 - 1rg_mse: 56.0813
...
...
Epoch 28/30
40/40 - 0s - loss: 29.1198 - 10cls_loss: 0.4775 - 2cls_loss: 0.2573 - 1rg_loss: 28.3849 - 10cls_accuracy: 0.8616 - 2cls_accuracy: 0.9131 - 1rg_mse: 28.3849
Epoch 29/30
40/40 - 0s - loss: 27.5318 - 10cls_loss: 0.4696 - 2cls_loss: 0.2518 - 1rg_loss: 26.8104 - 10cls_accuracy: 0.8645 - 2cls_accuracy: 0.9142 - 1rg_mse: 26.8104
Epoch 30/30
40/40 - 0s - loss: 27.1581 - 10cls_loss: 0.4620 - 2cls_loss: 0.2446 - 1rg_loss: 26.4515 - 10cls_accuracy: 0.8664 - 2cls_accuracy: 0.9158 - 1rg_mse: 26.4515
现在,我们可以测试 multi-input 模型并从中得到 multi-out。
pred10, pred2, pred1 = encoder.predict(
[
tf.expand_dims(xtrain[0], 0),
tf.expand_dims(xtrain[0], 0)
]
)
# regression part
pred1
array([[25.13295]], dtype=float32)
# even or odd
pred2.argmax()
0
# what digit
pred10.argmax()
5
如图 1 中所述,我有 3 个模型,每个模型都适用于特定领域。
这 3 个模型分别使用不同的数据集进行训练。
并且推理是连续的:
由于 python 的多进程库,我尝试并行调用这 3 个模型,但它非常不稳定,不建议这样做。
这是我必须确保一次完成所有操作的想法:
由于这 3 个模型共享一个共同的预训练模型,我想制作一个具有多个输入和多个输出的模型。
如下图所示:
就像在推理过程中那样,我将调用一个模型,该模型将同时执行所有 3 个操作。
我看到使用 KERAS 的函数 API,这是可能的,但我不知道该怎么做。 数据集的输入具有相同的维度。这些是 (200,200,3) 的照片。
如果有人有一个共享共同结构的多输入多输出模型的例子,我没问题。
更新
这是我的代码示例,但它 returns 是一个错误,因为 layers. concatenate (...)
线传播的形状未被 EfficientNet
模型考虑。
age_inputs = layers.Input(shape=(IMG_SIZE, IMG_SIZE, 3), name="age_inputs")
gender_inputs = layers.Input(shape=(IMG_SIZE, IMG_SIZE, 3)
, name="gender_inputs")
emotion_inputs = layers.Input(shape=(IMG_SIZE, IMG_SIZE, 3),
name="emotion_inputs")
inputs = layers.concatenate([age_inputs, gender_inputs, emotion_inputs])
inputs = layers.Conv2D(3, (3, 3), activation="relu")(inputs)
model = EfficientNetB0(include_top=False,
input_tensor=inputs, weights="imagenet")
model.trainable = False
inputs = layers.GlobalAveragePooling2D(name="avg_pool")(model.output)
inputs = layers.BatchNormalization()(inputs)
top_dropout_rate = 0.2
inputs = layers.Dropout(top_dropout_rate, name="top_dropout")(inputs)
age_outputs = layers.Dense(1, activation="linear",
name="age_pred")(inputs)
gender_outputs = layers.Dense(GENDER_NUM_CLASSES,
activation="softmax",
name="gender_pred")(inputs)
emotion_outputs = layers.Dense(EMOTION_NUM_CLASSES, activation="softmax",
name="emotion_pred")(inputs)
model = keras.Model(inputs=[age_inputs, gender_inputs, emotion_inputs],
outputs =[age_outputs, gender_outputs, emotion_outputs],
name="EfficientNet")
optimizer = keras.optimizers.Adam(learning_rate=1e-2)
model.compile(loss={"age_pred" : "mse",
"gender_pred":"categorical_crossentropy",
"emotion_pred":"categorical_crossentropy"},
optimizer=optimizer, metrics=["accuracy"])
(age_train_images, age_train_labels), (age_test_images, age_test_labels) = reg_data_loader.load_data(...)
(gender_train_images, gender_train_labels), (gender_test_images, gender_test_labels) = cat_data_loader.load_data(...)
(emotion_train_images, emotion_train_labels), (emotion_test_images, emotion_test_labels) = cat_data_loader.load_data(...)
model.fit({'age_inputs':age_train_images, 'gender_inputs':gender_train_images, 'emotion_inputs':emotion_train_images},
{'age_pred':age_train_labels, 'gender_pred':gender_train_labels, 'emotion_pred':emotion_train_labels},
validation_split=0.2,
epochs=5,
batch_size=16)
我们可以在 tf. keras
中使用其出色的函数 API 轻松做到这一点。在这里,我们将带您了解如何使用函数 API.
classification
和 regression
)的 multi-out
根据你上一张图,你需要一个输入模型和三个不同类型的输出。为了演示,我们将使用 MNIST
这是一个手写数据集。它通常是 10 class class化问题数据集。从中,我们将创建一个额外的 2 class classifier(无论数字是 even
还是 odd
)以及1回归部分(预测一个数字的平方,即对于输入9的图像,应该给出近似的平方)。
数据集
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
(xtrain, ytrain), (_, _) = keras.datasets.mnist.load_data()
# 10 class classifier
y_out_a = keras.utils.to_categorical(ytrain, num_classes=10)
# 2 class classifier, even or odd
y_out_b = keras.utils.to_categorical((ytrain % 2 == 0).astype(int), num_classes=2)
# regression, predict square of an input digit image
y_out_c = tf.square(tf.cast(ytrain, tf.float32))
因此,我们的训练对将是 xtrain
和 [y_out_a, y_out_b, y_out_c]
,与您上一张图相同。
模型建筑
让我们使用 tf. keras
的函数 API 相应地构建模型。请参阅下面的模型定义。 MNIST
个样本是 28 x 28
个灰度图像。所以我们的输入就是这样设置的。我猜你的数据集可能是 RGB,所以相应地改变输入维度。
input = keras.Input(shape=(28, 28, 1), name="original_img")
x = layers.Conv2D(16, 3, activation="relu")(input)
x = layers.Conv2D(32, 3, activation="relu")(x)
x = layers.MaxPooling2D(3)(x)
x = layers.Conv2D(32, 3, activation="relu")(x)
x = layers.Conv2D(16, 3, activation="relu")(x)
x = layers.GlobalMaxPooling2D()(x)
out_a = keras.layers.Dense(10, activation='softmax', name='10cls')(x)
out_b = keras.layers.Dense(2, activation='softmax', name='2cls')(x)
out_c = keras.layers.Dense(1, activation='linear', name='1rg')(x)
encoder = keras.Model( inputs = input, outputs = [out_a, out_b, out_c], name="encoder")
# Let's plot
keras.utils.plot_model(
encoder
)
需要注意的一点是,在模型定义期间定义 out_a
、out_b
和 out_c
时,我们设置了非常重要的 name
变量。他们的名字分别设置为'10cls'
、'2cls'
和'1rg'
。您也可以从上图(最后 3 个尾巴)中看到这一点。
编译并运行
现在,我们可以明白为什么 name
变量很重要了。为了 运行 模型,我们需要先使用适当的 loss
函数、metrics
和 optimizer
对其进行编译。现在,如果你知道,对于 classification
和 regression
问题,optimizer
可以相同,但对于 loss
函数和 metrics
应该改变.在我们的模型中,它有一个 multi-type 输出模型(2 个 class 化和 1 个回归),我们需要为每种类型设置适当的 loss
和 metrics
。请看下面是如何完成的。
encoder.compile(
loss = {
"10cls": tf.keras.losses.CategoricalCrossentropy(),
"2cls": tf.keras.losses.CategoricalCrossentropy(),
"1rg": tf.keras.losses.MeanSquaredError()
},
metrics = {
"10cls": 'accuracy',
"2cls": 'accuracy',
"1rg": 'mse'
},
optimizer = tf.keras.optimizers.Adam(learning_rate=0.001)
)
看,我们上述模型的每个最后输出,在这里由它们的 name
变量表示。我们为它们设置了适当的编译。希望你能理解这部分。现在,是时候训练模型了。
encoder.fit(xtrain, [y_out_a, y_out_b, y_out_c], epochs=30, verbose=2)
Epoch 1/30
1875/1875 - 6s - loss: 117.7318 - 10cls_loss: 3.2642 - 4cls_loss: 0.9040 - 1rg_loss: 113.5637 - 10cls_accuracy: 0.6057 - 4cls_accuracy: 0.8671 - 1rg_mse: 113.5637
Epoch 2/30
1875/1875 - 5s - loss: 62.1696 - 10cls_loss: 0.5151 - 4cls_loss: 0.2437 - 1rg_loss: 61.4109 - 10cls_accuracy: 0.8845 - 4cls_accuracy: 0.9480 - 1rg_mse: 61.4109
Epoch 3/30
1875/1875 - 5s - loss: 50.3159 - 10cls_loss: 0.2804 - 4cls_loss: 0.1371 - 1rg_loss: 49.8985 - 10cls_accuracy: 0.9295 - 4cls_accuracy: 0.9641 - 1rg_mse: 49.8985
Epoch 28/30
1875/1875 - 5s - loss: 15.5841 - 10cls_loss: 0.1066 - 4cls_loss: 0.0891 - 1rg_loss: 15.3884 - 10cls_accuracy: 0.9726 - 4cls_accuracy: 0.9715 - 1rg_mse: 15.3884
Epoch 29/30
1875/1875 - 5s - loss: 15.2199 - 10cls_loss: 0.1058 - 4cls_loss: 0.0859 - 1rg_loss: 15.0281 - 10cls_accuracy: 0.9736 - 4cls_accuracy: 0.9727 - 1rg_mse: 15.0281
Epoch 30/30
1875/1875 - 5s - loss: 15.2178 - 10cls_loss: 0.1136 - 4cls_loss: 0.0854 - 1rg_loss: 15.0188 - 10cls_accuracy: 0.9722 - 4cls_accuracy: 0.9736 - 1rg_mse: 15.0188
<tensorflow.python.keras.callbacks.History at 0x7ff42c18e110>
这就是最后一层的每个输出如何通过他们关注的 loss
函数进行优化。仅供参考,有一件事需要提及,.compile
您可能需要的模型有一个基本参数:loss_weights
- to weight the loss contributions of different model outputs. See my other answer here 在此。
预测/推断
让我们看看一些输出。我们现在希望这个模型能够预测 3 件事:(1) 数字是什么,(2) 它是偶数还是奇数,以及 (3) 它的平方值。
import matplotlib.pyplot as plt
plt.imshow(xtrain[0])
如果我们想快速检查模型的输出层
encoder.output
[<KerasTensor: shape=(None, 10) dtype=float32 (created by layer '10cls')>,
<KerasTensor: shape=(None, 2) dtype=float32 (created by layer '4cls')>,
<KerasTensor: shape=(None, 1) dtype=float32 (created by layer '1rg')>]
将此 xtrain[0]
(我们知道 5)传递给模型进行预测。
# we expand for a batch dimension: (1, 28, 28, 1)
pred10, pred2, pred1 = encoder.predict(tf.expand_dims(xtrain[0], 0))
# regression: square of the input dgit image
pred1
array([[22.098022]], dtype=float32)
# even or odd, surely odd
pred2.argmax()
0
# which number, surely 5
pred10.argmax()
5
更新
根据您的评论,我们也可以扩展上述模型以采用 multi-input。我们需要改变一些事情。为了演示,我们将使用 mnist
数据集的 train
和 test
个样本作为 multi-input.
(xtrain, ytrain), (xtest, _) = keras.datasets.mnist.load_data()
xtrain = xtrain[:10000] # both input sample should be same number
ytrain = ytrain[:10000] # both input sample should be same number
y_out_a = keras.utils.to_categorical(ytrain, num_classes=10)
y_out_b = keras.utils.to_categorical((ytrain % 2 == 0).astype(int), num_classes=2)
y_out_c = tf.square(tf.cast(ytrain, tf.float32))
print(xtrain.shape, xtest.shape)
print(y_out_a.shape, y_out_b.shape, y_out_c.shape)
# (10000, 28, 28) (10000, 28, 28)
# (10000, 10) (10000, 2) (10000,)
接下来,我们需要修改上面模型的一些部分,取multi-input。接下来,如果您现在绘图,您将看到新图表。
input0 = keras.Input(shape=(28, 28, 1), name="img2")
input1 = keras.Input(shape=(28, 28, 1), name="img1")
concate_input = layers.Concatenate()([input0, input1])
x = layers.Conv2D(16, 3, activation="relu")(concate_input)
...
...
...
# multi-input , multi-output
encoder = keras.Model( inputs = [input0, input1],
outputs = [out_a, out_b, out_c], name="encoder")
现在,我们可以按如下方式训练模型
# multi-input, multi-output
encoder.fit([xtrain, xtest], [y_out_a, y_out_b, y_out_c],
epochs=30, batch_size = 256, verbose=2)
Epoch 1/30
40/40 - 1s - loss: 66.9731 - 10cls_loss: 0.9619 - 2cls_loss: 0.4412 - 1rg_loss: 65.5699 - 10cls_accuracy: 0.7627 - 2cls_accuracy: 0.8815 - 1rg_mse: 65.5699
Epoch 2/30
40/40 - 0s - loss: 60.5408 - 10cls_loss: 0.8959 - 2cls_loss: 0.3850 - 1rg_loss: 59.2598 - 10cls_accuracy: 0.7794 - 2cls_accuracy: 0.8928 - 1rg_mse: 59.2598
Epoch 3/30
40/40 - 0s - loss: 57.3067 - 10cls_loss: 0.8586 - 2cls_loss: 0.3669 - 1rg_loss: 56.0813 - 10cls_accuracy: 0.7856 - 2cls_accuracy: 0.8951 - 1rg_mse: 56.0813
...
...
Epoch 28/30
40/40 - 0s - loss: 29.1198 - 10cls_loss: 0.4775 - 2cls_loss: 0.2573 - 1rg_loss: 28.3849 - 10cls_accuracy: 0.8616 - 2cls_accuracy: 0.9131 - 1rg_mse: 28.3849
Epoch 29/30
40/40 - 0s - loss: 27.5318 - 10cls_loss: 0.4696 - 2cls_loss: 0.2518 - 1rg_loss: 26.8104 - 10cls_accuracy: 0.8645 - 2cls_accuracy: 0.9142 - 1rg_mse: 26.8104
Epoch 30/30
40/40 - 0s - loss: 27.1581 - 10cls_loss: 0.4620 - 2cls_loss: 0.2446 - 1rg_loss: 26.4515 - 10cls_accuracy: 0.8664 - 2cls_accuracy: 0.9158 - 1rg_mse: 26.4515
现在,我们可以测试 multi-input 模型并从中得到 multi-out。
pred10, pred2, pred1 = encoder.predict(
[
tf.expand_dims(xtrain[0], 0),
tf.expand_dims(xtrain[0], 0)
]
)
# regression part
pred1
array([[25.13295]], dtype=float32)
# even or odd
pred2.argmax()
0
# what digit
pred10.argmax()
5