关于感知器模型
感知器是一个简单的监督学习的机器学习算法,也是最早的神经网络结构。作为一个二分类的线性分类模型,其输入为实例的特征向量,输出为实例的类别。数据:
是一个d维的特征向量,
是目标标签,
目标:利用上述给定的数据学习一个超平面
使其可以将数据集的正例点和负实例点划分到两侧。即:
,
算法详解
损失函数
为学习上述的超平面,选择误分类点的总数作为损失函数是一个很直观的选择,但是由于该损失函数对参数非连续可导,因此采用误分类点到超平面
的总距离作为损失函数。
对于错误分类的实例,当真实标签为
,错误的预测结果为
;真实标签为
时,错误的预测结果为
,因此,错误分类点
到超平面的距离可由如下表示:
由于感知机的目的在于使所有训练样本分类正确,
对于判断是否分类正确没有影响,因此相关损失函数中可略去该项。对于误分类实例集合M,可得如下损失函数:
求解
原始形式
感知器学习算法是误分类驱动的,可采用随机梯度下降算法对参数
和
进行优化。公式(2)的梯度为:
对于随机采样并错误分类的点
,其对
和
的更新贡献如下:
其中
是学习率,通过不断的采样可利用公式(5)和(6)对
和
进行不断更新直到全部分类正确。
对偶形式
考察公式(5)和(6),如果学习率
,则上式变为:
在训练过程中,如果
被采样了100次,而其中30次被错误分类,那么实例
对w和b带来的变化分别为:
和
。更一般地,对任意实例
,若其在训练过程中共有
次被分类错误,则其对
和
带来的变化分别为
和
。在学习率
下,上述变化可表示为
和
。那么,训练过程中如果
和
的初始值为0,则最终
和
学习得到的结果为:
感知器的模型最终可表示为:
从上式可以看到,在感知机的对偶形式下,实例仅以内积的形式出现 ,在计算前可以计算所有实例之间由内积构成的矩阵,即Gram矩阵(Gram matrix),以加快计算速度。
小贴士超平面及点到超平面的距离
超平面是在空间
中的一个子空间
。在三维空间中,超平面是一个二维平面,而在二维空间中超平面则为一条直线,此时,点到超平面的距离就变成了我们中学所熟悉的点到直线的距离——如果直线表达式为
,那么点
到该直线的距离为:
数据介绍
Iris数据集是常用的分类实验数据集,由Fisher, 1936收集整理。Iris也称鸢尾花卉数据集,是一类多重变量分析的数据集。数据集包含150个数据样本,分为3类,每类50个数据,每个数据包含4个属性(下表中的前四列)。可通过花萼长度,花萼宽度,花瓣长度,花瓣宽度4个属性预测鸢尾花卉属于(Setosa,Versicolour,Virginica)三个种类中的哪一类。
代码
加载必要的包
import numpy as np
from sklearn.model_selection import train_test_split
from sklearn.datasets import load_iris
加载数据
iris = load_iris()
# 数据中前五个样例的属性向量
iris.data[:5]
array([[5.1, 3.5, 1.4, 0.2],
[4.9, 3. , 1.4, 0.2],
[4.7, 3.2, 1.3, 0.2],
[4.6, 3.1, 1.5, 0.2],
[5. , 3.6, 1.4, 0.2]])
# 对应的标签
iris.target[:5]
array([0, 0, 0, 0, 0])
X = iris.data[:100] #iris数据总共有三类,每类50个样本,我们只取前两类做二分类任务
y = iris.target[:100]
y = np.where(y == 1, 1, -1) #把原始标签由(0,1)调整为(-1,1)
划分数据
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.4)
原始形式
def evaluation(X,y,w,b):
p = np.dot(X, w) + b
pred = np.where(p <= 0.0, -1, 1)
ture_num = (pred==y).sum()
total_num = X.shape[0]
acc = 1.0*ture_num / total_num
return acc
def PerceptronBase(X,y,eta,epoch):
w = np.zeros(X.shape[1])
b = 0
errors = []
for i in range(epoch):
error = 0
for xi, yi in zip(X, y):
p = np.dot(xi, w) + b
if p*yi<=0: #当预测错误的时候更新参数
deta_w = yi*xi*eta
deta_b = yi*eta
w += deta_w
b += deta_b
error += 1
errors.append(error)
acc = evaluation(X_test,y_test,w,b)
info = ' Epoch: [{0}] Train_Error: {erro_:d} Acc: {acc_:.4f}'.format(i,erro_=error,acc_=acc)
print(info)
return w,b
w,b = PerceptronBase(X_train,y_train,0.01,5)
Epoch: [0] Train_Error: 7 Acc: 1.0000
Epoch: [1] Train_Error: 0 Acc: 1.0000
Epoch: [2] Train_Error: 0 Acc: 1.0000
Epoch: [3] Train_Error: 0 Acc: 1.0000
Epoch: [4] Train_Error: 0 Acc: 1.0000
对偶形式
def PerceptronDual(X,y,eta,epoch):
n_samples, n_features = X.shape
alpha, b = [0] * n_samples, 0
w = np.zeros(n_features)
i = 0
for i in range(epoch):
error = 0
for j in range(n_samples):
p = np.dot(X[j], w) + b
if p*y[j]<=0:
alpha[j] += 1
error+=1
alpha_npy = np.array(alpha)[:,np.newaxis]
y_npy = y[:,np.newaxis]
w = (alpha_npy* X * y_npy).sum(0)*eta
b = (alpha_npy* y_npy).sum(0)*eta
acc = evaluation(X_test,y_test,w,b)
info = ' Epoch: [{0}] Train_Error: {erro_:d} Acc: {acc_:.4f}'.format(i,erro_=error,acc_=acc)
print(info)
return w,b
w,b = PerceptronDual(X_train,y_train,0.01,5)
Epoch: [0] Train_Error: 60 Acc: 0.5000
Epoch: [1] Train_Error: 30 Acc: 0.5000
Epoch: [2] Train_Error: 30 Acc: 0.5000
Epoch: [3] Train_Error: 30 Acc: 0.5000
Epoch: [4] Train_Error: 30 Acc: 0.5000
项目地址