Derive the Evidence Lower Bound from Jensen's inequality, calculate the closed-form Gaussian KL divergence, master the reparameterization trick, and inspect zero-dependency implementations in Python and Rust.
04. Generative AI, Large Language Models & Diffusion9 min read
Standard deterministic autoencoders compress high-dimensional inputs x into discrete latent codes z=f(x). However, because deterministic autoencoders do not enforce continuity across latent space, the resulting manifold contains arbitrary unmapped regions (holes) where decoding novel vectors generates degraded artifacts.
Variational Autoencoders (VAEs) (Kingma and Welling, 2013) reformulate representation learning into probabilistic Bayesian inference, mapping each sample to a continuous probability distribution and optimizing the Evidence Lower Bound (ELBO).
ReparameterizationBayesian Deep Learning
z = mu + sigma * epsilon
Isolates stochasticity into parameter-free noise epsilon ~ N(0, I) to enable end-to-end backpropagation.
1. Mathematical Derivation of the Evidence Lower Bound (ELBO)#
Let x∈RD be observed data and z∈Rd be unobserved latent factors with prior distribution p(z)=N(0,I).
The marginal likelihood of observation x integrates over all possible latent states:
p(x)=∫p(x,z)dz=∫pθ(x∣z)p(z)dz
Architecture Diagram
Rendering diagram...
Because true posterior p(z∣x)=p(x)p(x∣z)p(z) is computationally intractable to evaluate in high dimensions, we introduce a parameterized variational approximation qϕ(z∣x)≈p(z∣x).
1
Step 1: Formulate the Log-Marginal Likelihood
Multiply and divide the integrand by qϕ(z∣x):
lnp(x)=ln∫p(x,z)dz=ln∫qϕ(z∣x)qϕ(z∣x)p(x,z)dz
Express the integral as an expectation with respect to variational distribution qϕ(z∣x):
lnp(x)=lnEqϕ(z∣x)[qϕ(z∣x)p(x,z)]
2
Step 2: Apply Jensen's Inequality
Because the natural logarithm f(u)=ln(u) is a strictly concave function, Jensen's Inequality states that lnE[Y]≥E[lnY]. Applying this yields the lower bound:
lnp(x)≥Eqϕ(z∣x)[ln(qϕ(z∣x)p(x,z))]≡ELBO(ϕ,θ)
3
Step 3: Exact Decomposition via KL Divergence
We can confirm the exact tightness gap by expanding the joint distribution p(x,z)=p(z∣x)p(x):
Because the Kullback-Leibler divergence is non-negative (DKL≥0), maximizing the ELBO simultaneously maximizes marginal log-likelihood lnp(x) while driving the variational posterior qϕ(z∣x) toward the true posterior p(z∣x).
4
Step 4: Decompose ELBO into Reconstruction and Regularization
2. Closed-Form Analytical Derivation of Gaussian KL Divergence#
Assume the variational posterior is a diagonal multivariate Gaussian qϕ(z∣x)=N(μ,diag(σ2)) and the prior is a standard normal distribution p(z)=N(0,I) in Rd.
To compute gradients of the reconstruction loss with respect to encoder parameters ϕ:
∇ϕEqϕ(z∣x)[lnpθ(x∣z)]
If we sample z directly from stochastic distribution N(μ(x),Σ(x)), the sampling step creates a non-differentiable node in the computation graph. Gradients cannot backpropagate through random number generators.
Architecture Diagram
Rendering diagram...
The Reparameterization Trick reformulates random variable z as a deterministic function of inputs, parameters, and an external auxiliary noise variable ϵ:
z=μ(x)+σ(x)⊙ϵ,where ϵ∼N(0,I)
Now, the expectation is taken over the parameter-free noise distribution p(ϵ):
Gradients flow seamlessly into μ and σ via standard backpropagation:
∂μ∂z=1,∂σ∂z=ϵ
4. From-Scratch Implementation: Zero Dependencies#
The following implementations compute the complete VAE Loss Function (Reconstruction Mean Squared Error + Closed-Form Gaussian KL Divergence) and reparameterization sampling from scratch in pure Python and pure Rust.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
import math
import random
from typing import List, Tuple
classVAEPrimitives:@staticmethoddefreparameterize(mu: List[float], log_var: List[float])-> List[float]:# z = mu + exp(0.5 * log_var) * epsilon, where epsilon ~ N(0, 1)
z =[]for m, lv inzip(mu, log_var):
std = math.exp(0.5* lv)
eps = random.gauss(0.0,1.0)
z.append(m + std * eps)return z
@staticmethoddefkl_divergence_loss(mu: List[float], log_var: List[float])->float:# D_KL = -0.5 * sum(1 + log_var - mu^2 - exp(log_var))
d_kl =0.0for m, lv inzip(mu, log_var):
d_kl +=-0.5*(1.0+ lv -(m **2)- math.exp(lv))return d_kl
@staticmethoddefreconstruction_loss(x_true: List[float], x_recon: List[float])->float:# Mean Squared Error as negative Gaussian log-likelihood surrogatereturnsum((t - r)**2for t, r inzip(x_true, x_recon))/len(x_true)@classmethoddeftotal_vae_loss(
cls,
x_true: List[float],
x_recon: List[float],
mu: List[float],
log_var: List[float],
beta_kl:float=1.0)-> Tuple[float,float,float]:
recon = cls.reconstruction_loss(x_true, x_recon)
kl = cls.kl_divergence_loss(mu, log_var)
total = recon + beta_kl * kl
return total, recon, kl
if __name__ =="__main__":
random.seed(42)# Latent vector dimension 3
mu =[0.1,-0.2,0.05]
log_var =[-0.1,0.0,0.2]# Sample latent code z
z_sample = VAEPrimitives.reparameterize(mu, log_var)print("Reparameterized Latent Vector z:")print(" ",[round(v,4)for v in z_sample])# Compute loss on synthetic reconstruction
x_target =[1.0,0.0,0.5,0.2]
x_pred =[0.95,0.05,0.48,0.22]
total_loss, recon_l, kl_l = VAEPrimitives.total_vae_loss(x_target, x_pred, mu, log_var)print("\nLoss Components:")print(f" Reconstruction Loss (MSE): {recon_l:.6f}")print(f" KL Divergence Penalty: {kl_l:.6f}")print(f" Total VAE Loss: {total_loss:.6f}")
In the Variational Autoencoder ELBO equation, why does maximizing the lower bound force the approximate posterior q_phi(z|x) to match true posterior p(z|x)?
Concept check
How does the reparameterization trick z = mu(x) + sigma(x) * epsilon enable backpropagation through stochastic latent variables?