感知机

来源:互联网 发布:缩鼻翼手术多少钱知乎 编辑:程序博客网 时间:2024/05/01 09:49

感知机是二分类线性分类模型, 其输入为实例的特征向量, 输出为实例的类别, 取+1和-1二值。

感知机公式: 这里写图片描述

感知机的几何解释是,线性方程w*x+b=0 将特征空间划分为正负两个部分:
这里写图片描述

损失函数

如果训练集是可分的,感知机的学习目的是求得一个能将训练集正实例点和负实例点完全分开的分离超平面。为了找到这样一个平面(或超平面),即确定感知机模型参数w和b,我们采用的是损失函数,同时并将损失函数极小化。

对于损失函数的选择,我们采用的是误分类点到超平面的距离,也就是点到直线的距离:这里写图片描述, 其中||w||是L2范数。

对于误分类点(xi,yi)来说:这里写图片描述,误分类点到超平面的距离为:这里写图片描述,假设所有误分类点集合为M, 那么,所有误分类点到超平面的总距离为:这里写图片描述, 由于||w||对超平面的构成不起决定性作用,我们可以等比例的缩放w, b得到相同的超平面,于是我们可以使||w||为1,那么感知机的损失函数就为:这里写图片描述。其实 y*(w*x + b)称为函数间隔, 可以相对地表示点x距离超平面的远近。

可以看出,损失函数L(w,b)是非负的。如果没有误分类点,则损失函数的值为0,而且误分类点越少,误分类点距离超平面就越近,损失函数值就越小。同时,损失函数L(w,b)是连续可导函数

学习算法

感知机学习算法是对以下最优化问题的算法:

这里写图片描述
使用梯度下降法进行优化,损失函数的梯度为:
损失函数的梯度

算法伪代码:

输入:T={(x1,y1),(x2,y2)...(xN,yN)}(其中xi∈X=Rn,yi∈Y={-1, +1},i=1,2...N,学习速率为η)输出:w, b;感知机模型f(x)=sign(w·x+b)(1) 初始化w0,b0,权值可以初始化为0或一个很小的随机数(2) 在训练数据集中选取(x_i, y_i)(3) 如果yi(w xi+b)≤0           w = w + ηy_ix_i           b = b + ηy_i(4) 转至(2),直至训练集中没有误分类点

Python实现

正样本点:x1=(3,3)T,x2=(4,3)T
负样本点:x1=(1,1)T
求感知机模型f(x)=sign(w⋅x+b)

import copyfrom matplotlib import pyplot as pltfrom matplotlib import animationtraining_set = [[(3, 3), 1], [(4, 3), 1], [(1, 1), -1]]w = [0, 0]b = 0history = []def update(item):    """    update parameters using stochastic gradient descent    :param item: an item which is classified into wrong class    :return: nothing    """    global w, b, history    w[0] += 1 * item[1] * item[0][0]    w[1] += 1 * item[1] * item[0][1]    b += 1 * item[1]    print w, b    history.append([copy.copy(w), b])    # you can uncomment this line to check the process of stochastic gradient descentdef cal(item):    """    calculate the functional distance between 'item' an the dicision surface. output yi(w*xi+b).    :param item:    :return:    """    res = 0    for i in range(len(item[0])):        res += item[0][i] * w[i]    res += b    res *= item[1]    return resdef check():    """    check if the hyperplane can classify the examples correctly    :return: true if it can    """    flag = False    for item in training_set:        if cal(item) <= 0:            flag = True            update(item)    # draw a graph to show the process    if not flag:        print "RESULT: w: " + str(w) + " b: " + str(b)    return flagif __name__ == "__main__":    for i in range(1000):        if not check(): break    # first set up the figure, the axis, and the plot element we want to animate    fig = plt.figure()    ax = plt.axes(xlim=(0, 2), ylim=(-2, 2))    line, = ax.plot([], [], 'g', lw=2)    label = ax.text([], [], '')    # initialization function: plot the background of each frame    def init():        line.set_data([], [])        x, y, x_, y_ = [], [], [], []        for p in training_set:            if p[1] > 0:                x.append(p[0][0])                y.append(p[0][1])            else:                x_.append(p[0][0])                y_.append(p[0][1])        plt.plot(x, y, 'bo', x_, y_, 'rx')        plt.axis([-6, 6, -6, 6])        plt.grid(True)        plt.xlabel('x')        plt.ylabel('y')        plt.title('Perceptron Algorithm')        return line, label    # animation function.  this is called sequentially    def animate(i):        global history, ax, line, label        w = history[i][0]        b = history[i][1]        if w[1] == 0: return line, label        x1 = -7        y1 = -(b + w[0] * x1) / w[1]        x2 = 7        y2 = -(b + w[0] * x2) / w[1]        line.set_data([x1, x2], [y1, y2])        x1 = 0        y1 = -(b + w[0] * x1) / w[1]        label.set_text(history[i])        label.set_position([x1, y1])        return line, label    # call the animator.  blit=true means only re-draw the parts that have changed.    print history    anim = animation.FuncAnimation(fig, animate, init_func=init, frames=len(history), interval=1000, repeat=True,                                   blit=True)    plt.show()    anim.save('perceptron.gif', fps=2, writer='imagemagick')

可视化:
这里写图片描述

该算法是收敛的,具体证明过程可参考:《统计学习方法》P31
请其对偶形式本质上是一样的,在此不再多述,想了解的可以参考:《统计学习方法》P33

参考:
[1] 统计学习方法, 李航 著

原创粉丝点击