这一章介绍神经网络,从简单单元到简单的神经网络——感知机,再到复杂的多层神经网络的学习算法——BP算法,和一些常见的神经网络,最后介绍了深度学习。
接下来我们就从最简单的神经元模型来了解神经网络,
5.1神经元模型
所谓的神经网络其实是模仿生物的神经系统来对真实的事例做出反应,而我们在机器学习中所提到的主要是神经网络学习。
在介绍神经元模型之前,我们先来看看生物神经网络中的神经元,对于生物的神经元在受到兴奋信号时向其他相连的神经元释放化学物质,来引起它们的电位变化,一旦超过某个阈值则引起这些神经元兴奋。
M-P神经元模型:它便是模仿上面生物神经元情形设计出来的,该模型会接收一定的输入值,将这些值按权重加总,然后与阈值比较,经激活函数处理后输出。
【注:图中的f(x)便是激活函数】
常将Sigmoid函数作为激活函数:
把多个神经元按一定的层次结构连接起来便得到了神经网络。所以下面我们来介绍最简单的神经网络——感知机。
5.2感知机与多层网络
感知机:由两层神经元组成,输入层接收信号传递给输出层,输出层是M-P神经元(阈值逻辑单元)。感知机只有输出层可以进行激活函数处理,即只有一层功能神经元,所以只能处理简单的与、或、非等线性可分问题。
感知机的学习规则:作为神经元我们需要得到的变量有阈值θ和权重,但是这里将阈值看作一个固定输入-1.0的“哑结点”所对应的连接权重,所以只需要求n+1个权重即可。对训练样例(x,y),若当前感知机的输出为,则感知机权重将这样调整:,其中,称为学习率。
通过感知机的学习规则对权重不断的调整,最终使感知机输出的预测值与样例的值相同,便得到我们所需要的感知机了。
而对于非线性可分问题,就要使用多层功能神经元。如下图:在输出层与输入层之间的一层神经元称为隐层或隐含层。
【注:隐含层和输出层神经元都是拥有激活函数的功能神经元】
多层前馈神经网络:每层神经元与下一层神经元全互连,神经元之间不存在同层连接,也不存在跨层连接。
5.3误差逆传播算法
神经网络的学习过程其实就是通过训练数据来调整权重和阈值,那么多层网络(包含隐含层的神经网络)的阈值和权重要怎么调整呢?
对于多层网络,主要使用的算法是误差逆传播算法(简称BP算法)。
BP算法是怎么样的呢?接下来我们一起来看一下吧。我们需要先定义一些变量。
BP算法
给定训练集,即输入示例由d个属性描述,输出维实值向量。给定一个拥有d个输入神经元、个输出神经元、q个隐藏神经元的多层前馈网络结构,其中输出层第个神经元的阈值用表示,隐藏层第h个神经元的阈值用表示。输出层第个神经元与隐藏层第h个神经元之间的连接权为,隐藏层第h个神经元与输出层第j个神经元之间的连接权为。
记隐藏层第h个神经元接收到的输入为:
输出层第j个神经元接收到的输入为,其中为隐藏层第h个神经元的输出
假设隐藏和输出层的激活函数为Sigmoid函数。
对于训练例,假定神经网络的输出为即。
则网络在上的均方误差为:
在定义说明好变量后,我们就需要来求这些阈值和连接权了,共有个未知数要确定。
【注:输入到隐藏层d*q个权值,隐藏到输出,q个隐藏层阈值,个输出层的阈值】
BP算法与感知机学习规则类似,都基于梯度下降策略,通过训练例对阈值和权重进行不断的调整来得到最终的阈值与权重。
调整的规则:对于任意参数的更新估计式为:
下面是以隐藏到输出层的权重来说明如何更新:
【注:BP算法的目标是最小化训练集D上的累计误差】
标准BP算法:每次针对一个训练集样例来更新权重与阈值,所以更新频繁,需要多次迭代。
累计BP算法:读取整个训练集D后才对参数进行更新,更新频率低,但是累计误差下降到一定程度后进一步下降就很慢了。
试错法:用来调整设置隐藏层的神经元个数。
BP神经网络因为表示能力强大,所以常常会过拟合,如何缓解其过拟合呢?主要有两个方法:①“早停”策略,将数据集分为训练集和验证集,训练集训练后以验证集来测试其误差,若训练集误差下降而验证集误差上升则停止训练,并返回最小验证误差的阈值和权重。②“正则化”策略,在误差目标函数增加一个用于描述网络复杂度的部分,如:连接权与阈值的平方和,使误差目标函数变为:,其中用于对经验误差和网络复杂度进行折中。
5.4全局最小与局部极小
对和,若存在使得,都有成立,则为局部极小值。
若对于参数空间中任意都有,则为全局最小值。
我们在进行参数寻优过程中,若只找到一个局部极小值它就是全局最小,但是若有多个局部极小值,我们就容易陷入局部极小。
我们通常用三种策略来跳出局部极小:①以多组不同参数值初始化多个神经元网络,按标准方法训练后,取其中误差最小的解作为最终参数。(更接近全局最小)②“模拟退火”,每一步都以一定的概率接受比当前解更差的结果,以此来跳出局部极小。③使用随机梯度下降,在计算梯度时加入了随机因素,即使陷入局部极小梯度也可能不为0。
5.5其他常见神经网络
①RBF网络
该网络隐藏层使用径向基函数作为激活函数,输出层则是对隐藏层输出的线性组合。
训练规则:①确定神经元中心,常用的方法包括随机取样、聚类等。②利用BP算法来确定参数。
假定输入为d维向量x,输出为实值,RBF网络可以表示为:,其中第i个隐层神经元对应的中心,是径向基函数。
②ART网络
竞争型学习:神经网络中常用的一种无监督学习策略,网络的输出神经元相互竞争,每一时刻仅有一个竞争胜利的神经元被激活,其他神经元被抑制(这种机制称“胜利者通吃”)。
ART网路就是竞争型学习的代表,该网络由比较层、识别层、识别阈值和重置模块构成。
原理:比较层接收输入样本,并传递到识别层,识别层每个神经元对应一个模式类,计算输入向量与每个识别层神经元所对应的模式类的代表向量之间的距离,距离最小者获胜。然后输入向量与获胜神经元所对应的代表向量之间的相似度大于识别阈值,则将输入样本归入为该代表向量所属类别,若不大于则重置模块将在识别层增加一个新的神经元,其代表向量为当前输入向量。
③SOM网络
SOM网络:一种竞争型学习的无监督神经网络,它能将高维输入数据映射到低维空间,同时保持输入数据在高维空间的拓扑结构,即将高维空间中相似的样本点映射到网络输出层中的相邻神经元。
SOM训练的目标:每个输出层神经元找到合适的权向量,以达到保持拓扑结构的目的。
④级联相关网络
结构自适应网络:将网络结构也作为学习目标,且希望在训练中找到最符合数据特点的网络结构。
级联相关网路是结构自适应网络的代表,主要有两个成分:“级联”(指建立层次连接的层级结构)和“相关”(指通过最大化新神经元的输出与网络误差之间的相关性来训练相关的参数)
⑤Elman网络
递归神经网络:允许网络中出现环形结构,从而让一些神经元的输出反馈回来作为输入信号的网络。
Elman网络就是常用的递归神经网络,其隐层神经元通常使用Sigmoid激活函数。
⑥Boltzmann机
Boltzmann机:为网络状态定义一个“能量”,该网络追求最小化这个能量函数,
令向量表示n个神经元的状态(Boltzmann机中的神经元都是布尔型只有两种状态),表示神经元i与j之间的连接权,表示神经元i的阈值,则其状态向量所对应的Boltzmann机能量定义为:。
受限Boltzmann机:只保留了显层与隐层之间的连接。
常用对比散度(简称CD)算法来训练。假定网路中有d个显层神经元和q个隐层神经元,令分别表示显、隐层的状态向量,则由于同一层内不存在连接,有。CD算法对每个训练样本v,先根据第一个式子算出隐层神经元状态的概率分布,再根据这个概率分布采样得到h,再根据第二个式子从h从产生v',再从v'产生h';连接权的更新公式:。
5.6深度学习
典型的深度学习模型就是很深层的神经网络,而增加神经网络的复杂程度有两个方法:
①增加隐层的数目。
②增加隐层的神经元数目。
【注:方法①优于②,方法①不仅增加了拥有激活函数的神经元数目还增加了激活函数嵌套的层数】
对于多隐层的网络训练方法主要有两种:
①预训练(每次训练一层隐结点)+微调(预训练后利用BP算法对整个网络进行调整)
②权共享,即让每一组神经元使用相同的连接权。
深度学习又称特征学习或表示学习:通过机器学习来自己产生特征,而不用事先给定。
【补】BP算法的例子,通过随机给定变量和预先设定初始变量权重和输入,发现随机给定变量的迭代后的效果很可能比预先给定变量的效果来的好,而通过阈值的修改我们可以得到一个效果更好的模型,虽然可能过拟合。下面是例子代码。
import math
import numpy as np
from numpy import *
#******设定模型所需的激活函数******#
def sigmoids(z):
a = []
for each in z:
b = 1/(1+math.exp(-each[0]))
a.append(b)
return a
#******设定前向传播过程******#
def forwordmd(x,w,v,b1,b2):
net1 = w.T*x+b1
h = np.matrix(sigmoids(np.array(net1))).T #隐藏单元
net2 = v.T*h+b2
pred_y = np.matrix(sigmoids(np.array(net2))).T #输出单元
return pred_y,h
#******设定模型反向传播********#
def Bpaugorith(y,pred_y,h,v,aph,w):
errorter = 0.5*(y-pred_y).T*(y-pred_y) #给出误差公式
#给出输出单元对应误差项
a1 = multiply(pred_y-y,pred_y) #矩阵对应元素相乘
a2 = multiply(a1,1-pred_y) #隐藏层到输出层的误差项
verror = h*a2.T #权重的更新值△
#计算隐藏单元的对应误差
werror = x*(multiply(multiply(h,1-h),(v*a2))).T
#更新权重
vupdate = v - aph*verror
wupdate = w - aph*werror
return vupdate,wupdate,errorter
#主程序部分,设置了输入值、初始值、输出值的真实值、迭代次数
if __name__ =='__main__':
'''x = matrix([0.05,0.10]).T
y = matrix([0.01,0.99]).T
#给出初始权重
w = matrix([[0.15,0.20],[0.25,0.30]])
b1 = matrix([0.1,0.1]).T
v = matrix([[0.40,0.45],[0.50,0.55]])
b2 = matrix([0.2,0.2]).T
'''
#随机参数生成
np.random.seed(0)
w = matrix(np.random.normal(0,1,[2,2]))
b1 = matrix(np.random.normal(0,1,[1,2]))
v = matrix(np.random.normal(0,1,[2,2]))
b2 = matrix(np.random.normal(0,1,[1,2]))
#学习率
aph=0.5
#迭代次数
'''n = 10
for i in range(n):
#激活前向算法
pred_y, h= forwordmd(x,w,v,b1,b2) #得到预测值和隐藏层的值
#更新权重
vupdate,wupdate,errorvalue = Bpaugorith(y,pred_y,h,v,aph,w) #得到更新权重
w,v = wupdate,vupdate
print('预测值:' )
print(pred_y)
print('更新的权重v:')
print(vupdate)
print('更新的权重w:')
print(wupdate)
print('损失值:')
print(errorvalue)
'''
#设置阈值E
e,m = 0.19,1
pred_y,h = forwordmd(x,w,v,b1,b2)
vupdate,wupdate,errorvalue = Bpaugorith(y,pred_y,h,v,aph,w)
w,v = wupdate,vupdate
while errorvalue>e:
pred_y,h = forwordmd(x,w,v,b1,b2)
vupdate,wupdate,errorvalue = Bpaugorith(y,pred_y,h,v,aph,w)
w,v = wupdate,vupdate
m = m+1
print('阈值e:%.2f'%e)
print('迭代次数m:%d次'%m)
print('预测值:' )
print(pred_y)
print('更新的权重v:')
print(vupdate)
print('更新的权重w:')
print(wupdate)
print('损失值:')
print(errorvalue)
代码例子参考:https://gitee.com/someone317/backpropagation_algorithm_test/blob/master/BPtest1.py#