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

雷锋网 2017-07-10 12:49
分享到:
导读

但是使用自动编码器我们就能够通过输出图片的编码过程得到这种类型图片的编码之后的分布,这样通过解码器就能够生成我们想要的图片,然而自动编码器还有着一个功能就是生成数据。

什么是自动编码器自动编码器(AutoEncoder)最开始作为一种数据的压缩方法,其特点有: 跟数据相关程度很高,这意味着自动编码器只能压缩与训练数据相似的数据,这个其实比较显然,因为使用神经网络提取的特征一般是高度相关于原始的训练集,使用人脸训练出

   什么是自动编码器自动编码器(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 地址:

  5GxpM

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

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

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

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

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

图片 编码器 自动 生成 网络
分享到:

1.TMT观察网遵循行业规范,任何转载的稿件都会明确标注作者和来源;
2.TMT观察网的原创文章,请转载时务必注明文章作者和"来源:TMT观察网",不尊重原创的行为TMT观察网或将追究责任;
3.作者投稿可能会经TMT观察网编辑修改或补充。


观点约架