MediumLoss Functions

Implement KL Divergence

Loss Functions

Medium

Problem

Compute the Kullback-Leibler divergence from distribution P to distribution Q:

D_{\mathrm{KL}}(P\,\|\,Q) = \sum_i P_i\log\left(\frac{P_i}{Q_i}\right)

Here, P_i and Q_i are corresponding probabilities. A term with P_i=0 contributes zero. Clamp positive-indexed Q_i values to at least eps before division, then return the sum as a Python float.

Theory

Kullback-Leibler (KL) divergence measures how one probability distribution differs from another. It answers the question: "If I use distribution Q to approximate distribution P, how much information do I lose?"

D_{KL}(P || Q) = \sum_x P(x) \log \frac{P(x)}{Q(x)}

Where:


Interpreting the Formula

Breaking down P(x) \log \frac{P(x)}{Q(x)}:

The ratio \frac{P(x)}{Q(x)}:

Weighting by P(x):


Key Properties of KL Divergence

Non-negativity:

D_{KL}(P || Q) \geq 0 With equality if and only if P = Q everywhere.

Asymmetry:

D_{KL}(P || Q) \neq D_{KL}(Q || P) KL divergence is NOT a distance metric. The order matters.

Unbounded:


Numerical Example

True distribution P: [0.7, 0.2, 0.1] Model distribution Q: [0.5, 0.3, 0.2]

D_{KL}(P || Q) = 0.7 \log \frac{0.7}{0.5} + 0.2 \log \frac{0.2}{0.3} + 0.1 \log \frac{0.1}{0.2}

Computing each term:

Total: 0.235 - 0.081 - 0.069 = 0.085

This is in nats (natural log). For bits, use \log_2: D_{KL} \approx 0.085 / \ln(2) \approx 0.123 bits


Forward vs. Reverse KL

Forward KL: D_{KL}(P || Q)

Reverse KL: D_{KL}(Q || P)

This distinction is crucial in variational inference and generative modeling.


Continuous Distributions

For continuous probability densities p and q:

D_{KL}(p || q) = \int p(x) \log \frac{p(x)}{q(x)} dx

Special case: two Gaussians

For p = \mathcal{N}(\mu_1, \sigma_1^2) and q = \mathcal{N}(\mu_2, \sigma_2^2):

D_{KL}(p || q) = \log \frac{\sigma_2}{\sigma_1} + \frac{\sigma_1^2 + (\mu_1 - \mu_2)^2}{2\sigma_2^2} - \frac{1}{2}

This closed-form expression is used extensively in variational autoencoders (VAEs).


KL Divergence and Cross-Entropy

KL divergence is related to cross-entropy and entropy:

D_{KL}(P || Q) = H(P, Q) - H(P)

Where:

Since H(P) is constant with respect to Q:


The Gradient

For a parametric model Q_\theta:

\frac{\partial D_{KL}}{\partial \theta} = -\sum_x P(x) \frac{1}{Q_\theta(x)} \frac{\partial Q_\theta(x)}{\partial \theta}

This shows:


Where KL Divergence Is Used

Variational Autoencoders (VAEs):

Knowledge distillation:

Reinforcement learning (policy optimization):

Information theory:

Language models:


Numerical Stability

Computing KL divergence directly can cause issues:

Solutions:

Examples

Example 1

Input
p = [0.4, 0.6], q = [0.5, 0.5], eps = 1e-12
Output
0.020136
Explanation
The distributions are similar but not identical, so the divergence is small and positive.

Example 2

Input
p = [0.3, 0.7], q = [0.3, 0.7], eps = 1e-12
Output
0.0

Example 3

Input
p = [0.9, 0.1], q = [0.5, 0.5], eps = 1e-12
Output
0.368064

Hints

  1. Create a mask with positive = p > 0.
  2. Use np.clip(q[positive], eps, None) before computing the log ratio.

Requirements

Constraints

Starter Code

import numpy as np

def kl_divergence(p: list, q: list, eps: float = 1e-12) -> float:
    """
    Returns the divergence as a float.
    """
    # Write code here
    pass

Test Cases

CaseMatches
Basicpublic
Identicalpublic
Concentratedpublic