查看原文
其他

【41计划打卡-11】深度学习3-感知机

叉烧 CS的陋室 2022-08-08


往期精彩:

【41计划打卡-06】python基础的自学笔记

【41计划打卡-08】深度学习1-数学基础

【41计划打卡-09】贝叶斯统计思想

【41计划打卡-10】深度学习2-神经网络的概念和含义

开始之前做一发广告,我的一位学长开了知乎专栏,主写机器学习和统计学习方面的内容,有兴趣可以看看,有兴趣可以关注一下。下面是他第一篇文章的链接,

https://zhuanlan.zhihu.com/p/26596771

【本文唯一授权知乎专栏初学者KIRA的数学笔记】

前言

感知机,不严谨的说,可以看做是神经网络中的一个神经,用于接收、处理、传递信息的单元。在李航老师的《统计学习方法》中,将其解释为一种二分类的线性分类模型。在今天的篇章中将会介绍感知机。

原文链接是我在有道云笔记用markdown写的,这篇文章中涉及的代码将会放在我的github里面。https://github.com/ZBayes/Neural_Networks/tree/master/Peceptron

感知机初探

先是比较严格的定义,见下图:

以二维为例,一些点分布在一个平面直角坐标系内,这些点代表不同的个体,每个个体均属于-1或者1两类中的一个,感知机能找到一条直线,使得他们将平面分成两份,其中一侧是属于1,另一侧属于-1(当然了,知识满足最小误差)。如下图所示,找到条线,把红色和蓝色的分开。

找到这条线之后,当有新的点需要去判断属于哪一类时,只要计算该点在线的那一侧即可。

感知机使用的条件

其实非常简单,要另感知机生效,有较好的分类效果,这些点根据类-1和1的分布必须是线性可分的,要存在一条线令他们分开,才能去找。严格的定义如下:

但是,在计算之前,似乎没太多人去做这个判断,而是直接去训练感知机,如果结果怎么训练都不好,多半就是这个训练集线性不可分了。

感知机的训练方法

说是训练感知机,其实说白了就是求感知机里面你的两个参数,分别是w和b,于是问题就简单了,可以将问题根据损失函数最小化的无约束最优化问题解决。形式是这样的:

说说这个公式的构造,yi是实际值,而(w*xi+b)是预测值,yi只有两个值,1和-1,而分类器其实就是根据(w*xi+b)的正负性得到的,所以,两者如果同号,就表示分类正确,两者相乘为正,如果不同号则说明分类错误,两者相乘为负,换句话说,如果这两者相乘的结果越大,则说明分类越正确,反之亦然。求和说明把训练集内所有的样本都算出来,现在的公式是越大越好,前面加一个符号,就越小越好,于是,就有了上面的公式。

求解这个问题的方法就很多了,最速下降法,牛顿法,高级点的,遗传算法、模拟退火,粒子群之类的,都可以算(究其历史,其实“训练”这个词来源与计算机类专业的人,在数学中,喜欢叫做迭代或者粗暴的叫做计算,看来学术圈里面的神经网络和机器学习,能写一篇啊哈哈哈)。最常见的,应该就是随机梯度下降法了(Stochastic Gradient Descnt,SGD)。

随机梯度下降法

这个方法的核心其实就是最速下降法的变种,变在求最速下降方向时用的是随机取的一个样本求得的梯度方向。

此处不赘述最速下降法是啥,简单地说,就是一个瞎子在爬山,他要到山顶,那么他是按照最陡的方向走一步,然后再次判断最陡的地方,再走一步,直到到达山顶。(每步长度相同)

所以这个方法的关键就在于怎么求方向。

理论证明,最陡的方向就是梯度方向(负导数方向!)。因为需要求的而是w和 b,所以对上面的最优化问题,对w和b求偏导,有:

可以发现,这个梯度方向其实和y以及x的值有关,所以需要抽取错分类的x和y来计算上面的梯度,然后带入上面的梯度,求得迭代公式。

现随机取一个错分点yi,xi,则能用下面的方式求出新的w和b。

根据新的w和b,继续进行分类,随机拿出错分点继续算,如此迭代,最终得到最优解。严格地,其迭代过程如下:

代码实现

代码实现或运算

这里主要用python,python虽然有些人没学过,但是我相信,python这种比较高级的、接近人类自然语言的计算机语言大家应该能看懂。网址来源是这位老师。链接是:http://blog.csdn.net/amira_von/article/details/50934028

# -*- coding: utf-8 -*-  

""" 

Created on Sat Mar 19 13:49:04 2016 

 

@author: fengxinhe 

"""  

import copy  

from matplotlib import pyplot as pl  

from matplotlib import animation as ani  

  

w=[0,0]  #weight vector  

b=0      #bias   

yita=0.5   #learning rate  

data=[[(1,1),1],[(1,-1),1],[(-1,1), 1], [(-1,-1), -1]]

record=[]  

  

""" 

if y(wx+b)<=0,return false; else, return true 

"""  

def sign(vec):  

    global w,b  

    res=0  

    res=vec[1]*(w[0]*vec[0][0]+w[1]*vec[0][1]+b)    

    if res>0: return 1  

    else: return -1  

      

""" 

update the paramaters w&b 

"""  

def update(vec):  

    global w,b,record  

    w[0]=w[0]+yita*vec[1]*vec[0][0]  

    w[1]=w[1]+yita*vec[1]*vec[0][1]  

    b=b+yita*vec[1]  

    record.append([copy.copy(w),b])  

  

""" 

check and calculate the whole data one time 

if all of the input data can be classfied correctly at one time,  

we get the answer 

"""   

def perceptron():  

    count=1  

    for ele in data:  

        flag=sign(ele)  

        if not flag>0:  

            count=1  

            update(ele)  

        else:  

            count+=1  

    if count>=len(data):  

        return 1  

          

        

          

if __name__ == "__main__":  

  while 1:  

       if perceptron() > 0:  

            break  

  print record  

x1=[]  

y1=[]  

x2=[]  

y2=[]  

  

#display the animation of the line change in searching process  

fig = pl.figure()  

ax = pl.axes(xlim=(-2, 2), ylim=(-2, 2))  

line,=ax.plot([],[],'g',lw=2)  

  

def init():  

    line.set_data([],[])  

    for p in data:  

        if p[1]>0:  

            x1.append(p[0][0])  

            y1.append(p[0][1])  

        else:  

            x2.append(p[0][0])  

            y2.append(p[0][1])  

    pl.plot(x1,y1,'or')  

    pl.plot(x2,y2,'ob')  

    return line,  

  

  

def animate(i):  

    global record,ax,line  

    w=record[i][0]  

    b=record[i][1]  

    x1=-5  

    y1=-(b+w[0]*x1)/w[1]  

    x2=6  

    y2=-(b+w[0]*x2)/w[1]  

    line.set_data([x1,x2],[y1,y2])  

    return line,  

      

animat=ani.FuncAnimation(fig,animate,init_func=init,frames=len(record),interval=1000,repeat=True,  

                                   blit=True)  

pl.show() 


我努力地找了一下,似乎没看到比较靠谱的py的感知机包,然而并没有。上面的就当做一个示例吧~

线性可分问题的解释

这里,我还是比较喜欢matlab的可视化,所以用下面的代码来画画逻辑或和逻辑异或的点的分布。

% ORx1=[1,1;1,-1;-1,1]; x2=[-1,-1]; subplot(1,2,1) hold on axis([-2,2,-2,2]) plot(x1(:,1),x1(:,2),'b*') plot(x2(:,1),x2(:,2),'g*') hold off% XORx1=[1,1;-1,-1]; x2=[-1,1;1,-1]; subplot(1,2,2) hold on axis([-2,2,-2,2]) plot(x1(:,1),x1(:,2),'b*') plot(x2(:,1),x2(:,2),'g*') hold off

画出来的图像是这样的:

左边的是或的图像,可以看到很明显可以找到一条线,能区分不同标记的点,相反,右边的异或是找不到这样的一条线的,所以并不能用感知机描述异或。

感知机不能解决线性可分问题,那么有两个思路,一个是将点投射到新的空间,或者把分类的直线转为曲线,这是非线性支持向量机的思想,另外一个思路就是,一个不行,那就两个感知机,那便是现在非常流行的神经网络!

参考文献

  • 李航. 统计学习方法

  • 吴岸城. 神经网络与深度学习

  • FXH_94. 感知机Python实现


微信:zgr950123
QQ:545281848欢迎关注

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存