所有关于电路
技术文章

如何使用TensorFlow构建变形式自动码器

4月6日,2020年4月通过Henry Ansah Fordjour.

学习自动编码器的关键部分,如何改进变分自动编码器,以及如何使用TensorFlow构建和训练变分自动编码器。

多年来,我们看到许多领域和行业利用人工智能(AI)的力量推动研究的界限。数据压缩和重建也不例外,其中人工智能的应用可用于构建更强大的系统。

在本文中,我们将着眼于一个非常流行的AI用自动编码器压缩数据并重构压缩数据的用例。

autoencoder应用程序

自动编码器已经引起了机器学习领域许多人的注意,通过自动编码器的改进和几种变体的发明,这一事实已经很明显。他们已经在几个领域取得了一些有前景的(如果不是最先进的)成果,例如神经机翻译,药物发现,图像去噪和其他几个。

AutoEncoder的部分

自动化器,如大多数神经网络,通过向后传播梯度来学习,以优化一组权重 - 但自身额度的架构和大多数神经网络的架构之间最引人注目的差异是瓶颈。此瓶颈是将数据压缩成较低尺寸的表示的手段。AutoEncoder的其他两个重要部分是编码器和解码器。

融合这三个部件一起形成“香草”自动化器,虽然更复杂的组件可能有一些额外的组件。

让我们单独看一下这些组件。

编码器

这是数据压缩和重构的第一阶段,它实际上负责数据压缩阶段。编码器是一个前馈神经网络,它接收数据特征(比如图像压缩时的像素)并输出一个潜在向量,其大小小于数据特征的大小。

图片由詹姆斯·大金

为了使重构数据具有鲁棒性,编码器在训练过程中优化其权值,将输入数据表示的最重要特征压缩到小型的潜在向量中。这确保解码器拥有关于输入数据的足够信息,以便以最小的损失重构数据。

潜伏载体(瓶颈)

AutoEncoder的瓶颈或潜在矢量组件是最重要的部分 - 当我们需要选择其大小时,它会变得更加重要。

编码器的输出是给我们潜在的向量的原因,并且应该持有我们输入数据的最重要的特征表示。它还用作解码器部分的输入,并将有用表示传播到解码器以进行重建。

选择一个较小的潜在向量意味着我们得到一个输入数据特征的表示,与输入数据有关的信息更少。选择一个更大的潜在向量大小在某种程度上弱化了使用自动编码器压缩的整个想法,同时也增加了计算成本。

解码器

该阶段得出了我们的数据压缩和重建过程。就像编码器一样,这个组件也是前馈神经网络,但它看起来有点与编码器不同。这种差异来自于解码器作为输入尺寸的潜伏向量比解码器的输出更小的级别。

解码器的函数是生成从非常接近输入的潜像的输出。

图片由Chiman Kwan.

培训AutoEncoders.

通常,在培训AutoEncoders中,我们将这些组件构建在一起,而不是独立构建它们。我们用优化算法如梯度下降或ADAM优化器培训他们的端到端。

损失功能

值得讨论的autoencoder培训程序的一部分是损失函数。数据重建是一项代成任务,与我们的目标是最大化预测正确类的概率的其他机器学习任务,我们驱动我们的网络以产生靠近输入的输出。

我们可以用几个损失函数来实现这个目标,比如l1, l2,均方误差,以及其他一些函数。这些损失函数的共同之处在于,它们测量输入和输出之间的差异(即,距离或相同程度),从而使它们成为合适的选择。

Autoencoder网络

一切都在,我们一直在使用多层的Perceptron为了设计我们的编码器和解码器——但事实证明,在图像数据压缩的情况下,我们可以使用更专业的框架,如卷积神经网络(CNNs),来捕捉关于输入数据的更多空间信息。

令人惊讶的是,研究表明,经常性网络用作文本数据的AutoEncoders,但我们不会在本文的范围内进入这一点。用于多层的Perceptron中使用的编码器潜在矢量解码器的概念仍然适用于卷积AutoEncoders。唯一的区别是我们使用卷积层设计解码器和编码器。

所有这些AutoEncoder网络都适用于压缩任务,但有一个问题。

我们讨论过的网络具有零创造力。我的意思是零创造力是它们只能生成他们看到或被培训的输出。

通过调整架构设计,我们可以诱导某种程度的创造力。结果称为变形性自动化器。

图片由黄德·科博辛克斯

变分Autoencoder

变型自动编码器引入了两个主要的设计变化:

  • 我们输出两个参数向量:均值和方差,而不是将输入转换为潜在编码。
  • 将额外的丢失项称为KL发散损失被添加到初始损失函数中。

变形AutoEncoder背后的想法是,我们希望我们的解码器使用由由编码器生成的平均矢量和方差向量的分布采样的潜伏向量来重建我们的数据。

来自分发的采样功能授予解码器的受控空间从。在训练变形AutoEncoder之后,每当我们执行输入数据的前进通量时,编码器会产生均衡的平均值和方差向量,用于确定从该分发来采样潜伏的载体。

平均矢量确定输入数据的编码应该居中,并且方差确定我们希望从中挑选编码的径向空间或圆圈以产生现实的输出。这意味着,对于具有相同输入数据的每个前进传递,我们的变化性AutoEncoder可以生成围绕平均矢量和方差空间内为中心的输出的不同变体。

为了比较,在查看标准的autoEncoder时,当我们尝试生成网络尚未训练的输出时,由于编码器产生的潜在矢量空间中的不连续性,它会产生不现一体的输出。

图片由Irhum shafkat.

既然我们对一个变形的autalencoder有直观的理解,让我们看看如何在Tensorflow中构建一个。

用于变分自动编码器的TensorFlow代码

我们将通过准备好我们的数据集来启动我们的示例。为简单起见,我们将使用Mnist DataSet。

(test_images, _) = tf.keras.datasets. mist .load_data()

train_images = train_images.reshape(train_images.shape [0],28,28,1).astype('float32')

test_images = test_images.reshape(test_images.shape [0],28,28,1).astype('float32')

#将图像标准化为[0,1]的范围

train_images / = 255。

test_images / = 255。

#二值化

train_images [train_images> = .5] = 1。

train_images[train_images < .5] = 0。

test_images [test_images> = .5] = 1。

test_images[test_images < .5] = 0。

TRAIN_BUF = 60000

BATCH_SIZE = 100

TEST_BUF = 10000

train_dataset = tf.data.Dataset.from_tensor_slices (train_images) .shuffle (TRAIN_BUF) .batch (BATCH_SIZE)

test_dataset = tf.data.dataset.from_tensor_slices(test_images).shuffle(test_buf).batch(batch_size)

获取数据集并为任务进行准备。

Class Cvae(TF.Keras.model):

def __init__(自我,latent_dim):

超级(CVAE自我). __init__ ()

自我。latent_dim = latent_dim

自我。inference_net = tf.keras.Sequential (

(

tf.keras.layers.InputLayer(Input_Shape =(28,28,1)),

tf.keras.layers.conv2d(

过滤器= 32,kernel_size = 3,strides =(2,2),激活='relu'),

tf.keras.layers.conv2d(

过滤器= 64,kernel_size = 3,strides =(2,2),激活='relu'),

tf.keras.layers.flatten(),

#没有激活

tf.keras.layers.dense(latent_dim + latent_dim),

]

)

self.generative_net = tf.keras.sequentient(

(

tf.keras.layers.InputLayer (input_shape = (latent_dim)),

tf.keras.layers。密度(单位= 7 * 7 * 32,激活= tf.nn.relu),

tf.keras.layers.reshape(target_shape =(7,7,32)),

tf.keras.layers.conv2dtranspose(

过滤器= 64,

kernel_size = 3,

进步= (2,2),

padding =“相同”,

激活='relu'),

tf.keras.layers.conv2dtranspose(

过滤器= 32,

kernel_size = 3,

进步= (2,2),

padding =“相同”,

激活='relu'),

#没有激活

tf.keras.layers.conv2dtranspose(

filter =1, kernel_size=3, strides=(1,1), padding="SAME"),

]

)

@tf.function

def示例(自我,每股收益= None):

如果EPS不是:

eps = tf.random.normal(shape =(100,self.latent_dim))

返回self.decode (eps、apply_sigmoid = True)

def编码(self,x):

均值,logvar = tf.split(self.inference_net(x),num_or_size_splits = 2,轴= 1)

返回的意思是,logvar

def Reparameterize(self,mean,logvar):

eps = tf.random.normal(shape = mean.shape)

返回EPS * TF.EXP(LOGVAR * .5)+均值

def解码(self,z,apply_sigmoid = false):

分对数= self.generative_net (z)

如果apply_sigmoid:

probs = tf.sigmoid(Logits)

回报probs.

返回Logits.

这两个代码片段准备了我们的数据集并构建了我们的变化性AutoEncoder模型。在模型代码片段中,有几个辅助函数来执行编码,采样和解码。

计算梯度的Reparameterization

有一个Reparameterize函数,我们还没有讨论,但解决了我们的变分性AutoEncoder网络中的一个非常重要的问题。回想一下,在解码阶段期间,我们将从由编码器生成的平均值和方差向量控制的分布中进行潜伏的向量。这在通过我们的网络前进传播数据时不会产生任何问题,但由于采样操作不可分辨地,从解码器从解码器返回到编码器时会导致大问题。

简单来说,我们无法从采样操作中计算渐变。

解决这个问题的一个好方法是应用重新参数化技巧。首先生成均值0和方差1的标准高斯分布,然后用编码器生成的均值和方差对该分布执行可微分的加法和乘法操作。

请注意,我们将差异转换为代码空间中的代码空间。这是为了确保数值稳定性。额外的损失期限,Kullback-Leibler分歧引入损失,以确保我们生成的分布尽可能接近均值为0,方差为1的标准高斯分布。

驱动分布的手段为零,确保我们生成的分布彼此非常接近,以防止分布之间的不连续性。接近1的方差意味着我们具有更温和的(即,不是非常大而不是非常小的)空间来生成从中的编码。

图片由Jeremy Jordan.

在执行Reparameterization技巧之后,通过将方差向量乘以具有标准高斯分布的差异向量和将结果添加到平均矢量而获得的分布非常类似于由平均值和方差向量控制的分布。

构建变形AutoEncoder的简单步骤

让我们通过总结构建变形AutiaceOder的步骤来包装本教程:

  1. 建立编解码器网络。
  2. 在编码器和解码器之间应用Reparameterize技巧以允许反向传播。
  3. 培训两台网络端到端。

可以找到上面使用的完整代码在官方Tensorflow网站上

精选图像修改过Chiman Kwan.