感知机 perceptron : 二分类的线性分类模型,属于判别模型
基本概念:
数据集T:
T= { (x1,y1),(x2,y2) , .....(xn,yn)} yi ={ -1, +1 } i ∈ (1,n)
线性可分数据集: (linearly separable date set)
存在某个超平面 w.x+b = 0,能够将数据集的正实例点和负实例点全部正确划分到超平面的两侧.
即:yi = +1 , w.xi +b > 0
yi = -1 , w.xi +b < 0
sign为符号函数:
h(x)=sign(w⋅x+b) 感知机函数
线性分类器的几何表示有:直线(二维)平面(3维)、超平面(高纬)
下图中间的直线即 w⋅x+b=0
学习策略:求得一个能够将训练集正实例点和负实例点完全正确分开的超平面(separating hyperplane)
损失函数: 误分类总点数 -> 所有误分类点到超平面距离之和 (转换问题求解)
极小化损失函数:点到直线的距离(有代数形式和向量形式)
推导:
1:点到直线的距离
2:对误分类点
如果 w * xi + b> 0 , yi = -1 (将负实例点判断为正实例点)
(w * xi + b) * yi < 0
如果 w * xi + b< 0 , yi = 1 (将正实例点判断为负实例点)
(w * xi + b) * yi < 0
距离是整数,所以对一个误分类点 d
3: 一个数可以不用考虑
4:所有误分类距离相加
极小化目标函数:
梯度下降: 分别对 w, b 求偏导数
极小化过程不是一次使M中所有误分类点的梯度下降,而是一次随机的选取一个误分类点使其梯度下降。使用的规则为 θ:=θ−α∇θℓ(θ),其中α是步长,∇θℓ(θ)是梯度。
随机选取一个误分类点根据上面的规则,更新w,b
w:= w -η*yi*xi
b:=b-η*yi
η是学习率 learingrate (0,1),这样,通过迭代可以期待损失函数L(w,b)不断减小,直至为0.
算法的收敛性证明:
感知机学习算法原始形式:
输入:T={(x1,y1),(x2,y2)...(xN,yN)}(其中xi∈X=Rn,yi∈{-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 + ηyixi
b = b + ηyi
(4) 转至(2),直至训练集中没有误分类点
实例:
《统计学习方法》第二版李航 P40
正实例点:x1 =(3,3) x2=(4,3)
负实例点:x3=(1,1)
import numpy as np
import matplotlib.pyplot as plt
#训练数据
x = np.array([(3.0,3.0),(4.0,3),(1,1)])
#标签
y = np.array([(1),(1),(-1)])
#参数初始化
w = np.array([0.0,0.0])
b = np.array([0.0])
learngrate = 1
i = 0
while True:
if y[i]*(w@x[i] +b )<= 0: # 出现分类错误的点
w += learngrate*x[i]*y[i] #参数更新
b += learngrate*y[i]
i=0
elif i<2:
i+=1
else :
break
print("训练结果:w= ",w,"b=",b)
#画图
#训练数据点
x1 = [3,4,1]
x2 = [4,3,1]
plt.plot(x1,x2,'ro')
#超平面
x_1 =np.linspace(1,5)
x_2 =-(w[0]*x_+b)/w[1] #根据超平面公式
plt.plot(x_1,x_2)
plt.grid(True) # 显示网格
plt.xlabel('x1')
plt.ylabel('x2') # 为了和原理中表达方式一致,横纵坐标应该是x1,x2
plt.show()
感知机的对偶形式:(运筹学 线性规划)
对偶,简单地说,就是换一个不同的角度去解答相似问题,但是问题的解是相通的。
感知机:对偶形式是从增量的角度去看到参数的更新的。即先把所有的增量求出来,最后的参数就是在原来的参数基础上加上总的增量。
简单理解:记录每个样本由于误分类而进行更新的次数x。(ai =x)
有可能样本点一次也没更新,离超平面较远的。 (ai = 0)
有可能样本点不停的更新,在超平面附近的点。(ai =x)
ai = ni*η (η :学习速率为,ni:第i个样本被修改的次数)
最后的w ,b 可以表示为:(w每个样本点被误判的次数乘以 yixi的累加和)
感知机对偶形式算法:
注意:
1: ai :=ai +η =niη +η =(ni+1)η (该样本点,更新一次)
2: Gram 矩阵的作用:
xj.xi: 将训练集中各个样本内积计算出来,以矩阵形式存储
G = [ xj* xi ] n*n
可以降低算法复杂度,主要是对高维空间减少计算量。
感知机对偶算法实现:
《统计学习方法》第二版李航 P45
正实例点:x1 =(3,3) x2=(4,3)
负实例点:x3=(1,1)
import numpy as np
from matplotlib import pyplot as plt
from matplotlib import animation
#训练数据
x = np.array([(3.0,3.0),(4.0,3),(1,1)])
#标签
y = np.array([(1),(1),(-1)])
#参数初始化
alpha = np.zeros(len(x),np.float)
b = np.array([0.0])
learngrate = 1
def Gram_matrix(x):
"""
x: 训练数据
return: g [ndim][ndim] ndim训练数据个数
"""
ndim = len(x)
g = np.empty((ndim,ndim),np.float)
for i in range(ndim):
for j in range(ndim):
g[i][j] =x[i]@x[j]
return g
g = Gram_matrix(x)
history = [] # 保存每次训练的 w ,b
i = 0
while True: #
if y[i]*(alpha*y@g[i]+b)<=0: #对应感知机算法(3)
alpha[i] = alpha[i] +learngrate # 参数更新
b = b+ learngrate*y[i]
history.append([alpha*y@x,b])
i= 0 #对应(4)
elif i<len(x)-1:
i = i+1
else:
break
print('最终的结果:alpha :',alpha)
print(" w: ",alpha*y@x,'b:',b)
# 训练过程可视化
fig = plt.figure(figsize=(6, 6))
ax = plt.gca()
ax.grid()
line, = ax.plot([], [], '-', lw=2)
def init():
line.set_data([],[])
x1,x2,x1_,x2_ = [],[],[],[]
for i in range(len(x)):
if y[i]>0:
x1.append(x[i][0])
x2.append(x[i][1])
else :
x1_.append(x[i][0])
x2_.append(x[i][1])
plt.plot(x1, x2, 'bo', x1_, x2_, 'rx')
plt.axis([-1,6,-1,6])
return line ,
def update(i):
global history ,ax ,line
w = history[i][0]
b = history[i][1]
x1 = -6
y1 = -(b+x1*w[0])/w[1]
x2 = 6
y2 =-(b+x2*w[0])/w[1]
line.set_data([x1,x2],[y1,y2])
return line,
ani = animation.FuncAnimation(fig, update, range(len(history)), init_func=init, interval=200,
repeat=False)
ani.save('Perceptron_1.gif', writer='imagemagick', fps=100)
plt.show()
人工制造数据集:
from numpy import *
import numpy as np
import pandas as pd
import matplotlib.pyplot as plt
from matplotlib.lines import Line2D
def makeLinearSeparableDataSet(weights ,numLines):
"""
weights 是一个列表,里面存储的是我们用来产生随机数据的那条直线的法向量。
numLines 是一个正整数,表示需要创建多少个数据点。
Return a linear Separable data Set
Randomly generate numLines points on both sides of the
hyperplane . weights * x = 0
Notice : weights and x are vecors
"""
w = np.array(weights) # <class 'numpy.ndarray'> 一个数组 ,w法向量的垂线
numFeatures = len(weights) #len 求长度
dataSet = zeros((numLines,numFeatures+1)) #产生一个全0 矩阵 n*n
for i in range(numLines):
x = np.random.rand(1,numFeatures)*20 -10
innerProduct = np.sum(w*x)
if innerProduct <=0 :
dataSet[i] = append(x,-1)
else :
dataSet[i] = append(x,1)
return dataSet
# 人工制造数据集 100个
data=makeLinearSeparableDataSet([5,3],100)
print(data)
x = data[:,0:2]
y = data[:,-1]
#参数初始化
alpha = np.zeros(len(x),np.float)
b = np.array([0.0])
learngrate = 1
def Gram_matrix(x):
"""
x: 训练数据
return: g [ndim][ndim] ndim训练数据个数
"""
ndim = len(x)
g = np.empty((ndim,ndim),np.float)
for i in range(ndim):
for j in range(ndim):
g[i][j] =x[i]@x[j]
return g
g = Gram_matrix(x)
history = [] # 保存每次训练的 w ,b
i = 0
while True: #
if y[i]*(alpha*y@g[i]+b)<=0: #对应感知机算法(3)
alpha[i] = alpha[i] +learngrate # 参数更新
b = b+ learngrate*y[i]
history.append([alpha*y@x,b])
i= 0 #对应(4)
elif i<len(x)-1:
i = i+1
else:
break
print('最终的结果:alpha :',alpha)
print(" w: ",alpha*y@x,'b:',b)
# 训练过程可视化
fig = plt.figure(figsize=(6, 6))
ax = plt.gca()
ax.grid()
line, = ax.plot([], [], '-', lw=2)
def init():
line.set_data([],[])
x1,x2,x1_,x2_ = [],[],[],[]
for i in range(len(x)):
if y[i]>0:
x1.append(x[i][0])
x2.append(x[i][1])
else :
x1_.append(x[i][0])
x2_.append(x[i][1])
plt.plot(x1, x2, 'bo', x1_, x2_, 'rx')
plt.axis([-10,10,-10,10])
return line ,
def update(i):
global history ,ax ,line
w = history[i][0]
b = history[i][1]
x1 = -6
y1 = -(b+x1*w[0])/w[1]
x2 = 6
y2 =-(b+x2*w[0])/w[1]
line.set_data([x1,x2],[y1,y2])
return line,
ani = animation.FuncAnimation(fig, update, range(len(history)), init_func=init, interval=200,
repeat=False)
ani.save('P_1.gif', writer='imagemagick', fps=100)
plt.show()
References:
[1]https://blog.csdn.net/Dream_angel_Z/article/details/48915561
[2] 统计学习方法, 李航 著
[3] https://www.bilibili.com/video/BV1dJ411B7gh?from=search&seid=407699525287630939(浙江大学机器学习课程 )