深度学习概述:从感知机到深度网络(上)

深度学习概述:从感知机到深度网络(上)
近些年来,人工智能领域又活跃起来,除了传统了学术圈外,Google、Microsoft、facebook等工业界优秀企业也纷纷成立相关研究团队,并取得了很多令人瞩目的成果。这要归功于社交网络用户产生的大量数据,这些数据大都是原始数据,需要被进一步分析处理;还要归功于廉价而又强大的计算资源的出现,比如GPGPU的快速发展。除去这些因素,AI尤其是机器学习领域出现的一股新潮流

近些年来,人工智能领域又活跃起来,除了传统了学术圈外,Google、Microsoft、facebook等工业界优秀企业也纷纷成立相关研究团队,并取得了很多令人瞩目的成果。这要归功于社交网络用户产生的大量数据,这些数据大都是原始数据,需要被进一步分析处理;还要归功于廉价而又强大的计算资源的出现,比如GPGPU的快速发展。

除去这些因素,AI尤其是机器学习领域出现的一股新潮流很大程度上推动了这次复兴——深度学习。本文中我将介绍深度学习背后的关键概念及算法,从最简单的元素开始并以此为基础进行下一步构建。

机器学习基础如果你不太熟悉相关知识,通常的机器学习过程如下:

  1. 机器学习算法需要输入少量标记好的样本,比如10张小狗的照片,其中1张标记为1(意为狗)其它的标记为0(意为不是狗)——本文主要使用监督式、二叉分类。
  2. 这些算法“学习”怎么样正确将狗的图片分类,然后再输入一个新的图片时,可以期望算法输出正确的图片标记(如输入一张小狗图片,输出1;否则输出0)。

这通常是难以置信的:你的数据可能是模糊的,标记也可能出错;或者你的数据是手写字母的图片,用其实际表示的字母来标记它。

感知机感知机是最早的监督式训练算法,是神经网络构建的基础。

假如平面中存在  n  个点,并被分别标记为“0”和“1”。此时加入一个新的点,如果我们想知道这个点的标记是什么(和之前提到的小狗图片的辨别同理),我们要怎么做呢?

一种很简单的方法是查找离这个点最近的点是什么,然后返回和这个点一样的标记。而一种稍微“智能”的办法则是去找出平面上的一条线来将不同标记的数据点分开,并用这条线作为“分类器”来区分新数据点的标记。

宽客网

在本例中,每一个输入数据都可以表示为一个向量  x  = ( x_1, x_2 ) ,而我们的函数则是要实现“如果线以下,输出0;线以上,输出1”。

用数学方法表示,定义一个表示权重的向量  w  和一个垂直偏移量  b 。然后,我们将输入、权重和偏移结合可以得到如下传递函数:

宽客网

这个传递函数的结果将被输入到一个激活函数中以产生标记。在上面的例子中,我们的激活函数是一个门限截止函数(即大于某个阈值后输出1):

宽客网

训练感知机的训练包括多训练样本的输入及计算每个样本的输出。在每一次计算以后,权重  w  都要调整以最小化输出误差,这个误差由输入样本的标记值与实际计算得出值的差得出。还有其它的误差计算方法,如 均方差 等,但基本的原则是一样的。

缺陷这种简单的感知机有一个明显缺陷:只能学习 线性可分函数 。这个缺陷重要吗?比如  XOR,这么简单的函数,都不能被线性分类器分类(如下图所示,分隔两类点失败):

宽客网

为了解决这个问题,我们要使用一种多层感知机,也就是——前馈神经网络:事实上,我们将要组合一群这样的感知机来创建出一个更强大的学习机器。

前馈神经网络神经网络实际上就是将大量之前讲到的感知机进行组合,用不同的方法进行连接并作用在不同的激活函数上。

宽客网

我们简单介绍下前向神经网络,其具有以下属性:

一个输入层,一个输出层,一个或多个隐含层。上图所示的神经网络中有一个三神经元的输入层、一个四神经元的隐含层、一个二神经元的输出层。

每一个神经元都是一个上文提到的感知机。

输入层的神经元作为隐含层的输入,同时隐含层的神经元也是输出层神经元的输入。

每条建立在神经元之间的连接都有一个权重  w  (与感知机中提到的权重类似)。

在  t  层的每个神经元通常与前一层(  t - 1层 )中的每个神经元都有连接(但你可以通过将这条连接的权重设为0来断开这条连接)。

为了处理输入数据,将输入向量赋到输入层中。在上例中,这个网络可以计算一个3维输入向量(由于只有3个输入层神经元)。假如输入向量是 [7, 1, 2],你将第一个输入神经元输入7,中间的输入1,第三个输入2。这些值将被传播到隐含层,通过加权传递函数传给每一个隐含层神经元(这就是前向传播),隐含层神经元再计算输出(激活函数)。

输出层和隐含层一样进行计算,输出层的计算结果就是整个神经网络的输出。

超线性如果每一个感知机都只能使用一个线性激活函数会怎么样?整个网络的最终输出也仍然是将输入数据通过一些线性函数计算过一遍,只是用一些在网络中收集的不同权值调整了一下。换名话说,再多线性函数的组合还是线性函数。如果我们限定只能使用线性激活函数的话,前馈神经网络其实比一个感知机强大不到哪里去,无论网络有多少层。

正是这个原因, 大多数神经网络都是使用的非线性激活函数,如对数函数、双曲正切函数、阶跃函数、整流函数等。不用这些非线性函数的神经网络只能学习输入数据的线性组合。

训练大多数常见的应用在 多层感知机的监督式训练的算法都是反向传播算法。基本的流程如下:

  1. 将训练样本通过神经网络进行前向传播计算。
  2. 计算输出误差,常用均方差:

宽客网

其中  t  是目标值,  y  是实际的神经网络计算输出。其它的误差计算方法也可以,但MSE(均方差)通常是一种较好的选择。

宽客网

  1. 网络误差通过 随机梯度下降 的方法来最小化。

梯度下降很常用,但在神经网络中,输入参数是一个训练误差的曲线。每个权重的最佳值应该是误差曲线中的全局最小值(上图中的  global minimum )。在训练过程中,权重以非常小的步幅改变(在每个样本或每小组样本训练完成后)以找到全局最小值,但这可不容易,训练通常会结束在局部最小值上(上图中的local minima)。如例子中的,如果当前权重值为0.6,那么要向0.4方向移动。

这个图表示的是最简单的情况,误差只依赖于单个参数。但是,网络误差依赖于每一个网络权重,误差函数非常、非常复杂。

好消息是反向传播算法提供了一种通过利用输出误差来修正两个神经元之间权重的方法。关系本身十分复杂,但对于一个给定结点的权重修正按如下方法(简单):

宽客网

其中  E  是输出误差,  w_i  是输入  i  的权重。

实质上这么做的目的是利用权重  i 来修正梯度的方向。关键的地方在于误差的导数的使用,这可不一定好计算:你怎么样能给一个大型网络中随机一个结点中的随机一个权重求导数呢?

答案是:通过反向传播。误差的首次计算很简单(只要对预期值和实际值做差即可),然后通过一种巧妙的方法反向传回网络,让我们有效的在训练过程中修正权重并 (期望) 达到一个最小值。

隐含层隐含层十分有趣。根据 普适逼近原理 ,一个具有有限数目神经元的隐含层可以被训练成可逼近任意随机函数。换句话说,一层隐含层就强大到可以学习任何函数了。这说明我们在多隐含层(如深度网络)的实践中可以得到更好的结果。

隐含层存储了训练数据的内在抽象表示,和人类大脑(简化的类比)保存有对真实世界的抽象一样。接下来,我们将用各种方法来搞一下这个隐含层。

一个网络的例子可以看一下这个通过  testMLPSigmoidBP  方法用Java实现的简单(4-2-3)前馈神经网络,它将  IRIS  数据集进行了分类。这个数据集中包含了三类鸢尾属植物,特征包括花萼长度,花瓣长度等等。每一类提供50个样本给这个神经网络训练。特征被赋给输入神经元,每一个输出神经元代表一类数据集(“1/0/0” 表示这个植物是Setosa,“0/1/0”表示 Versicolour,而“0/0/1”表示 Virginica)。分类的错误率是2/150(即每分类150个,错2个)。

大规模网络中的难题神经网络中可以有多个隐含层:这样,在更高的隐含层里可以对其之前的隐含层构建新的抽象。而且像之前也提到的,这样可以更好的学习大规模网络。增加隐含层的层数通常会导致两个问题:

  1. 梯度消失:随着我们添加越来越多的隐含层,反向传播传递给较低层的信息会越来越少。实际上,由于信息向前反馈,不同层次间的梯度开始消失,对网络中权重的影响也会变小。
  2. 过度拟合:也许这是机器学习的核心难题。简要来说,过度拟合指的是对训练数据有着过于好的识别效果,这时导至模型非常复杂。这样的结果会导致对训练数据有非常好的识别较果,而对真实样本的识别效果非常差。

下面我们来看看一些深度学习的算法是如何面对这些难题的。

自编码器大多数的机器学习入门课程都会让你放弃前馈神经网络。但是实际上这里面大有可为——请接着看。

自编码器就是一个典型的前馈神经网络,它的目标就是学习一种对数据集的压缩且分布式的表示方法(编码思想)。

宽客网

从概念上讲,神经网络的目的是要训练去“重新建立”输入数据,好像输入和目标输出数据是一样的。换句话说:你正在让神经网络的输出与输入是同一样东西,只是经过了压缩。这还是不好理解,先来看一个例子。

压缩输入数据:灰度图像这里有一个由28x28像素的灰度图像组成的训练集,且每一个像素的值都作为一个输入层神经元的输入(这时输入层就会有784个神经元)。输出层神经元要有相同的数目(784),且每一个输出神经元的输出值和输入图像的对应像素灰度值相同。

在这样的算法架构背后,神经网络学习到的实际上并不是一个训练数据到标记的“映射”,而是去学习数据本身的内在结构和特征(也正是因为这,隐含层也被称作特征探测器(feature detector))。通常隐含层中的神经元数目要比输入/输入层的少,这是为了使神经网络只去学习最重要的特征并实现特征的降维。

我们想在中间层用很少的结点去在概念层上学习数据、产生一个紧致的表示方法。

流行感冒为了更好的描述自编码器,再看一个应用。

这次我们使用一个简单的数据集,其中包括一些感冒的症状。如果感兴趣,这个例子的源码发布在 这里 。

数据结构如下:

输入数据一共六个二进制位

前三位是病的证状。例如, 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  = 健康

我们来训练一个自编码器(使用反向传播),六个输入、六个输出神经元,而只有两个隐含神经元。

在经过几百次迭代以后,我们发现,每当一个“生病”的样本输入时,两个隐含层神经元中的一个(对于生病的样本总是这个)总是显示出更高的激活值。而如果输入一个“健康”样本时,另一个隐含层则会显示更高的激活值。

再看学习本质上来说,这两个隐含神经元从数据集中学习到了流感症状的一种紧致表示方法。为了检验它是不是真的实现了学习,我们再看下过度拟合的问题。通过训练我们的神经网络学习到的是一个紧致的简单的,而不是一个高度复杂且对数据集过度拟合的表示方法。

某种程度上来讲,与其说在找一种简单的表示方法,我们更是在尝试从“感觉”上去学习数据。

本文译自http://www.toptal.com/machine-learning/an-introduction-to-deep-learning-from-perceptrons-to-deep-networks。
数据分析, 数据挖掘, 神经元, 隐含层