【12】自编码器(Auto-Encoder)的介绍与pytorch实现

简介: 【12】自编码器(Auto-Encoder)的介绍与pytorch实现

1.自编码器的介绍


自编码器的思想很简单,就是将一张图像通过Encoder变成一个code,然后再通过Decoder将这个生成出来的code重构成一张图像,然后希望重构出来的图像与原图像越接近好。

image.png


1)传统自编码器

通过神经网络来实现传统的自编码器

image.png

传统自编码器的目的是使输出与输入尽量相同,这完全可以通过学习两个恒等函数来完成,但是这样的变换没有任何意义,因为我们真正关心的是隐层表达,而不是实际输出.因此,针对自编码器的很多改进方法都是对隐层表达增加一定的约束,迫使隐层表达与输入不同.如果此时模型还可以重建输入信号,那么说明隐层表达足以表示输入信号,这个隐层表达就是通过模型自动学习出来的有效特征.


2)降噪自编码器

一个好的表达应该能够捕获输入信号的稳定结构,具有一定的鲁棒性,同时对重建信号是有用的.


降噪自编码器的提出是受到一个现象的启发,那就是对于部分被遮挡或损坏的图像,人类仍然可以进行准确的识别.因此,降噪自编码器的主要研究目标是:隐层表达对被局部损坏的输入信号的鲁棒性.也就是说,如果一个模型具有足够的鲁棒性,那么被局部损坏的输入在隐层上的表达应该与没有被破坏的干净输入几乎相同,而利用这个隐层表达就完全可以重建干净的输入信号.


因此,降噪自编码器通过对干净输入信号人为加入一些噪声,使干净信号受到局部损坏,产生与它对应的一个损坏信号,然后将这个损坏信号送入传统自编码器,使其尽量重建一个与干净输入相同的输出.

image.png


3)卷积自编码器

卷积神经网络所取得的各种优异表现,直接推动了卷积自编码器的产生.严格上来说,卷积自编码器 属于传统自编码器的一个特例,它使用卷积层和池化层替代了原来的全连接层.传统自编码器一般使用的是全连接层,对于一维信号并没有什么影响,而对于二维图像或视频信号,全连接层会损失空间信息,通过采用卷积操作,卷积自编码器能很好的保留二维信号的空间信息.


卷积自编码器与传统自编码器非常类似,其主要差别在于卷积自编码器采用卷积方式对输入信号进行线性变换,并且其权重是共享的,这点与卷积神经网络一样.因此,重建过程就是基于隐藏编码的基本图像块的线性组合.

image.png

对于其中的Unpooling与Deconvolution可能会有些理解问题。


  1. Unpooling

我们知道,卷积中的池化层就是将原本一个局部区域中去平均或者是去最大来实现尺寸的下降,通常池化后的尺度大小是原来的二分之一。或者,池化也可以理解为下采样。而Unpooling可以理解为上采样。


其中的一种实现的方式是,其保留上一步池化的记忆,也就是记住了选择的是最大值的那个区域,然后当尺度扩张时,保留那个最大的值,然后在其他的地方补0,从而实现尺寸的变大。

image.png

另外的一种方法是,不需要补0,而是单一扩张区域中直接复制一模一样的值。


Unpooling后的效果:

image.png

2. Deconvolution


其实Deconvolution就是convolution,其中convolution是通过卷积而降维,而Deconvolution可以通过padding来实现扩维。如下图,convolution是左边的操作,Deconvolution其实就是右边的操作。

image.png


2.自编码器的应用


基于自编码器降维得到的隐藏变量code,其实可以有一些应用的。


1)文字检索(Text Retrieval)

我们可以将一篇文章,当成是一个二维空间中一个数据分布。一篇文章代表了这个数据分布中的一个点,那么我们可以将一篇文章通过自编码器提取到一个二维的code。

image.png

然后根据这歌二维的code在数据空间中的分布来检索其与其他文章的相识性,从而实现分类或其他操作。

image.png


2)相识图像检索(Similar Image Search)

其实我们还可以通过自编码寻找数据分布的能力,来进行图像检索。具体的操作是,当我们希望寻找一些相识图像的时候,如果我们使用的pixel之间的相识性,也就是如果我们根绝两张图像之间的像素点的分布来做损失,那么得到的结果往往不会太好。

image.png


但是,这时候我们可以通过将需要寻找的图像通过编码器变成一个code,然后通过这个code来进行检索。也就是说,如果两张图像的code,之间的差异是比较小的,我们可以相信这有可能找到我们需要的图像,而最后的结果往往比上诉的找像素之间的分布的结果要好。最起码自编码器中的code找到知道我们要找的是一个人像。

image.png


3)模型的预训练(Pre-training)

我们知道在神经网络的训练中,通常初始化这一步是非常中重要的,所以,其实我们可以使用自编码器来实现预训练的操作。


当我们进行半监督学习时候,我们通常有非常多的unlabel的data,然后只有少部分的带label的data,那么这时候,我们就可以使用这些大量的unlabel的data来对模型进行预训练。


我们假设模型结构是3层隐藏层的全连接神经网络结构,那么对于第一层隐藏层来说,我们输入一个图像,然后通过自编码器,经过这隐层层得到一个1000维的code,而这个code其实就是第二层的隐含层。当然此时需要避免当code比图像的维度还要高的时候,网络可以原封不动的直接保留整个图像的维度信息,需要注意这点。然后通过Decoder将code重构出原来的模型,此时我们可以固定住第一层隐藏层的参数,因为这已经训练好了。

image.png


同样的,我们对第二层隐藏层就行训练,将第二层应汉成变成一个code,而这个code的维度就是第三层隐藏层的维度,然后再重构出来,然后再固定第二层隐藏层的参数。

image.png

类似的,对于其他的隐藏层操作类似。当保留好全部网络层数的参数时,这个网络就已经预训练好了。现在只需要使用那些少量的带label的data来对网络进行back propagation,稍微调整一下参数即可。


但是,其实对于现在的网络来说,没有初始化一般也是可以训练出来的,但这是得益于训练技术的提高,在曾经没有初始化与有初始化的差距还是比较大的。


3.自编码器的实现


框架使用Pytorch

数据集使用MNIST


参考代码

model.py


import torch
import torchvision
import torch.nn as nn
# 定义自编码器结构
class Auto_Encoder(nn.Module):
    def __init__(self):
        super(Auto_Encoder, self).__init__()
        # 定义编码器结构
        self.Encoder = nn.Sequential(
            nn.Linear(784, 256),
            nn.ReLU(),
            nn.Linear(256, 64),
            nn.ReLU(),
            nn.Linear(64, 20),
            nn.ReLU()
        )
        # 定义解码器结构
        self.Decoder = nn.Sequential(
            nn.Linear(20, 64),
            nn.ReLU(),
            nn.Linear(64, 256),
            nn.ReLU(),
            nn.Linear(256, 784),
            nn.Sigmoid()
        )
    def forward(self, input):
        code = input.view(input.size(0), -1)
        code = self.Encoder(code)
        output = self.Decoder(code)
        output = output.view(input.size(0), 1, 28, 28)
        return output


train.py


import torch
import torchvision
from torch import nn, optim
from torchvision import datasets, transforms
from torchvision.utils import save_image
from torch.utils.data import DataLoader
from model import Auto_Encoder
import os
# 定义超参数
learning_rate = 0.0003
batch_size = 64
epochsize = 30
root = 'E:/学习/机器学习/数据集/MNIST'
sample_dir = "image"
if not os.path.exists(sample_dir):
    os.makedirs(sample_dir)
# 图像相关处理操作
transform = transforms.Compose([
    transforms.ToTensor(),
    transforms.Normalize(mean=[0.5], std=[0.5])
])
# 训练集下载
mnist_train = datasets.MNIST(root=root, train=True, transform=transform, download=False)
mnist_train = DataLoader(dataset=mnist_train, batch_size=batch_size, shuffle=True)
# 测试集下载
mnist_test = datasets.MNIST(root=root, train=False, transform=transform, download=False)
mnist_test = DataLoader(dataset=mnist_test, batch_size=batch_size, shuffle=True)
# image,_ = iter(mnist_test).next()
# print("image.shape:",image.shape)   # torch.Size([64, 1, 28, 28])
AE = Auto_Encoder()
AE.load_state_dict(torch.load('AE.ckpt'))
criteon = nn.MSELoss()
optimizer = optim.Adam(AE.parameters(), lr=learning_rate)
print("start train...")
for epoch in range(epochsize):
    # 训练网络
    for batchidx, (realimage, _) in enumerate(mnist_train):
        # 生成假图像
        fakeimage = AE(realimage)
        # 计算损失
        loss = criteon(fakeimage, realimage)
        # 更新参数
        optimizer.zero_grad()
        loss.backward()
        optimizer.step()
        if batchidx%300 == 0:
            print("epoch:{}/{}, batchidx:{}/{}, loss:{}".format(epoch, epochsize, batchidx, len(mnist_train), loss))
    # 生成图像
    realimage,_ = iter(mnist_test).next()
    fakeimage = AE(realimage)
    # 真假图像何必成一张
    image = torch.cat([realimage, fakeimage], dim=0)
    # 保存图像
    save_image(image, os.path.join(sample_dir, 'image-{}.png'.format(epoch + 1)), nrow=8, normalize=True)
    torch.save(AE.state_dict(), 'AE.ckpt')


结果展示

image.png

Epoch1生成的图像

image.png

Epoch10生成的图像

image.png

Epoch30生成的图像


结果可以看出慢慢训练得变好,但是还是有些模糊,使用VAE的效果可能会好一点。



目录
相关文章
|
5月前
|
机器学习/深度学习 XML 自然语言处理
Transformer 架构—Encoder-Decoder
Transformer 架构—Encoder-Decoder
271 1
|
5月前
|
机器学习/深度学习 编解码
LeViT-UNet:transformer 编码器和CNN解码器的有效整合
LeViT-UNet:transformer 编码器和CNN解码器的有效整合
137 0
|
5月前
|
PyTorch 算法框架/工具
Bert Pytorch 源码分析:三、Transformer块
Bert Pytorch 源码分析:三、Transformer块
67 0
|
16天前
|
机器学习/深度学习 自然语言处理 搜索推荐
预训练的词嵌入(Word Embedding)
预训练的词嵌入(Word Embedding)
|
5月前
|
存储 缓存 分布式计算
You Only Cache Once:YOCO 基于Decoder-Decoder 的一个新的大语言模型架构
YOCO是一种新的解码器-解码器架构,旨在解决大型语言模型推理时的内存限制问题。通过只缓存一次键值对,YOCO显著减少了GPU内存占用,与Transformer相比,内存使用降低了约L倍。模型由自解码器和交叉解码器组成,自解码器使用滑动窗口注意力,而交叉解码器利用全局KV缓存。实验表明,YOCO在保持竞争力的性能同时,提高了推理速度,尤其是在处理长序列时。此外,YOCO还减少了预填充时间,提升了吞吐量。
158 3
|
5月前
|
机器学习/深度学习 人工智能 监控
论文介绍:Masked-attention Mask Transformer (Mask2Former)——通用图像分割的新架构
【5月更文挑战第24天】Mask2Former,一种新型的图像分割架构,采用遮蔽注意力机制聚焦局部特征,提升模型收敛速度和性能,在COCO、Cityscapes等数据集上刷新记录。其元架构结合背景特征提取器、像素解码器和Transformer解码器,实现高效训练和性能提升。尽管在处理小对象和泛化能力上仍有局限,但Mask2Former为通用图像分割开辟了新路径。[链接](https://arxiv.org/abs/2112.01527)
153 5
|
5月前
|
机器学习/深度学习 BI
[RoFormer]论文实现:ROFORMER: ENHANCED TRANSFORMER WITH ROTARY POSITION EMBEDDING
[RoFormer]论文实现:ROFORMER: ENHANCED TRANSFORMER WITH ROTARY POSITION EMBEDDING
45 1
|
机器学习/深度学习
自动编码器(Autoencoder
自动编码器(Autoencoder)是一种无监督式学习模型,旨在通过降低数据维度来提高机器学习模型的性能。它由编码器(Encoder)和解码器(Decoder)两个主要部分组成。编码器的作用是将输入数据压缩成低维度的隐向量,从而捕获数据的主要特征;解码器的作用是将隐向量还原回原始数据空间。自动编码器可以实现类似 PCA 的数据降维和数据压缩功能。
107 2
|
5月前
|
机器学习/深度学习 自然语言处理 机器人
编码器-解码器(Encoder-Decoder)结构
编码器-解码器(Encoder-Decoder)结构
474 5
|
机器学习/深度学习 自然语言处理 算法
【Transformer系列(1)】encoder(编码器)和decoder(解码器)
【Transformer系列(1)】encoder(编码器)和decoder(解码器)
3566 0
【Transformer系列(1)】encoder(编码器)和decoder(解码器)