感知机原始形式、对偶形式

感知机的原始形式

对于输入样本特征数据,感知机通过以下函数将其映射至{+1,-1}的输出空间 

f(x)=sign(wx+b)f(x)=sign(w⋅x+b)
(1) 
对于所有的错分类点iMi∈M,都有yi(wxi+b)>0−yi(w⋅xi+b)>0,因此我们可以定义如下的损失函数作为优化准则: 
L(w,b)=xiMyi(wxi+b)L(w,b)=−∑xi∈Myi(w⋅xi+b)
(2) 
通过求解损失函数(2)的梯度(3), 
wL(w,b)=xiMyixibL(w,b)=xiMyi∇wL(w,b)=−∑xi∈Myixi∇bL(w,b)=−∑xi∈Myi
(3) 
我们很容易就可以得到感知机学习算法的原始形式. 
ww+ηyixibb+ηyiw←w+ηyixib←b+ηyi
(4) 
整个算法流程如下:

  1. 选取初值w0,b0
  2. 在训练集中任意选取点(xi,yi)
  3. 如果yi(wxi+b)>0−yi(w⋅xi+b)>0则按照(4)式更新w,b4
  4. 重复2直到没有被误分的点

感知机的对偶形式

相比于原始形式,其对偶形式在理解上没有前者那么直观,网上关于其实现代码的例子也比较少。 
在《统计学习方法》一书中,关于对偶形式有如下的描述:

对偶形式的基本想法是,将w和b表示为实例xixi 和标记 yiyi 的线性组合的形式,通过求解其系数而求得w和b.

假设w0=0,b=0,那么从(4)式可以看出,当所有的点均不发生误判时,最后的w,b一定有如下的形式: 

w=i=1Nniηyixi=i=1Nαiyixib=i=1Nniηyi=i=1Nαiyiw=∑i=1Nniηyixi=∑i=1Nαiyixib=∑i=1Nniηyi=∑i=1Nαiyi

(5) 
其中αi=niηαi=niηnini代表对第i个样本的学习次数,感知机对偶形式的完整形式即为(6)式: 
f(x)=sign(j=1Nαjyjxjx+b)f(x)=sign(∑j=1Nαjyjxj⋅x+b)
(6)


注:经过对偶形式变换,原始形式中 w 和 b的迭代转换成 α 和 b 的迭代。且此时训练数据中有多少个样本,α 值就有多少个值。

                                                     

由于表示第i个样本被用来调整参数的次数,表示学习率或者步长。也就说第i个样本被用来调整参数,则

累加一个,因此的更新方式就是累加


  1. 初始化α=0α=0,b=0b=0.
  2. 任意选取(xi,yi)
  3. 如果yi(j=1Nαjyjxjxi+b)0yi(∑j=1Nαjyjxj⋅xi+b)≤0,即发生误判,则对αi,bαi,b进行更新: 
    αiαi+ηbibi+ηyiαi←αi+ηbi←bi+ηyi
  4. 重复2直到所有点都被正确分类

简而言之,感知机的对偶形式就是把对w,bw,b的学习变成了对α,bα,b的学习,原始形式中,ww在每一轮迭代错分时都需要更新,而采用对偶形式时,对于某一点(xi,yi)发生错分时,我们只需要更新其对应的αiαi即可,最后按照(5)式即可一次计算出ww
同时我们上述步骤3中的yi(j=1Nαjyjxjxi+b)0yi(∑j=1Nαjyjxj⋅xi+b)≤0可以看出,xjxixj⋅xi仅以内积的形式出现,因此我们可以是先计算出x的gram矩阵存储起来,这样正式训练时只需要查表就可以得到xjxixj⋅xi的值,这样做可以方便程序的优化,提高运算的速度。 

原始形式和对偶形式对参数b的处理是相同的。 

例:训练数据集,其正实例点是 x1=(3,3)^T, x2=(4,3)^T ,负实例点是x3=(1,1)^T

                                                

                                  

                               


python实现:

原始形式实现:

from __future__ import division
import random
import numpy as np
import matplotlib.pyplot as plt  


def sign(v):
    if v>=0:
        return 1
    else:
        return -1

def train(train_num,train_datas,lr):
    w=[0,0]
    b=0
    for i in range(train_num):
        x=random.choice(train_datas)
        x1,x2,y=x
        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):
            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)  
    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  # 样本集
    w,b=train(train_num=50,train_datas=train_datas,lr=0.01)
    plot_points(train_datas,w,b)

对偶形式实现:

from __future__ import division
import random
import numpy as np
import matplotlib.pyplot as plt  


def sign(v):
    if v>=0:
        return 1
    else:
        return -1

def train(train_num,train_datas,lr):
    w=0.0
    b=0
    datas_len = len(train_datas)
    alpha = [0 for i in range(datas_len)]
    train_array = np.array(train_datas)
    gram = np.matmul(train_array[:,0:-1] , train_array[:,0:-1].T)
    for idx in range(train_num):
        tmp=0
        i = random.randint(0,datas_len-1)
        yi=train_array[i,-1]
        for j in range(datas_len):
            tmp+=alpha[j]*train_array[j,-1]*gram[i,j]
        tmp+=b
        if(yi*tmp<=0):
            alpha[i]=alpha[i]+lr
            b=b+lr*yi
    for i in range(datas_len):
        w+=alpha[i]*train_array[i,0:-1]*train_array[i,-1]
    return w,b,alpha,gram

def plot_points(train_datas,w,b):
    plt.figure()
    x1 = np.linspace(0, 8, 100)
    x2 = (-b-w[0]*x1)/(w[1]+1e-10)
    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):
            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)  
    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  # 样本集
    w,b,alpha,gram=train(train_num=500,train_datas=train_datas,lr=0.01)
    plot_points(train_datas,w,b)


阅读更多
换一批

没有更多推荐了,返回首页