更多文章可以访问我的博客Aengus | Blog
定义
假设输入空间是,输出空间是,由输入空间到输出空间的如下函数:
称为感知机。称作权值或权值向量,称作偏置,是和的内积,sign是符号函数:
感知机的假设空间是全体线性函数。
感知机学习策略
感知机的损失函数一个选择是误分类的点的个数,但是由于这样的损失函数不是参数,的连续可导函数,不易优化。损失函数的另外一个选择是误分类点到超平面的总距离,这是感知机所采用的。我们知道,一个点到一个平面的距离为:
而且,对于误分类的数据总有
成立。这是因为如果点本来为正类,即,若误分类,则得到的,这样上式就大于0;反之,如果本来,误分类得到的结果,上式结果仍大于0。因此,所有误分类的点(记集合为)到超平面的距离就是
不考虑,就得到了感知机的损失函数。
感知机学习算法
利用梯度下降法对感知机进行求解:
随机选择一个误分类点,对进行更新:
其中称为步长,又称作学习率。通过迭代可以让不断减小,直至为0。
原始形式
假设输入线性可分的数据集为,其中,,学习率。则采用以下步骤进行求解:
-
选取初值;
-
在训练集中选取数据;
-
如果,
-
回到步骤2,直至训练集中没有误分类点;
最终输出为;感知机模型。
对偶形式
在每次迭代的更新中:
设修改次,则关于的增量分别是和,这里,那么最后的结果可以表示为:
因此我们就可以用对偶形式来叙述感知机算法:
假设输入线性可分的数据集为,其中,,学习率。则采用以下步骤进行求解:
-
;
-
在训练集中选取数据;
-
如果,则
-
回到步骤2,直至训练集中没有误分类点;
最终输出为,感知机模型,其中。
由于对偶形式中训练集仅以内积的形式出现。为了方便可以预先将训练集的内积计算出来并以矩阵的形式保存,这个矩阵称为Gram矩阵:
代码实现
下面是利用Python实现的感知机算法:
import numpy as np
def sign(w, x_i, b):
"""
符号函数
:param w: 权重矩阵,形如[1, 2, 3, 4, 5]
:param x_i: 训练集的一个样本,列数(行数)和权重矩阵相同
:param b: 偏置
:return: +1,-1
"""
if np.matmul(w.T, x_i) + b > 0:
return 1
else:
return -1
def perceptron(w0, b0, eta, x, y):
"""
感知机算法原始形式:
1. 选取初值w0, b0;
2. 在训练集中选取数据(xi, yi);
3. 如果y_i(w * x_i) <= 0,更新w, b;
4. 回到2,直到训练集中没有误分类点;
:param w0: 初始w0,维数与x相同
:param b0: 初始b0,常数
:param eta: 步长
:param x: 训练集
:param y: 训练集标签
:return: 包含w, b的元祖
"""
m, n = x.shape
w = w0
b = b0
iterations = 0
while True:
iterations = iterations + 1
for i in range(m):
if y[i] * sign(w, x[i], b) > 0:
continue
else:
w = w + eta*y[i]*x[i]
b = b + eta*y[i]
corr_num = 0
for j in range(m):
if y[j] * sign(w, x[j], b) > 0:
corr_num = corr_num + 1
if corr_num == m:
break
print("经过了", iterations + 1, "次迭代算法收敛")
return w, b
def perceptron_duality(eta, x, y):
"""
感知机算法的对偶形式:
1. 初始化alpha,b;
2. 在训练集中选取(x_i, y_i);
3. 如果 y_i * (\sum^N_{j=1}(\alpha_j y_j x_j * x_i) + b) <= 0,更新alpha,b;
4. 转回2,直至没有误分类数据;
:param eta: 步长
:param x: 训练集
:param y: 训练集的标签
:return: w和b的二元元祖
"""
m, n = x.shape
alpha = np.zeros(m)
b = 0
# Gram矩阵
gram = np.zeros((m, m))
for i in range(m):
for j in range(m):
gram[i, j] = np.matmul(x[i].T, x[j])
iterations = 0
while True:
iterations = iterations + 1
for i in range(m):
if y[i] * (sum(alpha[j]*y[j]*gram[j, i] for j in range(m)) + b) > 0:
continue
else:
alpha[i] = alpha[i] + eta
b = b + eta*y[i]
corr_num = 0
for i in range(m):
if y[i] * (sum(alpha[j]*y[j]*gram[j, i] for j in range(m)) + b) > 0:
corr_num = corr_num + 1
if corr_num == m:
break
w = sum(alpha[i] * y[i] * x[i] for i in range(m))
b = sum(alpha[i]*y[i] for i in range(m))
print("经过", iterations+1, "次迭代后,算法收敛")
return w, b
参考
李航《统计学习方法(第二版)》第二章
网友评论