Differences
This shows you the differences between two versions of the page.
Both sides previous revision Previous revision Next revision | Previous revision | ||
start:深度学习教程---从感知到深度网络 [2017/09/09 20:54] vanabel [自动编码器] |
start:深度学习教程---从感知到深度网络 [2019/06/27 22:37] (current) |
||
---|---|---|---|
Line 1: | Line 1: | ||
- | ====== 深度学习教程──从感知到深度网络 ====== | + | ====== 深度学习教程──从感知器到深度网络 ====== |
[[https://www.toptal.com/machine-learning/an-introduction-to-deep-learning-from-perceptrons-to-deep-networks|本文]]原作者是Java工程师**Ivan Vasilev**, 同时作者也开发了[[https://github.com/ivan-vasilev/neuralnetworks|Java深度学习库]], 大家可以去点赞. 这里我将根据我的理解, 作一记录. | [[https://www.toptal.com/machine-learning/an-introduction-to-deep-learning-from-perceptrons-to-deep-networks|本文]]原作者是Java工程师**Ivan Vasilev**, 同时作者也开发了[[https://github.com/ivan-vasilev/neuralnetworks|Java深度学习库]], 大家可以去点赞. 这里我将根据我的理解, 作一记录. | ||
Line 63: | Line 63: | ||
> 一系列线性函数的线性复合还是线性函数,故大多数的神经网络用的是非线性激活函数。 | > 一系列线性函数的线性复合还是线性函数,故大多数的神经网络用的是非线性激活函数。 | ||
- | 正因为如此,大多数神经网络使用非线性的激活函数,例如[logistic](https://en.wikipedia.org/wiki/Sigmoid_function)函数、[tanh](https://en.wikipedia.org/wiki/Tanh)函数、[binary](https://en.wikipedia.org/wiki/Artificial_neuron#Step_function)函数或者[rectifier](https://en.wikipedia.org/wiki/Rectified_linear_unit)函数。如果不用非线性函数,那么神经网络只能学习其输入的线性组合这类函数。 | + | 正因为如此,大多数神经网络使用非线性的激活函数,例如[[wp>Sigmoid_function|Logistic函数]]、[[wp>Tanh|tanh函数]]、[[wp>Artificial_neuron#Step_function| binary函数]]或者[[wp>Rectified_linear_unit|rectifier函数]]。如果不用非线性函数,那么神经网络只能学习其输入的线性组合这类函数。 |
==== 感知器的训练 ==== | ==== 感知器的训练 ==== | ||
有监督训练多层感知器的深度学习中最常见的算法是所谓的反向传播算法(backpropagation)。其基本过程是: | 有监督训练多层感知器的深度学习中最常见的算法是所谓的反向传播算法(backpropagation)。其基本过程是: | ||
Line 74: | Line 73: | ||
$$ | $$ | ||
其中$t$是目标向量而$y$是实际的输出向量。当然,也可以使用其他的误差,但标准差是一个很好的选择。 | 其中$t$是目标向量而$y$是实际的输出向量。当然,也可以使用其他的误差,但标准差是一个很好的选择。 | ||
- | 3. 利用[随机负向梯度流](https://en.wikipedia.org/wiki/Stochastic_gradient_descent)的方法来最小化神经网络的误差。 | + | 3. 利用[[wp>Stochastic_gradient_descent|随机负向梯度流]]的方法来最小化神经网络的误差。 |
{{ :start:extrema_example.jpg?400 |Extrema example}} | {{ :start:extrema_example.jpg?400 |Extrema example}} | ||
负向梯度流就是通常的,但在神经网络中,它是以输入参数为自变量而以训练后输出的误差为因变量的函数。因此,每个权重的最优解就是使得取这些权重时误差达到**整体极小**。在训练阶段,权重不断的以很小的步长更新(在每个训练样本之后或者小批量的多个样本之后更新),每次更新都使得输出与目标之间的误差减小。我们应该注意,这不是一件容易的事,如上图所示,你往往会在局部极小点处结束。例如,权重的值为0.6,则此时它需要变向0.4(言外之意,极有可能变向另一个方向,此时会在1左右达到局部极小值)。 | 负向梯度流就是通常的,但在神经网络中,它是以输入参数为自变量而以训练后输出的误差为因变量的函数。因此,每个权重的最优解就是使得取这些权重时误差达到**整体极小**。在训练阶段,权重不断的以很小的步长更新(在每个训练样本之后或者小批量的多个样本之后更新),每次更新都使得输出与目标之间的误差减小。我们应该注意,这不是一件容易的事,如上图所示,你往往会在局部极小点处结束。例如,权重的值为0.6,则此时它需要变向0.4(言外之意,极有可能变向另一个方向,此时会在1左右达到局部极小值)。 | ||
Line 80: | Line 79: | ||
上图还只是最简单的情形,即误差只依赖于单一参数(权重)。一般而言,神经网络的误差依赖于每一个权重,因此实际的误差函数比上述例子复杂得多的多。 | 上图还只是最简单的情形,即误差只依赖于单一参数(权重)。一般而言,神经网络的误差依赖于每一个权重,因此实际的误差函数比上述例子复杂得多的多。 | ||
- | 正是由于反向传播算法(backpropagation)方法的引入,它使得任何两个神经元之间的权重可以基于输出误差来更新。向后传播的推导本身有些复杂,但是给定节点的权重更新却很简单: | + | 正是由于`反向传播算法`([[wp>Backpropagation|backpropagation]])方法的引入,它使得任何两个神经元之间的权重可以基于输出误差来更新。向后传播的推导本身有些复杂,但是给定节点的权重更新却很简单: |
$$ | $$ | ||
\Delta w_i=-\alpha\frac{\partial E}{\partial w_i}, | \Delta w_i=-\alpha\frac{\partial E}{\partial w_i}, | ||
Line 88: | Line 87: | ||
本质上,我们的目的是沿着权重$i$的梯度方向移动。这里的关键词是,理所当然地,误差的导数,它并不总是容易计算的:对在超大神经网络中的随机隐式节点的随机权重,如何计算这一导数? | 本质上,我们的目的是沿着权重$i$的梯度方向移动。这里的关键词是,理所当然地,误差的导数,它并不总是容易计算的:对在超大神经网络中的随机隐式节点的随机权重,如何计算这一导数? | ||
- | 答案是:通过反向传播算法(backpropagation)。首先在输出单元计算误差,此时计算公式非常简单(基于预测输出与目标输出的差),而后以一种聪明的方式沿着神经网络反向传播,这样就让我们能够有效的更新在训练阶段的权重进而得到整体极小值。 | + | 答案是:通过`反向传播算法`(backpropagation)。首先在输出单元计算误差,此时计算公式非常简单(基于预测输出与目标输出的差),而后以一种聪明的方式沿着神经网络反向传播,这样就让我们能够有效的更新在训练阶段的权重进而得到整体极小值。 |
==== 隐式层 ==== | ==== 隐式层 ==== | ||
- | 隐式层特别有意思。 由泛逼近定理([universal approximation theorem](https://en.wikipedia.org/wiki/Universal_approximation_theorem)), 通过训练一个具有有限神经元的隐式层神经网络可以逼近任意随机函数。换言之,一个单一的隐式层已经足够强大到学习**任何**函数。也就是说,在实践中,通常我们利用更多的多隐式层(即更深的网)会使得神经网络学习得更好。 | + | 隐式层特别有意思。 由`泛逼近定理`([[wp>https://en.wikipedia.org/wiki/Universal_approximation_theorem|universal approximation theorem]]), 通过训练一个具有有限神经元的隐式层神经网络可以逼近任意随机函数。换言之,一个单一的隐式层已经足够强大到学习**任何**函数。也就是说,在实践中,通常我们利用更多的多隐式层(即更深的网)会使得神经网络学习得更好。 |
> 隐式层是神经网络存储训练数据内部抽象表示的地方。 | > 隐式层是神经网络存储训练数据内部抽象表示的地方。 | ||
Line 117: | Line 115: | ||
大多数机器学习入门都停止在前馈神经网络这一步。但是可能的网络空间远非如此──所以让我们继续。 | 大多数机器学习入门都停止在前馈神经网络这一步。但是可能的网络空间远非如此──所以让我们继续。 | ||
+ | `自动编码器`([[wp>Autoencoder| Autoencoder]])是典型的前馈型神经网络,旨在**学习一个经过压缩的、分布表示(编码)的数据集**。 | ||
+ | {{ :start:autoencoder.png?400 | Autoencoder}} | ||
+ | 概念上来说,网络被训练成“重新生成”输入,即,输入以及目标数据是一样的。换句话说:你尝试着输出跟你输入的一模一样的东西,但在某种程度上经过了压缩。这是个容易让人迷糊的方法,所以让我们来看一个实例。 | ||
=== 输入压缩:灰度图像 === | === 输入压缩:灰度图像 === | ||
+ | |||
+ | 假设训练数据由像素28x28的灰度图片组成而且每一个像素值都赋给一个输入层的神经元(即输入层将有784个神经元)。之后,输出层也将同输入层一样有784个单元,并且每个输出元的目标值都将是图像中每一个像素的灰度值。 | ||
+ | |||
+ | 这样的结构背后的直觉是网络将不会学习如何在训练数据和标签之间建立一个“映射”关系,而是学习数据本身的**内部结构**和**特征**。(也因此,隐式层也称为**特征探测器**)。通常,隐式层神经元的个数要小于输入/输出层,这也就迫使神经网络只学习那些最为重要的特征,同时实现一个维度上的约化。 | ||
+ | |||
+ | > 我们期望中间层具有较少的节点从而从抽象概念的层次学习数据,最终生成一个压缩过的表示。 | ||
+ | |||
+ | 实际上,我们期望中间层具有较少的节点从而从抽象概念的层次学习数据,最终生成一个压缩过的表示。这样在一定程度上能够捕捉到我们输入的关键特征。 | ||
=== 流行性疾病 === | === 流行性疾病 === | ||
- | ==== 回到机器学习 ==== | + | |
+ | 为了更进一步展示自编码器,让我们再来看一个应用。 | ||
+ | |||
+ | 在这个实例中,我们将使用一个简单的关于流感症状的数据集(想法属于[这篇博客](http://blog.echen.me/2011/07/18/introduction-to-restricted-boltzmann-machines/))。如果你有兴趣,这个实例的代码可在[testAEBackpropagation方法](https://github.com/ivan-vasilev/neuralnetworks/blob/master/nn-core/src/test/java/com/github/neuralnetworks/test/AETest.java)中找到。 | ||
+ | |||
+ | 如下就是这个数据集如何被分解的: | ||
+ | |||
+ | * 这里有六个二进制输入特征。 | ||
+ | |||
+ | * 前三个表示疾病的症状。比如,`1 0 0 0 0 0`指这名患者体温过高,`0 1 0 0 0 0`代表咳嗽,`1 1 0 0 0 0` 暗示着咳嗽和高体温,等等。 | ||
+ | |||
+ | * 后三个特征是"相反"特征:当一名病人有其中一项症状,她或他就有更少的可能性患病。例如, `0 0 0 1 0 0`暗示这名病人接种过流感疫苗,同时也存在将两个数据集特征结合起来的情况:`0 1 0 1 0 0` 暗示着一个接种过疫苗的病人同时在咳嗽,诸如此类。 | ||
+ | |||
+ | 我们将考虑如下情况,当一个患者拥有前三种患病症状中至少两种症状时,他/她是患病的,同时如果有后三种"相反"症状里的两种,我们认他/她是健康的,比如: | ||
+ | |||
+ | * `111000`, `101000`, `110000`, `011000`, `011100` = 生病 | ||
+ | |||
+ | * `000111`, `001110`, `000101`, `000011`, `000110` = 健康 | ||
+ | |||
+ | 我们将会利用6个输入元和6个输出元以及**仅2个隐藏元**来训练自动编码器(通过反向传播算法)。 | ||
+ | |||
+ | 在经过数百次迭代之后,我们观察到当每一个“生病”样本被机器学习的网络表示出来时,两个隐层神经元中的一个(和每个“生病”样本相同的单元)总是表现出比其他神经元更高的激活值。相反的,当一个“健康”样本被表示,另一个隐藏神经元有更强的激活反应。 | ||
+ | === 回到机器学习 === | ||
+ | |||
+ | 本质上,我们的两个隐层神经元都是从流感症状数据集中**学到了**数据的压缩表示。为了看看这如何与学习相关联,我们回到过拟合的问题上来。通过训练我们的网络来进行数据的压缩表示,我们更偏爱一个较为简单的表示方法而不是一个十分复杂、有可能在训练数据上过拟合的理论模型。 | ||
+ | |||
+ | 在某种程度上,由于偏好这样更为简单的表示方法,我们也会尝试从一个更接近“真理”的意义上去学习数据。 | ||
+ | ===== 有限Boltzmann机 ===== | ||
+ | |||
+ | 下一个逻辑步骤是看看有限玻尔兹曼机[[wp>Restricted_Boltzmann_machine|Restricted Boltzmann machine]] (RBM),一个可以从它自身输入来学习概率分布的随机生成神经网络。 | ||
+ | {{ :start:rbm.png?400 |RBM}} | ||
+ | RBMS由隐藏层(hidden layer)、可见层(visible layer)、以及偏置层(bias layer)所组成。不同于前馈神经网络,在可见层和隐层之间的连接是无向的(值可以同时从隐层传到可见层,反之亦然)同时还是全连接的(给定层的每个神经元都会和下一层的每个神经元相连接——如果我们允许任意层次的任意神经元来连接到其他任何层次,那么就是`玻尔兹曼机`(Boltzmann)(并非有限玻尔兹曼机(restricted Boltzmann)))。 | ||
+ | |||
+ | 标准的RBM有二进制隐藏元和可见元:即是说在伯努利分布下神经元的激活值为0或者1,但是这里也有其他非线性的变量。 | ||
+ | |||
+ | 研究者们知晓RBMs已经有一定的年月,但最近关于对比分歧无监督训练算法的介绍又重新挑起了研究者们的兴趣。 | ||
+ |