【干货】对抗自编码器PyTorch手把手实战系列——PyTorch实现自编码器

即使是非计算机行业, 大家也知道很多有名的神经网络结构, 比如CNN在处理图像上非常厉害, RNN能够建模序列数据. 然而CNN, RNN之类的神经网络结构本身, 并不能用于执行比如图像的内容和风格分离, 生成一个逼真的图片, 用少量的label信息来分类图像, 或者做数据压缩等任务. 因为上述几个任务, 都需要特殊的网络结构和训练算法 .

有没有一个网络结构, 能够把上述任务全搞定呢? 显然是有的, 那就是对抗自编码器Adversarial Autoencoder(AAE) . 在本文中, 我们将构建一个AAE, 来压缩数据, 分离图像的内容和风格, 用少量样本来分类图像, 然后生成它们。

本系列文章, 专知小组一共分成四篇讲解:

  • 自编码器, 以及如何用PyTorch实现自编码器
  • 对抗自编码器, 以及如何用PyTorch实现对抗自编码器
  • 自编码器实例应用: 被玩坏的神经画风迁移(没办法太典型了)
  • 自编码器实例应用: 用极少label分类MNIST

PyTorch实现自编码器

首先我们先回顾一下什么是自编码器 , 然后用PyTorch 进行简单的实现。

1.自编码器



如图所示, 自编码器的输入和输出是一样的, 也就是说, 它不需要监督信息(label), 它主要有两部分构成:

编码器(Encoder) : 输入数据

(可以是文本, 图像, 视频, 语音), 输出latent code, 比如上图, 输入数据是

的一张图像, 输出的是

的隐层值h, 或者称之为latent code, 当然h的大小你可以随便设置. 在这种设置下, encoder 起到了压缩图片的作用, 将一个图片从

变化成了

, 就像你用压缩软件( 比如WinRAR)压缩图片一样. 如果我们把Encoder记做函数q, 那么Encoder就是在做:

解码器(Decoder) : 输入数据为上一步的输出数据h, 它努力把h重构成x, 上图的例子中, Decoder需要把

的重构回

,并使得

和原来的x约相似越好, 就像你用压缩然见解压一个压缩文件一样. 如果我们把Decoder记做函数p, 那么Decoder就是在做:

这个模型似乎是一个天然的降维模型. 但是, 除了降维,Autoencoder还能干什么?

  • 图片降噪(Image Denosiong), 输入嘈杂的图像, Autoencoder可以生成清晰无噪声的图像. 当把数据输入自编码器后, 我们可以强制让自编码器的隐层学习更鲁棒的特征, 而不是仅仅识别他们, 这样的自编码器, 在下图左边的图上进行训练, 就可以把中间的噪声数据, 重建成右边的样子。
  • 语义哈希, 这可以降低数据的维度, 加速信息检索, 目前有非常的人在研究这一方向.
  • 生成模型, 比如本系列文章要介绍的Adversarial Autoencoder(AAE)
  • 其他大量应用

2.PyTorch实现



我们先从简单的全连接网络开始我们的第一部分.

这个Encoder包含

的输入层, 两层隐层, 每层1000个节点, 一个输出层层数为2

import torch
import torch.nn as nn

encoder = nn.Sequential(
  nn.Linear(28*28, 1000)
  nn.ReLU()
  nn.Linear(1000, 1000)
  nn.ReLU()
  nn.Linear(1000, 2)
)
decoder = nn.Sequential(
  nn.Linear(2, 1000)
  nn.ReLU()
  nn.Linear(2, 1000)
  nn.ReLU()
  nn.Linear(1000, 28*28)
  nn.Sigmoid() #压缩到0-1之间 
)

所以, 整个模型是:

import torch
import torch.nn as nn


class AutoEncoder(nn.Module):
    def __init__(self):
        super(AutoEncoder, self).__init__()

        self.encoder = nn.Sequential(
            nn.Linear(28 * 28, 1000)
        nn.ReLU()
        nn.Linear(1000, 1000)
        nn.ReLU()
        nn.Linear(1000, 2)
        )
        self.decoder = nn.Sequential(
            nn.Linear(2, 1000)
        nn.ReLU()
        nn.Linear(2, 1000)
        nn.ReLU()
        nn.Linear(1000, 28 * 28)
        nn.Sigmoid()
        )

        def forward(self, x):
            encoded = self.encoder(x)
            decoded = self.decoder(encoded)

            return encoded, decoded

模型实现完成后, 我们要准备一下数据:

import torchvision
import torch.utils.data as Data


BATCH_SIZE = 64
DOWNLOAD_MNIST = False # 本地没有数据的话, 设成True可以下载

# 从torchvison里加载MNIST数据, 然后转成Tensor
train_data = torchvision.datasets.MNIST(
    root='./mnist/',
    train=True,                                    
    transform=torchvision.transforms.ToTensor(),   
    download=DOWNLOAD_MNIST,
)

# 加载数据, 维度是(batch_size, n_channel, n_width, n_height )
train_loader = Data.DataLoader(dataset=train_data, 
                               batch_size=BATCH_SIZE, 
                               shuffle=True)

我们选择MSE损失函数来度量重构出来的图像

与原来的图像x的相似程度

loss_func = nn.MSELoss()

LR = 0.005
# 用Adam来优化参数
optimizer = torch.optim.Adam(autoencoder.parameters(), lr=LR)

接下来就可以实现训练步骤了:

EPOCH = 10
autoencoder = AutoEncoder()
for epoch in range(EPOCH):
    for step, (x, y) in enumerate(train_loader):
        b_x = Variable(x.view(-1, 28*28))   # reshape 成(batch, 28*28)
        b_y = Variable(x.view(-1, 28*28))   
        b_label = Variable(y)               # batch label

        encoded, decoded = autoencoder(b_x)

        loss = loss_func(decoded, b_y) # 算误差     
        optimizer.zero_grad()          # 清空累计导数     
        loss.backward()                # 求导     
        optimizer.step()               # 优化一步                    

        if step % 100 == 0:
            print('Epoch: ', epoch, '| train loss: %.4f' % loss.data[0])

可以看一下重建的图像怎么样:

我们可以观察到, 输入的这张3的图片, 一些奇怪的地方呗去掉了(3的左上角).

接下来, 让我们看一下latent code, 它只有2维, 我们可以随便填一个值让Decoder去生成图片, 比如我们认为的令

,让后将它输入到Decoder中:

这好像是个6的图片, 当然也可能是0, 不管怎么说, 这不是一个清晰的数字图片. 这是因为Encoder的输出并不能覆盖整个2维空间(它的输出分布有很多空白)。 因此,如果我们输入一些Decoder没见过的值,我们会看到一下奇怪的输出图像。 这可以通过在生成latent code 时, 将Encoder的输出限制为随机分布(比如,均值为0.0和标准偏差为2.0的正态分布)。 Adversarial Autoencoder就是这么做到的,我们将在第2部分中看看它的实现。

原文发布于微信公众号 - 专知(Quan_Zhuanzhi)

原文发表时间:2018-03-08

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

发表于

我来说两句

0 条评论
登录 后参与评论

相关文章

机器学习之随机森林

机器执行的每一个步都依赖于我们的指令。它们需要指导去哪里做什么,就像一个不了解周围环境而无法自己做决定的孩子。因此,开发人员会需要为机器编写指令。然而当我们谈论...

21080
来自专栏游戏开发那些事

【Unity3d游戏开发】Unity3D中的3D数学基础---向量

向量是2D、3D数学研究的标准工具,在3D游戏中向量是基础。因此掌握好向量的一些基本概念以及属性和常用运算方法就显得尤为重要。在本篇博客中,马三就来和大家一起回...

14310
来自专栏梦里茶室

TensorFlow深度学习笔记 循环神经网络实践

加载数据 使用text8作为训练的文本数据集 text8中只包含27种字符:小写的从a到z,以及空格符。如果把它打出来,读起来就像是去掉了所有标点的wikip...

30150
来自专栏社区的朋友们

深度学习入门实战(三):图片分类中的逻辑回归

上一讲我们介绍了一下线性回归如何通过TensorFlow训练,这一讲我们介绍下逻辑回归模型,一句话说概括,逻辑回归就是多分类问题。

4.7K00
来自专栏WD学习记录

机器学习 学习笔记(10)序列最小最优化算法

序列最小最优化算法(Sequential minimal optimization)

17120
来自专栏深度学习与数据挖掘实战

干货|深度学习面试问答集锦

No.19 CNN中,conv layer、ReLu layer、Pooling layer、Fully connected layer的区别?

13240
来自专栏大数据挖掘DT机器学习

机器学习模型的特性

机器学习模型中有许多种不同方法可以用来解决分类和回归问题。对同一个问题来说,这些不同模型都可以被当成解决问题的黑箱来看待。然而,每种模型都源自于不同的...

355110
来自专栏机器学习原理

机器学习(7)——聚类算法聚类算法

聚类算法 前面介绍的集中算法都是属于有监督机器学习方法,这章和前面不同,介绍无监督学习算法,也就是聚类算法。在无监督学习中,目标属性是不存在的,也就是所说的不存...

1.6K70
来自专栏机器学习原理

图像处理和数据增强图片处理数据增强颜色空间转换噪音数据的加入样本不均衡

82240
来自专栏cloudskyme

跟我一起数据挖掘(23)——C4.5

C4.5简介 C4.5是一系列用在机器学习和数据挖掘的分类问题中的算法。它的目标是监督学习:给定一个数据集,其中的每一个元组都能用一组属性值来描述,每一个元组属...

36490

扫码关注云+社区

领取腾讯云代金券