Do keras loss have to output one scalar per batch or one scalar for the whole batch ?
ML System Design practice on Codemia
Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.
Introduction
In Keras, a custom loss does not usually need to collapse the entire batch into one number by hand. The normal contract is that the loss computes a value for each sample, and Keras then applies its configured reduction to turn those values into the scalar objective used for backpropagation.
The Short Answer
When you pass a loss to model.compile, Keras is generally happy with a tensor of per-sample losses. For a batch of size N, that often means a result shaped like (N,) after reducing any feature dimension inside each sample.
Keras then reduces those per-sample losses according to the selected reduction behavior. In the common case, that becomes a single scalar such as the mean batch loss.
So the practical rule is:
- inside the loss, reduce over the prediction dimensions that belong to one sample
- let Keras reduce across the batch unless you have a specific reason not to
What Built-In Losses Do
A built-in loss such as mean squared error illustrates the pattern:
Output:
The loss above returns one value per row in the batch. Keras can then average those values during training.
If you write the loss as a Loss class, Keras still expects the call method to produce unreduced or partially reduced loss values that it can aggregate according to the configured reduction.
A Correct Custom Loss
Here is a custom loss function that returns one value per sample:
axis=-1 removes the feature dimension for each sample. The batch dimension remains, which is what Keras wants in most cases.
When a Scalar Is Also Acceptable
You can return a scalar for the whole batch if you intentionally reduce everything yourself. TensorFlow can still differentiate that scalar. However, doing so means you take control over batch reduction semantics.
This works, but it is usually less flexible:
- sample weighting becomes harder to reason about
- distributed training behavior is easier to get wrong
- you may accidentally double-reduce if you mix APIs carelessly
That is why per-sample loss values are the safer default.
Why Shape Matters
Keras distinguishes between sample dimensions and feature dimensions. Suppose your model outputs shape (batch_size, 10) for ten regression targets. The loss should usually reduce across the 10 outputs for each sample, not across the entire batch.
If you forget axis=-1, the loss tensor may keep extra dimensions such as (batch_size, 10). Sometimes Keras can still reduce it, but the result may not match your intention. Always think explicitly about which axes represent one example and which axis represents the batch.
Using a Loss Class
If you need configuration, subclass keras.losses.Loss:
This preserves the standard Keras pattern: compute a per-sample loss, then let the framework reduce across the batch.
Mental Model for Backpropagation
Backpropagation still needs one scalar objective in the end. The question is not whether a scalar is required eventually; it is where that scalar should be formed.
In Keras, the clean answer is usually:
- your loss computes per-sample values
- Keras applies sample weights and reduction
- the training loop obtains the final scalar used for gradients
That division of responsibility keeps custom losses composable with the rest of the framework.
Common Pitfalls
- Returning a tensor with extra feature dimensions because you forgot to reduce across
axis=-1. That often produces unexpected training behavior. - Reducing over the whole batch inside the loss without meaning to. This can interfere with weighting and distributed execution semantics.
- Assuming the loss must always return exactly one scalar from the function. In standard Keras usage, per-sample loss values are normal.
- Writing a mathematically correct loss that uses Python branching instead of TensorFlow ops. That can break graph execution and differentiation.
- Ignoring sample weights and masking when designing the loss. Letting Keras handle batch reduction makes those features easier to preserve.
Summary
- Keras custom losses typically return one value per sample, not one manually computed scalar for the whole batch.
- Keras then reduces those values into the scalar objective needed for gradient updates.
- Returning a single batch scalar can work, but it is usually less flexible.
- The most important design choice is reducing over feature axes while keeping the batch axis intact.
- If you match Keras' expected shapes, custom losses stay compatible with weighting, masking, and distribution strategies.
Related reading
- Does applying a Dropout Layer after the Embedding Layer have the same effect as applying the dropout through the LSTM dropout parameter?
- Does batch normalisation work with a small batch size?
- Does bias in the convolutional layer really make a difference to the test accuracy?
- Does config.gpu_options.allow_growthTrue reduce performance in the long run?
- Do not use tf.reset_default_graph to clear nested graphs
- Does dropout layer go before or after dense layer in TensorFlow?
- Do we need to use beam search in training process?
- Do you apply min max scaling separately on training and test data?
.png&w=3840&q=75)
Tackling System Design Interview Problems
A short course that equips you with the skills to approach system design interviews methodically.
Start the free courseTrack what you have practised
A free account saves your progress, solutions and study plan across every problem on Codemia.
ML System Design practice on Codemia
Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.