深度学习自动编码器还能用于数据生成?这篇文章告诉你答案

  什么是自动编码器

自动编码器(AutoEncoder)最开始作为一种数据的压缩方法,其特点有:

  • 跟数据相关程度很高,这意味着自动编码器只能压缩与训练数据相似的数据,这个其实比较显然,因为使用神经网络提取的特征一般是高度相关于原始的训练集,使用人脸训练出来的自动编码器在压缩自然界动物的图片是表现就会比较差,因为它只学习到了人脸的特征,而没有能够学习到自然界图片的特征;
  • 压缩后数据是有损的,这是因为在降维的过程中不可避免的要丢失掉信息;

到了2012年,人们发现在卷积网络中使用自动编码器做逐层预训练可以训练更加深层的网络,但是很快人们发现良好的初始化策略要比费劲的逐层预训练有效地多,2014年出现的Batch Normalization技术也是的更深的网络能够被被有效训练,到了15年底,通过残差(ResNet)我们基本可以训练任意深度的神经网络。

所以现在自动编码器主要应用有两个方面,第一是数据去噪,第二是进行可视化降维。然而自动编码器还有着一个功能就是生成数据。

我们之前讲过GAN,它与GAN相比有着一些好处,同时也有着一些缺点。我们先来讲讲其跟GAN相比有着哪些优点。

第一点,我们使用GAN来生成图片有个很不好的缺点就是我们生成图片使用的随机高斯噪声,这意味着我们并不能生成任意我们指定类型的图片,也就是说我们没办法决定使用哪种随机噪声能够产生我们想要的图片,除非我们能够把初始分布全部试一遍。但是使用自动编码器我们就能够通过输出图片的编码过程得到这种类型图片的编码之后的分布,相当于我们是知道每种图片对应的噪声分布,我们就能够通过选择特定的噪声来生成我们想要生成的图片。

第二点,这既是生成网络的优点同时又有着一定的局限性,这就是生成网络通过对抗过程来区分“真”的图片和“假”的图片,然而这样得到的图片只是尽可能像真的,但是这并不能保证图片的内容是我们想要的,换句话说,有可能生成网络尽可能的去生成一些背景图案使得其尽可能真,但是里面没有实际的物体。

  自动编码器的结构

首先我们给出自动编码器的一般结构

从上面的图中,我们能够看到两个部分,第一个部分是编码器(Encoder),第二个部分是解码器(Decoder),编码器和解码器都可以是任意的模型,通常我们使用神经网络模型作为编码器和解码器。输入的数据经过神经网络降维到一个编码(code),接着又通过另外一个神经网络去解码得到一个与输入原数据一模一样的生成数据,然后通过去比较这两个数据,最小化他们之间的差异来训练这个网络中编码器和解码器的参数。当这个过程训练完之后,我们可以拿出这个解码器,随机传入一个编码(code),希望通过解码器能够生成一个和原数据差不多的数据,上面这种图这个例子就是希望能够生成一张差不多的图片。

这件事情能不能实现呢?其实是可以的,下面我们会用PyTorch来简单的实现一个自动编码器。

首先我们构建一个简单的多层感知器来实现一下。

class autoencoder(nn.Module):
    def __init__(self):
        super(autoencoder, self).__init__()
        self.encoder = nn.Sequential(
            nn.Linear(28*28, 128),
            nn.ReLU(True),
            nn.Linear(128, 64),
            nn.ReLU(True),
            nn.Linear(64, 12),
            nn.ReLU(True),
            nn.Linear(12, 3)
        )
        self.decoder = nn.Sequential(
            nn.Linear(3, 12),
            nn.ReLU(True),
            nn.Linear(12, 64),
            nn.ReLU(True),
            nn.Linear(64, 128),
            nn.ReLU(True),
            nn.Linear(128, 28*28),
            nn.Tanh()
        )

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

这里我们定义了一个简单的4层网络作为编码器,中间使用ReLU激活函数,最后输出的维度是3维的,定义的解码器,输入三维的编码,输出一个28x28的图像数据,特别要注意最后使用的激活函数是Tanh,这个激活函数能够将最后的输出转换到-1 ~1之间,这是因为我们输入的图片已经变换到了-1~1之间了,这里的输出必须和其对应。

训练过程也比较简单,我们使用最小均方误差来作为损失函数,比较生成的图片与原始图片的每个像素点的差异。

同时我们也可以将多层感知器换成卷积神经网络,这样对图片的特征提取有着更好的效果。

class autoencoder(nn.Module):
    def __init__(self):
        super(autoencoder, self).__init__()
        self.encoder = nn.Sequential(
            nn.Conv2d(1, 16, 3, stride=3, padding=1),  # b, 16, 10, 10
            nn.ReLU(True),
            nn.MaxPool2d(2, stride=2),  # b, 16, 5, 5
            nn.Conv2d(16, 8, 3, stride=2, padding=1),  # b, 8, 3, 3
            nn.ReLU(True),
            nn.MaxPool2d(2, stride=1)  # b, 8, 2, 2
        )
        self.decoder = nn.Sequential(
            nn.ConvTranspose2d(8, 16, 3, stride=2),  # b, 16, 5, 5
            nn.ReLU(True),
            nn.ConvTranspose2d(16, 8, 5, stride=3, padding=1),  # b, 8, 15, 15
            nn.ReLU(True),
            nn.ConvTranspose2d(8, 1, 2, stride=2, padding=1),  # b, 1, 28, 28
            nn.Tanh()
        )

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

这里使用了 nn.ConvTranspose2d(),这可以看作是卷积的反操作,可以在某种意义上看作是反卷积。

我们使用卷积网络得到的最后生成的图片效果会更好,具体的图片效果我就不再这里放了,可以在我们的github上看到图片的展示。github 地址:

http://t.cn/RK5gxpM

  变分自动编码器(Variational Auto Encoder)

变分编码器是自动编码器的升级版本,其结构跟自动编码器是类似的,也由编码器和解码器构成。

回忆一下我们在自动编码器中所做的事,我们需要输入一张图片,然后将一张图片编码之后得到一个隐含向量,这比我们随机取一个随机噪声更好,因为这包含着原图片的信息,然后我们隐含向量解码得到与原图片对应的照片。

但是这样我们其实并不能任意生成图片,因为我们没有办法自己去构造隐藏向量,我们需要通过一张图片输入编码我们才知道得到的隐含向量是什么,这时我们就可以通过变分自动编码器来解决这个问题。

其实原理特别简单,只需要在编码过程给它增加一些限制,迫使其生成的隐含向量能够粗略的遵循一个标准正态分布,这就是其与一般的自动编码器最大的不同。

这样我们生成一张新图片就很简单了,我们只需要给它一个标准正态分布的随机隐含向量,这样通过解码器就能够生成我们想要的图片,而不需要给它一张原始图片先编码。

在实际情况中,我们需要在模型的准确率上与隐含向量服从标准正态分布之间做一个权衡,所谓模型的准确率就是指解码器生成的图片与原图片的相似程度。我们可以让网络自己来做这个决定,非常简单,我们只需要将这两者都做一个loss,然后在将他们求和作为总的loss,这样网络就能够自己选择如何才能够使得这个总的loss下降。另外我们要衡量两种分布的相似程度,如何看过之前一片GAN的数学推导,你就知道会有一个东西叫KL divergence来衡量两种分布的相似程度,这里我们就是用KL divergence来表示隐含向量与标准正态分布之间差异的loss,另外一个loss仍然使用生成图片与原图片的均方误差来表示。

我们可以给出KL divergence 的公式

这里变分编码器使用了一个技巧“重新参数化”来解决 KL divergence 的计算问题。

这时不再是每次产生一个隐含向量,而是生成两个向量,一个表示均值,一个表示标准差,然后通过这两个统计量来合成隐含向量,这也非常简单,用一个标准正态分布先乘上标准差再加上均值就行了,这里我们默认编码之后的隐含向量是服从一个正态分布的。这个时候我们是想让均值尽可能接近0,标准差尽可能接近1。而论文里面有详细的推导如何得到这个loss的计算公式,有兴趣的同学可以去看看具体推到过程:

https://arxiv.org/pdf/1606.05908.pdf

下面是PyTorch的实现:

reconstruction_function = nn.BCELoss(size_average=False)  # mse loss

def loss_function(recon_x, x, mu, logvar):
    """
    recon_x: generating images
    x: origin images
    mu: latent mean
    logvar: latent log variance
    """
    BCE = reconstruction_function(recon_x, x)
    # loss = 0.5 * sum(1 + log(sigma^2) - mu^2 - sigma^2)
    KLD_element = mu.pow(2).add_(logvar.exp()).mul_(-1).add_(1).add_(logvar)
    KLD = torch.sum(KLD_element).mul_(-0.5)
    # KL divergence
    return BCE + KLD

另外变分编码器除了可以让我们随机生成隐含变量,还能够提高网络的泛化能力。

最后是VAE的代码实现:

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

        self.fc1 = nn.Linear(784, 400)
        self.fc21 = nn.Linear(400, 20)
        self.fc22 = nn.Linear(400, 20)
        self.fc3 = nn.Linear(20, 400)
        self.fc4 = nn.Linear(400, 784)

    def encode(self, x):
        h1 = F.relu(self.fc1(x))
        return self.fc21(h1), self.fc22(h1)

    def reparametrize(self, mu, logvar):
        std = logvar.mul(0.5).exp_()
        if torch.cuda.is_available():
            eps = torch.cuda.FloatTensor(std.size()).normal_()
        else:
            eps = torch.FloatTensor(std.size()).normal_()
        eps = Variable(eps)
        return eps.mul(std).add_(mu)

    def decode(self, z):
        h3 = F.relu(self.fc3(z))
        return F.sigmoid(self.fc4(h3))

    def forward(self, x):
        mu, logvar = self.encode(x)
        z = self.reparametrize(mu, logvar)
        return self.decode(z), mu, logvar

VAE的结果比普通的自动编码器要好很多,下面是结果:

  

VAE的缺点也很明显,他是直接计算生成图片和原始图片的均方误差而不是像GAN那样去对抗来学习,这就使得生成的图片会有点模糊。现在已经有一些工作是将VAE和GAN结合起来,使用VAE的结构,但是使用对抗网络来进行训练,具体可以参考一下这篇论文:

https://arxiv.org/pdf/1512.09300.pdf

文中相关代码链接:

http://t.cn/RK5gxpM

英文参考:

http://t.cn/RtoJRAa

====================================分割线================================

本文作者:AI研习社

本文转自雷锋网禁止二次转载,原文链接

时间: 2024-08-02 07:33:02

深度学习自动编码器还能用于数据生成?这篇文章告诉你答案的相关文章

如何用 Caffe 生成对抗样本?这篇文章告诉你一个更高效的算法

Fast Gradient Sign方法 先回顾一下<杂谈CNN:如何通过优化求解输入图像>中通过加噪音生成对抗样本的方法,出自Christian Szegedy的论文<Intriguing properties of neural networks>: 其中n是要求的噪音,是相应的系数,L是x+n属于某个类别的loss,c是某个错误类别的标签.论文中用来得到图像噪声的办法是L-BFGS,这个方法虽然稳定有效,但是很考验算力的,Christian在Google反正机器多又强,用这个

【Science】超越深度学习300倍, Vicarious发布生成视觉模型,LeCun批“这就是AI炒作的教科书”

最近大家都在探索"超越深度学习"的方法,"美国版DeepMind" Vicarious 近日在Science上发布的一项研究,使用不同于深度学习的方法,将数据使用效率提升了300多倍,"对于未来的通用人工智能有重要意义".该研究称,使用这种新的技术,他们攻破了网站常见的验证码防御,相当于通过了"反向图灵测试".LeCun对这家公司和他们的研究提出了尖锐的批评,说"这是AI炒作教科书式的例子".不过,支持Vi

清华机器学习科学家李建:如何用深度学习来解析时空大数据?

雷锋网AI科技评论按:6月24日下午,钛媒体和杉数科技主办的2017 AI 大师论坛在京举行,论坛邀请了五位算法优化.机器学习领域的顶尖教授.学者出席并发表学术演讲,雷锋网(公众号:雷锋网)记者也对论坛进行了跟踪报道.本篇内容根据机器学习领域专家李建的论坛分享实录整理而成. 李建,清华大学交叉信息研究院助理教授.杉数科技科学家,美国马里兰大学博士.国内机器学习领域最顶尖的前沿科学家之一,国际学术会议VLDB 2009和ESA 2010最佳论文奖获得者,清华211基础研究青年人才支持计划以及教育部

深度学习进入太空,用于寻找月球登陆点

NASA收集了大量数据,但从所收集的数据中得出有用的信息却又是另外一回事了.雷锋网(公众号:雷锋网)消息,据TC报道,NASA已经开始招募像英特尔这样的科技公司,去帮助它分析数据.它的合作伙伴包括英特尔2016年收购的深度学习公司Nervana,它可以帮助将数字转化为有用的信息. 通过人工智能系统,研究人员能够分析从卫星收集的大量月球3D图像,总数据量达到了约200TB.从图像中,研究人员可生成月球的两极的地图,并详细定位出陨石坑的位置,这需要克服了因表面阴影带来的度困难. 英特尔人工智能产品部

深度学习与大数据解析

深度学习的概念于2006年提出,是机器学习研究中的一个新的领域,其动机在于建立.模拟人脑进行分析学习的神经网络,它模仿人脑的机制来解释数据,例如图像.声音和文本,已被应用于许多领域,如人脸识别.语音识别等.深度学习已成为人工智能领域研究的热点. 随着人工智能的迅速发展,通过深度学习,用计算机来模拟人的思考.推理.规划等思维过程和智能行为取得了长足进步.人工智能的重要特征就是拥有学习的能力,也就是说系统的能力会随着经验数据的积累不断演化和提升.近年来,正是得益于深度学习为大数据处理开辟了有效途径,

Enlitic创始人Jeremy Howard专访:我眼中的深度学习与数据科学

提起Jeremy Howard,人工智能和大数据领域的从业者们可谓无人不知无人不晓. 他是Enlitic.FastMail.Optimal Decisions Group三家科技公司的创始人兼CEO,是大数据竞赛平台Kaggle的前主席和首席科学家,是美国奇点大学(Singularity University)最年轻的教职工,是在2014达沃斯论坛上发表主题演讲的全球青年领袖,他在 TED 上的演讲<The wonderful and terrifying implications of com

深度学习的核心:掌握训练数据的方法

       Hello World!今天我们将讨论深度学习中最核心的问题之一:训练数据.深度学习已经在现实世界得到了广泛运用,例如:无人驾驶汽车,收据识别,道路缺陷自动检测,以及交互式电影推荐等等. 我们大部分的时间并不是花在构建神经网络上,而是处理训练数据.深度学习需要大量的数据,然而有时候仅仅标注一张图像就需要花费一个小时的时间!所以我们一直在考虑:能否找到一个方法来提升我们的工作效率?是的,我们找到了. 现在,我们很自豪的将Supervisely令人惊叹的新特性公诸于世:支持AI的标注工

专访 | 清华大学朱军:深度学习“盛行”,传统方法何去何从?

朱军博士是清华大学计算机系长聘副教授.智能技术与系统国家重点实验室副主任.卡内基梅隆大学兼职教授.2013年,入选IEEE Intelligent Systems的"人工智能10大新星"(AI's 10 to Watch).他主要从事机器学习研究,在国际重要期刊与会议发表学术论文80余篇.担任国际期刊IEEE TPAMI和Artificial Intelligence的编委.国际会议ICML 2014地区联合主席.以及ICML.NIPS等国际会议的领域主席. 清华大学计算机系长聘副教授

揭开知识库问答KB-QA的面纱5·深度学习上篇

自 2015 年开始,深度学习用于 KB-QA 的方法取得了很好的效果,并逐渐成为了 KB-QA 的主流方法.也涌现出了一批使用深度学习提升传统的语义解析.信息抽取和向量建模方法的优秀论文.本期,我们先以深度学习提升向量建模方法为例,作为深度学习篇的上篇,为大家进一步揭开知识库问答的面纱. 我们在揭开知识库问答KB-QA的面纱4·向量建模篇介绍了 KB-QA 中介绍了传统方法之一的向量建模(Vector Modeling)方法,该方法具有操作性强,不需要任何手工的特征等优点. 今天,我们将介绍一