← Back to blog

Variational Autoencoders for Anomaly Detection: A Gentle Introduction

Variational Autoencoders (VAEs) have become one of my favorite tools for unsupervised anomaly detection. In this post I want to give an intuitive walkthrough of how they work and why the math matters — with proper equations along the way.

The core idea

A VAE learns a probabilistic mapping between a data space \(\mathcal{X}\) and a latent space \(\mathcal{Z}\). Given an input \(x\), the encoder produces a distribution \(q_\phi(z \mid x)\) over latent codes, and the decoder maps a latent code \(z\) back to a distribution \(p_\theta(x \mid z)\) over reconstructions.

When trained on normal data only, the VAE learns to reconstruct healthy inputs well. At test time, anomalous regions produce large reconstruction errors — and that's our anomaly signal.

The ELBO

The objective is the Evidence Lower Bound (ELBO):

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

The first term encourages good reconstruction; the second keeps the learned posterior close to a prior \(p(z)\), typically \(\mathcal{N}(0, I)\).

The reparameterization trick

To backpropagate through the sampling step \(z \sim q_\phi(z \mid x)\), we use the reparameterization trick:

\[ z = \mu_\phi(x) + \sigma_\phi(x) \odot \epsilon, \quad \epsilon \sim \mathcal{N}(0, I) \]

This turns a stochastic node into a deterministic function of \(\phi\) and an auxiliary noise variable \(\epsilon\), making gradients well-defined.

Anomaly scoring

The simplest anomaly score is the per-pixel reconstruction error:

\[ \mathcal{A}(x) = \| x - \hat{x} \|^2, \quad \hat{x} = \mathbb{E}_{q_\phi(z|x)}[p_\theta(x|z)] \]

But in my work I showed that gradients of the loss w.r.t. the input are even more informative1:

\[ \mathcal{A}_{\text{grad}}(x_i) = \left\| \frac{\partial \mathcal{L}}{\partial x_i} \right\|^2 \]

This "score-based" localization highlights which pixels the model is struggling with — giving us spatially precise anomaly maps without pixel-level supervision.

A minimal PyTorch snippet

import torch
import torch.nn as nn

class VAE(nn.Module):
    def __init__(self, dim_in=784, dim_hidden=128, dim_latent=32):
        super().__init__()
        self.encoder = nn.Sequential(
            nn.Linear(dim_in, dim_hidden),
            nn.ReLU(),
        )
        self.fc_mu = nn.Linear(dim_hidden, dim_latent)
        self.fc_logvar = nn.Linear(dim_hidden, dim_latent)
        self.decoder = nn.Sequential(
            nn.Linear(dim_latent, dim_hidden),
            nn.ReLU(),
            nn.Linear(dim_hidden, dim_in),
            nn.Sigmoid(),
        )

    def reparameterize(self, mu, logvar):
        std = torch.exp(0.5 * logvar)
        eps = torch.randn_like(std)
        return mu + eps * std

    def forward(self, x):
        h = self.encoder(x)
        mu, logvar = self.fc_mu(h), self.fc_logvar(h)
        z = self.reparameterize(mu, logvar)
        return self.decoder(z), mu, logvar

The KL divergence for a Gaussian posterior has a nice closed form:

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

Context-encoding extension

In my Context-encoding VAE (ceVAE), we mask parts of the input and force the model to infer them from context. The anomaly score becomes:

\[ \mathcal{A}_{\text{ceVAE}}(x) = \sum_{k \in \text{patches}} \mathcal{L}_{\text{recon}}(x_k \mid x_{\setminus k}) \]

where \(x_{\setminus k}\) denotes the input with patch \(k\) removed. This forces the model to learn semantic relationships rather than copying.

Why this matters

The key insight across all of these approaches: reconstruction alone isn't enough. You need the model to learn meaningful structure so that anomalies violate semantic expectations, not just pixel statistics. That's what gradients and context-encoding give you.


::: tip Want to try this yourself? Check out batchgenerators for data augmentation pipelines that pair well with VAE training on medical images. :::


  1. Zimmerer, Petersen, Kohl, Maier-Hein. "A Case for the Score: Identifying Image Anomalies using Variational Autoencoder Gradients." NeurIPS Workshop 2018.