tensorflowmachine-learningkerasdeep-learningmultilabel-classification

Multi-Output ResNet Model in Keras: Issue with Loss Dictionary and Training


I am working on a multi-output classification task using Keras and ResNet50. The dataset consists of facial images, and each image has four associated labels representing the intensity of boredom, engagement, confusion, and frustration, each ranging from 1 to 4.

  1. Frame: Absolute paths to the images.
  2. Boredom: Intensity of boredom (1 to 4).
  3. Engagement: Intensity of engagement (1 to 4).
  4. Confusion: Intensity of confusion (1 to 4).
  5. Frustration: Intensity of frustration (1 to 4).

I want to create a ResNet-based model with multiple outputs to predict these four labels simultaneously.

from tensorflow import keras
from tensorflow.keras import Input
from tensorflow.keras.applications import ResNet50
from tensorflow.keras import layers, models

base_model = ResNet50(input_shape=(128, 128, 3),
                      include_top=False,
                      weights='imagenet')

model = models.Sequential([
    base_model,
    layers.GlobalAveragePooling2D(),
    layers.Dense(64, activation='relu'),
    layers.Dense(4, activation='softmax', name='Boredom'),
    layers.Dense(4, activation='softmax', name='Engagement'),
    layers.Dense(4, activation='softmax', name='Confusion'),
    layers.Dense(4, activation='softmax', name='Frustration')
])


model.compile(optimizer='adam',
              loss={'Boredom': 'categorical_crossentropy',
                    'Engagement': 'categorical_crossentropy',
                    'Confusion': 'categorical_crossentropy',
                    'Frustration': 'categorical_crossentropy'},
              metrics=['accuracy'])
model.summary()
Error:
ValueError: Found unexpected losses or metrics that do not correspond to any Model output: dict_keys(['Boredom', 'Engagement', 'Confusion']). Valid mode output names: ['Frustration']. Received struct is: {'Boredom': 'categorical_crossentropy', 'Engagement': 'categorical_crossentropy', 'Confusion': 'categorical_crossentropy'}

I don't really know what is wrong, the names are matching


Solution

  • If you use Sequential you have in general only one output. Use the functional approach to have multiple output layers.

    from tensorflow import keras
    from tensorflow.keras import Input
    from tensorflow.keras.applications import ResNet50
    from tensorflow.keras import layers, models
    
    inputs = Input(shape=(128, 128, 3))
    base_model = ResNet50(input_shape=(128, 128, 3),
                          include_top=False,
                          weights='imagenet')
    
    x = base_model(inputs)
    x = layers.GlobalAveragePooling2D()(x)
    x = layers.Dense(64, activation='relu')(x)
    # Now generate 4 outputs
    boredom = layers.Dense(4, activation='softmax', name='Boredom')(x)
    engagement = layers.Dense(4, activation='softmax', name='Engagement')(x)
    confusion = layers.Dense(4, activation='softmax', name='Confusion')(x)
    frustration = layers.Dense(4, activation='softmax', name='Frustration')(x)
    
    # explicitly state your output layers when creating the model:
    model = models.Model(inputs, [boredom, engagement, confusion, frustration])
    
    
    model.compile(optimizer='adam',
                  loss={'Boredom': 'categorical_crossentropy',
                        'Engagement': 'categorical_crossentropy',
                        'Confusion': 'categorical_crossentropy',
                        'Frustration': 'categorical_crossentropy'},
                  metrics=['accuracy'])