TheHummel
TheHummel

Reputation: 93

CNN with multiple output types

I am a newcomer to convolutional neural networks and have the following question: Is there a way to create a CNN with multiple outputs, including 10 for classification and two more for regression with Keras in Python?

Upvotes: 5

Views: 1973

Answers (1)

Nicolas Gervais
Nicolas Gervais

Reputation: 36604

Yes it's possible. You can do this by using the Functional API or the Subclassing API (see example below). I think this short example where I did both regression and classification on the Iris dataset could help you. It's not a CNN, but you'd just have to change the layers and the dataset. Most of the rest remains the same.

You can see that there are 2 targets, one for classification and the other one regression. There are also two different losses, of course.

import os
os.environ['TF_CPP_MIN_LOG_LEVEL'] = '3'
import tensorflow as tf
from tensorflow.keras.layers import Dense
from tensorflow.keras import Model
from sklearn.datasets import load_iris
from functools import partial
iris, target = load_iris(return_X_y=True)

X = iris[:, :3]
y = iris[:, 3]
z = target

onehot = partial(tf.one_hot, depth=3)

dataset = tf.data.Dataset.from_tensor_slices((X, y, z)).shuffle(150)

train_ds = dataset.take(120).\
    shuffle(10).batch(8).\
    map(lambda a, b, c: (a, b, onehot(c)))

test_ds = dataset.skip(120).take(30).\
    shuffle(10).batch(8).\
    map(lambda a, b, c: (a, b, onehot(c)))

next(iter(train_ds))

class MyModel(Model):
    def __init__(self):
        super(MyModel, self).__init__()
        self.d0 = Dense(64, activation='relu')
        self.d1 = Dense(128, activation='relu')
        self.d2 = Dense(1)
        self.d3 = Dense(3)

    def call(self, x, training=None, **kwargs):
        x = self.d0(x)
        x = self.d1(x)
        a = self.d2(x)
        b = self.d3(x)
        return a, b

model = MyModel()

loss_obj_reg = tf.keras.losses.MeanAbsoluteError()
loss_obj_cat = tf.keras.losses.CategoricalCrossentropy(from_logits=True)

optimizer = tf.keras.optimizers.Adam(learning_rate=1e-3)

loss_reg_train = tf.keras.metrics.Mean(name='regression loss')
loss_cat_train = tf.keras.metrics.Mean(name='categorical loss')

loss_reg_test = tf.keras.metrics.Mean(name='regression loss')
loss_cat_test = tf.keras.metrics.Mean(name='categorical loss')

train_acc = tf.keras.metrics.CategoricalAccuracy()
test_acc = tf.keras.metrics.CategoricalAccuracy()


@tf.function
def train_step(inputs, y_reg, y_cat):
    with tf.GradientTape() as tape:
        pred_reg, pred_cat = model(inputs, training=True)
        reg_loss = loss_obj_reg(y_reg, pred_reg)
        cat_loss = loss_obj_cat(y_cat, pred_cat)

    gradients = tape.gradient([reg_loss, cat_loss], model.trainable_variables)
    optimizer.apply_gradients(zip(gradients, model.trainable_variables))
    loss_reg_train(reg_loss)
    loss_cat_train(cat_loss)

    train_acc(y_cat, pred_cat)


@tf.function
def test_step(inputs, y_reg, y_cat):
    pred_reg, pred_cat = model(inputs, training=False)
    reg_loss = loss_obj_reg(y_reg, pred_reg)
    cat_loss = loss_obj_cat(y_cat, pred_cat)

    loss_reg_test(reg_loss)
    loss_cat_test(cat_loss)

    test_acc(y_cat, pred_cat)


for epoch in range(250):

    loss_reg_train.reset_states()
    loss_cat_train.reset_states()

    loss_reg_test.reset_states()
    loss_cat_test.reset_states()

    train_acc.reset_states()
    test_acc.reset_states()

    for xx, yy, zz in train_ds:
        train_step(xx, yy, zz)

    for xx, yy, zz in test_ds:
        test_step(xx, yy, zz)

    template = 'Epoch {:3} ' \
               'MAE {:5.3f} TMAE {:5.3f} ' \
               'Entr {:5.3f} TEntr {:5.3f} ' \
               'Acc {:7.2%} TAcc {:7.2%}'

    print(template.format(epoch+1,
                        loss_reg_train.result(),
                        loss_reg_test.result(),
                        loss_cat_train.result(),
                        loss_cat_test.result(),
                        train_acc.result(),
                        test_acc.result()))
Epoch 239 MAE 0.137 TMAE 0.127 Entr 0.097 TEntr 0.044 Acc  97.50% TAcc 100.00%
Epoch 240 MAE 0.128 TMAE 0.140 Entr 0.110 TEntr 0.075 Acc  95.83% TAcc  96.67%
Epoch 241 MAE 0.136 TMAE 0.095 Entr 0.088 TEntr 0.044 Acc  97.50% TAcc 100.00%
Epoch 242 MAE 0.133 TMAE 0.116 Entr 0.132 TEntr 0.141 Acc  93.33% TAcc  93.33%
Epoch 243 MAE 0.135 TMAE 0.156 Entr 0.130 TEntr 0.066 Acc  95.00% TAcc 100.00%
Epoch 244 MAE 0.139 TMAE 0.125 Entr 0.109 TEntr 0.107 Acc  94.17% TAcc  93.33%
Epoch 245 MAE 0.119 TMAE 0.082 Entr 0.105 TEntr 0.076 Acc  96.67% TAcc  96.67%

Upvotes: 4

Related Questions