感知器原理及线性分类技术实现

2021年9月29日 21点热度 0条评论 来源: chiqi1020

在说起感知器之前,需要先说一下神经网络的定义:

神经网络是由具有适应性的简单单元组成的广泛并行互联的网络,它的组织能够模拟生物神经系统对真实世界物体所作出的交互反应。

感知器(M-P神经元模型)

        感知器(Perceptron)由两层神经元组成,如图所示,输入层接收外界输入信号后传递给输出层,输出层是M-P神经元,亦称“阈值逻辑单元”。在M-P神经元模型中,神经元接收到来自n个其他神经元传递过来的输入信号,这些输入信号通过带权重的连接进行传递,神经元接收到的总输入值将与神经元的阈值进行比较,然后通过“激活函数”(activation function)处理以产生神经元的输出。

        理想中的激活函数是下图所示的阶跃函数,它将输入值映射为输出值“0”或“1”,显然“1”对应于神经元兴奋,“0”对应于神经元抑制。然而,阶跃函数具有不连续、不光滑等不太好的性质,因此实际常用Sigmoid函数作为激活函数,如图所示,它把可能在较大范围内变化的输入值挤压到(0,1)输出范围内,因此,有时也称为“挤压函数”。

把许多个这样的神经元按一定的层次结构连接起来,就得到了神经网络。

感知器能很容易地实现逻辑与、或、非的运算,注意到

            

假定函数f为图(a)中的阶跃函数,且x1,x2的取值为0或1,下面通过有两个输入神经元的感知器来实现逻辑与、或、非的运算。

  • “与”(x1∧x2):令w1=w2=1,θ=2,则

        

        仅在x1=x2=1时,y=1;

  • “或”(x1∨x2):令w1=w2=1,θ=0.5,则

        

        当x1=1或x2=1时,y=1;

  • “非”(¬x1):令w1=-0.6,w2=0,θ=-0.5,则

        

        当x1=1时,y=0;当x1=0时,y=1;

更一般地,给定训练数据集,权重wi(i=1,2,.... , n)以及阈值θ可通过学习得到,阈值θ可看作一个固定输入为-1.0的哑结点所对应的连接权重w(n+1),这样,权重和阈值的学习就可统一为权重的学习。

感知器权重(w)更新策略

感知器学习规则非常简单,对训练样例(x,y),若当前感知器的输出为,则感知器权重将这样调整:

        其中η∈(0, 1)称为学习率(learning rate),从上式可看出,若感知器对训练样例(x,y)预测正确,即,则感知器不发生变化,否则将根据错误的程度进行权重调整。

单层感知器的缺陷

        需要注意的是,单层感知器只有输出层神经元进行激活函数处理,即只拥有一层功能神经元(functional neuron),其学习能力非常有限,事实上,上述与、或、非问题都是线性可分的问题,可以证明,若两类模式是线性可分的,即存在一个线性超平面能将它们分开,感知器的学习过程一定会收敛(converge)而求得适当的权向量w=(w1;w2;.... ;wn;w(n+1));否则感知器学习过程将会发生振荡,w难以稳定下来,不能求得合适的解。即使是非常简单的非线性可分问题也不能解决,如:异或问题。

多层网络

        要解决非线性可分问题,需要考虑使用多层功能神经元。例如图5.5中这个简单的两层感知器就能解决异或问题,在图中,输出层与输入层之间的一层神经元,被称为隐层或隐含层(hidden layer),隐含层和输入层神经元都是拥有激活函数的功能神经元

        更一般地,常见的神经网络是形如图5.6所示的层级结构,每层神经元与下一层神经元全互连,神经元之间不存在同层连接,也不存在跨层连接,这样的神经网络结构通常称为“多层前馈神经网络”,其中输入层神经元接收外界输入,隐层与输入层神经元对信号进行加工,最终结果由输出层神经元输出;换言之,输入层神经元仅是接受输入,不进行函数处理,隐层与输出层包含功能神经元。因此,图5.6(a)通常被称为“两层网络”,即称为单隐层网络,只需包含隐层,即可称为多层网络。神经网络的学习过程,就是根据训练数据来调整神经元之间的“连接权”以及每个功能神经元的阈值;换言之,神经网络“学”到的东西,蕴含在连接权阈值中。

利用感知器实现线性分类

接下来通过单层感知器来实现对样本的线性分类,这里选用的激活函数为符号函数:

为了处理方便,这里将x=0的情况归为sgn(0)=1,即

        

# 导入一些需要的包
import random
import numpy as np
import matplotlib.pyplot as plt
# 定义自定义的符号函数
def sign(vec):
    if vec >= 0:
        return 1
    else:
        return -1
# 训练权重和阈值
def train(train_num, train_datas, lr):  # lr为学习率
    w = [0, 0]
    b = 0
    for i in range(train_num):
        x = random.choice(train_datas)  # 从序列中获取一个随机元素
        x1, x2, y = x  # 把随机选取的样本的分量依次赋值给x1,x2,y
        if(y*sign((w[0]*x1 + w[1]*x2 + b)) <= 0):  # 训练算法,如果符号函数与输出结果不一致,则更新权重和阈值
            w[0] += lr*y*x1
            w[1] += lr*y*x2
            b += lr*y
    return w, b  # 最终返回训练完成的权重和阈值
# 通过画图来查看模型对样本分类的好坏
def plot_points(train_datas, w, b):
    plt.figure()  # 创建图表
    x1 = np.linspace(0, 8, 100)
    x2 = (-b-w[0]*x1)/w[1]  # 分类直线满足的方程
    plt.plot(x1, x2, color='r', label='y1 data')  # 画出分类直线
    datas_len = len(train_datas)  # 看有几行,几个样本
    for i in range(datas_len):
        if(train_datas[i][-1]==1):  # 正样本用圆点标记,向量的最后一个分量[-1],也可以用[2]
            plt.scatter(train_datas[i][0], train_datas[i][1], s=50)
        else:
            plt.scatter(train_datas[i][0], train_datas[i][1], marker='x',s=50)  # 负样本用x标记
    plt.show()  # 画图

在上段程序中,对于已经训练好的权重和阈值,满足:

所以有

# 执行程序
if __name__=='__main__':
    train_data1 = [[1, 3, 1], [2, 2, 1], [3, 8, 1], [2, 6, 1]]  # 正样本
    train_data2 = [[2, 1, -1], [4, 1, -1], [6, 2, -1], [7, 3, -1]]  # 负样本
    train_datas = train_data1 + train_data2  # 样本集
    print(train_datas)
    w, b = train(train_num=50, train_datas=train_datas, lr=0.01)  # 训练50次
    plot_points(train_datas, w, b)  # 画出样本点及分类直线

显示结果:

在以后的博客中,逐渐涉及多层神经网络的构建与应用,深入其中,更能体会到神经网络的奥妙。

 

参考:

1、机器学习/周志华著.--北京:清华大学出版社,2016(2017.3重印)

 

 

转载于:https://my.oschina.net/u/3888421/blog/2253176

    原文作者:chiqi1020
    原文地址: https://blog.csdn.net/chiqi1020/article/details/100606789
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系管理员进行删除。