变分自编码器 VAE
VAE 用概率潜空间、重参数化和 KL 正则支持从先验采样。
学习目标
- 两维高斯后验的 KL 与重参数化
- 为什么编码器常输出 logvar 而不是方差?
- 说明:重参数化保证可微采样路径,不保证没有后验塌缩,也不保证所有随机样本都合理。
为什么需要这个概念
变分自编码器用近似后验 q(z|x) 编码输入,常输出高斯均值 mu 和 logvar,通过重参数化采样,再优化重构项与相对先验的 KL 项。
学习前需要掌握
背景与问题
普通自编码器的潜在空间可能零散、不适合随机采样。VAE 把编码结果变成分布,再用先验约束形成更可采样的空间,同时保留输入重构能力。
概念定义
变分自编码器用近似后验 q(z|x) 编码输入,常输出高斯均值 mu 和 logvar,通过重参数化采样,再优化重构项与相对先验的 KL 项。
直观理解
编码器给出的不是一个坐标,而是坐标附近的一团概率云;KL 约束让这些云与规定的公共坐标分布保持联系。
核心原理
对角高斯后验可写为 z=mu+exp(0.5×logvar)×epsilon,epsilon 来自标准正态。随机性来自与参数无关的 epsilon,因此梯度仍可通过 mu 和 logvar 传回编码器。直接从由参数定义的分布抽样后当常量使用会失去这种路径。
标准正态先验下,单样本 KL 为 -0.5×sum(1+logvar−mu²−exp(logvar))。应先明确按 latent 维求和、按 batch 如何归一化;重构项若按像素平均或求和,都会改变它与 KL 的相对尺度。
重构概率模型取决于数据,例如连续值与二元像素需要不同观测假设。KL 太强可能让后验忽略输入,太弱则先验采样质量不佳;beta 只是权衡参数,不能在不说明归一化时跨实现照搬。
数学表达
核心公式
变分自编码器用近似后验 q(z|x) 编码输入,常输出高斯均值 mu 和 logvar,通过重参数化采样,再优化重构项与相对先验的 KL 项。
变量含义
Nbatch sizeD/H特征或隐藏维度
计算步骤
- 1标准差为 (1,1),采样 z=(1.5,-1)。
- 2KL=0.5×(1²+0²)=0.5。
- 3本例总目标为 2+0.5=2.5。
代码对应位置
示例 1两维高斯后验的 KL 与重参数化的最小验证:使用完整构造输入核对两维高斯后验的 KL 与重参数化,输出只表示本例计算。
变量解释
| 变量 | 含义 |
|---|---|
N | batch size |
D/H | 特征或隐藏维度 |
完整数值示例
两维高斯后验的 KL 与重参数化
已知条件
- mu=(1,0),logvar=(0,0),先验为标准正态
- 构造 epsilon=(0.5,-1) 以便复核
- 重构平方误差按维求和为 2,beta=1
计算步骤
- 标准差为 (1,1),采样 z=(1.5,-1)。
- KL=0.5×(1²+0²)=0.5。
- 本例总目标为 2+0.5=2.5。
计算结果
latent 为 (1.5,-1),KL 为 0.5,总目标为 2.5。
处理前后对比
- 重参数化保证可微采样路径,不保证没有后验塌缩,也不保证所有随机样本都合理。
两维高斯后验的 KL 与重参数化
固定 epsilon 只是把随机抽样的一次条件写清楚,不代表训练时始终使用它。真正训练需要不断采样,或按明确推断策略使用后验均值。
若把两维重构误差改为均值,重构项会从 2 变成 1,相同 beta 下相对 KL 权重翻倍。因此报告一个 VAE loss 前必须交代求和与平均轴。
计算与实现步骤
- 标准差为 (1,1),采样 z=(1.5,-1)。
- KL=0.5×(1²+0²)=0.5。
- 本例总目标为 2+0.5=2.5。
代码实现
示例 1
两维高斯后验的 KL 与重参数化的最小验证
example_01.py用途:使用完整构造输入核对两维高斯后验的 KL 与重参数化,输出只表示本例计算。
import torch
mu = torch.tensor([[1., 0.]], requires_grad=True)
logvar = torch.zeros_like(mu)
epsilon = torch.tensor([[0.5, -1.]])
z = mu + torch.exp(0.5 * logvar) * epsilon
kl = -0.5 * (1 + logvar - mu.square() - logvar.exp()).sum(-1).mean()
x, reconstruction = torch.tensor([[0., 2.]]), torch.tensor([[1., 1.]])
recon = (reconstruction - x).square().sum(-1).mean()
print("z:", z.detach().tolist())
print(f"reconstruction={recon.item():.1f} KL={kl.item():.1f} total={(recon + kl).item():.1f}")代码解析
解析始终位于完整代码下方,并按实际代码段逐项对应。
输入数据与任务
使用完整构造输入核对两维高斯后验的 KL 与重参数化,输出只表示本例计算。
mean- 训练特征逐列均值。
Step 1 · 1–10 行
导入当前步骤需要的数值计算、预处理、模型或评价工具。依赖集中写在代码开头,便于复现。
import torch
mu = torch.tensor([[1., 0.]], requires_grad=True)
logvar = torch.zeros_like(mu)
epsilon = torch.tensor([[0.5, -1.]])
z = mu + torch.exp(0.5 * logvar) * epsilon
kl = -0.5 * (1 + logvar - mu.square() - logvar.exp()).sum(-1).mean()
x, reconstruction = torch.tensor([[0., 2.]]), torch.tensor([[1., 1.]])
recon = (reconstruction - x).square().sum(-1).mean()
print("z:", z.detach().tolist())
print(f"reconstruction={recon.item():.1f} KL={kl.item():.1f} total={(recon + kl).item():.1f}")代码与数学原理
减去训练均值并除以训练标准差,对应代码中的 mean/std 或 StandardScaler。
预期输出或运行结果
z: [[1.5, -1.0]] reconstruction=2.0 KL=0.5 total=2.5
常见错误 · 4 条
- 不要在测试集上调用 fit 或 fit_transform;测试集只能复用训练参数。
- logvar 当 std
- KL/recon reduction 不一致
- β 过大潜变量失效
实际应用
- 连续潜变量表示与采样
- 分析重构和潜在先验的权衡
常见错误
- logvar 当 std
- KL/recon reduction 不一致
- β 过大潜变量失效
常见问题
为什么编码器常输出 logvar 而不是方差?
logvar 可取任意实数,经指数得到正方差,便于网络参数化;仍需检查过大指数引起的数值溢出。
这个示例能说明什么边界?
重参数化保证可微采样路径,不保证没有后验塌缩,也不保证所有随机样本都合理。
推荐学习资料
参考库不会生成虚假资源或无效外部链接。