【自己动手写机器学习算法】第2章 感知机

第2章 感知机

感知机模型实际是最简单的模型之一,台大林轩田老师发布的《机器学习基石》教程中,称之为“知错能改验算法”,就是发现错误进行纠正,具体这个算法的过程如下。

2.1感知机模型

定义: 输入空间到输出空间的函数为 f ( x ) = s i g n ( w ⋅ x + b ) f(x) = sign(w\cdot x + b) f(x)=sign(wx+b)
其中
s i g n ( x ) = { + 1 , x ≥ 0 − 1 , x &lt; 0 sign(x)=\left\{ \begin{array}{rcl} +1, &amp; &amp; {x \geq 0}\\ -1, &amp; &amp; {x &lt; 0} \end{array} \right. sign(x)={+1,1,x0x<0
目的: 学习一组 w w w b b b来定义一个超平面 f ( x ) f(x) f(x)对数据进行线性分割.
另外, 真实类别标签 y y y的取值范围集合是 { + 1 , − 1 } \{ +1,-1\} {+1,1}

#定义sign函数
def sign(x):
    if x>= 0:
        return 1
    if x<0:
        return -1

2.2学习策略

既然上面 s i g n ( x ) sign\left( x\right) sign(x)已经定义好了,那么接下来要做的就是求解 w w w b b b

先定义损失函数,并用它来量化模型好不好,由于损失函数是说明一个模型“出现问题”的指标,所以我们需要最小化之.
这里以距离作为损失函数的考量指标,首先,定义输入空间任一点 ( x 0 , y 0 ) (x_0,y_0) (x0,y0)到分类超平面的距离为
d i s t a n c e = 1 ∥ w ∥ ∣ w ⋅ x 0 + b   ∣ distance = \frac{1}{\left\|w\right\|} \left|w\cdot x_0+b \ \right| distance=w1wx0+b 
对于真实数据集样本 ( x i , y i ) (x_i,y_i) (xi,yi),根据2.1中的式子,若分类正确, w ⋅ x i + b ≥ 0 w\cdot x_i + b \geq 0 wxi+b0 y i ≥ 0 y_i \geq 0 yi0,若是分错的, w ⋅ x i + b ≥ 0 w\cdot x_i + b \geq 0 wxi+b0 y i &lt; 0 y_i &lt; 0 yi<0
则对于被误分类的数据 ( x i , y i ) (x_i,y_i) (xi,yi),会得到如下不等式关系
− y i ( w ⋅ x i + b ) &gt; 0 -y_i(w\cdot x_i +b)&gt;0 yi(wxi+b)>0
且误分类点到超平面的距离为
d i s t a n c e = − 1 ∥ w ∥ y i ( w ⋅ x i + b ) distance = -\frac{1}{\left\|w\right\|}y_i(w\cdot x_i +b) distance=w1yi(wxi+b)
若定义所有被误分类的点的集合为 M M M,则所有被误分类的点到超平面的总距离为
A L L _ d i s t a n c e = − 1 ∥ w ∥ ∑ x i ∈ M y i ( w ⋅ x i + b ) ALL\_distance = -\frac{1}{\left\|w\right\|}\sum_{x_i\in M} y_i(w\cdot x_i +b) ALL_distance=w1xiMyi(wxi+b)
此时,我们不关心 1 ∥ w ∥ \frac{1}{\left\|w\right\|} w1,定义损失函数为 L ( w , b ) = − ∑ x i ∈ M y i ( w ⋅ x i + b ) L(w,b) = -\sum_{x_i \in M}y_i(w\cdot x_i +b) L(w,b)=xiMyi(wxi+b)
(注: L L L是个非负函数,可以进行即最小值的求解,且最理想的状态是使 L = 0 L=0 L=0)

2.3设置最优化函数

当前,为了得到最终的 f ( x ) f(x) f(x),这里需要最小化式子 L ( w , b ) = − ∑ x i ∈ M y i ( w ⋅ x i + b ) L(w,b) = -\sum_{x_i \in M}y_i(w\cdot x_i +b) L(w,b)=xiMyi(wxi+b)来求得 w w w b b b,所以有目标
min ⁡ w , b L ( w , b ) = − ∑ x i ∈ M   y i ( w ⋅ x i + b ) \underset{w,b}{\min} L(w,b) = -\sum_{x_i \in M}\ y_i(w\cdot x_i +b) w,bminL(w,b)=xiM yi(wxi+b)
由于真实环境中,数据往往是高维度的数据,单纯的使用高数中学习的求导等于0的方法在这里已经很不好用了。而求解高维数据的极值问题,专业的描述方法称之为“凸优化”问题,即对凸函数求解极值的过程。为了最小化上式,这里使用SGD(随机梯度下降算法来求解),详见2.3.1

2.3.1随机梯度下降(stochastic gradient descent,SGD)

这里对SGD方法进行讲解:
首先,要求解的问题空间可以理解为求解 min ⁡ w , b L ( w , b ) = − ∑ x i ∈ M   y i ( w ⋅ x i + b ) \underset{w,b}{\min} L(w,b) = -\sum_{x_i \in M}\ y_i(w\cdot x_i +b) w,bminL(w,b)=xiM yi(wxi+b),在三维空间中,可以想象成求解盆地的那个时候的值.SGD的"下降"思路是一次随机选择一个误分类点来指导损失函数使其梯度下降(往盆地的方向走),直到下降到不能再低的时候停止。
假设误分类点的集合 M M M固定,则 L ( w , b ) L(w,b) L(w,b)的梯度为
∇ w L ( w , b ) = − ∑ x i ∈ M y i x i \nabla_w L(w,b)= -\sum_{x_i \in M}y_i x_i wL(w,b)=xiMyixi
∇ b L ( w , b ) = − ∑ x i ∈ M y i \nabla_b L(w,b)= -\sum_{x_i \in M}y_i bL(w,b)=xiMyi
随机选取一个误分类点 ( x i , y i ) (x_i,y_i) (xi,yi),对 w w w b b b进行更新:
w ← w + η y i x i w \leftarrow w + \eta y_i x_i ww+ηyixi
b ← b + η y i b \leftarrow b + \eta y_i bb+ηyi
其中, η \eta η是学习率,学习率应该在(0,1]之间,学习率就相当于下台阶一样,你步子跨得大了,一次下两个台阶,下降得快,步子小了,一次跨一个,下降的就慢。

2.3.2感知机学习算法的原始形式

输入: T = { ( x 1 , y 1 ) , ( x 2 , y 2 ) , . . . , ( x N , y N ) } T=\{(x_1,y_1),(x_2,y_2),...,(x_N,y_N)\} T={(x1,y1),(x2,y2),...,(xN,yN)} ,学习率 η ( 0 &lt; η ≤ 1 ) \eta(0 &lt; \eta \leq 1) η(0<η1)
输出: w w w b b b,感知机模型 f ( x ) = s i g n ( w ⋅ x + b ) f(x) = sign(w\cdot x + b) f(x)=sign(wx+b)

  • (1)选取 w w w, b b b(可以随机选取)
  • (2)在训练集合中选择数据 ( x i , y i ) (x_i,y_i) (xi,yi)
  • (3)如果 y i ( w ⋅ x i + b ) ≤ 0 y_i(w\cdot x_i +b)\leq 0 yi(wxi+b)0
    w ← w + η y i x i w \leftarrow w + \eta y_i x_i ww+ηyixi
    b ← b + η y i b \leftarrow b + \eta y_i bb+ηyi
  • (4)跳至(2),直至训练集中没有误分类点或者损失函数降低到给定阈值的范围之内
# 这里定义算法的测试样本
import numpy as np
x = np.array([[3,4],[1,1],[4,3],[1,0],[3,1],[4,2],[2,2],[4,0]]) # 定义三个数据向量(8行_2列,数组)
y = np.array([1,-1,1,-1,-1,1,-1,1]).T # 定义类别标签(8行_1列,向量)
w0 = np.array([0.5,0.5]) # 定义并初始化参数向量(1行2列,向量)
b0 = 0.0 # 偏置项
eta = 0.02 # 学习率
posindex = x[y[:] == 1] # 绘图用,标记正样本id
negindex = x[y[:] == -1] # 绘图用,标记负样本id
# 绘制散点图
import matplotlib.pyplot as plt
plt.figure(0)
# c='red'定义为红色,alpha是透明度,marker是画的样式
plt.scatter(posindex[:,0], posindex[:,1], c='red', alpha=1, marker='+', label='pickup') 
# c='red'定义为红色,alpha是透明度,marker是画的样式
plt.scatter(negindex[:,0], negindex[:,1], c='green', alpha=1, marker='o', label='pickup') 
plt.axis([0,5,-1,5])
plt.show()

这里写图片描述

# 定义损失函数,根据2.2-2.3的推导
def calLoss(x,y,w,b):
    """
    计算损失,包含4个参数,分别为:
    x: 数据
    y: 类别标签
    w: 参数向量
    b: 偏置项
    返回损失值
    """
    loss = 0
    for i in range(len(x)):
        if(y[i] * (np.dot(w,x[i].T) + b) < 0):
            loss = loss + (-y[i] * (np.dot(w,x[i].T) + b))
    return loss

# 测试:
w = w0
b = b0
iterNum = 40
for iter in range(iterNum):
    print('========================iteration'+ str(iter)+'========================')
    for i in range(len(x)):
        if(y[i] * (np.dot(w,x[i].T) + b) < 0):# 如果wx+b小于0,则表示分错了,使用2.3.1中的SGD方法更新权值
            w = w + eta * y[i] * x[i]
            b = b + eta * y[i]
            break
        loss = calLoss(x,y,w,b)
    print('w =',w,', b =',b,'\tLoss = ' + str(loss))
    if loss == 0:
        break
    #以下部分是画图,可以动态展示学习过程中的每次迭代过程的模型变化,如果不想看,也可以注释掉,直接输出每次迭代的参数学习结果
    plt.figure(i)
    plt.scatter(posindex[:,0], posindex[:,1], c='red', alpha=1, marker='+', label='pickup')
    plt.scatter(negindex[:,0], negindex[:,1], c='green', alpha=1, marker='o', label='pickup')
    xrange = np.arange(-1, 6, .01)
    yrange = np.arange(-1, 5, .01)
    xrange, yrange = np.meshgrid(xrange, yrange)
    f = w[0]*xrange + w[1]*yrange + b
    plt.contour(xrange, yrange, f,0)
    plt.savefig(str(iter)+'.png')
    plt.show()

iteration0
w = [ 0.48 0.48] , b = -0.02 Loss = 5.5

iteration1
w = [ 0.46 0.46] , b = -0.04 Loss = 5.2

iteration2
w = [ 0.44 0.44] , b = -0.06 Loss = 4.9

iteration3
w = [ 0.42 0.42] , b = -0.08 Loss = 4.6

iteration4
w = [ 0.4 0.4] , b = -0.1 Loss = 4.3
这里写图片描述
iteration5
w = [ 0.38 0.38] , b = -0.12 Loss = 4.0

iteration6
w = [ 0.36 0.36] , b = -0.14 Loss = 3.7

iteration7
w = [ 0.34 0.34] , b = -0.16 Loss = 3.4

iteration8
w = [ 0.32 0.32] , b = -0.18 Loss = 3.1

iteration9
w = [ 0.3 0.3] , b = -0.2 Loss = 2.8

iteration10
w = [ 0.28 0.28] , b = -0.22 Loss = 2.5

iteration11
w = [ 0.26 0.26] , b = -0.24 Loss = 2.2

iteration12
w = [ 0.24 0.24] , b = -0.26 Loss = 1.9

iteration13
w = [ 0.22 0.22] , b = -0.28 Loss = 1.62

iteration14
w = [ 0.2 0.2] , b = -0.3 Loss = 1.36
这里写图片描述
iteration15
w = [ 0.18 0.18] , b = -0.32 Loss = 1.1

iteration16
w = [ 0.16 0.16] , b = -0.34 Loss = 0.84

iteration17
w = [ 0.1 0.14] , b = -0.36 Loss = 0.6

iteration18
w = [ 0.04 0.12] , b = -0.38 Loss = 0.2

iteration19
w = [ 0.12 0.12] , b = -0.36 Loss = 0.22
这里写图片描述
iteration20
w = [ 0.06 0.1 ] , b = -0.38 Loss = 0.24

iteration21
w = [ 0.14 0.1 ] , b = -0.36 Loss = 0.14
这里写图片描述
iteration22
w = [ 0.08 0.08] , b = -0.38 Loss = 0.28
这里写图片描述
iteration23
w = [ 0.16 0.08] , b = -0.36 Loss = 0.06
这里写图片描述
iteration24
w = [ 0.1 0.06] , b = -0.38 Loss = 0.32
这里写图片描述
iteration25
w = [ 0.1 0.06] , b = -0.38 Loss = 0

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值