机器学习_感知机

2018-12-01  本文已影响0人  克里斯托弗的梦想

近期,打算重温机器学习算法,之前看过之后就忘了,没有达到真正的消化,这次以思考总结和代码实践为主,发现一些不懂问题会记录下来,然后找人讨论后补充问题答案,大家看到的话,也希望能给我一些建议,希望以此来带动自己一个人学习中的不足。
声明:我写作可能比较口语化,主要为了写的时候思路稍微清晰点,勿见怪。

感知机模型

首先,感知机是二分类的线性分类模型,它的输入是样本的特征向量,输出是样本的类别,取+1,-1二值(问题1)。感知机模型其实形象的看,就是几何语言中所说的超平面,能够把正负样本进行线性划分,这里我们称它为分离超平面。

下面用统计学习方法一书中专业术语定义感知机模型。


感知机学习策略

首先,假设训练集是线性可分的(问题2),就是说一定存在一个分离超平面,使得正负样本完全正确的分开。那下面就是怎么找这个超平面了,就是确定感知机模型的参数w和b,因此就需要一个学习策略,而这个学习策略也就是机器学习中常见的使损失函数极小化。

如何定义感知机模型的损失函数呢
思路1:误分类样本的总数。如果误分类样本总数等于0,那不就自然确定了这个分离超平面嘛?但你怎么去优化呢,比如你先初始化了w,b确定了一个超平面,然后找到了误分类的样本总数,但接下来呢,咋做,很显然进行不下去了,因为这样的损失函数不是参数w,b的连续可导函数。
思路2:利用误分类点到超平面的总距离。任意一个点x到超平面距离如下:


这里,||w||是w的L2范数。
那么就有,

这里说明一下为什么不考虑1/||w||?
首先我们的目标就是减少超平面分类过程中出现的误分类样本,只不过我们用了点到超平面的距离这个公式,但它最终并不关心各个误分类点到超平面的距离,我们只关心我们的目标,是否分类正确了。而w的范式始终是大于0,对于我们判断是否为误分类点(通过是否-y(w*x+b)>0来判断是否为误分类点)没有影响!当然,你如果直接用这个距离当做损失函数也没错,可能在求解过程中比较复杂而已,影响性能。

好,那定义了最终的损失函数之后,怎么求得最终的分类超平面呢?这时候你就需要求解了,咋求解?很简单,不就是求L(w,b)最小值问题。这个高中大学都学过吧,咋求一个函数的最小值,从而确定参数的值,这个可以自己回忆下。这里我们利用最优化理论的知识去求参数,最简单就是梯度下降法,梯度下降这里原理不多说,以后复习到会开专章讨论。
最终的损失函数求解minL(w,b):


梯度下降法



采用随机梯度下降,就是随机选取一个误分类点,对w,b进行更新:



这里的n(打不出来公式那个阿拉伯字符)就是学习率,在(0,1]之间取值,也可以理解为更新w,b的步长。

下面用一个小例子模仿求解分离超平面的过程,也就是求w和b。
例子如下图:



其实你会发现,感知机学习算法存在许多解,比如你的初始值选取不同,可能w,b最后的值就不同,也就是你的分离超平面不同,还有你的步长n的选取也影响最终的结果。想象一下,假设正负样本线性可分,会存在一个分离超平面,但是不是不保证这是唯一的一个分离超平面呢!

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

通过我们看那个例子,可知我们是一个样本一个样本的代入求解感知机模型。比如,先定义初始值w,b,然后代入一个样本到模型,发现这个是误分类的样本,开始根据随机梯度下降法更新w,b,然后再继续重复,只不过代入到的模型是更新后的w,b。其实这个过程可以连续在一起写
就是最终学习到的w,b如下表示:


可以看出,一个实例样本更新次数越多,意味着它距离超平面越近,但同时说明也越难正确分类,这样的实例样本对学习结果影响就最大。

其实,从对偶形式看出,我们再迭代更新w,b,其实就是一步步去更新那个a(打印不出那个阿拉伯字符),a相当于把原始形式中的w写成展开形式,所以更新时只加η就够了,b还用的原始形式,没有变。

下面有两个问题思考:
1、感知机是针对线性可分的训练集建立的模型,但大部分分类很难保证训练集线性可分,这个就是感知机的缺陷,对非线性的可分该怎么处理呢,或者对不可分的训练集该怎么处理呢?
2、感知机的输出样本类别是(+1,-1),那么是否可以用其他类别代替呢,比如(0,1)是否可行呢?

实现代码
# 原始形式的感知机算法
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
# 加载数据,分别存储实例样本和对应的标签,数据就是每行3个数,最后一个数是标签,用的tab键,比如某一行 2  4  -1
def load_data():
    data = np.loadtxt('test.txt')
    data_mat = data[:, 0:2]
    label_mat = data[:, 2]
    return data_mat, label_mat

# sign()函数定义
def sign(val):
    if val >= 0:
        return 1
    else:
        return -1
    
# 根据感知机原始形式训练模型步骤,更新w,b
def train_perceptron(data_mat, label_mat, eta):
    """训练模型,参数eta是学习率"""
    # m是样本个数,n是特征维度
    m, n = data_mat.shape
    # 根据样本特征维度大小初始化权重w向量
    weight = np.zeros(n)
    # 就是那个b,偏执项
    bias = 0 
    flag = True
    while flag:
        for i in range(m):
            if label_mat[i]*(np.dot(weight, data_mat[i])+bias)<=0:
                weight = weight + eta*label_mat[i]*data_mat[i].T
                bias = bias + eta*label_mat[i]
                print("weight, bias: ", end="")
                print(weight, end=" ")
                print(bias)
                flag=True
                break
            else:
                flag=False
    return weight, bias


def plot_result(data_mat, label_mat, weight, bias):
    fig = plt.figure()
    axes = fig.add_subplot(111)
    type1_x = []
    type1_y = []
    type2_x = []
    type2_y = []
    for i in range(len(label_mat)):
        if label_mat[i] == -1:
            type1_x.append(data_mat[i][0])
            type1_y.append(data_mat[i][1])
            
        if label_mat[i] == 1:
            type2_x.append(data_mat[i][0])
            type2_y.append(data_mat[i][1])
    # 样本的散点图
    type1 = axes.scatter(type1_x, type1_y, marker='x', s=20, c='red')
    type2 = axes.scatter(type2_x, type2_y, marker='o', s=20, c='blue')
    # 这个是为了画出那条分离超平面,先把x1 分别取0.1和4,求出x2,然后两点确定一条直线,就画出来了
    y = (0.1 * (-weight[0])/ weight[1] + -bias / weight[1], 4.0 * (-weight[0]) / weight[1] + (-bias )/ weight[1])
    axes.add_line(Line2D((0.1, 4.0), y, linewidth=1, color='blue'))
    
    plt.xlabel('X')
    plt.ylabel('Y')
    
    plt.show()


if __name__ == "__main__":
    dataMat, labelMat = load_data()
    weight, bias = train_perceptron(dataMat, labelMat, 1)
    plot_result(dataMat, labelMat, weight, bias)
import numpy as np
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D


def loadData():
    data = np.loadtxt('test.txt')
    dataMat = data[:, 0:2]
    labelMat = data[:, 2]
    # 这个和上面的代码稍微不同,数据格式变化,比如[1,1,-1]变成[ [1], [1], [-1] ],为后面的公式代入做准备。
    labelMat = labelMat.reshape((labelMat.shape[0], 1))
    return dataMat, labelMat


def trainModel(dataMat, labelMat, alpha, b, eta):
    """
    训练模型
    b:bias
    eta:learning rate
    """
    flag = True
    while flag:
        for i in range(m):
            # 这个根据对偶形式的公式
            if (labelMat[i, 0] * (np.sum((alpha * labelMat * np.dot(dataMat, dataMat[i].T).reshape((m, 1)))) + b)) <= 0:
                alpha[i] = alpha[i] + eta
                b = b + eta * labelMat[i]
                flag = True
                break
            else:
                flag = False
    w = np.dot(dataMat.T, alpha * labelMat)
    return w, b


# 可视化结果
def plotResult(dataMat, labelMat, weight, bias):
    fig = plt.figure()
    axes = fig.add_subplot(111)

    type1_x = []
    type1_y = []
    type2_x = []
    type2_y = []
    for i in range(len(labelMat)):
        if (labelMat[i] == -1):
            type1_x.append(dataMat[i][0])
            type1_y.append(dataMat[i][1])

        if (labelMat[i] == 1):
            type2_x.append(dataMat[i][0])
            type2_y.append(dataMat[i][1])

    type1 = axes.scatter(type1_x, type1_y, marker='x', s=20, c='red')
    type2 = axes.scatter(type2_x, type2_y, marker='o', s=20, c='blue')

    y = (0.1 * -weight[0] / weight[1] + -bias / weight[1], 4.0 * -weight[0] / weight[1] + -bias / weight[1])
    axes.add_line(Line2D((0.1, 4.0), y, linewidth=1, color='blue'))

    plt.xlabel('X')
    plt.ylabel('Y')

    plt.show()


if __name__ == "__main__":
    dataMat, labelMat = loadData()
    m, n = dataMat.shape
   # 这个是a,在对偶形式中不断更新的,从而更新w
    alpha = np.zeros((m, 1))
    b = 0
   # 学习率
    eta = 1
    w, b = trainModel(dataMat, labelMat, alpha, b, eta)
    print("w: ", end="")
    print(w)
    print("b: %d" % b)
    plotResult(dataMat, labelMat, w, b)

参考代码及博客:
1、代码参考:https://github.com/yangliu0/MachineLearning/tree/master/Perceptron
2、博客:http://www.88812315.cn/smzx/xiangqing45226319.htm
3、书籍:统计学习方法(李航)- 感知机

上一篇 下一篇

猜你喜欢

热点阅读