神经网络实际上是一个相对古老的算法,但是后来沉寂了一段时间,不过现在,它又成为许多机器学习问题的首选技术。不过我们为什么还需要这个学习算法呢?我们已经有线性回归和logistic回归算法了,为什么还要研究神经网络?为了阐述神经网络算法的目的,我们首先来看几个机器学习问题作为例子,这几个问题的解决都需要学习复杂的非线性假设。
假如有一个监督学习分类问题,它的训练集如图所示:
如果利用logistic回归来解决这个问题,你可以构造一个包含很多非线性项的logistic回归函数,这里的g仍是sigmoid函数。
当多项式项数足够多时,那么可能就能得到可以分开正样本和负样本的假设。
当只有两个特征,比如和
时,这种方法确实能得到不错的结果。因为你可以把
和
的所有组合都包含到多项式中。但是许多有趣的机器学习问题的特征远不止两项。
我们之前已经讨论过房价预测的问题,假设现在要处理的是关于住房的分类问题,假设一个房子有很多特征,你想预测房子在未来半年内能被卖出去的概率,所以这是一个分类问题。我们可以想出很多特征,对于不同的房子有可能就有上百个特征。
对于这类问题,如果要包含所有的二次项,即使只包含二次多项式,最终也有很多项,比如,
,
,
,...,
还有,
等等很多项,因此,即使只考虑二次项,即只考虑两个项的乘积,那么在n=100的情况下,最终也有大约5000个特征,而且渐渐地,二次项的个数大约以
的量级增长,其中,n是原始特征的个数,即
到
这些项,事实上,二次项的个数大约为
,因此要包含所有的二次项,似乎并不是一个好方法,而且由于项数过多,最后的结果很有可能是过拟合的,此外,在处理这么多项时,也存在运算量过大的问题。当然,你也可以试试只包含上面那些二次项的子集,例如,我们只考虑
,
,
,直到
这些项,这样就可以将二次项的数量大幅度减少,减少到只有100个二次项。但是,由于忽略了太多相关项,在处理类似下图的数据时,不可能得到理想的结果。实际上,如果只包含
,
,
,到
,这一百个二次项,你就不能拟合出一些特别的假设。比如可能会拟合出一个椭圆状的曲线,但是肯定不能拟合出像下面这个数据集这样复杂的分界线。
所以,5000个二次项看起来已经很多了。如果现在假设包括立方项或者三次项,例如,
,
等等,可以想象,类似的三次项有很多很多,事实上,三次项的个数是
的量级,当n=100时,可以计算出来,最后能得到大概17000个三次项,所以,当特征个数n很大时,将这些高阶多项式项数包括到特征里,会使特征空间急剧膨胀,当特征个数n很大时,增加特征来建立非线性分类器并不是一个好做法。
对于许多实际的机器学习问题,特征个数n是很大的,下面来看一个例子,关于计算机视觉中的一个问题,假设你想要使用机器学习算法来训练一个分类器,来检测图像并判断是否为一辆汽车?
很多人可能会好奇,当我们自己看这副图像时,这是什么,一目了然。你肯定会觉得奇怪,为什么学习算法竟可能会不知道图像是什么,为了解答这个疑问,取出这个图片中的一小部分,将其放大,比如图中红色方框内的部分。
当人眼看到一辆汽车的时候,计算机实际上看到的却是一个数据矩阵,或者说表示像素强度值的网格,告诉我们图像中每个像素的亮度值,因为计算机视觉问题就是根据像素点亮度矩阵来告诉我们这些数值代表一个汽车门把手。
具体而言,当我们用机器学习算法构造一个汽车识别器时,我们要做的就是提供一个带标签的样本集,其中一些样本是各类汽车,另一部分样本不是车,将这个样本集输入给学习算法以训练出一个分类器,然后进行测试,输入一幅新图片时,让分类器判定这是什么。
为了理解引入非线性假设的必要性,我们从学习算法的训练样本中找出一些汽车图片和一些非汽车图片,我们从图片中选择一组像素点位,然后在坐标系中标出这辆汽车的位置,车的位置取决于像素点1和像素点2的强度。
接着用同样的方法来处理其它图片,再看一个汽车的例子,观察这两个相同的像素位置,这幅图片中,像素点1有一个像素强度,像素点2也有一个不同的像素强度,所以在坐标系中处于另一个位置。
继续画上两个非汽车样本
然后继续在坐标系中画上更多的新样本,用 + 表示汽车图片,用 - 表示非汽车图片,我们将发现汽车样本和非汽车样本分布在坐标系中的不同区域。
因此我们现在需要一个非线性假设来尽量分开这两类样本,这里的特征空间维数是多少?假设我们用50*50像素的图片,这样的图片已经很小了,长宽只各有50个像素,但这依然是2500个像素点,因此特征向量的元素数量,N=2500,特征向量x就是包含了所有像素强度的列表,包括像素点1、像素点2的亮度,直到最后一个像素点的亮度,对于典型的计算机图片表示方法,如果存储的是每个像素点的灰度值,那么每个元素的值应该在0到255之间,因此这个问题中n=2500,但是,这只是使用灰度图片的情况,如果我们用的是RGB彩色图像,每个像素点包含红、绿、蓝三个值,那么n=7500。
因此,如果要通过包含所有的二次项特征来学习得到非线性假设,那么总共就有约300万个特征,这数字大得有点离谱了,对于每个样本都要找到并表示所有这300万个特征,这计算成本太高了。因此只是包括平方项或者立方项特征,简单的logistic回归算法并不是一个在n很大时学习复杂的非线性假设的好办法
神经网络算法由来已久,它最初产生的目的是制造能模拟大脑的机器,它能很好地解决不同的机器学习问题。神经网络的起源是人们想尝试设计出模仿大脑的算法,它的理念就是,如果我们想要建立学习系统,那为什么不去模仿我们所认识的最神奇的学习机器,人类的大脑呢,神经网络逐渐兴起于20世纪八九十年代,但由于各种原因,在90年代的后期应用减少了,但是现在,神经网络又流行起来了。
想一想模拟大脑这件事情,人类大脑能做这么多神奇的事情,大脑可以学会去看,去处理图像,学会听声音,学会处理触觉,学习数学,大脑能处理各种不同的令人惊奇的事情,似乎如果想要模拟它,需要写各种不同的软件来模拟所有大脑所做的这些五花八门的事情,不过能不能假设大脑做所有这些不同事情的方法不需要用上千个不同的程序去实现,相反的,大脑处理的方法只需要一个学习算法就可以了。尽管这只是一个假设,不过是有这方面的证据的。
大脑的这一小片的红色区域是听觉皮层,我们能理解别人所说的话靠的是耳朵接收到声音信号并把声音信号传递给听觉皮层。
神经系统科学家做了一个有趣的实验把耳朵到听觉皮层的神经切断,然后将大脑的神经重新连接,使得从眼睛经由视觉神经传递的信号最终将传到听觉皮层,这样做的结果是,听觉皮层将学会看。
下面再举另一个例子
这块红色的脑组织是躯体感觉皮层,这是用来处理触觉的,如果做一个类似的重接实验,那么躯体感觉皮层也能学会看。
这个实验和其它一些类似的实验被称为神经重接实验,其中引申出的理念就是,如果有一块脑组织可以处理光、声或触觉信号,那么也许存在一种学习算法可以同时处理视觉、听觉和触觉,而不是需要运行上千个不同的程序或者上千个不同的算法来做这些大脑所完成的成千上万的美好事情。也许我们需要做的就是找出一些近似的或实际的大脑学习算法,然后实现它,让大脑自己学习如何处理这些不同类型的数据。
神经网络模仿了大脑中的神经元或者神经网络,为了解释如何表示假设模型,先来看单个神经元在大脑中是什么样的,我们的大脑中充满了这样的神经元,神经元是大脑中的细胞。
其中有两点值得注意,一是神经元有像这样的细胞体。
二是神经元有很多输入通道叫做树突,可以把它们想象成输入电线,它们接收来自其它神经元的信息,神经元有一条输出通道叫做轴突,这条输出通道是用来给其它神经元传递信号或者传送信息的。
简而言之,神经元是一个计算单元,它从输入通道接收一定数目的信息,并做一些计算,然后将结果通过它的轴突传送到其它节点或者大脑中的其它神经元。
在一个神经网络里,或者说我们在电脑上实现的人工神经网络里,我们将使用一个很简单的模型来模拟神经元的工作,我们将神经元模拟成一个逻辑单元。
这个黄色圆圈可以把它想象成类似于神经元细胞体的东西,然后我们通过树突或者说输入通道传递给它一些信息,然后神经元做一些计算,并通过它的输出通道就是轴突,输出计算结果。
这里的假设函数是:
通常x和θ是我们的参数向量。这是一个很简单的模型,甚至可以说是过于简单的模型来模拟神经元接受输入、
和
,再通过计算输出结果。在绘制神经网络时,通常输入节点只绘制除
的节点,有必要的时候,会增加一个额外的节点
,这个
节点有时也被称为偏置单元或偏置神经元,但因为
总是等于1,所以有时会画出它,有时不会画出,这取决于在具体例子中加上
是不是表示起来更方便。
带有sigmoid或者logistic激活函数的人工神经元,在神经网络术语中,激活函数是指代非线性函数g(z)的另一个术语。
被称为模型的参数,但在关于神经网络的文献里,有时可能会看到人们称之为模型的权重,权重其实和模型的参数是一样的东西。
之前的图是单个的神经元,神经网络其实就是一组神经元连接在一起的集合。
神经网络中的第一层也被称为输入层,因为我们在这一层输入特征,例如、
和
。最后一层称为输出层,因为这一层的神经元,它输出假设的最终计算结果,中间的第二层被称为隐藏层,隐藏层不是特别好的术语,但是直觉上我们知道,在监督学习中,你能看到输入,也能看到正确的输出,而隐藏层的值在训练集里是看不到的,它的值不是x也不是y,所以我们叫它隐藏层。实际上任何非输入层或非输出层的层就被称为隐藏层。
为了解释神经网络具体的计算步骤,还有些记号要解释,表示第j层第i个神经元的激活项,具体来说
表示第二层的第一个激活项,所谓激活项是指由一个具体神经元计算并输出的值,此外,神经网络被
这些矩阵参数化,
就是权重矩阵,它控制从第j层到第j+1层,比如说第一层到第二层,或者第二层到第三层的映射。
隐藏单元和输出单元的计算方式如下,其中g是sigmoid激活函数也叫做logistic激活函数,
在这个神经网络中有三个输入单元和三个隐藏单元,就是控制着从三个输入单元到三个隐藏单元的映射的参数矩阵,因此
就是一个3*4的矩阵。更一般地来说,如果一个网络在第j层有
个单元,在j+1层有
个单元,那么矩阵
,即控制第j层到第j+1层映射的矩阵,它的维度为
* (
+ 1 )
下面来讲解如何进行高效地计算,并展示一个向量化的实现方法。
定义=g(
),接着类似地定义
这些Z值都是线性组合,是某个特定的神经元的输入值、
、
、
的加权线性组合。
然后给出特征向量x和z的定义
接着向量化、
、
的计算
这里的、
都是三维向量,激活项g也就是S型函数,逐个作用于
中的每个元素。
顺便说一下,在输入层的输入x,也可以看做是第一层的激活项,如果定义 = x,那
就是一个向量了,就可以通过把
定义为输入层的激活项,来替换x。
最后要计算假设函数的实际输出值
这个计算的过程也称为前向传播,这样命名是因为,我们从输入单元的激活项开始,然后进行前向传播给隐藏层,计算隐藏层的激活项,然后继续前向传播并计算输出层的激活项,这个依次计算激活项,从输入层到隐藏层再到输出层的过程叫前向传播。
这种前向传播的方法也可以帮助我们了解神经网络的作用和它为什么能够帮助我们学习有趣的非线性假设函数。
先暂时盖住神经网络的左边部分,观察图中剩下的部分,会发现这看起来很像逻辑回归。也就是用这个节点,这个逻辑回归单元来预测h(x)的值。
这实际上就是逻辑回归,但输入逻辑回归的特征是通过隐藏层计算的数值。这个神经网络所做的事情就像是逻辑回归,但是它不是使用原本的、
、
作为特征,而是用
、
、
作为新的特征,有趣的是特征项
、
、
是学习得到的函数输入值,具体来说就是从第一层映射到第二层的函数,这个函数由其它参数
决定。
在神经网络中,它没有用输入特征、
、
来训练逻辑回归,而是自己训练逻辑回归的输入
、
、
,可以想象根据为
选择的不同参数,有时可以学习到一些很有趣和复杂的特征,就可以得到一个更好的假设函数,比使用原始输入
、
、
时得到的假设更好,也可以选择用多项式,例如
、
等作为输入项,但这个算法可以灵活地尝试快速学习任意的特征项,把这些
、
、
输入最后的单元。
我们也可以用其它的图来表示神经网络,神经网络中神经元的连接方式被称为神经网络的架构,架构是指不同的神经元的连接方式,下面给出一个例子,包含了不同的神经网络架构。
在第二层有三个隐藏单元,它们会计算一些比如说输入层的复杂功能,然后第三层可以将第二层训练出的特征项作为输入,然后在第三层计算出更复杂的特征,在到达输出层(也就是第四层)的时候,就可以利用在第三层训练出的更复杂的特征作为输入,以此得到非常有趣的非线性假设函数。顺便说一下,在这样的网络里,第一层被称为输入层,第四层是输出层,第二层和第三层都是隐藏层。
考虑下面的问题,我们有和
两个输入特征,它们都是二进制的,所以
和
只可能是0或1,在这个例子中有两个正样本和两个负样本。
具体来说我们需要计算目标函数
XNOR是 NOT( XOR
)的另一种写法,
XOR
表示当这两个值恰好其中一个等于1时,这个式子为真。这个例子中,如果我们用XNOR的话结果会好一些,也就是当这些正样本同时为真或同时为假时,y的值才为1,如果y等于0,那么它们有且仅有一个为真。那么我们能不能构建一个神经网络来拟合这样的训练集呢?为了建立能够拟合XNOR运算的神经网络,我们先从一个比较简单的,能够拟合AND运算的网络入手。
具体来说,假设有两个二进制的输入和
(只能取0或1),现在目标函数是y =
AND
,AND的意思是逻辑与。
怎样来得到只含单个神经元的网络来计算这个AND函数呢?为此,要在这里加一个偏置单元,也称为+1单元,现在来对神经网络中的权重或者说参数进行赋值。
这意味着将-30赋值给的系数,对应图中的+1单元,中间的+20对应
的系数,下面的+20对应
的系数,这意味着假设模型h(x)=g(-30+20
+20
),-30其实就是
,+20是
,最后一个+20是
。
来看看这个小小的神经元是如何进行计算的,首先来回顾一下,S型激活函数g(z)的图形如下:
试试和
对应的四种输入组合,发现h(x)的结果确实是逻辑与的计算结果,h(x)就近似等于
AND
下图是一个或运算函数的例子:
从计算结果可以看出它的确实现了逻辑或函数的功能。
下面给一个神经网络如何进行逻辑非运算的例子,即计算函数 NOT
若要实现逻辑非运算,大体思想就是在预期得到非结果的变量前面放一个很大的负权重,比如说,这就是对
做逻辑非运算的主要思路。
现在把下面的这三块单独的部分组合到网络中
将这三部分组合在一起,来计算 XNOR
这个神经网络有一个输入层,一个隐藏层和一个输出层。最后会得到一个非线性的决策边界用以计算XNOR函数。更通俗的解释是,我们的输入都放在输入层,然后在中间放一个隐藏层,用来计算一些关于输入的略微复杂的功能,然后再继续增加一层,用于计算一个更复杂非线性函数,这就是为什么神经网络可以计算这种复杂的函数。
当网络拥有许多层,在第二层中有一些关于输入相对简单的函数,第三层又在此基础上计算更加复杂的方程,再往后,计算的函数越来越复杂。
要在神经网络中实现多类别分类,采用的方法本质上是"一对多法"的拓展。假设有一个计算机视觉的例子,现在我们需要识别四个类别的对象,通过图像来辨别出哪些是行人、汽车、摩托车或者货车。我们要做的就是建立一个有四个输出单元的神经网络,现在神经网络的输出将是一个含4个数的向量,输出变成了一个四维的向量。那么现在我们要做的就是用第一个输出单元来判断图中是否是一个行人,再用第二个输出单元来判断图片中是否是一辆汽车,接着用第三个输出单元来判断图中是否是一辆摩托车,最后用第四个输出单元来判断图中是否是一辆货车。
这其实就像"一对多法",现在可以说是有4个逻辑回归分类器,它们每一个都将识别图片中的物体是否是四种类别中的一种。