MediumLoss Functions

Implement Dice Loss

Loss Functions

Medium

Problem

Compute Dice loss for two equally shaped prediction and target masks. First calculate the smoothed Dice coefficient:

\operatorname{Dice}(P,Y) = \frac{2\sum_i P_iY_i + \varepsilon}{\sum_i P_i + \sum_i Y_i + \varepsilon}

Then calculate the loss:

L_{\mathrm{Dice}} = 1 - \operatorname{Dice}(P,Y)

Here, P_i and Y_i are corresponding mask values and \varepsilon is eps. Sum across every dimension and return the loss as a Python float.

Theory

In semantic segmentation, the goal is to classify each pixel in an image:

The challenge: class imbalance is extreme.

If you use pixel-wise cross-entropy:


What Dice Loss Measures

Dice loss is based on the Dice coefficient (also called the Sorensen-Dice coefficient or F1 score):

\text{Dice} = \frac{2 |A \cap B|}{|A| + |B|}

Where:

The Dice coefficient ranges from 0 (no overlap) to 1 (perfect overlap).


Converting to a Differentiable Loss

The set-based formula is not differentiable. For training, we use soft predictions:

\text{Dice Loss} = 1 - \frac{2 \sum_i p_i g_i + \epsilon}{\sum_i p_i + \sum_i g_i + \epsilon}

Where:

This is "soft" because:


Numerical Example

Consider a tiny 4-pixel image:

Pixel Ground Truth g Prediction p p \cdot g
1 1 0.9 0.9
2 1 0.7 0.7
3 0 0.2 0.0
4 0 0.1 0.0

Calculations:

Dice coefficient:

\text{Dice} = \frac{2 \times 1.6}{1.9 + 2} = \frac{3.2}{3.9} \approx 0.82

Dice loss:

\text{Loss} = 1 - 0.82 = 0.18


Why Dice Loss Handles Imbalance

Consider extreme imbalance: 1000 pixels, only 10 are foreground.

With cross-entropy:

With Dice loss:

Dice loss asks: "What fraction of the foreground did you capture?" rather than "What fraction of pixels did you classify correctly?"


The Gradient

For a predicted probability p_i on a foreground pixel (g_i = 1):

\frac{\partial \text{Dice}}{\partial p_i} = \frac{2(\sum g)(\sum p + \sum g) - 2(\sum pg)(1)}{(\sum p + \sum g)^2}

Key insight:


Dice vs. IoU (Jaccard)

IoU (Intersection over Union) is a related metric:

\text{IoU} = \frac{|A \cap B|}{|A \cup B|}

Relationship to Dice:

\text{Dice} = \frac{2 \cdot \text{IoU}}{1 + \text{IoU}}

They are monotonically related: maximizing one maximizes the other.

Differences:


Generalized Dice Loss

For multi-class segmentation, Generalized Dice Loss (GDL) handles multiple classes and per-class weighting:

\text{GDL} = 1 - 2 \frac{\sum_{c} w_c \sum_i p_{ic} g_{ic}}{\sum_{c} w_c (\sum_i p_{ic} + \sum_i g_{ic})}

Where:

This balances the contribution of rare classes against common ones.


Combining Dice with Cross-Entropy

A common practice is to use both losses together:

L = \alpha \cdot \text{Dice Loss} + (1 - \alpha) \cdot \text{Cross-Entropy}

Why combine them?


Where Dice Loss Is Used

Examples

Example 1

Input
p = [0.9, 0.7, 0.1, 0.0], y = [1, 1, 0, 0], eps = 1e-8
Output
0.135135
Explanation
The soft intersection is 1.6, producing a Dice coefficient of approximately 0.864865.

Example 2

Input
p = [1.0, 1.0, 0.0, 0.0], y = [1, 1, 0, 0], eps = 1e-8
Output
0.0

Example 3

Input
p = [1.0, 1.0], y = [0, 0], eps = 1e-8
Output
1.0

Hints

  1. Use np.sum(p * y) for the soft intersection.
  2. Compute the coefficient before returning 1.0 - coefficient.

Requirements

Constraints

Starter Code

import numpy as np

def dice_loss(p: list, y: list, eps: float = 1e-8) -> float:
    """
    Returns the loss as a float.
    """
    # Write code here
    pass

Test Cases

CaseMatches
Basic mixed predictionspublic
Perfect predictionpublic
No overlap 2-elementExample 3public