iwantcoding.com
🔥 Daily 👥 Rooms 🏆 Top Log in Sign up

Losses

A loss function turns predictions and labels into a single number that gradient descent minimizes. Pick the wrong one and the model can’t learn the task you think you’re training. TensorFlow ships dozens of standard losses plus a clean API for custom ones.

Built-in losses + masks + custom

EXAMPLE
import tensorflow as tf
import tensorflow.keras as keras

# 1) Regression losses
mse  = keras.losses.MeanSquaredError()
mae  = keras.losses.MeanAbsoluteError()
huber = keras.losses.Huber(delta=1.0)        # robust to outliers
msle = keras.losses.MeanSquaredLogarithmicError()

y_true = tf.constant([1.0, 2.0, 3.0])
y_pred = tf.constant([1.1, 1.9, 2.8])
print(mse(y_true, y_pred).numpy())            # 0.01

# 2) Binary classification
bce        = keras.losses.BinaryCrossentropy(from_logits=True)
bce_focal  = keras.losses.BinaryFocalCrossentropy(gamma=2.0, from_logits=True)

# from_logits=True means the model outputs raw logits (no sigmoid)
# Numerically more stable than sigmoid + BCE separately.

logits = tf.constant([[2.0], [-1.0], [0.5]])
labels = tf.constant([[1.0], [0.0], [1.0]])
print(bce(labels, logits).numpy())

# 3) Multi-class
cce  = keras.losses.CategoricalCrossentropy(from_logits=True)         # one-hot labels
scce = keras.losses.SparseCategoricalCrossentropy(from_logits=True)   # integer labels

# Most common: int labels + logits
logits = tf.constant([[2.0, 1.0, 0.1], [0.1, 2.0, 0.5]])
labels = tf.constant([0, 1])
print(scce(labels, logits).numpy())

# 4) Class imbalance — weighted loss
class_weights = {0: 1.0, 1: 5.0, 2: 2.0}
model.fit(X, y, class_weight=class_weights)

# Or sample weights per example
sample_w = tf.where(labels == 1, 5.0, 1.0)
model.fit(X, y, sample_weight=sample_w)

# 5) Sequence losses — mask the padding!
loss_fn = keras.losses.SparseCategoricalCrossentropy(
    from_logits=True, reduction='none',         # don't reduce yet
)

def masked_loss(y_true, y_pred):
    mask = tf.cast(y_true != 0, tf.float32)     # 0 = PAD token
    loss = loss_fn(y_true, y_pred) * mask
    return tf.reduce_sum(loss) / tf.reduce_sum(mask)

# 6) Custom loss — function form
def quantile_loss(q):
    def loss(y_true, y_pred):
        e = y_true - y_pred
        return tf.reduce_mean(tf.maximum(q * e, (q - 1) * e))
    return loss

model.compile(optimizer='adam', loss=quantile_loss(0.9))

# 7) Custom loss — class form (recommended; serializable)
@keras.utils.register_keras_serializable()
class DiceLoss(keras.losses.Loss):
    def __init__(self, smooth=1.0, name='dice_loss'):
        super().__init__(name=name)
        self.smooth = smooth

    def call(self, y_true, y_pred):
        y_true = tf.cast(y_true, tf.float32)
        y_pred = tf.sigmoid(y_pred)
        inter = tf.reduce_sum(y_true * y_pred, axis=[1, 2, 3])
        union = tf.reduce_sum(y_true + y_pred, axis=[1, 2, 3])
        dice  = (2 * inter + self.smooth) / (union + self.smooth)
        return 1 - tf.reduce_mean(dice)

    def get_config(self):
        return {'smooth': self.smooth, 'name': self.name}

# 8) Combine losses (multi-task or hybrid)
bce = keras.losses.BinaryCrossentropy(from_logits=True)

def bce_dice(y_true, y_pred):
    return bce(y_true, y_pred) + DiceLoss()(y_true, y_pred)

model.compile(optimizer='adam', loss=bce_dice)

# 9) Multiple outputs, multiple losses
model.compile(
    optimizer='adam',
    loss={'class': 'sparse_categorical_crossentropy', 'bbox': 'mse'},
    loss_weights={'class': 1.0, 'bbox': 0.5},
)

# 10) Common bugs
#   • from_logits=False with raw logits → wrong loss, model trains but slowly
#   • from_logits=True after a softmax layer → double softmax, gradients vanish
#   • CategoricalCrossentropy with int labels → shape error or NaN
#   • Forgetting to mask PAD tokens → loss dominated by padding
#   • MSE on classification → won't converge well
#   • Cross-entropy on imbalanced data without weights → predicts majority class

Why it matters

Almost every loss has a from_logits flag — set it correctly or training will silently underperform. Pair it with the right final-layer choice: from_logits=True means no sigmoid/softmax in your model output, False means there is one.

Tip: Tweak the snippet with Try it Yourself », then sit the quiz at the bottom of the page.

Example

Example
from tensorflow.keras import losses
losses.SparseCategoricalCrossentropy()
losses.BinaryCrossentropy()
losses.MeanSquaredError()
Try it Yourself »

Discussion

Loading…