感知机
感知机(perceptron)是二类分类的线性分类模型,于 1957 年由 Rosenblatt 提出,是神经网络与支持向量机的基础,其输入为实例的特征向量,输出为实例的类别,取 +1 和 -1 二值。感知机对应于输入空间(特征空间)中将实例划分为正负两类的分离超平面,属于判别模型。感知机学习旨在求出将训练数据进行线性划分的分离超平面。
【过程】:
- 导入基于误分类的损失函数。
- 利用梯度下降法对损失函数进行极小化,求得感知机模型。
【优点】:简单而易于实现。
【形式】:
- 原始形式;
- 对偶形式。
感知机模型
感知机是一种线性分类模型,属于判别模型。
【假设空间】:定义在特征空间中的所有线性分类模型(linear classification model)或线性分类器(linear classifier),即函数集合 {f|f(x) = w.x + b}。
感知机学习策略
数据集的线性可分性
给定一个数据集
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)
其中,
x
i
∈
χ
=
R
n
,
y
i
∈
Y
=
{
+
1
,
−
1
}
,
i
=
1
,
2
,
.
.
.
,
N
x_i \in \chi = R^n, y_i \in Y = \{+1, -1\}, i = 1,2,...,N
xi∈χ=Rn,yi∈Y={+1,−1},i=1,2,...,N,如果存在某个超平面 S
w
⋅
x
+
b
=
0
w \cdot x + b = 0
w⋅x+b=0
能够将数据集的正实例点和负实例点完全正确地划分到超平面的两侧,即对所有 y i = + 1 y_i = +1 yi=+1 的实例,有 w ⋅ x i + b > 0 w \cdot x_i + b > 0 w⋅xi+b>0,对所有 y i = − 1 y_i = -1 yi=−1 的实例 i,有 w ⋅ x i + b < 0 w \cdot x_i + b < 0 w⋅xi+b<0,则称数据集 T 为线性可分数据集(linearly separable data set);否则,称数据集 T 线性不可分。
感知机学习策略
假设训练数据集是线性可分的,感知机学习的目标是求得一个能够将训练集正实例点和负实例点完全正确分开的分离超平面。
为了找出这样的超平面,即确定感知机模型参数 w、b,需要确定一个学习策略,即定义(经验)损失函数并将损失函数极小化。
- 误分类点的总数:这样的损失函数不是参数 w、b 的连续可导函数,不易优化。
- 误分类点到超平面 S 的总距离:感知机所采用的策略。
感知机学习算法
感知机学习问题转化为求解损失函数 L ( w , b ) = − ∑ x i ∈ M y i ( w ∗ x i + b ) L(w, b) = -\sum_{x_i \in M}y_i(w * x_i + b) L(w,b)=−∑xi∈Myi(w∗xi+b) 的最优化问题,最优化的方法是随机梯度下降法。
原始形式
感知机学习算法是对以下最优化问题的算法。给定一个训练数据集
T
=
(
x
i
,
y
i
)
,
(
x
2
,
y
2
)
,
.
.
.
,
(
x
N
,
y
N
)
T = {(x_i, y_i), (x_2, y_2), ..., (x_N, y_N)}
T=(xi,yi),(x2,y2),...,(xN,yN)
其中,
x
i
∈
χ
∈
R
n
x_i \in \chi \in R^n
xi∈χ∈Rn,
y
i
∈
Y
=
{
−
1
,
1
}
,
i
=
1
,
2
,
.
.
.
,
N
y_i \in Y = \{-1, 1\}, i = 1,2,...,N
yi∈Y={−1,1},i=1,2,...,N,求参数 w、b,使其为以下损失函数极小化问题的解
m
i
n
w
,
b
L
(
w
,
b
)
=
−
∑
x
i
∈
M
y
i
(
w
∗
x
i
+
b
)
min_{w,b}L(w, b) = - \sum_{x_i \in M}y_i(w * x_i + b)
minw,bL(w,b)=−xi∈M∑yi(w∗xi+b)
其中 M 为误分类点的集合。
感知机学习算法是误分类驱动的,具体采用随机下降梯度法(stochastic gradient descent)。
- 首先,任意选取一个超平面 w 0 , b 0 w_0, b_0 w0,b0,通常选择 0。
- 然后用梯度下降法不断地极小化目标函数。
【注意】:极小化过程中不是一次使 M 中所有误分类点的梯度下降,而是一次随机选取一个误分类点使其梯度下降。
假设误分类点集合 M 是固定的,那么损失函数 L(w, b) 的梯度由以下式子给出(对损失函数求偏导)。
∇
w
L
(
w
,
b
)
=
−
∑
x
i
∈
M
y
i
x
i
∇
b
L
(
w
,
b
)
=
−
∑
x
i
∈
M
y
i
\nabla_wL(w, b) = -\sum_{x_i \in M}y_ix_i \\ \nabla_bL(w, b) = -\sum_{x_i \in M}y_i
∇wL(w,b)=−xi∈M∑yixi∇bL(w,b)=−xi∈M∑yi
随机选取一个误分类点
(
x
i
,
y
i
)
(x_i, y_i)
(xi,yi),对 w,b 进行更新。
w
←
w
+
η
y
i
x
i
b
←
b
+
η
y
i
w \leftarrow w + \eta y_ix_i \\ b \leftarrow b + \eta y_i
w←w+ηyixib←b+ηyi
η
(
0
<
η
≤
1
)
\eta(0 \lt \eta \leq 1)
η(0<η≤1) 是步长,在统计学习中又称为学习率(learning rate)。这样,通过迭代可以期待损失函数 L(w, b) 不断减小,直到为 0。综上所述,得到如下算法。
【算法】:感知机学习算法的原始形式。
- 输入:训练数据集 T = ( x i , y i ) , ( x 2 , y 2 ) , . . . , ( x N , y N ) T = {(x_i, y_i), (x_2, y_2), ..., (x_N, y_N)} T=(xi,yi),(x2,y2),...,(xN,yN),其中 x i ∈ χ ∈ R n x_i \in \chi \in R^n xi∈χ∈Rn, y i ∈ Y = { − 1 , 1 } , i = 1 , 2 , . . . , N y_i \in Y = \{-1, 1\}, i = 1,2,...,N yi∈Y={−1,1},i=1,2,...,N;学习率 η ( 0 < η ≤ 1 ) \eta(0 \lt \eta \leq 1) η(0<η≤1)。
- 输出:w,b;感知机模型 f(x) = sign(w * x + b)。
- 过程:
- 选取初值 w 0 , b 0 w_0, b_0 w0,b0;
- 在训练集中选取数据 ( x i , y i ) (x_i, y_i) (xi,yi);
- 如果
y
i
(
w
∗
x
i
+
b
)
≤
0
y_i(w * x_i + b) \leq 0
yi(w∗xi+b)≤0
w ← w + η y i x i b ← b + η y i w \leftarrow w + \eta y_ix_i \\ b \leftarrow b + \eta y_i w←w+ηyixib←b+ηyi - 转至(2),直至训练集中没有误分类点。
【说明】:当一个实例点被误分类,即位于分离超平面的错误一侧时,则调整 w、b 的值,使分离超平面向该误分类点的一侧移动,以减少该误分类点与超平面间的距离,直至超平面越过该误分类点使其被正确分类。
代码实现
def percerptron(x, y, step=1):
# 初始化权值 w 和偏置 b
w, b = np.zeros(x.shape[1]), 0
# 当权值和偏置为 0 时,任何点都为误分类点
error_point_index = 0
while True:
is_flag = False
# 更新权值 w 和偏置 b
w += step * x[error_point_index] * y[error_point_index]
b += step * y[error_point_index]
# 继续遍历寻找误分类点
for i in range(0, x.shape[0]):
fx = np.dot(w, x[i]) + b
if -y[i] * fx > 0:
error_point_index = i
is_flag = True
break
# 没有找到误分类点即退出循环
if not is_flag:
break
return (w, b)
上述代码能实现二分类的前提是数据集是线性可分的。如果数据集线性不可分,则修正一个误分类点就会导致另一个正确分类点转为误分类点,从而导致无法结束循环。基于上述考虑,引出以下两个问题:
- 若数据集线性不可分,该如何处理?
- 每次都要遍历数据集寻找误分类点,如果误分类点处于数据集的后半部分,这会导致检索误分类点的时间开销增大。那么该如何减小这部分开销呢?
第一个问题又可细分为:
- 如何判断数据集是否线性可分?
- 若数据集线性不可分,如何通过感知机进行二分类?
接下来依次针对提出的问题寻找解决方案。
判断数据集是否线性可分
通过查阅资料,并对所查资料进行整合,可以归纳为以下三种方式。
- 画图法
- 检查凸包
- 线性回归判断
画图法
当数据向量是一维、二维或者是三维时,可以通过数据可视化的方式将图像绘制出来,这样直观上就能看出来。
例如上图,可以清楚地知道数据集是线性不可分的。
线性回归判断
将线性回归应用于数据集,然后检查最小平方误差。如果最小平方误差显示高准确度,则表示数据集本质上是线性的。
具体内容可参考:喜欢打酱油的老鸟的博客《如何判断机器学习数据集是否是线性的?》
检查凸包
图像法和线性回归判断都只能近似地判断数据集是否线性可分,并且都存在缺陷。
- 图像法:面对高维数据时无法使用。
- 线性回归判断:数据集数据比较集中时,最小平方误差也会显示高准确度,并且如何设定阈值也是一个问题。
那么有没有公式化的、严格地判断数据集是否线性可分的方法呢?这就是检查凸包(convex hull)。
【凸包】:凸包就是一个凸的闭合曲线(曲面),且刚好包裹当前分类的所有数据。
【判断过程】:
- 为每个分类绘制凸包。
- 如果凸包之间不重叠(通过判断凸包之间的边是否相交来实现),那么这两个分类所组成的数据集是线性可分的,反之则不是线性可分。
数据集线性不可分,如何实现
现在流行的解决线性不可分的方法就是使用核函数(kernel)。
【本质思想】:把原始的样本通过核函数映射到高维空间中,让样本在高维特征空间中是线性可分的,然后再使用常见的线性分类器。
例如地图上常见的等高线,在二维平面上显然是线性不可分的,但在实际的山峰以及 3D 模型中,可以看到不同的曲线映射到 3D 模型的高度也不同,那么我们就可以通过平行于由 x 轴与 y 轴构成的平面来划分数据集。
核函数的作用就是将低维平面上的坐标点通过一定的公式计算出新的维度。更多内容可参考腾阳的博客《机器学习笔记5:线性不可分问题》
有没有简单的做法?即允许存在部分的误差。
【思路】:先根据 Novikoff 定理确定大致的误分类次数并计算每次迭代过程的误分类点。
- 若能够在大致估计的误分类次数之内完成自然是最好的,同时也表明该数据集是线性可分的。
- 如果超过该误分类次数,则开始获取最近 N(自行设定) 次的误分类点情况,若发现两个点不断地交替,则可以跳出循环。
优化检索误分类点过程
在寻找误分类点的过程中也可以对算法进行优化:
- 将经常出现的误分类点添加到 list 中,先循环该 list,判断里面的点是否被误分了,再循环所有的点。
- 也可以先对数据进行一次排序,然后采用二分法的方式去寻找误分类点。
算法的收敛性
Novikoff 定理表明:误分类的次数 k 是有上界的,经过有限次搜索可以找到将训练数据完全正确分开的分离超平面。也就是说,当训练数据集线性可分时,感知机学习算法原始形式迭代是收敛的。当训练集线性不可分时,感知机学习算法不收敛,迭代结果会发生震荡。
证明过程可参考李航编写的《统计学习方法》。
后话
结合查阅的资料以及自身的思考所写,若有错误请各位大佬指出。本文仍然会在后续有新的资料以及感悟后进行更新,欢迎各位收藏与评论。
参考
- 如何(高效)判断数据是否线性可分:https://blog.csdn.net/wangxin1982314/article/details/73480554
- 如何判断机器学习数据集是否是线性的?:https://blog.csdn.net/weixin_42137700/article/details/86060381
- 机器学习笔记5:线性不可分问题:https://blog.csdn.net/weixin_41931602/article/details/80461544
- 李航《统计学习方法》