一,感知机(Perceptron)
1.1 介绍
大名鼎鼎的感知机,是一个二分类模型,也是最早的AI模型之一。它的原理简单,便于理解,且实现简单,在线性分类问题上效果卓越,在60年代备受瞩目。但也正是因为它受到的期望过高,当潜在的一些问题暴露出来后(如无法拟合XOR函数,无法解决非线性问题),人们大失所望,直接导致了第一次的AI寒冬。
不过它采用梯度下降的方式来对损失函数进行优化的方式,模拟神经网络运行的创思,成为了现在深度学习最重要的基础之一,同时也成为了学习神经网络的入门模型之一。
与把线性分类任务拆分为两步的Fisher判别不同(请见我另一篇,LDA-Fisher线性判别),感知机是研究如何得到线性判别函数 g(x) = wx + w0的。
机智的人可能会发现,它研究的函数,怎么跟线性回归长得那么像?其实不能说像,简直一模一样。
关于线性回归和感知机,以下给出几个区分点:
1. 线性回归一般是回归任务,而感知机是二分类任务;
2.线性回归的计算函数y=ax+b所计算出来的值就是结果值,而感知机则是会根据计算出来的值是否大于0 ,来决定最后的取值为1还是-1(也有的版本是取1和0的)
3.线性回归在限定损失函数是平方误差下,是可以直接得到解析解的,而感知机则不行,转而采用的梯度下降求解。
1.2 公式推导
1.2.1 变量定义
假设我们拥有n个d维的样本向量x, 并知晓它们每一个对应的真实标签(仅有两类).为了方便讨论,我们把向量x增加1维,变成增广的样本向量形式,如下:
y = [ 1, x1, x2, x3, ... , xd ]
请注意,上面表示的仅仅是一个样本,n个样本的总数据集用矩阵表示的话应该是n个上面的y作为行向量。而x1代表该样本在第一个特征的取值,其他的同理。
所以下面当我们提到y1的时候,你要知道就是原来数据集里的第一个样本 增广了一列1.
之所以要这么做,是因为我们将要训练的权重向量会定义为:
a = [w0, w1, w2, w3,..., wd]
最终的线性判别函数就变为:
g(y) = a y^T (实在搞不懂怎么在右上角打小T)
这样就看起来十分简洁了。
1.2.2 线性可分
下面给出判断样本集是否线性可分的定义:
对于一组样本 y1,y2,y3,...yn,若存在权向量a, 使得对于任一样本有:
当yi 属于类别C1时,g(yi) < 0;
当yi属于类别C2时,g(yi) < 0;
则称该数据集是线性可分的。
如下图所示,左边明显是线性可分的,我们可以用一条斜线就分开了两类数据。右边则是非线性可分的情况。
更进一步的,让我们对样本y的表达式再做如下改动:
1.2.3 损失函数
通过定义好损失函数之后,就可以利用梯度下降来求解出目标权重向量a了。
有的观察仔细的可能会发现,判别函数计算结果是0的样本也是被加入到损失函数的计算中去了,这是因为我们的分类准则只有大于0或者小于0的时候才会分到某一类中,如果计算结果是0,那么代表的是分类失败。
显然,当Loss(a) = 0时,所对应的权向量a就是满足我们目标,把数据集线性分开了的解向量。所以我们的优化目标也就是把Loss(a)的值最小化。
1.2.4 梯度下降
把Loss(a)最小化的方式我们选择用梯度下降来求解,也就是不断更新a的值,即 把当前t时刻的a权向量的值 加上 目标函数的负梯度方向的一个修正量 从而得到 下一个时刻t+1的a权向量。
1.2.5 算法步骤:
每次只修正1个样本,所以等价于批量为1的随机梯度下降的只有一层的神经网络。
- 任意选择初始的权向量a(0), 里面的0就是当前时刻t为0;
- 考察样本Y0, 若 g(Y0) <=0, 则 a(t+1) = a(t) + pY0 ,否则继续遍历样本
- 重复第2步,知道所有样本都有g(Y) > 0, 也就是Loss(a)=0
1.2.6 关于余量
原本我们的对一个样本的判别条件是,如果g(y) >0,那么就认为它属于第一类。但是如果结果只是0.001呢?虽然也是大于0,但是也给它分为第一类,是不是有点不太稳,尤其是我们的模型还存在偏差,还要考虑泛化性能的情况下。
所以为了提高置信度,一般会设置一个余量b, 使得只有g(y) > b, 才认为是第一类。这么做也就是压缩了两个类别之间的解向量的可取范围,使你能够取到的解向量更少,也更加精准了。但同时也更加难以去找到这个解向量了,计算量会变大。 所以这个余量b也是挺重要的一个超参数,需要仔细衡量。
1.3 代码实例
import numpy as np
def perceptron_fit(X: np.array, y: np.array, n_iter=1000, learning_rate=0.01):
'''
训练感知机模型
X: 输入特征数组 shape: [n_samples, n_features]
y: 类别数组,类别标签为1或-1 shape: [n_samples]
n_iter: 迭代次数
learning_rate: 学习率
'''
# 初始化权重向量,添加偏置项
w = np.zeros(X.shape[1] + 1)
# 添加偏置项到X中
X = np.hstack([np.ones((X.shape[0], 1)), X])
# 迭代训练模型
for _ in range(n_iter):
for xi, target in zip(X, y):
# 计算预测值
prediction = np.dot(xi, w)
# 检查预测值是否正确分类
if target * prediction <= 0:
# 更新权重
w += learning_rate * target * xi
return w
def perceptron_predict(X: np.array, w: np.array):
'''
使用训练好的感知机模型进行预测
X: 输入特征数组 shape: [n_samples, n_features]
w: 训练好的权重数组 shape: [n_features + 1]
'''
# 添加偏置项到X中
X = np.hstack([np.ones((X.shape[0], 1)), X])
# 计算预测值
predictions = np.dot(X, w)
# 应用激活函数(sign函数)
predictions = np.where(predictions > 0, 1, -1)
return predictions
# 示例使用感知机模型
# X, y 为数据集的特征和标签,其中y的取值为1或-1
# w = perceptron_fit(X, y)
# predictions = perceptron_predict(X, w)
我这里只是简单的给了算法的过程代码。
使用这个模型更加要关注的时训练前的数据预处理,比如把特征都缩放到同一个范围这对感知机这种采取梯度下降的模型的收敛速度起到很大的影响,还有确保你的数据集是线性可分的,才会取到比较好的效果。
公式代码图都是手敲,给个三连支持下呗(●´ω`●)
标签:1.2,推导,样本,感知机,实例,线性,np,向量 From: https://blog.csdn.net/nmbnn8821750/article/details/137146032