深度学习:自动编码器基础和类型

深度学习:自动编码器基础和类型本文转载自《机器之心》,原文链接:https://mp.weixin.qq.com/s/QuDa__mi1NX1wOxo5Ki94A,如有侵权请联系删除。很显然,深度学习即将对我们的社会产生重大显著的影响。Mobibit创始人兼CEOPramodChandrayan近日在codeburst.io上发文对自动编码器的基础知识和类型进行了介绍并给出了代码实例。机器之心对本文进行了…

大家好,又见面了,我是你们的朋友全栈君。

本文转载自《机器之心》,原文链接:https://mp.weixin.qq.com/s/QuDa__mi1NX1wOxo5Ki94A ,如有侵权请联系删除。

很显然,深度学习即将对我们的社会产生重大显著的影响。Mobibit 创始人兼 CEO Pramod Chandrayan 近日在 codeburst.io 上发文对自动编码器的基础知识和类型进行了介绍并给出了代码实例。机器之心对本文进行了编译。
在这里插入图片描述

继续我之前的文章《深度学习:什么&为什么?》(https://goo.gl/Ka3YoF),今天我们将进一步了解深度学习的架构类型,并详细讨论自动编码器。

当人类大脑与深度学习机器合作时:
在这里插入图片描述

在我们开始揭秘深度网络之前,让我们先定义一下深度学习。根据我的理解:

深度学习是一种先进的机器学习技术,其中存在多个彼此通信的抽象层,每一层都与前一层深度相连,并根据前一层馈送的输出进行决策。」

Investopedia 将深度学习定义成:

深度学习是人工智能(AI)领域中机器学习中的一个子集,其有网络状的结构,可以从非结构化或无标记的数据中以无监督的方式学习。也被称为深度神经学习或深度神经网络。」

今天我们将深入解读无监督预训练网络(Unsupervised Pertained Networks)的工作方式。

一、UPN:无监督预训练网络

这种无监督学习网络可以进一步分类成

  • 自动编码器
  • 深度信念网络(DBN)
  • 生成对抗网络(GAN)

自动编码器是一种有三层的神经网络:输入层、隐藏层(编码层)和解码层。该网络的目的是重构其输入,使其隐藏层学习到该输入的良好表征。

自动编码器神经网络是一种无监督机器学习算法,其应用了反向传播,可将目标值设置成与输入值相等。自动编码器的训练目标是将输入复制到输出。在内部,它有一个描述用于表征其输入的代码的隐藏层。
在这里插入图片描述

自动编码器的目标是学习函数 h(x)≈x。换句话说,它要学习一个近似的恒等函数,使得输出 x^ 近似等于输入 x。自动编码器属于神经网络家族,但它们也和 PCA(主成分分析)紧密相关。

关于自动编码器的一些关键事实:

  • 它是一种类似于 PCA 的无监督机器学习算法
  • 它要最小化和 PCA 一样的目标函数
  • 它是一种神经网络
  • 这种神经网络的目标输出就是其输入

尽管自动编码器与 PCA 很相似,但自动编码器比 PCA 灵活得多。在编码过程中,自动编码器既能表征线性变换,也能表征非线性变换;而 PCA 只能执行线性变换。因为自动编码器的网络表征形式,所以可将其作为层用于构建深度学习网络。

自动编码器的类型:

  1. 去噪自动编码器
  2. 稀疏自动编码器
  3. 变分自动编码器(VAE)
  4. 收缩自动编码器(CAE/contractive autoencoder)

1.1、A. 去噪自动编码器

这是最基本的一种自动编码器,它会随机地部分采用受损的输入来解决恒等函数风险,使得自动编码器必须进行恢复或去噪。

这项技术可用于得到输入的良好表征。良好的表征是指可以从受损的输入稳健地获得的表征,该表征可被用于恢复其对应的无噪声输入。

去噪自动编码器背后的思想很简单。为了迫使隐藏层发现更加稳健的特征并且为了防止其只是学习其中的恒等关系,我们在训练自动编码器时会让其从受损的版本中重建输入。

应用在输入上的噪声量以百分比的形式呈现。一般来说,30% 或 0.3 就很好,但如果你的数据非常少,你可能就需要考虑增加更多噪声。

1.2、堆叠的去噪自动编码器(SDA):
在这里插入图片描述

这是一种在层上使用了无监督预训练机制的去噪自编码器,其中当一层被预训练用于在之前层的输入上执行特征选择和特征提取后,后面会跟上一个监督式的微调(fine-tuning)阶段。SDA 只是将很多个去噪自动编码器融合在了一起。一旦前面 k 层训练完成,我们就可以训练第 k+1 层,因为我们现在可以根据下面的层计算代码或隐含表征。

一旦所有层都预训练完成,网络就会进入一个被称为微调的阶段。在这里我们会为微调使用监督学习机制,以最小化被监督任务上的预测误差。然后,我们以训练多层感知器的方式训练整个网络。在这个阶段,我们仅考虑每个自动编码器的编码部分。这个阶段是有监督的,自此以后我们就在训练中使用目标类别了。

1.3、使用代码示例解释 SDA

这一节源自 deeplearning.net(对于想要理解深度学习的人来说,这个网站提供了很好的参考),其中使用案例对堆叠的去噪自动编码器进行了很好的解释。

我们可以以两种方式看待堆叠的去噪自动编码器:一是自动编码器列表,二是多层感知器(MLP)。在预训练过程中,我们使用了第一种方式,即我们将我们的模型看作是一组自动编码器列表,并分开训练每个自动编码器。在第二个训练阶段,我们使用第二种方式。这两种方式是有联系的,因为:

  • 自动编码器和 MLP 的 sigmoid 层共享参数;
  • MLP 的中间层计算出的隐含表征被用作自动编码器的输入。
class SdA(object):
   """Stacked denoising auto-encoder class (SdA) A stacked denoising autoencoder model is obtained by stacking several dAs. The hidden layer of the dA at layer `i` becomes the input of the dA at layer `i+1`. The first layer dA gets as input the input of the SdA, and the hidden layer of the last dA represents the output. Note that after pretraining, the SdA is dealt with as a normal MLP, the dAs are only used to initialize the weights. """
   def __init__(
       self,
       numpy_rng,
       theano_rng=None,
       n_ins=784,
       hidden_layers_sizes=[500, 500],
       n_outs=10,
       corruption_levels=[0.1, 0.1]
   ):
       """ This class is made to support a variable number of layers. :type numpy_rng: numpy.random.RandomState :param numpy_rng: numpy random number generator used to draw initial weights :type theano_rng: theano.tensor.shared_randomstreams.RandomStreams :param theano_rng: Theano random generator; if None is given one is generated based on a seed drawn from `rng` :type n_ins: int :param n_ins: dimension of the input to the sdA :type hidden_layers_sizes: list of ints :param hidden_layers_sizes: intermediate layers size, must contain at least one value :type n_outs: int :param n_outs: dimension of the output of the network :type corruption_levels: list of float :param corruption_levels: amount of corruption to use for each layer """
       self.sigmoid_layers = []
       self.dA_layers = []
       self.params = []
       self.n_layers = len(hidden_layers_sizes)
       assert self.n_layers > 0
       if not theano_rng:
       theano_rng = RandomStreams(numpy_rng.randint(2 ** 30))
       # allocate symbolic variables for the data
       self.x = T.matrix('x')   # the data is presented as rasterized images
       self.y = T.ivector('y')  # the labels are presented as 1D vector of
                                # [int] labels

self.sigmoid_layers 将会存储 MLP 形式的 sigmoid 层,而 self.dA_layers 将会存储与该 MLP 层关联的去噪自动编码器。接下来,我们构建 n_layers sigmoid 层和 n_layers 去噪自动编码器,其中 n_layers 是我们的模型的深度。我们使用了多层感知器中引入的 HiddenLayer 类,但有一项修改:我们将 tanh 非线性替换成了 logistic 函数


在这里插入图片描述

我们链接了 sigmoid 层来构建一个 MLP,而且我们在构建自动编码器时使得每个自动编码器的编码部分都与其对应的 sigmoid 层共享权重矩阵和偏置。


for i in range(self.n_layers):
           # construct the sigmoidal layer
           # the size of the input is either the number of hidden units of
           # the layer below or the input size if we are on the first layer
           if i == 0:
               input_size = n_ins
           else:
               input_size = hidden_layers_sizes[i - 1]
           # the input to this layer is either the activation of the hidden
           # layer below or the input of the SdA if you are on the first
           # layer
           if i == 0:
               layer_input = self.x
           else:
               layer_input = self.sigmoid_layers[-1].output
           sigmoid_layer = HiddenLayer(rng=numpy_rng,input=layer_input,n_in=input_size,n_out=hidden_layers_sizes[i],activation=T.nnet.sigmoid)
           # add the layer to our list of layers
           self.sigmoid_layers.append(sigmoid_layer)
           # its arguably a philosophical question...
           # but we are going to only declare that the parameters of the
           # sigmoid_layers are parameters of the StackedDAA
           # the visible biases in the dA are parameters of those
           # dA, but not the SdA
           self.params.extend(sigmoid_layer.params)
           # Construct a denoising autoencoder that shared weights with this
           # layer
           dA_layer = dA(numpy_rng=numpy_rng,theano_rng=theano_rng,input=layer_input,n_visible=input_size,n_hidden=hidden_layers_sizes[i],W=sigmoid_layer.W,bhid=sigmoid_layer.b)
           self.dA_layers.append(dA_layer)

现在我们只需要在这个 sigmoid 层上添加一个 logistic 层即可,这样我们就有了一个 MLP。我们将使用 LogisticRegression 类,这个类是在使用 logistic 回归分类 MNIST 数字时引入的。

# We now need to add a logistic layer on top of the MLP
       self.logLayer = LogisticRegression(
           input=self.sigmoid_layers[-1].output,
           n_in=hidden_layers_sizes[-1],
           n_out=n_outs
       )
       self.params.extend(self.logLayer.params)
       # construct a function that implements one step of finetunining
       # compute the cost for second phase of training,
       # defined as the negative log likelihood
       self.finetune_cost = self.logLayer.negative_log_likelihood(self.y)
       # compute the gradients with respect to the model parameters
       # symbolic variable that points to the number of errors made on the
       # minibatch given by self.x and self.y
       self.errors = self.logLayer.errors(self.y)

SdA 类也提供了一种为其层中的去噪自动编码器生成训练函数的方法。它们会作为一个列表返回,其中元素 i 是一个函数——该函数实现了训练对应于第 i 层的 dA 的步骤。

def pretraining_functions(self, train_set_x, batch_size):
       ''' Generates a list of functions, each of them implementing one step in trainnig the dA corresponding to the layer with same index. The function will require as input the minibatch index, and to train a dA you just need to iterate, calling the corresponding function on all minibatch indexes. :type train_set_x: theano.tensor.TensorType :param train_set_x: Shared variable that contains all datapoints used for training the dA :type batch_size: int :param batch_size: size of a [mini]batch :type learning_rate: float :param learning_rate: learning rate used during training for any of the dA layers '''
       # index to a [mini]batch
       index = T.lscalar('index')  # index to a minibatch

为了修改训练过程中的受损水平或学习率,我们将它们与 Theano 变量联系了起来。

corruption_level = T.scalar('corruption')  # % of corruption to use
       learning_rate = T.scalar('lr')  # learning rate to use
       # begining of a batch, given `index`
       batch_begin = index * batch_size
       # ending of a batch given `index`
       batch_end = batch_begin + batch_size
       pretrain_fns = []
       for dA in self.dA_layers:
           # get the cost and the updates list
           cost, updates = dA.get_cost_updates(corruption_level,learning_rate)
           # compile the theano function
           fn = theano.function(
               inputs=[
                   index,
                   theano.In(corruption_level, value=0.2),
                   theano.In(learning_rate, value=0.1)
               ],
               outputs=cost,
               updates=updates,
               givens={ 
   
                   self.x: train_set_x[batch_begin: batch_end]
               }
           )
           # append `fn` to the list of functions
           pretrain_fns.append(fn)
       return pretrain_fns

现在任意 pretrain_fns[i] 函数都可以使用索引参数了,可选的有 corruption(受损水平)或 lr(学习率)。注意这些参数名是在它们被构建时赋予 Theano 变量的名字,而不是 Python 变量(learning_rate 或 corruption_level)的名字。在使用 Theano 时一定要记住这一点。我们用同样的方式构建了用于构建微调过程中所需函数的方法(train_fn、valid_score 和 test_score)。

def build_finetune_functions(self, datasets, batch_size, learning_rate):
       '''Generates a function `train` that implements one step of finetuning, a function `validate` that computes the error on a batch from the validation set, and a function `test` that computes the error on a batch from the testing set :type datasets: list of pairs of theano.tensor.TensorType :param datasets: It is a list that contain all the datasets; the has to contain three pairs, `train`, `valid`, `test` in this order, where each pair is formed of two Theano variables, one for the datapoints, the other for the labels :type batch_size: int :param batch_size: size of a minibatch :type learning_rate: float :param learning_rate: learning rate used during finetune stage '''
       (train_set_x, train_set_y) = datasets[0]
       (valid_set_x, valid_set_y) = datasets[1]
       (test_set_x, test_set_y) = datasets[2]
       # compute number of minibatches for training, validation and testing
       n_valid_batches = valid_set_x.get_value(borrow=True).shape[0]
       n_valid_batches //= batch_size
       n_test_batches = test_set_x.get_value(borrow=True).shape[0]
       n_test_batches //= batch_size
       index = T.lscalar('index')  # index to a [mini]batch
       # compute the gradients with respect to the model parameters
       gparams = T.grad(self.finetune_cost, self.params)
       # compute list of fine-tuning updates
       updates = [
           (param, param - gparam * learning_rate)
           for param, gparam in zip(self.params, gparams)
       ]
       train_fn = theano.function(
           inputs=[index],
           outputs=self.finetune_cost,
           updates=updates,
           givens={ 
   
              self.x: train_set_x[
                   index * batch_size: (index + 1) * batch_size
               ],
               self.y: train_set_y[
                   index * batch_size: (index + 1) * batch_size
               ]
           },
           name='train'
       )
       test_score_i = theano.function(
           [index],
           self.errors,
           givens={ 
   
               self.x: test_set_x[
                   index * batch_size: (index + 1) * batch_size
               ],
               self.y: test_set_y[
                   index * batch_size: (index + 1) * batch_size
               ]
           },
           name='test'
       )
       valid_score_i = theano.function(
           [index],
           self.errors,
           givens={ 
   
               self.x: valid_set_x[
                   index * batch_size: (index + 1) * batch_size
               ],
               self.y: valid_set_y[
                   index * batch_size: (index + 1) * batch_size
               ]
           },
           name='valid'
       )
       # Create a function that scans the entire validation set
       def valid_score():
           return [valid_score_i(i) for i in range(n_valid_batches)]
       # Create a function that scans the entire test set
       def test_score():
           return [test_score_i(i) for i in range(n_test_batches)]
       return train_fn, valid_score, test_score

注意,valid_score 和 test_score 并不是 Theano 函数,而是分别在整个验证集和整个测试集上循环的 Python 函数,可以在这些集合上产生一个损失列表。

总结

下面给出的几行代码就构建了一个堆叠的去噪自动编码器:

numpy_rng = numpy.random.RandomState(89677)
   print('... building the model')
   # construct the stacked denoising autoencoder class
   sda = SdA(
       numpy_rng=numpy_rng,
       n_ins=28 * 28,
       hidden_layers_sizes=[1000, 1000, 1000],
       n_outs=10
   )

该网络的训练分两个阶段:逐层的预训练,之后是微调。

对于预训练阶段,我们将在网络的所有层上进行循环。对于每个层,我们都将使用编译过的实现 SGD 步骤的函数,以优化权重,从而降低该层的重构成本。这个函数将根据 pretraining_epochs 在训练集上执行固定数量的 epoch。

#########################
   # PRETRAINING THE MODEL #
   #########################
   print('... getting the pretraining functions')
   pretraining_fns = sda.pretraining_functions(train_set_x=train_set_x,batch_size=batch_size)
   print('... pre-training the model')
   start_time = timeit.default_timer()
   ## Pre-train layer-wise
   corruption_levels = [.1, .2, .3]
   for i in range(sda.n_layers):
       # go through pretraining epochs
       for epoch in range(pretraining_epochs):
           # go through the training set
           c = []
           for batch_index in range(n_train_batches):
               c.append(pretraining_fns[i](index=batch_index,
                        corruption=corruption_levels[i],
                        lr=pretrain_lr))
           print('Pre-training layer %i, epoch %d, cost %f' % (i, epoch, numpy.mean(c, dtype='float64')))
   end_time = timeit.default_timer()
   print(('The pretraining code for file ' +
          os.path.split(__file__)[1] +
          ' ran for %.2fm' % ((end_time - start_time) / 60.)), file=sys.stderr)

这里的微调循环和多层感知器中的微调过程很相似。唯一的区别是它使用了 build_finetune_functions 给出的函数。

执行代码

用户可以通过调用以下 Python CLI 来运行该代码:

python code/SdA.py

默认情况下,该代码会为每一层运行 15 次预训练 epoch,其批大小为 1。第一层的受损水平为 0.1,第二层为 0.2,第三层为 0.3。预训练的学习率为 0.001,微调学习率为 0.1。预训练耗时 585.01 分钟,每 epoch 平均 13 分钟。微调经历了 36 epoch,耗时 444.2 分钟,每 epoch 平均 12.34 分钟。最后的验证分数是 1.39%,测试分数是 1.3%。这些结果是在配置了 Intel Xeon E5430 @ 2.66GHz CPU 的机器上得到的,它有单线程的 GotoBLAS

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-用户IM,转载请注明出处:https://javaforall.cn/136351.html原文链接:https://javaforall.cn

【正版授权,激活自己账号】: Jetbrains全家桶Ide使用,1年售后保障,每天仅需1毛

【官方授权 正版激活】: 官方授权 正版激活 支持Jetbrains家族下所有IDE 使用个人JB账号...

(0)


相关推荐

  • intellij idea 激活码2099【2022最新】

    (intellij idea 激活码2099)这是一篇idea技术相关文章,由全栈君为大家提供,主要知识点是关于2021JetBrains全家桶永久激活码的内容IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.cn/100143.htmlCJM5ZJBPHS-eyJsa…

  • LAMP搭建和配置

    LAMP搭建和配置LAMP搭建和配置LAMP是由Linux,Apache,MySQL,PHP组成的,即把Apache、MySQL以及PHP安装在Linux系统上,组成一个环境来运行PHP的脚本语言。Apache是最常用的Web服务软件,而MySQL是比较小型的数据库软件。三个角色可以安装在一台机器上,也可以分开(但httpd和php要在一起的)为什么需要LAMP?手动逐个编译安装各个组件,需要输入各种命令,且有可能会中途出错。对于想要成功搭建LAMP建站环境来说,可以节约大量时间和精力。LAMP有什么

  • URL 字符编码建议收藏

    URL编码会将字符转换为可通过因特网传输的格式。URL-统一资源定位器Web浏览器通过URL从web服务器请求页面。URL是网页的地址,比如http://www.cnblogs.co

    2021年12月20日
  • @Transactional作用(成像原理)

    事务主要保证了数据操作的原子性,一致性,隔离性和持久性。事务不会跨线程传播,事务不能跨数据源。

  • DIY 手动制作自己的win pe

    DIY 手动制作自己的win pe首先,写在前面的话,从网上下载的winpe用着总是觉得不安心(。。。),在然后自己做的pe可以封装进去自己常用的工具。准备1,在MSDN我告诉你上面下载win764sp1的安装包。2,EasyBoot和UltraISO。这两个工具自己去官网下载。注册的话,自己百度注册#码。3,imagex工具,(这个工具应该是在windowAIK里面)。我这用的是一个64位的程序。(…

  • 华三路由交换配置命令_H3C路由器常用基本配置命令「建议收藏」

    华三路由交换配置命令_H3C路由器常用基本配置命令「建议收藏」H3C路由器常用基本配置命令[Quidway]sysnamerouter_name命名路由器(或交换机)[Quidway]delete删除FlashROM中的配置[Quidway]save将配置写入FlashROM[Quidway]interfaceserial0进入接口配置模式[Quidway]quit退出接口模式到系统视图[Quidway]shutdown/undoshutdown…

    2022年10月17日

发表回复

您的电子邮箱地址不会被公开。

关注全栈程序员社区公众号