Autoencoder
自编码器无需标签即可学习将数据压缩为紧凑编码并重建数据。本文介绍其结构、变体、异常检测和代码。
自编码器是一种经过训练、能够重现自身输入的神经网络。编码器会将输入映射为紧凑代码,通常称为潜在表示;解码器会将代码映射回重建结果;训练过程则会最小化输入与重建结果之间的差异。由于目标就是输入本身,自编码器可以从无标签数据中学习,属于无监督学习;如今通常将其归为自监督学习。要让网络发挥作用,需要加入某种限制,防止它直接复制输入,例如设置狭窄的瓶颈、添加噪声、遮蔽输入或施加稀疏性惩罚;这些限制会迫使网络学习使数据可压缩的结构。自编码器可用于降维、异常检测、去噪、预训练,以及用作现代图像生成器的压缩阶段。
自编码器的工作原理#
编码器 f 将输入 x 映射为代码 z = f(x),解码器 g 生成重建结果 x̂ = g(z),训练过程使用重建损失(例如 x 与 x̂ 的均方误差),并通过反向传播进行优化。在欠完备自编码器中,z 的维度远少于 x,因此代码构成一个潜在空间摘要,只保留解码器所需的信息。使用平方误差训练的线性自编码器会学习与主成分分析(PCA)相同的子空间;Pierre Baldi 和 Kurt Hornik 于 1989 年证明了这一结论;非线性激活函数则使更深的自编码器能够捕捉 PCA 无法表示的曲线结构。Geoffrey Hinton 和 Ruslan Salakhutdinov 在 2006 年发表于《Science》的论文中表明,对于图像和文档,深度自编码器生成的低维代码远优于 PCA。
不依赖狭窄瓶颈的变体会改为破坏输入,并仍然使用干净的原始数据来评估重建结果:
自编码器的类型#
- 去噪:向输入添加噪声,并训练网络恢复干净的原始数据,正如 Pascal Vincent 及其同事在 2008 年所描述的那样。学到的特征能够抵御这种破坏,训练好的模型还可以清理含噪图像或信号。
- 稀疏:使用比输入更多的代码单元,同时对同时处于激活状态的单元数量进行惩罚。在稀疏自编码器上训练大语言模型 (LLMs)的内部激活值,会将这些激活拆分为许多特征,每个特征通常都对应一个可解释的概念。
- 变分 (VAE):编码器会输出代码的概率分布,而 KL 散度惩罚会使其接近标准正态分布,因此解码随机采样的代码就能生成新数据。Diederik Kingma 和 Max Welling 于 2013 年提出了 VAE。
- 向量量化 (VQ-VAE):通过向量量化,将每个代码向量映射到学习得到的代码本中距离最近的条目,从而把图像或音频转换为自回归模型能够生成的离散词元。
- 掩码:隐藏大部分输入并重建缺失部分。掩码自编码器 (MAE)会隐藏图像中 75% 的图块,以这种方式训练的编码器则会成为其他视觉任务的强大骨干网络。Ultralytics 包中运行的 Meta 分割一切模型 (SAM),其图像编码器基于经过 MAE 预训练的 Vision Transformer,而 SAM 2 则基于经过 MAE 预训练的 Hiera 编码器,因此每个可提示掩码背后的特征最初都是通过填补隐藏图块学到的。
利用重建误差进行异常检测#
只用正常数据训练的自编码器能够很好地重建正常输入,却无法很好地重建陌生输入,因此重建误差可以作为制造缺陷、欺诈交易或故障机器的异常分数,无需标注异常数据。下面的 PyTorch代码片段使用 scikit-learn 自带的手写数字数据集训练一个小型自编码器,排除所有数字 7,然后比较模型在留出数字和数字 7 上的误差:
import torch
from sklearn.datasets import load_digits
from torch import nn
# 8x8 handwritten digits scaled to [0, 1]; every 7 is held out as the unseen anomaly
digits = load_digits()
x = torch.tensor(digits.data / 16, dtype=torch.float32)
normal, sevens = x[digits.target != 7], x[digits.target == 7]
train, test = normal[:1200], normal[1200:]
# Encoder: 64 pixels to an 8-number code; decoder: code back to 64 pixels
torch.manual_seed(0)
encoder = nn.Sequential(nn.Linear(64, 32), nn.ReLU(), nn.Linear(32, 8))
decoder = nn.Sequential(nn.Linear(8, 32), nn.ReLU(), nn.Linear(32, 64), nn.Sigmoid())
model = nn.Sequential(encoder, decoder)
optimizer = torch.optim.Adam(model.parameters(), lr=0.01)
for step in range(1000):
optimizer.zero_grad()
nn.functional.mse_loss(model(train), train).backward() # reconstruction error
optimizer.step()
with torch.no_grad():
for name, data in [("Held-out digits", test), ("Unseen 7s", sevens)]:
print(f"{name}: reconstruction error {nn.functional.mse_loss(model(data), data):.4f}")它会输出留出数字的重建误差 0.0163,以及数字 7 的重建误差 0.0547;后者平均高出 3.4 倍。为每张图像的误差设置阈值,就能将这一差距转化为异常标记。自编码器也可能泛化能力过强,从而准确重建某些异常,因此实际系统会使用包含已知异常的验证数据来调整瓶颈大小和阈值。
自编码器与相关概念的比较#
- 生成对抗网络 (GANs):GAN 生成器将随机噪声映射为数据,并通过判别器进行学习,不需要编码器或重建目标。VAE 也能生成数据,其基于似然的目标函数训练起来更稳定,但生成的图像往往更模糊。
- U-Net:结构同样采用编码器-解码器,但会将输入映射为不同的目标,例如分割掩码;它还会通过跳跃连接绕过瓶颈,而在自编码器中,这种做法会让网络直接复制输入。
- 对比学习:通过比较样本来学习表征,因此其特征能够捕捉图像之间的差异,同时忽略重建损失必须保留的像素级细节。
- 嵌入:编码器生成的代码就是一种嵌入,而自编码器只是多种嵌入学习方法之一。
图像生成中的自编码器#
潜空间扩散模型(例如 Stable Diffusion)会在自编码器的潜空间中执行扩散过程,并在最后将结果解码回像素。Stable Diffusion 1.x 使用经过 KL 正则化的自编码器,将 512×512 RGB 图像压缩为 64×64×4 的潜表示,使扩散模型在每个去噪步骤中需要处理的数值减少 48 倍。










