EasyVAE

KL Divergence Loss

Auto-Encoding Variational Bayes (VAE)

Easy

Problem

Compute the Kullback-Leibler divergence between a diagonal Gaussian posterior and the standard-normal prior used by a variational autoencoder.

D_{\mathrm{KL}}\bigl(q(z\mid x)\,\|\,\mathcal{N}(0,I)\bigr) = -\frac{1}{2B}\sum_{i=1}^{B}\sum_{j=1}^{L} \left(1 + \log \sigma_{ij}^2 - \mu_{ij}^2 - \exp(\log \sigma_{ij}^2)\right)

Here, B is batch size, L is latent width, \mu_{ij} is a posterior mean, and \log \sigma_{ij}^2 is its log-variance. Sum over latent coordinates, then average over the batch. Return the divergence as a Python float.

Theory

KL divergence is the regularization term in the Variational Autoencoder (VAE) loss that measures the distance between the learned approximate posterior q_\phi(z|x) and the chosen prior p(z) = \mathcal{N}(0, I). In Kingma and Welling's "Auto-Encoding Variational Bayes" (2014), this term encourages the encoder to produce latent distributions that remain close to a standard normal, enabling smooth interpolation and meaningful generation from the latent space.


What It Is

KL divergence -- short for Kullback-Leibler divergence -- quantifies how one probability distribution differs from a reference distribution. In information theory, D_{\text{KL}}(q \| p) measures the expected number of extra bits needed to encode samples from q using a code optimized for p. It is always non-negative and equals zero only when q and p are identical distributions.

In the VAE framework, the encoder network produces parameters \mu and \log \sigma^2 (commonly written as \text{log\_var}) for each input x, defining a Gaussian approximate posterior q_\phi(z|x) = \mathcal{N}(\mu, \text{diag}(\sigma^2)). The KL divergence term measures how far this learned posterior deviates from the unit Gaussian prior p(z) = \mathcal{N}(0, I). Without this regularization, the encoder could place each data point at an arbitrary, isolated location in latent space with near-zero variance, making the latent space useless for generation.

The critical property for VAEs is that when both distributions are Gaussian, the KL divergence has a closed-form solution -- no Monte Carlo sampling is needed. This makes the KL component computationally cheap and gradient-stable compared to the reconstruction term.


Key Equations

General KL divergence. For two continuous distributions q and p:

D_{\text{KL}}(q \| p) = \int q(z) \log \frac{q(z)}{p(z)} \, dz

This integral is intractable for most distribution pairs. However, when both q and p are Gaussian, every term has an analytic solution.

Derivation for diagonal Gaussian vs standard normal. Let q(z) = \mathcal{N}(\mu, \text{diag}(\sigma^2)) and p(z) = \mathcal{N}(0, I). Each latent dimension j is independent, so the KL decomposes as a sum over dimensions. For a single dimension:

\log q(z_j) = -\frac{1}{2}\log(2\pi) - \frac{1}{2}\log \sigma_j^2 - \frac{(z_j - \mu_j)^2}{2\sigma_j^2}

\log p(z_j) = -\frac{1}{2}\log(2\pi) - \frac{z_j^2}{2}

Taking the expectation under q and using \mathbb{E}_q[(z_j - \mu_j)^2] = \sigma_j^2 and \mathbb{E}_q[z_j^2] = \mu_j^2 + \sigma_j^2, the \log(2\pi) terms cancel, yielding the per-dimension KL:

D_{\text{KL}}^{(j)} = -\frac{1}{2}\left(1 + \log \sigma_j^2 - \mu_j^2 - \sigma_j^2 \right)

Summing over all J latent dimensions and substituting \log \sigma_j^2 = \text{log\_var}_j and \sigma_j^2 = \exp(\text{log\_var}_j):

D_{\text{KL}} = -\frac{1}{2} \sum_{j=1}^{J} \left(1 + \text{log\_var}_j - \mu_j^2 - \exp(\text{log\_var}_j) \right)

This is Equation 10 from Appendix B of Kingma and Welling (2014). For a batch of N samples, the final loss averages over the batch: \frac{1}{N}\sum_{i=1}^{N} D_{\text{KL}}^{(i)}.


Why KL Divergence

Regularizes the latent space. Without the KL term, the VAE reduces to a deterministic autoencoder. The encoder could map each input to a unique point with near-zero variance. The decoder would memorize these isolated points, and the latent space would have no structure -- points between encoded locations would decode to garbage. The KL term penalizes deviations from the prior, forcing the encoder to keep its posteriors overlapping.

Prevents the encoder from ignoring the prior. The prior p(z) = \mathcal{N}(0, I) defines the distribution from which latent codes are sampled during generation. If the encoder learns posteriors far from this prior, sampling from \mathcal{N}(0, I) at test time produces codes the decoder has never seen. The KL term ensures the encoder's output distribution stays close to the generation distribution.

Ensures smooth latent space for generation. When KL regularization is effective, nearby points in latent space decode to similar outputs. This continuity makes VAEs useful for interpolation: linearly moving between two latent codes produces semantically smooth transitions. The KL term creates this smoothness by preventing the encoder from carving out isolated regions for different inputs.

Information-theoretic grounding. The KL term emerges naturally from the Evidence Lower Bound (ELBO) derivation, not as an ad hoc regularizer. Maximizing the ELBO with respect to the encoder parameters simultaneously minimizes the KL divergence from the true posterior, making the variational approximation tighter.


The Four Terms

The closed-form KL for a single latent dimension contains four terms inside the summation: 1, \text{log\_var}_j, -\mu_j^2, and -\exp(\text{log\_var}_j). Each has a distinct role.

The constant 1. This baseline offset ensures the KL equals zero when the posterior matches the prior (\mu_j = 0, \text{log\_var}_j = 0). It balances the other three terms at equilibrium.

The \text{log\_var}_j term. When \text{log\_var}_j = 0, the variance equals 1 (matching the prior). When \text{log\_var}_j < 0, the posterior is too narrow, contributing a negative value that increases the overall KL. When \text{log\_var}_j > 0, the posterior is too wide, but the -\exp(\text{log\_var}_j) term grows even faster, still increasing the KL.

The -\mu_j^2 term. This penalizes the mean drifting from zero. The penalty is quadratic: \mu_j = 2 costs four times as much as \mu_j = 1. This prevents the encoder from spreading representations across distant regions of latent space.

The -\exp(\text{log\_var}_j) term. Since \exp(\text{log\_var}_j) = \sigma_j^2, this is the negative variance. Combined with the \text{log\_var}_j term, the pair \log \sigma_j^2 - \sigma_j^2 is maximized at \sigma_j^2 = 1, matching the prior's unit variance. For large variances, \exp(\text{log\_var}_j) grows exponentially. For small variances, \text{log\_var}_j \to -\infty dominates instead.

Equilibrium analysis. The expression f(\mu, v) = 1 + v - \mu^2 - e^v where v = \text{log\_var} has its maximum of 0 at \mu = 0, v = 0. The partial derivatives \partial f / \partial \mu = -2\mu = 0 and \partial f / \partial v = 1 - e^v = 0 confirm this unique maximum. Any deviation makes f negative, producing positive KL after the -\frac{1}{2} factor.


Why Closed-Form

The general KL integral is intractable for most distribution families. Estimating it via Monte Carlo requires drawing samples from q and computing the log-ratio, introducing variance in gradient estimates. Kingma and Welling (2014) highlight in Appendix B that the Gaussian-vs-Gaussian case admits an analytic solution, making the KL component of the ELBO variance-free.

The closed-form relies on three Gaussian properties. First, the entropy of \mathcal{N}(\mu, \sigma^2) is \frac{1}{2}\log(2\pi e \sigma^2) -- a function of variance alone. Second, \log p(z) is quadratic in z under a Gaussian prior, and expectations of quadratics under a Gaussian are computed from the mean and variance. Third, diagonal covariance makes the multivariate KL decompose as a sum of scalar KLs.

This is why the encoder parameterizes \text{log\_var} rather than \sigma or \sigma^2 directly. The network outputs an unconstrained real number, exponentiated to get \sigma_j^2 = \exp(\text{log\_var}_j). This ensures positivity without activation function constraints and plugs directly into the closed-form formula. If the posterior were non-Gaussian (e.g., a normalizing flow), the KL would require Monte Carlo estimation.


Paper Context

Kingma and Welling (2014) frame the VAE objective as maximizing the Evidence Lower Bound (ELBO) on \log p_\theta(x):

\mathcal{L}(\theta, \phi; x) = \mathbb{E}_{q_\phi(z|x)}[\log p_\theta(x|z)] - D_{\text{KL}}(q_\phi(z|x) \| p(z))

The first term is the reconstruction loss -- the expected log-likelihood of the data under the decoder. The second is the KL divergence regularizing the encoder. Together, minimizing -\mathcal{L} balances reconstruction quality against latent space regularity.

The paper states: "The KL divergence term acts as a regularizer, encouraging the approximate posterior to be close to the prior." The KL term ensures that sampling from p(z) = \mathcal{N}(0, I) and decoding produces plausible outputs, because the encoder is trained to place its posteriors near this prior.

Maximizing \mathcal{L} with respect to \phi tightens the variational bound (making q_\phi closer to the true posterior p(z|x)), while maximizing with respect to \theta increases the marginal likelihood. The KL term mediates: it prevents the encoder from placing mass in regions the prior does not support.

Beta-VAE weighting. Higgins et al. (2017) scale the KL by a factor \beta, yielding \mathcal{L}_\beta = \mathbb{E}[\log p_\theta(x|z)] - \beta \cdot D_{\text{KL}}. Setting \beta > 1 increases pressure toward the prior, encouraging disentangled representations. Setting \beta < 1 relaxes the constraint, allowing more information through the bottleneck at the cost of less regular structure. The original VAE corresponds to \beta = 1.


Numerical Example

Consider a batch of 2 samples with latent dimension 3. The encoder outputs:

Sample 1: \mu = [0.5, -0.3, 0.8], \text{log\_var} = [-0.2, 0.1, -0.5]

Sample 2: \mu = [0.0, 0.0, 0.0], \text{log\_var} = [0.0, 0.0, 0.0]

Computing KL for Sample 1, dimension by dimension:

Dimension j = 1: \mu_1 = 0.5, \text{log\_var}_1 = -0.2

1 + (-0.2) - (0.5)^2 - \exp(-0.2) = 1 - 0.2 - 0.25 - 0.8187 = -0.2687

Dimension j = 2: \mu_2 = -0.3, \text{log\_var}_2 = 0.1

1 + 0.1 - (-0.3)^2 - \exp(0.1) = 1 + 0.1 - 0.09 - 1.1052 = -0.0952

Dimension j = 3: \mu_3 = 0.8, \text{log\_var}_3 = -0.5

1 + (-0.5) - (0.8)^2 - \exp(-0.5) = 1 - 0.5 - 0.64 - 0.6065 = -0.7465

Sum over dimensions: -0.2687 + (-0.0952) + (-0.7465) = -1.1104

KL for Sample 1: -\frac{1}{2} \times (-1.1104) = 0.5552

Computing KL for Sample 2 (posterior matches prior exactly):

1 + 0 - 0 - \exp(0) = 1 - 1 = 0 \quad \text{for all } j

KL for Sample 2: -\frac{1}{2} \times 0 = 0.0 -- confirming that KL is zero when the posterior equals the prior.

Batch average: \frac{1}{2}(0.5552 + 0.0) = 0.2776

Dimension 3 of Sample 1 contributes the most (0.3733 of the 0.5552 total) because it has the largest mean displacement (\mu = 0.8) combined with a narrow variance (\sigma^2 = e^{-0.5} \approx 0.607).


The KL-Reconstruction Tradeoff

The VAE loss sums two competing objectives: reconstruction accuracy and KL regularization. These pull the model in opposite directions, and the balance determines the quality of both reconstruction and generation.

Too much KL pressure (posterior collapse). When the KL term dominates, the encoder collapses all posteriors to \mathcal{N}(0, I) regardless of input. The KL reaches zero, but the latent code carries no information about x. The decoder ignores z and produces the average output for every input. This posterior collapse is especially prevalent when the decoder is powerful (e.g., autoregressive) and can reconstruct reasonably without relying on z.

Too little KL pressure (unstructured latent space). When reconstruction dominates, the encoder maps each input to a tight, isolated Gaussian far from the origin. Reconstructions are excellent, but sampling from \mathcal{N}(0, I) produces codes in regions the decoder never trained on, generating nonsensical outputs. Interpolation passes through empty regions, producing artifacts.

Practical balancing strategies. KL annealing (Bowman et al., 2016) starts with \beta = 0 and linearly increases to 1, letting the model learn useful representations before regularization kicks in. Free bits (Kingma et al., 2016) sets a minimum KL per latent dimension. Cyclical annealing (Fu et al., 2019) repeatedly ramps \beta up and down, giving the model multiple chances to find equilibrium.


Pitfalls


Examples

Example 1

Input
mu = [[0,0]], log_var = [[0,0]]
Output
0
Explanation
A zero mean and zero log-variance describe the standard normal, so the divergence is zero.

Example 2

Input
mu = [[1,2]], log_var = [[0,0]]
Output
2.5

Example 3

Input
mu = [[0.5,-0.25],[1,0]], log_var = [[-1,0.5],[0.2,-0.4]]
Output
0.480206

Hints

  1. Recover variance with np.exp(log_var).
  2. Reduce the latent axis before averaging the batch.

Requirements

Constraints

Starter Code

import numpy as np

def kl_divergence(mu: np.ndarray, log_var: np.ndarray) -> float:
    """
    Returns the batch-mean KL divergence as a Python float.
    """
    pass

Test Cases

CaseMatches
Standard normal posteriorpublic
Shifted meanpublic
Two posterior samplespublic