统计学习方法(二)——感知机

/*先把标题给写了、这样就能常常提醒本身*/html

1. 感知机模型

咱们先来定义一下什么是感知机。所谓感知机,就是二类分类的线性分类模型,其输入为样本的特征向量,输出为样本的类别,取+1和-1二值,即经过某样本的特征,就能够准确判断该样本属于哪一类。顾名思义,感知机可以解决的问题首先要求特征空间是线性可分的,再者是二类分类,即将样本分为{+1, -1}两类。从比较学术的层面来讲,由输入空间到输出空间的函数:java

                                                                                                         (1)python

称为感知机,w和b为感知机参数,w为权值(weight),b为偏置(bias)。sign为符号函数:git

                                                                                                         (2)github

感知机模型的假设空间是定义在特征空间中的全部线性分类模型,即函数集合{f|f(x) = w·x + b}。在感知机的定义中,线性方程w·x + b = 0对应于问题空间中的一个超平面S,位于这个超平面两侧的样本分别被归为两类,例以下图,红色做为一类,蓝色做为另外一类,它们的特征很简单,就是它们的坐标算法

QQ截图20130410141720

图1api

做为监督学习的一种方法,感知机学习由训练集求得感知机模型,即求得模型参数w,b,这里x和y分别是特征向量和类别(也称为目标)。基于此,感知机模型能够对新的输入样本进行分类。网络

前面半抄书半自说自话把感知机的定义以及是用来干吗的简单记录了一下,做为早期的机器学习方法(1957年由Frank Rosenblatt提出),它是最简单的前馈神经网络,对以后的机器学习方法如神经网络起一个基础的做用,下一节将详细介绍感知机学习策略。机器学习

2. 感知机学习策略

上节说到,感知机是一个简单的二类分类的线性分类模型,要求咱们的样本是线性可分的,什么样的样本是线性可分的呢?举例来讲,在二维平面中,能够用一条直线将+1类和-1类完美分开,那么这个样本空间就是线性可分的。如图1就是线性可分的,图2中的样本就是线性不可分的,感知机就不能处理这种状况。所以,在本章中的全部问题都基于一个前提,就是问题空间线性可分。函数

QQ截图20130409223755

图2

为方便说明问题,咱们假设数据集中全部的的实例i,有;对的实例有

这里先给出输入空间中任一点到超平面S的距离:

                                                                                                               (3)

这里||w||是w的范数。

对于误分类的数据,根据咱们以前的假设,有

                                                                                                          (4)

所以误分类点到超平面S的距离能够写做:

                                                                                                            (5)

假设超平面S的误分类点集合为M,那么全部误分类点到超平面S的总距离为

                                                                                                    (6)

这里的||w||值是固定的,没必要考虑,这样就获得了感知机学习的损失函数。根据咱们的定义,这个损失函数天然是越小越好,由于这样就表明着误分类点越少、误分类点距离超平面S的距离越近,即咱们的分类面越正确。显然,这个损失函数是非负的,若全部的样本都分类正确,那么咱们的损失函数值为0。一个特定的样本集T的损失函数:在误分类时是参数w,b的线性函数。也就是说,为求得正确的参数w,b,咱们的目标函数为

                                                                                          (7)

而它是连续可导的,这就使得咱们能够比较容易的求得其最小值。

感知机学习的策略是在假设空间中选取使咱们的损失函数(7)最小的模型参数w,b,即感知机模型。

根据感知机定义以及咱们的假设,获得了感知机的模型,即目标函数(7),将其最小化的本质就是使得分类面S尽量的正确,下一节介绍将其最小化的方法——随机梯度降低。

3. 感知机学习算法

根据感知机学习的策略,咱们已经将寻找超平面S的问题转化为求解式(7)的最优化问题,最优化的方法是随机梯度降低法,书中介绍了两种形式:原始形式和对偶形式,并证实了在训练集线性可分时算法的收敛性。

3.1 原始形式

所谓原始形式,就是咱们用梯度降低的方法,对参数w和b进行不断的迭代更新。具体来讲,就是先任意选取一个超平面,对应的参数分别为,固然如今是能够任意赋值的,好比说选取为全为0的向量,的值为0。而后用梯度降低不断地极小化损失函数(7)。因为随机梯度降低(stochastic     gradient descent)的效率要高于批量梯度降低(batch gradient descent)(详情可参考Andrew Ng教授的讲义,在Part 1的LMS algorithm部分),因此这里采用随机梯度降低的方法,每次随机选取一个误分类点对w和b进行更新。

设误分类点集合M是固定的,为求式(7)的最小值,咱们须要知道往哪一个方向降低速率最快,这是可由对损失函数L(w, b)求梯度获得,L(w, b)的梯度为

接下来随机选取一个误分类点对w,b进行更新

                                                                                                                (8)

                                                                                                                      (9)

其中为步长,也称为学习速率(learning rate),通常在0到1之间取值,步长越大,咱们梯度降低的速度越快,也就能更快接近极小点。若是步长过大,就有直接跨过极小点致使函数发散的问题;若是步长太小,可能会耗费比较长的时间才能达到极小点。经过这样的迭代,咱们的损失函数就不断减少,直到为0。综上所述,获得以下算法:

算法1 (感知机学习算法的原始形式)

输入:训练数据集,其中,i = 1,2,…,N;学习率

输出:w,b;感知机模型

(1)选取初始值

(2)在训练集中选取数据

(3)若是(从公式(3)变换而来)

(4)转至(2),直至训练集中没有误分类点

这种学习算法直观上有以下解释:当一个样本被误分类时,就调整w和b的值,使超平面S向误分类点的一侧移动,以减小该误分类点到超平面的距离,直至超平面越过该点使之被正确分类。

书上还给出了一个例题,这是我推崇这本书的缘由之一,凡是只讲理论不给例子的行为都是耍流氓!

例1 如图3所示的训练数据集,其正实例点是,负实例点是,试用感知机学习算法的原始形式求感知机模型,即求出w和b。这里

QQ截图20130412173717

图3

这里咱们取初值,取。具体问题解释不写了,求解的方法就是算法1。下面给出这道题的Java代码(终于有一段是本身纯原创的了)。

 
 
package org.juefan.perceptron;
import java.util.ArrayList;
import org.juefan.basic.FileIO;
public class PrimevalPerceptron {
    
    public static ArrayList<Integer> w  = new ArrayList<>();
    public static int b ;
    
    /*初始化参数*/
    public PrimevalPerceptron(){
        w.add(5);
        w.add(-2);
        b = 3;
    }
    
    /**
     * 判断是否分类正确
     * @param data 待判断数据
     * @return 返回判断正确与否
     */
    public static boolean getValue(Data data){
        int state = 0;
        for(int i = 0; i < data.x.size(); i++){
            state += w.get(i) * data.x.get(i);
        }
        state += b;
        return state * data.y > 0? true: false;    
    }
    
    //此算法基于数据是线性可分的,若是线性不可分,则会进入死循环
    public static boolean isStop(ArrayList<Data> datas){
        boolean isStop = true;
        for(Data data: datas){
            isStop = isStop && getValue(data);
        }
        return isStop;
    }
    
    public static void main(String[] args) {
        PrimevalPerceptron model = new PrimevalPerceptron();
        ArrayList<Data> datas = new ArrayList<>();
        FileIO fileIO = new FileIO();
        fileIO.setFileName(".//file//perceptron.txt");
        fileIO.FileRead();
        for(String data: fileIO.fileList){
            datas.add(new Data(data));
        }
    
        /**
         * 若是所有数据都分类正确则结束迭代
         */
        while(!isStop(datas)){
            for(int i = 0; i < datas.size(); i++){
                if(!getValue(datas.get(i))){  //这里面能够理解为是一个简单的梯度降低法
                    for(int j = 0; j < datas.get(i).x.size(); j++)
                    w.set(j, w.get(j) + datas.get(i).y * datas.get(i).x.get(j));
                    b += datas.get(i).y;
                    System.out.println(w + "\t" + b);
                }
            }
        }    
        System.out.println(w + "\t" + b);        //输出最终的结果
    }
}

最后解得(这里应该是写错了,最终结果b=-3)。不过,若是选取的初值不一样,或者选取的误分类点不一样,咱们获得的超平面S也不尽相同,毕竟感知机模型的解是一组符合条件的超平面的集合,而不是某一个最优超平面。

3.2 算法的收敛性

一节纯数学的东西,用了两整页证实了Novikoff定理,看到这里才知道智商真的是个硬伤,反复看了两遍,又把证实的过程本身推导了一遍,算是看懂了,若是凭空证实的话,本身的功力还差得远。

Novikoff于1962年证实了感知机算法的收敛性,做为一个懒人,因为这一节涉及大量公式,即便有latex插件也是个麻烦的工做,具体什么状况我就不谈了,同时,哥伦比亚大学有这样的一篇叫《Convergence Proof for the Perceptron Algorithm》的笔记,讲解了这个定理的证实过程,也给了我一个偷懒的理由微笑

3.3 感知机学习算法的对偶形式

书上说对偶形式的基本想法是,将w和b表示为实例的线性组合形式,经过求解其系数而求得w和b。这个想法及下面的算法描述很容易看懂,只不过为何要这么作?将w和b用x和y来表示有什么好处呢?看起来也不怎么直观,计算量上彷佛并无减小。若是说支持向量机的求最优过程使用对偶形式是为了方便引入核函数,那这里的对偶形式是用来作什么的呢?暂且认为是对后面支持向量机的一个铺垫吧,或者是求解这种优化问题的一个广泛解法。

继续正题,为了方便推导,可将初始值都设为0,据上文,咱们对误分类点经过

来更新w,b,假设咱们经过误分类点更新参数的次数为次,那么w,b关于的增量为,为方便,可将来表示,很容易能够获得

                                                                                                         (10)

                                                                                                               (11)

这里i = 1,2,…,N。当时,表示第i个样本因为被误分类而进行更新的次数。某样本更新次数越多,表示它距离超平面S越近,也就越难正确分类。换句话说,这样的样本对学习结果影响最大。

算法2 (感知机学习算法的对偶形式)

输入:训练数据集,其中,i = 1,2,…,N;学习率

输出:,b;感知机模型

其中

(1)

(2)在训练集中选取样本

(3)若是

(4)转至(2)直到没有误分类样本出现

因为训练实例仅之内积的形式出现,为方便,可预先将训练集中实例间的内积计算出来并以矩阵形式存储(就是那个的部分),这就是所谓的Gram矩阵(线性代数学的很差的飘过ToT):

又到例题时间!再说一遍,这本书最大的好处就是有实例,凡是只讲理论不给例子的行为都是耍流氓!

例2 同例1,只不过是用对偶形式来求解。

一样过程再也不分析,给出个人求解代码:

 

package org.juefan.perceptron;
import java.util.ArrayList;
import org.juefan.basic.FileIO;
public class GramPerceptrom {
    
    public static ArrayList<Integer> a  = new ArrayList<>();
    public static int b ;
    
    /*初始化参数*/
    public GramPerceptrom(int num){
        for(int i = 0; i < num; i++)
            a.add(0);
        b = 0;
    }
    /**Gram矩阵*/
    public static ArrayList<ArrayList<Integer>> gram = new ArrayList<>();
    public void setGram(ArrayList<Data> datas){
        for(int i = 0; i < datas.size(); i++){
            ArrayList<Integer> rowGram = new ArrayList<>();
            for(int j = 0; j < datas.size(); j++){
                rowGram.add(Data.getInner(datas.get(i), datas.get(j)));
            }
            gram.add(rowGram);
        }
    }
    
    /**是否正确分类*/
    public static boolean isCorrect(int i, ArrayList<Data> datas){
        int value = 0;
        for(int j = 0; j < datas.size(); j++)
            value += a.get(j)*datas.get(j).y * gram.get(j).get(i);
        value = datas.get(i).y * (value + b);
        return value > 0 ? true: false;
    }
    
    //此算法基于数据是线性可分的,若是线性不可分,则会进入死循环
    public static boolean isStop(ArrayList<Data> datas){
        boolean isStop = true;
        for(int i = 0; i < datas.size(); i++){
            isStop = isStop && isCorrect(i, datas);
        }
        return isStop;
    }
    
    public static void main(String[] args) {
        ArrayList<Data> datas = new ArrayList<>();
        FileIO fileIO = new FileIO();
        fileIO.setFileName(".//file//perceptron.txt");
        fileIO.FileRead();
        for(String data: fileIO.fileList){
            datas.add(new Data(data));
        }
        GramPerceptrom gram  = new GramPerceptrom(datas.size());
        gram.setGram(datas);
        System.out.println(datas.size());
        while(!isStop(datas)){
            for(int i = 0; i < datas.size(); i++)
                if(!isCorrect(i, datas)){
                    a.set(i, a.get(i) + 1);
                    b += datas.get(i).y;
                    System.out.println(a + "\t" + b);
                }
        }
    }
}

 

4. 小结

终于写完一章的内容了,用了很多功夫,果真是提及来容易作起来难呢。不过经过这样记录的方式(虽然大部分是抄书),本身对相关算法的理论及过程就又学了一遍,以为这个时间仍是花的值得的。

本章介绍了统计学习中最简单的一种算法——感知机,对如今的机器学习理论来讲,这个算法的确是太简单了,但这样简单的东西倒是不少如今流行算法的基础,好比神经网络,好比支持向量机,Deep Learning还没了解过,不知道有多大联系。固然,实际应用价值不能说没有,能够用于一些简单的线性分类的状况,也能够由简单的二类分类扩展到多类分类(详见此PPT),能够用于天然语义处理等领域。

再将思路整理一下,尽可能掌握感知机算法,再好好看看维基百科连接中的有关文献。

 

PS:本文的内容转载自 http://www.cnblogs.com/OldPanda/archive/2013/04/12/3017100.html

原博主是Python写的代码,我这边改为Java了

对代码有兴趣的能够上本人的GitHub查看:https://github.com/JueFan/StatisticsLearningMethod/

2014-06-29:俩种算法的代码都完成了,更新完毕

相关文章
相关标签/搜索