早期几种不同的基础网络模型的介绍及实现

MP模型:1943年提出,是一种基于阈值逻辑运算法创造的神经网络计算模型。由固定的结构和权重组成。是一种简单的数学模型,模拟生物神经元的激活方式。成功证明神经元能够执行逻辑功能,开创了人工神经网络研究的时代。

 

 感知机模型:1957年提出,结构和MP模型相似,一般被视为最简单的人工神经网络,也被作为二元线性分类器广泛使用。一般是指单层的人工神经网络

 

 感知机的学习过程:就是将实际值和理论输出值做差,由此来调整每一个输出端的权重,学习规则是用来计算新的权重向量W和新的偏差值B的算法。

下面使用python简单的实现一个感知机的训练过程

import matplotlib.pyplot as plt
import math as math
import numpy as np
#迭代次数
n=0
#学习率
lr=0.10
#输入数据
#定义一个5行4列的数组对象 ndarray
#外界输入是4个值,前两个值是偏置,后面两个坐标某个点的坐标
X=np.array([[1,1,2,3],[1,1,4,5],[1,1,1,1],[1,1,5,3],[1,1,0,1]])
print(X[:,1])
#输出标签
Y=np.array([1,1,-1,1,-1])
#初始化权重的值,4个随机值,取值范围【-1,1】
W=(np.random.random(X.shape[1])-0.5)*2
print(W)
#更新权重函数
def get_update():
    global X,Y,W,lr,n
    n+=1
    #输出X与W的转置相乘,得到的结果由阶跃函数处理
    new_output=np.sign(np.dot(X,W.T))
    #调整权重:新的权重=旧的权重+改变权重
    #改变权重=标签的差值乘以输入X,再乘以学习率
    new_W=W+lr*((Y-new_output.T).dot(X)/int(X.shape[0]))
    W=new_W

def get_show():
    all_x=X[:,2]
    all_y= X[:, 3]
    negative_x=[1,0]
    negative_y=[1,1]
    #计算分界线斜率和截距
    k=-W[2]/W[3]
    b=-(W[0]+W[1])/W[3]
    x_data=np.linspace(0,5)
    plt.figure()
    plt.plot(x_data,x_data*k+b,'r')
    plt.plot(all_x, all_y, 'b*')
    plt.plot(negative_x, negative_y, 'yo')
    plt.xlabel('x')
    plt.xlabel('y')
    plt.show()

def main():
    for _ in range(100):
        get_update()
        new_outout=np.sign(np.dot(X,W.T))
        if(new_outout==Y.T).all():
            print('迭代次数:',n)
            break
    plt.pause(0.1)
    get_show()

if __name__ == '__main__':
    main()

结果如图所示

感知机本质是一种线性模型,只能处理线性分类问题,简单的异或问题都没有办法正常解决。

多层感知机(MLP)

由单层感知机推广而来,主要特点是有多个神经元层,一般将第一层叫做输入层,最后一层叫输出层,中间的叫做隐藏层。多层感知机没有规定隐藏层的数量,也对隐藏层和输入层神经元的个数没有限制。下面两张图为单层隐藏层前馈网络,多隐藏层前馈网络

多层感知机的关键问题:训练各层间的连接权值。比较常用的是使用反向传播BP算法对神经网络的连接权值进行训练。 误差逆传播(error BackPropagation,简称BP)算法。

BP算法

有一篇博文,将BP算法使用数据推算的方法展示,讲的非常好。可以参考一下;BP算法详解 - CharlesQAQ - 博客园

权重是位于连线上的值,神经元就是每一个小圈,是经过全连接计算后得到的值。偏置是一个常数。引用上面微博中的推算方法,进行bp算法的推算

目标:通过i1,i2输入和权值和偏置的加权计算,使得o1,o2的输出值,接近真正的输出值,0.1和0.99.这也是学习权值和偏置偏置值的意义。这样通过输入值和权值和偏置的加权计算就可以得到类别。下面开始推导:

step1:前向传播

输入层—->隐含层:

计算神经元h1和h2的输入加权和:

neth1=i1*w1+i2*w2+b1*1=0.05*0.15+0.1*0.2+0.35*1=0.3775

neth2=i1*w3+i2*w4+b1*1=0.05*0.25+0.1*0.3+0.35*1=0.5968

由于神经元处的输出是有激活函数的。所以需要使用激活函数计算神经元h1和h2的输入加权和作为第二层隐藏层的真正的输出。

 

隐含层—->输出层

 这样前向传播的过程就结束了,我们得到输出值为[0.75136079 , 0.772928465],与实际值[0.01 , 0.99]相差还很远,现在我们对误差进行反向传播,更新权值,重新计算输出。

 step2:反向传播

1.计算总误差

       总误差:(square error)

2.隐含层—->输出层的权值更新:

       以权重参数w5为例,如果我们想知道w5对整体误差产生了多少影响,可以用整体误差对w5求偏导求出:(链式法则)

 

    下面的图可以更直观的看清楚误差是怎样反向传播的:

   现在我们来分别计算每个式子的值:

 这样我们就计算出整体误差E(total)对w5的偏导值。

 将上面的每一步求导后的公式组合,不带入数值,能得到以下的表达式:

 

 

3.隐含层—->隐含层的权值更新: 

 方法其实与上面说的差不多,但是有个地方需要变一下,在上文计算总误差对w5的偏导时,是从out(o1)—->net(o1)—->w5,但是在隐含层之间的权值更新时,是out(h1)—->net(h1)—->w1,而out(h1)会接受E(o1)和E(o2)两个地方传来的误差,所以这个地方两个都要计算。

首先计算两个误差带来的误差

 

 

 

      这样误差反向传播法就完成了,最后我们再把更新的权值重新计算,不停地迭代,在这个例子中第一次迭代之后,总误差E(total)由0.298371109下降至0.291027924。迭代10000次后,总误差为0.000035085,输出为[0.015912196,0.984065734](原输入为[0.01,0.99]),证明效果还是不错的。

      总结:反向传播的过程就是第L层神经元的误差值,等于第L+1层所有与神经元j相连的神经元的误差值的权重之和乘以该神经元j的激活函数的梯度。

     这样的方法能够使分类变成非线性,也可以解决异或的问题。使用该方法,再次实现感知机的代码段。


import matplotlib.pyplot as plt
import math as math
import numpy as np
#迭代次数
n=0
#学习率
lr=0.11
#输入数据
#定义一个5行4列的数组对象 ndarray
#外界输入是6个值,前一个值是偏置,后面x1,x2,x1^2,x1*x2,x2^2
X=np.array([[1,0,0,0,0,0],[1,0,1,0,0,1],[1,1,0,1,0,0],[1,1,1,1,1,1]])
print(X[:,1])
#输出标签
Y=np.array([-1,1,1,-1])
#初始化权重的值,4个随机值,取值范围【-1,1】
W=(np.random.random(X.shape[1])-0.5)*2
print('初始化权重的值:',W)
#更新权重函数
def get_update():
    global X,Y,W,lr,n
    n+=1
    #输出X与W的转置相乘,得到的结果由阶跃函数处理
    new_output=np.sign(np.dot(X,W.T))
    #调整权重:新的权重=旧的权重+改变权重
    #改变权重=标签的差值乘以输入X,再乘以学习率
    new_W=W+lr*((Y-new_output.T).dot(X)/int(X.shape[0]))
    W=new_W
def get_line(x,root):
    a=W[5]
    b=W[2]+x*W[4]
    c = W[0] + x * W[1]+ x *x* W[3]
    if root==1:
        return(-b+np.sqrt(b*b-4*a*c))/(2*a)
    if root==2:
        return(-b-np.sqrt(b*b-4*a*c))/(2*a)
def get_show():
    #正样本
    x1=[0,1]
    y1=[1,0]
    # 负样本
    x2 = [0, 1]
    y2 = [0, 1]
    #计算分界线斜率和截距
    x_data=np.linspace(-1,2)
    plt.figure()
    plt.plot(x_data,get_line(x_data,1),'r')
    plt.plot(x_data, get_line(x_data, 2), 'r')
    plt.plot(x1, y1, 'bo')
    plt.plot(x2, y2, 'yo')
    plt.xlabel('x')
    plt.xlabel('y')
    plt.show()

def main():
    for _ in range(10000):
        get_update()
        get_show()
    last_outout=np.dot(X,W.T)
    print('最后逼近值:',last_outout)



if __name__ == '__main__':
    main()

BP算法改进

    BP算法易形成局部极小而得不到全局最优,训练次数多使得学习效率低,存在收敛速度慢等问题。

       传统的BP算法改进主要有两类:

                 启发式算法:如附加动量法,自适应算法。

                 数值优化算法:如共轭梯度法、牛顿迭代法等。

1,附加动量项

       这是一种广泛用于加速梯度下降法收敛的优化方法。附加动量法面临学习率的选取的困难,进而产生收敛速度与收敛性之间的矛盾。

       核心思想:在梯度下降搜索时,若当前梯度下降与之前梯度下降方向相同,则加速搜索,反之则减速搜索。

       标准BP算法的参数更新项为:

                               ∆ω(t)= ηg(t)

       式中,∆ω(t)为第t次迭代的参数调整量,η为学习率,g(t)为第t次迭代所计算出的梯度。

       添加动量项之后,基于梯度下降的参数更新为:

                             ∆ωt= ηgt+α∆ωt-1

       式中α被称为动量系数,一般α∈(0,1),α∆ω(t-1)代表之前梯度下降的方向和大小信息对当前梯度下降的调整作用。

2,自适应学习率

      核心思想:自适应改变学习率,使其根据环境变化增大或减小。

              ηt=σ(t)η(t-1)

     上式中,σ(t)为第 t 次迭代时的自适应学习速率因子。

3,引入陡度因子

     核心思想:如果在调整进入平坦区后,设法压缩神经元的净输入,使其输出退出激活函数的不饱和区,就可以改变误差函数的形状,从而使调整脱离平坦区。

在原激活函数中引入一个陡度因子λ

                                                        o=\frac{1}{1+e^{-\frac{net}{\lambda }}}

 

 

 

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值