InterviewsVector

How to handle class weight for multiple outputs in keras?

Quick answer

Keras does not accept class_weight for models with multiple outputs — it raises 'class_weight is only supported for Models with a single output'. The workaround is sample_weight: turn each output's class weights into a per-sample weight array, then pass them to model.fit as a dict keyed by output name, e.g. sample_weight={'out1': sw1, 'out2': sw2}. Alternatively, bake the class weighting into a separate custom loss per output using tf.gather.

Short answer: Keras rejects class_weight on a multi-output model — it raises "class_weight is only supported for Models with a single output." Convert each output's class weights into a per-sample weight array, then pass them to fit as a dict keyed by output name: sample_weight={"out1": sw1, "out2": sw2}. Or bake the weighting into a separate custom loss per output.

class_weight maps one {class: weight} dict to one set of labels. With several outputs, Keras can't tell which output the dict applies to, so it errors. The two reliable workarounds are below.

Turn each output's class weights into an array with one weight per training sample, then hand fit a dict keyed by the output layer names. This is the direct equivalent of class_weight, and it's the approach the Keras docs point you to.

import numpy as np
 
# class weights per output (from the class imbalance of each label set)
cw_out1 = {0: 1.0, 1: 5.0}            # binary, positive class is rare
cw_out2 = {0: 1.0, 1: 2.0, 2: 3.0}    # 3-class
 
# map each label to its weight -> one weight per sample, per output
sw_out1 = np.array([cw_out1[y] for y in y1_train])
sw_out2 = np.array([cw_out2[y] for y in y2_train])
 
model.compile(
    optimizer="adam",
    loss={"out1": "sparse_categorical_crossentropy",
          "out2": "sparse_categorical_crossentropy"},
)
 
model.fit(
    x_train,
    {"out1": y1_train, "out2": y2_train},
    sample_weight={"out1": sw_out1, "out2": sw_out2},
    epochs=10,
    batch_size=32,
)

The keys ("out1", "out2") must match the name= of each output layer. Note the per-output weight arrays are built independently — the earlier mistake is weighting only one output and passing a single array.

Option 2 — a weighted loss per output

If you'd rather keep the weighting inside the loss, give each output its own loss. Keras calls a per-output loss with that output's y_true/y_pred (not a list of all of them), so tf.gather the right weight for each label:

import tensorflow as tf
 
def make_weighted_loss(class_weights):
    cw = tf.constant(class_weights, dtype=tf.float32)   # shape [num_classes]
 
    def loss(y_true, y_pred):
        per_example = tf.keras.losses.sparse_categorical_crossentropy(y_true, y_pred)
        idx = tf.cast(tf.reshape(y_true, [-1]), tf.int32)
        weights = tf.gather(cw, idx)                     # weight per sample
        return tf.reduce_mean(per_example * weights)
 
    return loss
 
model.compile(
    optimizer="adam",
    loss={"out1": make_weighted_loss([1.0, 5.0]),
          "out2": make_weighted_loss([1.0, 2.0, 3.0])},
)
model.fit(x_train, {"out1": y1_train, "out2": y2_train}, epochs=10, batch_size=32)

Which to use

  • sample_weight dict — simplest, no custom code, mirrors class_weight semantics exactly. Prefer this.
  • Custom per-output loss — when you need more than class weighting (e.g. focal loss, or combining the weight with a per-sample importance).

Balance the outputs against each other with loss_weights={"out1": 1.0, "out2": 0.5} in compile — that's a separate knob from the class weighting above.

Sources

Key takeaways

  • Keras rejects class_weight for multi-output models and raises an error.
  • The workaround is sample_weight: turn your class weights into a per-sample weight array for each output.
  • Pass the sample weights as a dict keyed by output name to model.fit(sample_weight=...).
  • Alternatively, bake the class weighting directly into a custom loss for each output.

Frequently asked questions

Why does class_weight fail with multiple outputs in Keras?

Keras only supports class_weight for single-output models; with multiple outputs it cannot map one class-weight dict to several label sets, so it errors.

How do I weight classes per output?

Convert each output's class weights into a per-sample weight array and pass them to model.fit as a sample_weight dict keyed by the output layer names.

Is a custom loss an option?

Yes. You can multiply each output's loss by its class weights inside a custom loss function, which gives full control over how each output is weighted.

By Mohammad Wasi

Software Engineering Leader & Technical Author · Updated September 9, 2026


Related Posts