多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

自编码器(Autoencoder)系统入门:从潜在空间插值到去噪实战——NYU-DLSP20 深度学习课程 Week 07 讲义解读

自编码器(Autoencoder)系统入门:从潜在空间插值到去噪实战——NYU-DLSP20 深度学习课程 Week 07 讲义解读 示例工程【免费下载链接】NYU-DLSP20NYU Deep Learning Spring 2020项目地址https://gitcode.com/gh_mirrors/pyt/pytorch-Deep-Learning点击查看免费下载本文以 NYU-DLSP20本仓库对应的 PyTorch 深度学习课程Week 07 第三节讲义为核心系统讲解自编码器的定义、数学形式、重建损失、欠完备/过完备隐藏层以及去噪自编码器与收缩自编码器两大变体并结合仓库内 10-autoencoder.ipynb 给出可运行的 PyTorch 实战方案。读完本文你将掌握自编码器在图像生成、超分辨率、修复inpainting等场景中的底层原理理解潜在空间相对于像素空间的优势并能独立完成标准与去噪自编码器的训练、内核可视化与修复能力对比。该讲义由 Alfredo Canziani 讲授是 Week 07「能量模型与自编码器」单元的收尾章节前两节分别铺垫了能量模型EBM框架与自监督学习SSL中「掩码预测」的思想本节则将「重建输入」这一目标落实为可训练的神经网络结构。韩文版原文位于 docs/ko/week07/07-3.md英文版对应 docs/en/week07/07-3.md内容与下文一致。一、自编码器的应用全景先看它能做什么在给出严格定义之前讲义先用一组生动的例子说明自编码器及其背后的「数据流形manifold」概念在图像领域的具体应用这些例子也直接解释了后续理论部分的动机。1.1 图像生成与数据流形讲义以 StyleGAN2 生成的人脸图像开场图 1 中的两张人脸其实都是生成器的输出。人脸局部细节非常逼真但背景却显得怪异——左边模糊、右边物体变形。原因在于神经网络是在人脸样本上训练的人脸本身自由度受限而背景的变化性variability远高于人脸。这里的数据流形大约只有 50 维恰好与人脸图像的「自由度degrees of freedom」数量相当。这个例子说明生成模型本质上是在学习一个低维数据流形并在该流形附近采样。docs/images/week07/07-3/1_faces_gen.jpg 图 1StyleGAN2 生成的人脸训练数据流形外推失败的直观演示1.2 像素空间与潜在空间的插值差异这是讲义中最核心的直觉示例之一给定一张狗图 2 左和一张鸟图 2 右的图像在像素空间线性插值直接对两个像素向量做加权平均得到的是两幅图像逐渐淡化的叠加效果fading overlay左上到右下依次是「狗权重递减、鸟权重递增」结果只是重影叠加毫无语义。在潜在空间插值先把两幅图分别编码成潜在空间latent space中的表示对两个潜在向量做插值再交给解码器decoder重建就能得到从狗到鸟的连续、合理的语义变换图 4。docs/images/week07/07-3/3_dog2bird.jpg 图 2像素空间线性插值的叠加结果无语义的淡出叠加 docs/images/week07/07-3/4_model_d2b.jpg 图 3潜在空间插值后经解码器生成的结果狗到鸟的语义变换结论非常明确潜在空间远比像素空间更适合捕捉图像的结构。这也是后续「为什么要用潜在变量模型、为什么要学编码表示」的直接论据。1.3 变换示例在潜在空间中对编码向量施加特定操作还能得到可控的语义变换讲义给出四类示例每类两张图变换前/变换后缩放Zoom对应潜在向量的缩放操作平移Shift改变对象在画面中的位置亮度Brightness调节明暗旋转Rotation注意这里的旋转可以是 3D 的因为潜在空间承载了物体的三维姿态信息。docs/images/week07/07-3/5_zoom1.jpg docs/images/week07/07-3/5_zoom2.jpg 缩放 docs/images/week07/07-3/6_shift1.jpg docs/images/week07/07-3/6_shift2.jpg 平移 docs/images/week07/07-3/7_bright1.jpg docs/images/week07/07-3/7_bright2.jpg亮度 docs/images/week07/07-3/8_rotation1.jpg docs/images/week07/07-3/8_rotation2.jpg旋转可为 3D1.4 图像超分辨率Super-resolution讲义引用的模型对应 david-gpu/srez 项目思路目标是把低分辨率图像放大并重建出原始人脸。图 9 从左到右依次是16×16 的输入图像 → 标准双三次插值bicubic interpolation的结果 → 神经网络生成的输出 → 真实图像ground truth。输出图像清楚暴露了训练数据偏差问题左上角的亚洲男性被重建成了偏向欧洲人的面孔——训练图像分布不均衡所致左下角女性的重建结果怪异——训练数据中缺少该拍摄角度的样本。这说明自编码器/生成模型只能重建「训练流形上」的内容数据分布之外或分布稀缺的区域会被「拉回」到流形上从而产生偏差。这也是后续「异常检测」应用的思想基础。1.5 图像修复Inpainting在图 10 中人脸被盖上灰色补丁此时图像已经「离开」了训练流形。图 11 的修复结果是通过**能量函数最小化energy function minimization**在训练流形上寻找最接近的样本完成的——这与 Week 07 前两节讲解的能量模型EBM框架一脉相承可参考 docs/en/week07/07-1.md 中的能量函数定义。docs/images/week07/07-3/10_facepatch.jpg 图 4人脸盖上灰色补丁 docs/images/week07/07-3/11_fixfacepatch.jpg 图 5通过能量函数最小化重建的结果1.6 文本描述生成图像Caption to Image图 12 展示了从文字描述生成图像的流程先提取与关键视觉信息相关联的文本特征表示再将其解码decode成图像。这种「编码-解码」结构与自编码器共享同一套设计哲学。二、自编码器是什么结构与数学定义自编码器autoencoder是一种以**无监督unsupervised**方式训练的神经网络先学习数据的编码表示encoded representation再尽可能接近地从编码表示中重建出输入数据。因此自编码器的输出就是对输入的预测/重建。图 13 展示了基本自编码器的结构。按课程惯例它被视为一个3 层神经网络输入层$\boldsymbol{x}$编码器encoder由 $\boldsymbol{W_h}$ 定义的仿射变换affine transformation随后接一个挤压函数squashing如 Tanh得到中间隐藏层 $\boldsymbol{h}$解码器decoder由 $\boldsymbol{W_x}$ 定义的另一个仿射变换再跟一个挤压函数得到输出 $\boldsymbol{\hat{x}}$——即模型对输入的预测/重建docs/images/week07/07-3/13_ae_structure.png 图 6基本自编码器架构编码器 隐藏层 解码器数学上前向过程可写为$$ \boldsymbol{h} f(\boldsymbol{W_h}\boldsymbol{x} \boldsymbol{b_h}) \ \boldsymbol{\hat{x}} g(\boldsymbol{W_x}\boldsymbol{h} \boldsymbol{b_x}) $$各变量维度为$$ \boldsymbol{x},\boldsymbol{\hat{x}} \in \mathbb{R}^n,\qquad \boldsymbol{h} \in \mathbb{R}^d,\qquad \boldsymbol{W_h} \in \mathbb{R}^{d \times n},\qquad \boldsymbol{W_x} \in \mathbb{R}^{n \times d} $$与 PCA 的联系如果采用绑权tied weights即令 $\boldsymbol{W_x} \boldsymbol{W_h}^{\top}$解码权重取编码权重的转置那么该线性自编码器就等价于 PCA——它学习到的正是数据的主成分方向。这是理解自编码器「压缩信息」能力的一个重要观察。三、为什么使用自编码器预测输入本身看似无意义但正是「只允许重建训练流形上的内容」这一约束带来了实用价值1. 异常检测anomaly detection与图像去噪image denoising给定一个数据流形我们期望自编码器只重建流形内存在的输入。由于模型被约束为只重建训练中观察到的内容新输入中的任何扰动/变化都会被抹除——模型对这些扰动不敏感。因此输入中「不属于流形」的部分噪声、异常会在重建时被自动滤除。2. 图像压缩compression当中间层维度 $d$ 小于输入维度 $n$ 时编码器就是一个压缩器隐藏表示编码后的表示承载了该输入的几乎全部信息却占用更少的空间。这两点将在第五节「欠完备隐藏层」和第六节「去噪自编码器」中得到更严格的论证。四、重建损失Reconstruction Loss整个数据集的总损失是各样本损失的平均值$$ L \frac{1}{m} \sum_{j1}^m \ell(x^{(j)},\hat{x}^{(j)}) $$针对输入类型的不同讲义给出两种常用的逐样本损失输入为类别型categorical如二值像素时使用交叉熵损失Cross-Entropy Loss$$ \ell(\boldsymbol{x},\boldsymbol{\hat{x}}) -\sum_{i1}^n [x_i \log(\hat{x}_i) (1-x_i)\log(1-\hat{x}_i)] $$输入为实数值real-valued时使用均方误差Mean Squared Error, MSE$$ \ell(\boldsymbol{x},\boldsymbol{\hat{x}}) \frac{1}{2} \lVert \boldsymbol{x} - \boldsymbol{\hat{x}} \rVert^2 $$在第八节的实战中MNIST 像素经归一化后落在 $[-1,1]$属于连续值输入因此选用 MSE 作为损失函数这一点与讲义一致。五、欠完备与过完备隐藏层根据隐藏层维度 $d$ 与输入维度 $n$ 的关系自编码器分为两类图 14欠完备under-complete$d n$把输入信息压缩到更少维度中天然具有压缩能力过完备over-complete$d n$使用比输入更高维的编码让优化更容易。docs/images/week07/07-3/14_over_under_complete.png 图 7欠完备左与过完备右隐藏层对比恒等函数风险与信息瓶颈information bottleneck因为目标是重建输入模型极易把所有输入特征复制进隐藏层再原样输出退化为恒等函数identity function——这意味着什么都没学到。因此必须施加额外约束即信息瓶颈限制隐藏层只能取训练中见过的那些配置。这样模型只会做「选择性的重建」仅限于输入空间的子集对流形之外的一切都不敏感。过拟合问题欠完备层因为维度不足无法复制输入理论上比过完备层更不容易过拟合但若编码器和解码器足够强大它仍可能过拟合——例如模型可以为每个数据点单独关联一个编号并记住映射。缓解过拟合的方法包括正则化regularization、架构设计architectural等这也自然引出后文的去噪与收缩自编码器。一个值得注意的细节讲义在第八节内核比较时再次强调MNIST 输入维度是 $28\times28784$但由于图像中存在大量背景像素、有效自由度远低于 784即使隐藏层维度高达 500对于该数据集而言仍然属于过完备层。六、去噪自编码器Denoising Autoencoder图 15 给出了去噪自编码器的流形直觉。其核心假设是在训练时注入与现实中将要观察到的相同噪声分布从而学会如何稳健地恢复干净数据。将输入与输出对比图 16、图 17可以发现已经位于流形上的点几乎不动远离流形的点移动幅度很大用颜色表示每个输入点的移动距离时颜色越亮表示移动越远角落里的点大约移动了接近 1 个单位而两条分支内部的点由于在训练中被上下分支吸引几乎完全不动。换句话说去噪自编码器学习到的是一个「把带噪点拉回流形」的映射这正是去噪与异常检测应用的工作机制。在 Week 07 第二节讲义 docs/en/week07/07-2.md 中去噪自编码器还被明确归类为能量模型的对比式训练方法contrastive method先随机扰动训练样本提高该区域能量的候选点再训练编码器-解码器重建原始数据若训练得当能量会随离开流形的距离呈二次增长。BERT 的掩码词预测也被称为「掩码自编码器masked autoencoder」是同一思想在离散文本域的实现。七、收缩自编码器Contractive Autoencoder收缩自编码器图 18的损失函数在重建项之外额外加上隐藏表示对输入的梯度之平方范数$$ \mathcal{L}_{\text{contractive}} \text{重建损失} \lambda \left\lVert \frac{\partial \boldsymbol{h}}{\partial \boldsymbol{x}} \right\rVert^2 $$即在输入发生微小变化时最小化隐藏层的变化量。其收益是让模型对重建方向敏感、对其他可能方向不敏感——隐藏表示只沿流形相关的方向移动。图 19 从几何上概括了各类自编码器的通用工作原理假设训练流形是一条在三维空间中蜿蜒的一维曲线$\boldsymbol{x}\in \boldsymbol{X}\subseteq\mathbb{R}^{n}$自编码器的目标是把这条曲线「拉直」到潜在空间的一个方向上$\boldsymbol{z}\in \boldsymbol{Z}\subseteq\mathbb{R}^{d}$。于是输入空间中的每个点都被映射为潜在空间中的点建立点与点的对应但输入空间的区域与潜在空间的区域之间并没有对应关系随后由解码器把潜在点变换回有意义的输出层。这解释了为什么潜在空间中的线性插值能产生语义连贯的结果见 1.2 节。八、PyTorch 实战标准与去噪自编码器讲义对应的可运行实现位于仓库根目录的 10-autoencoder.ipynb本节按 notebook 的实际代码顺序展开并补充必要的注释保证可以复制运行。8.1 环境准备与数据加载依赖库与项目环境notebook 使用torch、torchvision、matplotlib与 OpenCVcv2用于最后的修复对比。仓库的 environment.ymlconda 环境NYU-DL已经包含了pytorch、torchvision、opencv、matplotlib、jupyterlab等依赖。数据加载部分使用 MNIST关键参数如下batch_size 256 img_transform transforms.Compose([ transforms.ToTensor(), transforms.Normalize((0.5,), (0.5,)) ]) dataset MNIST(./data, transformimg_transform, downloadTrue) dataloader DataLoader(dataset, batch_sizebatch_size, shuffleTrue)Normalize((0.5,), (0.5,))把原本 $[0,1]$ 的像素映射到 $[-1,1]$与解码器 Tanh 的输出范围匹配notebook 中的to_img函数用x 0.5 * (x 1)逆变换回 $[0,1]$ 并view(x.size(0), 28, 28)还原为图像display_images则负责把输入/输出批量可视化。设备选择沿用 notebook 的写法device torch.device(cuda:0 if torch.cuda.is_available() else cpu)8.2 模型架构与重建损失输入为 $28\times28784$ 的展平向量讲义规定的变换路线是 $784\to30\to784$标准自编码器取d 30欠完备隐藏层去噪自编码器把d改为500对 MNIST 而言仍是过完备层见第五节。编码器与解码器都在线性层后接双曲正切Tanh把输出限制在 $(-1,1)$损失函数选用MSE。# n 28 x 28 784 d 30 # 标准自编码器欠完备隐藏层 # d 500 # 去噪自编码器过完备隐藏层 class Autoencoder(nn.Module): def __init__(self): super().__init__() self.encoder nn.Sequential( nn.Linear(28 * 28, d), nn.Tanh(), ) self.decoder nn.Sequential( nn.Linear(d, 28 * 28), nn.Tanh(), ) def forward(self, x): x self.encoder(x) x self.decoder(x) return x model Autoencoder().to(device) criterion nn.MSELoss()优化器采用 Adam学习率1e-3learning_rate 1e-3 optimizer torch.optim.Adam(model.parameters(), lrlearning_rate)8.3 训练循环五个标准步骤训练标准自编码器的训练循环包含讲义强调的 5 个步骤。前向两步前向传播output model(img)——把输入图像送进模型计算损失loss criterion(output, img.data)——注意目标使用img.data不参与梯度。反向三步清空梯度optimizer.zero_grad()——防止梯度跨 batch 累积反向传播loss.backward()参数更新optimizer.step()译者注即按梯度更新模型参数。notebook 中训练num_epochs 20个 epoch并在每个 epoch 末尾打印损失、调用display_images展示重建输出。完整循环如下标准 AE 版本num_epochs 20 # do nn.Dropout() # 标准 AE 时注释掉 for epoch in range(num_epochs): for data in dataloader: img, _ data img img.to(device) img img.view(img.size(0), -1) # noise do(torch.ones(img.shape)).to(device) # img_bad (img * noise).to(device) # 标准 AE 时注释掉 # forward output model(img) # 标准 AE 输入 img去噪 AE 输入 img_bad loss criterion(output, img.data) # backward optimizer.zero_grad() loss.backward() optimizer.step() # log print(fepoch [{epoch 1}/{num_epochs}], loss:{loss.item():.4f}) display_images(None, output) # 标准 AE 传 (None, output)去噪 AE 传 (img_bad, output)8.4 去噪变体用 Dropout 构造噪声掩码去噪自编码器的训练只需在标准流程上追加三步notebook 中以注释形式与标准 AE 无缝切换do nn.Dropout() # 1) 创建 Dropout 函数随机关闭神经元 noise do(torch.ones(img.shape)).to(device) # 2) 生成二值噪声掩码 img_bad (img * noise).to(device) # 3) 干净图像与二值掩码逐元素相乘得到带噪图像随后把model(img)改为model(img_bad)用带噪图像做输入目标仍为原始img.data。切换到去噪模式时notebook 提醒需要同步做三件事1把隐藏层维度改为 5002重新实例化模型3把新参数重新传给优化器。8.5 内核权重可视化对比标准 AE vs 去噪 AE训练完成后用display_images(None, model.encoder[0].weight, 5)可视化编码器第一个线性层的权重每行权重可重排为 $28\times28$ 图像即一个「内核」。对比结果揭示了两种模型的本质区别标准 AE 的内核数字存在区域内的像素呈规律模式说明检测到了某种笔迹特征而数字区域之外的像素基本是随机的——标准自编码器不关心数字区域之外的像素去噪 AE 的内核每个学到模式的核都会把数字区域之外的像素设置为某个常数值——因为 dropout 掩码会随机抹掉数字区域内的像素模型被迫利用背景像素来推断被掩盖的内容于是它开始关心数字区域之外的像素。docs/images/week07/07-3/AE_kernels.png 图 8标准 AE 内核背景像素随机 docs/images/week07/07-3/denoiser_kernels.png 图 9去噪 AE 内核背景像素趋于常数8.6 与 OpenCV 修复算法的对比实验notebook 的最后一部分对应讲义图 24–27把去噪自编码器与 OpenCV 的两种经典修复算法做对比。前提是必须先训练好去噪自编码器notebook 中以大写注释强调RUN THIS ONLY AFTER HAVING TRAINED A DENOISING AE!!!from cv2 import inpaint, INPAINT_NS, INPAINT_TELEA对带噪 batch 中的样本把img_bad还原为 8-bit 图像、把 dropout 噪声转成二值掩码然后分别用INPAINT_TELEATelea 算法与INPAINT_NSNavier-Stokes 算法、修复半径 3 调用cv2.inpaintfor i in range(3, 7): corrupted_img ((img_bad.data.cpu()[i].view(28, 28) / 4 0.5) * 255).byte().numpy() mask 2 - noise.cpu()[i].view(28, 28).byte().numpy() dst_TELEA.append(inpaint(corrupted_img, mask, 3, INPAINT_TELEA)) dst_NS.append(inpaint(corrupted_img, mask, 3, INPAINT_NS))最后用torch.no_grad()依次展示[noise]、[img noise]、[img]、[output]以及[TELEA、NS]四组对比。讲义与 notebook 的对比结果显示在本实验MNIST 手写数字上去噪自编码器的修复输出相比 OpenCV 的 Telea / Navier-Stokes 修复更接近原始输入——这正是「学习数据流形」相对传统局部插值方法的优势所在。docs/images/week07/07-3/AE_output.png 图 10输入数据MNIST 数字 docs/images/week07/07-3/denoiser_output.png 图 11去噪 AE 重建结果 docs/images/week07/07-3/telea_output.png 图 12Telea 修复输出 docs/images/week07/07-3/navier-stokes_output.png 图 13Navier-Stokes 修复输出九、关键结论与延伸阅读回顾本讲可以提炼出四条核心结论自编码器是无监督的「重建式」网络输出即对输入的预测其价值不在于重建本身而在于「只能重建训练流形上的内容」这一约束由此获得去噪、异常检测与压缩能力。潜在空间优于像素空间对潜在表示做插值/变换能得到语义连贯的结果这源于编码器把数据流形「拉直」到了潜在空间。瓶颈与约束决定模型学到什么欠完备层天然压缩信息、不易复制输入过完备层优化更易但有过拟合与恒等映射风险需要正则化或架构约束如去噪、收缩机制来施加信息瓶颈。去噪自编码器是实用性与理论性的交汇点它既是能量模型框架下的对比式训练方法又能直接落地为 OpenCV 修复算法的可比较对手。延伸阅读建议均为本仓库现有资源能量模型框架铺垫docs/en/week07/07-1.mdEBM 定义、自由能与概率模型的对照自监督学习与 EBM 细节docs/en/week07/07-2.md去噪自编码器作为对比式方法、BERT 掩码自编码器、对比散度后续进阶潜在变量模型的概率化版本可继续阅读仓库内的 11-VAE.ipynb变分自编码器它把本讲的确定性潜在编码推广为概率分布运行环境使用 environment.yml 创建NYU-DLconda 环境即可覆盖本讲全部依赖含 OpenCV。赞分享示例工程【免费下载链接】NYU-DLSP20NYU Deep Learning Spring 2020项目地址https://gitcode.com/gh_mirrors/pyt/pytorch-Deep-Learning点击查看免费下载相关推荐GHelper1个EXE、0个后台服务把华硕笔记本的性能控制台跑起来GHelper1个EXE、0个后台服务把华硕笔记本的性能控制台跑起来 装官方 Armoury Crate任务管理器里常驻一排 ASUS 进程加一堆后台服务示例工程自编码器Autoencoder原理与 PyTorch 实战从能量模型视角到去噪自编码器实现NYU-DLSP20 课程笔记深度解析自编码器Autoencoder原理与 PyTorch 实战从能量模型视角到去噪自编码器实现NYU DLSP20 课程笔记深度解析 自编码器是深度学习中示例工程NYU-DLSP20 自编码器完全指南从流形插值到 PyTorch 去噪实现NYU DLSP20 自编码器完全指南从流形插值到 PyTorch 去噪实现 本指南以 NYU Deep Learning Spring 2020本仓库 p示例工程上一篇Source Han Serif CN7种字重免费商用中文字体完全指南下一篇VHDL转Verilog终极指南3步快速上手免费开源转换工具创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表