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

开发 开发工具 深度学习
很显然,深度学习即将对我们的社会产生重大显著的影响。今天我们将进一步了解深度学习的架构类型,并详细讨论自动编码器。

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

[[204722]]

继续我之前的文章《深度学习:什么&为什么?》(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):

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

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

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

使用代码示例解释 SDA

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

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

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

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

  1. class SdA(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. assert self.n_layers > 0 
  42. if not theano_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. for i in range(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. if i == 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. if i == 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. dAdA_layer = dA(numpy_rngnumpy_rng=numpy_rng,  
  32. theano_rngtheano_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. self.params.extend(self.logLayer.params)  
  7. # construct a function that implements one step of finetunining  
  8. # compute the cost for second phase of training,  
  9. # defined as the negative log likelihood  
  10. selfself.finetune_cost = self.logLayer.negative_log_likelihood(self.y) 
  11. # compute the gradients with respect to the model parameters 
  12. # symbolic variable that points to the number of errors made on the  
  13. # minibatch given by self.x and self.y  
  14. selfself.errors = self.logLayer.errors(self.y) 

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

  1. def pretraining_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. for dA in self.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. updatesupdates=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. return pretrain_fns 

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

  1. def build_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. for param, gparam in zip(self.params, gparams)  
  32.  
  33. train_fn = theano.function(  
  34. inputs=[index],  
  35. outputs=self.finetune_cost,  
  36. updatesupdates=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.  
  46. test_score_i = theano.function(  
  47. [index],  
  48. self.errors,  
  49. givens={  
  50. self.x: test_set_x[  
  51. index * batch_size: (index + 1) * batch_size  
  52. ],  
  53. self.y: test_set_y[  
  54. index * batch_size: (index + 1) * batch_size  
  55.  
  56. },  
  57.  
  58. valid_score_i = theano.function(  
  59. [index],  
  60. self.errors,  
  61. givens={  
  62. self.x: valid_set_x[  
  63. index * batch_size: (index + 1) * batch_size  
  64. ],  
  65. self.y: valid_set_y[  
  66. index * batch_size: (index + 1) * batch_size  
  67.  
  68. },  
  69.  
  70. # Create a function that scans the entire validation set  
  71. def valid_score():  
  72. return [valid_score_i(i) for i in range(n_valid_batches)]  
  73. # Create a function that scans the entire test set  
  74. def test_score(): 
  75. return [test_score_i(i) for i in range(n_test_batches)]  
  76. return train_fn, valid_score, test_score 

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

总结

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

  1. numpynumpy_rng = numpy.random.RandomState(89677)  
  2. print('... building the model')  
  3. # construct the stacked denoising autoencoder class  
  4. sda = SdA 
  5. numpy_rngnumpy_rng=numpy_rng,  
  6. n_ins=28 * 28,  
  7. hidden_layers_sizes=[1000, 1000, 1000],  
  8. n_outs=10  

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

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

  1. ######################### 
  2. # PRETRAINING THE MODEL #  
  3. #########################  
  4. print('... getting the pretraining functions')  
  5. pretraining_fns = sda.pretraining_functions(train_set_xtrain_set_x=train_set_x, 
  6. batch_sizebatch_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. for i in range(sda.n_layers):  
  12. # go through pretraining epochs  
  13. for epoch in range(pretraining_epochs): 
  14. # go through the training set 
  15. c = [] 
  16. for batch_index in range(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

【本文是51CTO专栏机构“机器之心”的原创译文,微信公众号“机器之心( id: almosthuman2014)”】

 

戳这里,看该作者更多好文

责任编辑:赵宁宁 来源: 51CTO专栏
相关推荐

2017-07-10 13:45:33

自动编码数据生成GAN

2019-05-22 17:34:16

代码开发工具

2021-03-29 11:37:50

人工智能深度学习

2021-03-22 10:52:13

人工智能深度学习自编码器

2021-12-17 10:09:47

编码器语言模型DeepMind

2017-08-16 21:58:05

自动编码器DeepCoder深度学习

2022-02-14 10:16:29

AI模型编码

2022-04-02 21:46:27

深度学习编码器图像修复

2022-03-02 13:44:10

3D模型数据

2017-12-26 10:48:37

深度学习原始数据

2021-11-02 20:44:47

数字化

2012-04-10 16:55:22

PowerSmart编码器

2012-04-01 16:40:45

编码器

2023-04-25 21:36:07

火山引擎

2020-07-03 08:45:26

神经网络结构

2023-03-28 16:05:01

2020-07-01 09:08:55

神经网络深度学习网络

2023-08-30 14:31:03

点赞
收藏

51CTO技术栈公众号