你好,游客 登录
背景:
阅读新闻

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

[日期:2017-09-25] 来源:机器之心  作者: [字体: ]

很显然,深度学习即将对我们的社会产生重大显著的影响。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)

A. 去噪自动编码器

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

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

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

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

堆叠的去噪自动编码器(SDA):

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

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

使用代码示例解释 SDA

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

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

  • 自动编码器和 MLP 的 sigmoid 层共享参数;

  • MLP 的中间层计算出的隐含表征被用作自动编码器的输入。

  1. classSdA(object):

  2. """Stacked denoising auto-encoder class (SdA)

  3. A stacked denoising autoencoder model is obtained by stacking several

  4. dAs. The hidden layer of the dA at layer `i` becomes the input of

  5. the dA at layer `i+1`. The first layer dA gets as input the input of

  6. the SdA, and the hidden layer of the last dA represents the output.

  7. Note that after pretraining, the SdA is dealt with as a normal MLP,

  8. the dAs are only used to initialize the weights.

  9. """

  10. def__init__(

  11. self,

  12. numpy_rng,

  13. theano_rng=None,

  14. n_ins=784,

  15. hidden_layers_sizes=[500,500],

  16. n_outs=10,

  17. corruption_levels=[0.1,0.1]

  18. ):

  19. """ This class is made to support a variable number of layers.

  20. :type numpy_rng: numpy.random.RandomState

  21. :param numpy_rng: numpy random number generator used to draw initial

  22. weights

  23. :type theano_rng: theano.tensor.shared_randomstreams.RandomStreams

  24. :param theano_rng: Theano random generator; if None is given one is

  25. generated based on a seed drawn from `rng`

  26. :type n_ins: int

  27. :param n_ins: dimension of the input to the sdA

  28. :type hidden_layers_sizes: list of ints

  29. :param hidden_layers_sizes: intermediate layers size, must contain

  30. at least one value

  31. :type n_outs: int

  32. :param n_outs: dimension of the output of the network

  33. :type corruption_levels: list of float

  34. :param corruption_levels: amount of corruption to use for each

  35. layer

  36. """

  37. self.sigmoid_layers =[]

  38. self.dA_layers =[]

  39. self.params =[]

  40. self.n_layers =len(hidden_layers_sizes)

  41. assertself.n_layers >0

  42. ifnottheano_rng:

  43. theano_rng =RandomStreams(numpy_rng.randint(2**30))

  44. # allocate symbolic variables for the data

  45. self.x =T.matrix('x')# the data is presented as rasterized images

  46. self.y =T.ivector('y')# the labels are presented as 1D vector of

  47. # [int] labels

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

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

  1. fori inrange(self.n_layers):

  2. # construct the sigmoidal layer

  3. # the size of the input is either the number of hidden units of

  4. # the layer below or the input size if we are on the first layer

  5. ifi ==0:

  6. input_size =n_ins

  7. else:

  8. input_size =hidden_layers_sizes[i -1]

  9. # the input to this layer is either the activation of the hidden

  10. # layer below or the input of the SdA if you are on the first

  11. # layer

  12. ifi ==0:

  13. layer_input =self.x

  14. else:

  15. layer_input =self.sigmoid_layers[-1].output

  16. sigmoid_layer =HiddenLayer(rng=numpy_rng,

  17. input=layer_input,

  18. n_in=input_size,

  19. n_out=hidden_layers_sizes[i],

  20. activation=T.nnet.sigmoid)

  21. # add the layer to our list of layers

  22. self.sigmoid_layers.append(sigmoid_layer)

  23. # its arguably a philosophical question...

  24. # but we are going to only declare that the parameters of the

  25. # sigmoid_layers are parameters of the StackedDAA

  26. # the visible biases in the dA are parameters of those

  27. # dA, but not the SdA

  28. self.params.extend(sigmoid_layer.params)

  29. # Construct a denoising autoencoder that shared weights with this

  30. # layer

  31. dA_layer =dA(numpy_rng=numpy_rng,

  32. theano_rng=theano_rng,

  33. input=layer_input,

  34. n_visible=input_size,

  35. n_hidden=hidden_layers_sizes[i],

  36. W=sigmoid_layer.W,

  37. bhid=sigmoid_layer.b)

  38. self.dA_layers.append(dA_layer)

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

  1. # We now need to add a logistic layer on top of the MLP

  2. self.logLayer =LogisticRegression(

  3. input=self.sigmoid_layers[-1].output,

  4. n_in=hidden_layers_sizes[-1],

  5. n_out=n_outs

  6. )

  7. self.params.extend(self.logLayer.params)

  8. # construct a function that implements one step of finetunining

  9. # compute the cost for second phase of training,

  10. # defined as the negative log likelihood

  11. self.finetune_cost =self.logLayer.negative_log_likelihood(self.y)

  12. # compute the gradients with respect to the model parameters

  13. # symbolic variable that points to the number of errors made on the

  14. # minibatch given by self.x and self.y

  15. self.errors =self.logLayer.errors(self.y)

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

  1. defpretraining_functions(self,train_set_x,batch_size):

  2. ''' Generates a list of functions, each of them implementing one

  3. step in trainnig the dA corresponding to the layer with same index.

  4. The function will require as input the minibatch index, and to train

  5. a dA you just need to iterate, calling the corresponding function on

  6. all minibatch indexes.

  7. :type train_set_x: theano.tensor.TensorType

  8. :param train_set_x: Shared variable that contains all datapoints used

  9. for training the dA

  10. :type batch_size: int

  11. :param batch_size: size of a [mini]batch

  12. :type learning_rate: float

  13. :param learning_rate: learning rate used during training for any of

  14. the dA layers

  15. '''

  16. # index to a [mini]batch

  17. index =T.lscalar('index')# index to a minibatch

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

  1. corruption_level =T.scalar('corruption')# % of corruption to use

  2. learning_rate =T.scalar('lr')# learning rate to use

  3. # begining of a batch, given `index`

  4. batch_begin =index *batch_size

  5. # ending of a batch given `index`

  6. batch_end =batch_begin +batch_size

  7. pretrain_fns =[]

  8. fordA inself.dA_layers:

  9. # get the cost and the updates list

  10. cost,updates =dA.get_cost_updates(corruption_level,

  11. learning_rate)

  12. # compile the theano function

  13. fn =theano.function(

  14. inputs=[

  15. index,

  16. theano.In(corruption_level,value=0.2),

  17. theano.In(learning_rate,value=0.1)

  18. ],

  19. outputs=cost,

  20. updates=updates,

  21. givens={

  22. self.x:train_set_x[batch_begin:batch_end]

  23. }

  24. )

  25. # append `fn` to the list of functions

  26. pretrain_fns.append(fn)

  27. returnpretrain_fns

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

  1. defbuild_finetune_functions(self,datasets,batch_size,learning_rate):

  2. '''Generates a function `train` that implements one step of

  3. finetuning, a function `validate` that computes the error on

  4. a batch from the validation set, and a function `test` that

  5. computes the error on a batch from the testing set

  6. :type datasets: list of pairs of theano.tensor.TensorType

  7. :param datasets: It is a list that contain all the datasets;

  8. the has to contain three pairs, `train`,

  9. `valid`, `test` in this order, where each pair

  10. is formed of two Theano variables, one for the

  11. datapoints, the other for the labels

  12. :type batch_size: int

  13. :param batch_size: size of a minibatch

  14. :type learning_rate: float

  15. :param learning_rate: learning rate used during finetune stage

  16. '''

  17. (train_set_x,train_set_y)=datasets[0]

  18. (valid_set_x,valid_set_y)=datasets[1]

  19. (test_set_x,test_set_y)=datasets[2]

  20. # compute number of minibatches for training, validation and testing

  21. n_valid_batches =valid_set_x.get_value(borrow=True).shape[0]

  22. n_valid_batches //=batch_size

  23. n_test_batches =test_set_x.get_value(borrow=True).shape[0]

  24. n_test_batches //=batch_size

  25. index =T.lscalar('index')# index to a [mini]batch

  26. # compute the gradients with respect to the model parameters

  27. gparams =T.grad(self.finetune_cost,self.params)

  28. # compute list of fine-tuning updates

  29. updates =[

  30. (param,param -gparam *learning_rate)

  31. forparam,gparam inzip(self.params,gparams)

  32. ]

  33. train_fn =theano.function(

  34. inputs=[index],

  35. outputs=self.finetune_cost,

  36. updates=updates,

  37. givens={

  38. self.x:train_set_x[

  39. index *batch_size:(index +1)*batch_size

  40. ],

  41. self.y:train_set_y[

  42. index *batch_size:(index +1)*batch_size

  43. ]

  44. },

  45. name='train'

  46. )

  47. test_score_i =theano.function(

  48. [index],

  49. self.errors,

  50. givens={

  51. self.x:test_set_x[

  52. index *batch_size:(index +1)*batch_size

  53. ],

  54. self.y:test_set_y[

  55. index *batch_size:(index +1)*batch_size

  56. ]

  57. },

  58. name='test'

  59. )

  60. valid_score_i =theano.function(

  61. [index],

  62. self.errors,

  63. givens={

  64. self.x:valid_set_x[

  65. index *batch_size:(index +1)*batch_size

  66. ],

  67. self.y:valid_set_y[

  68. index *batch_size:(index +1)*batch_size

  69. ]

  70. },

  71. name='valid'

  72. )

  73. # Create a function that scans the entire validation set

  74. defvalid_score():

  75. return[valid_score_i(i)fori inrange(n_valid_batches)]

  76. # Create a function that scans the entire test set

  77. deftest_score():

  78. return[test_score_i(i)fori inrange(n_test_batches)]

  79. returntrain_fn,valid_score,test_score

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

总结

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

  1. numpy_rng =numpy.random.RandomState(89677)

  2. print('... building the model')

  3. # construct the stacked denoising autoencoder class

  4. sda =SdA(

  5. numpy_rng=numpy_rng,

  6. n_ins=28*28,

  7. hidden_layers_sizes=[1000,1000,1000],

  8. n_outs=10

  9. )

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

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

  1. #########################

  2. # PRETRAINING THE MODEL #

  3. #########################

  4. print('... getting the pretraining functions')

  5. pretraining_fns =sda.pretraining_functions(train_set_x=train_set_x,

  6. batch_size=batch_size)

  7. print('... pre-training the model')

  8. start_time =timeit.default_timer()

  9. ## Pre-train layer-wise

  10. corruption_levels =[.1,.2,.3]

  11. fori inrange(sda.n_layers):

  12. # go through pretraining epochs

  13. forepoch inrange(pretraining_epochs):

  14. # go through the training set

  15. c =[]

  16. forbatch_index inrange(n_train_batches):

  17. c.append(pretraining_fns[i](index=batch_index,

  18. corruption=corruption_levels[i],

  19. lr=pretrain_lr))

  20. print('Pre-training layer %i, epoch %d, cost %f'%(i,epoch,numpy.mean(c,dtype='float64')))

  21. end_time =timeit.default_timer()

  22. print(('The pretraining code for file '+

  23. os.path.split(__file__)[1]+

  24. ' ran for %.2fm'%((end_time -start_time)/60.)),file=sys.stderr)

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

执行代码

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

  1. 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。 

原文链接:https://codeburst.io/deep-learning-types-and-autoencoders-a40ee6754663

收藏 推荐 打印 | 录入:Cstor | 阅读:
相关新闻      
本文评论   查看全部评论 (0)
表情: 表情 姓名: 字数
点评:
       
评论声明
  • 尊重网上道德,遵守中华人民共和国的各项有关法律法规
  • 承担一切因您的行为而直接或间接导致的民事或刑事法律责任
  • 本站管理人员有权保留或删除其管辖留言中的任意内容
  • 本站有权在网站内转载或引用您的评论
  • 参与本评论即表明您已经阅读并接受上述条款