As described in figure 1, I have 3 models which each apply to a particular domain.
The 3 models are trained separately with different datasets.
And inference is sequential :
I tried to parallelize the call of these 3 models thanks to the Multiprocess library of python but it is very unstable and it is not advised.
Here's the idea I got to make sure to do this all at once:
As the 3 models share a common pretrained-model, I want to make a single model that has multiple inputs and multiple outputs.
As the following drawing shows:
Like that during the inference, I will call a single model which will do all 3 operations at the same time.
I saw that with The Functional API of KERAS, it is possible but I have no idea how to do that. The inputs of the datasets have the same dimension. These are pictures of (200,200,3).
If anyone has an example of a Multi-Input Multi-output model that shares a common structure, I'm all ok.
UPADE
Here is the example of my code but it returns an error because of the layers. concatenate (...)
line which propagates a shape that is not taken into account by the EfficientNet
model.
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)
We can do that easily in
tf. keras
using its awesome Functional API. Here we will walk you through how to build multi-out with a different type (classification
andregression
) using Functional API.According to your last diagram, you need one input model and three outputs of different types. To demonstrate, we will use
MNIST
which is a handwritten dataset. It's normally a 10 class classification problem data set. From it, we will create an additionally 2 class classifier (whether a digit iseven
orodd
) and also a 1 regression part (which is to predict the square of a digit, i.e for image input of 9, it should give approximately it's square).Data Set
So, our training pairs will be
xtrain
and[y_out_a, y_out_b, y_out_c]
, the same as your last diagram.Model Building
Let's build the model accordingly using the Functional API of
tf. keras
. See the model definition below. TheMNIST
samples are a28 x 28
grayscale image. So our input is set in that way. I'm guessing your data set is probably RGB, so change the input dimension accordingly.One thing to note, while defining
out_a
,out_b
, andout_c
during model definition we set theirname
variable which is very important. Their names are set'10cls'
,'2cls'
, and'1rg'
respectively. You can also see this from the above diagram (last 3 tails).Compile and Run
Now, we can see why that
name
variable is important. In order to run the model, we need to compile it first with the properloss
function,metrics
, andoptimizer
. Now, if you know that, for theclassification
andregression
problem, theoptimizer
can be the same but for theloss
function andmetrics
should be changed. And in our model, which has a multi-type output model (2 classifications and 1 regression), we need to set properloss
andmetrics
for each of these types. Please, see below how it's done.See, each last output of our above model, which is here represented by their
name
variables. And we set proper compilation to them. Hope you understand this part. Now, time to train the model.That's how each of the outputs of the last layer optimizes by their concern
loss
function. FYI, one thing to mention, there is an essential parameter while.compile
the model which you might need:loss_weights
- to weight the loss contributions of different model outputs. See my other answer here on this.Prediction / Inference
Let's see some output. We now hope this model will predict 3 things: (1) is what the digit is, (2) is it even or odd, and (3) its square value.
If we like to quickly check the output layers of our model
Passing this
xtrain[0]
(which we know 5) to the model to do predictions.Update
Based on your comment, we can extend the above model to take multi-input too. We need to change things. To demonstrate, we will use
train
andtest
samples of themnist
data set to the model as a multi-input.Next, we need to modify some parts of the above model to take multi-input. And next if you now plot, you will see the new graph.
Now, we can train the model as follows
Now, we can test the multi-input model and get multi-out from it.