推导&实现:感知器准则&MSE算法&Fisher准则
推导&实现:感知器准则&MSE算法&Fisher准则
1 感知器准则
1.1 推导
第二个类别的样本特征向量
感知器算法采用最直观的准则,即最小错分样本数,(MSE的区别在于迭代更新
其中
为了求解感知器的准则函数,就是找到一个权矢量,使得惩罚函数最小化。我们使用机器学习中常用的梯度下降方法来迭代。惩罚函数对权矢量的梯度公式为:
利用梯度下降,我们有:
其中
1.2 算法步骤
我们得到下列感知器算法(批量调整版本):
当然,我们都知道这种对所有错分样本放到一起进行修正的做法是不妥当的,更妥当的办法是对每一个错分样本都单独修正,且每次都使用同一个固定步长,假如设步长为1,得到单样本调整版本的感知器算法:
感知器算法特点:
- 当样本线性可分情况下,学习率
合适时,算法具有收敛性 - 收敛速度较慢
- 当样本线性不可分情况下,算法不收敛,且无法判断样本是否线性可分
1.3 代码实现
# mnist训练集,感知器准则实现5&8二分类
# 核心代码
class Perceptron(Model):
def __init__(self, alpha=0.04, n_iter=20): #初始化
self.alpha = alpha #学习率
self.n_iter = n_iter #迭代次数
self.loss_saver = [] #损失收集
def fit(self, X, Y): #训练
m, n = np.shape(X)
self.bias = 0
self.W = np.ones(n) # w的初值是全1的长度为 n 的向量
for i in tqdm(range(self.n_iter)): # 循环迭代 显示进度条
for x, y in zip(X, Y): #遍历所有样本
y_now = np.dot(x, self.W) + self.bias # y_i=x_i*w+b
if y * y_now < 0.: #如果分类错误 更新w和b
self.W += x * self.alpha * y
self.bias += self.alpha * y
self.loss_saver.append(self.acc(X, Y))# 迭代一次加一个acc进序列
if 1-self.acc(X, Y) < EPS: # 结束
return
def predict(self, X):
return np.dot(X, self.W) + self.bias #预测值
def acc(self, X, Y):
return metrics.accuracy_score(Y, np.sign(self.predict(X))) #正确分类的比例
2 最小均方误差算法
2.1 推导
假设我们有一组二分类数据集
将所有
引入一个列向量
定义损失函数为所有
此处包含两个我们需要求解的东西:
其中
接下来要做的就是迭代求解最优的
2.2 算法步骤
-
将训练样本符号规范化,得 x,计算其伪逆
-
初始化:
,其中 只要为正即可 -
计算权重
,及误差 ,注: -
如果
的所有分量都为负数,则算法结束,无解;如果
,则算法结束,输出权重 ; -
迭代:
-
令
,返回步骤 3
2.3 代码实现
# mnist训练集,MSE算法实现5&8二分类
# 核心代码
class MSE(Model):
def __init__(self, c=0.04, n_iter=20):
self.c = c
self.n_iter = n_iter
self.loss_saver = []
def fit(self, X, Y):
m, n = X.shape
b = np.ones((m, 1)) #初始是一个全为1的列向量
X = np.concatenate([X, b], axis=1)
Y = Y.reshape((-1, 1)) #转置
X = X * Y #把-1类的样本的向量*-1
self.b = np.ones(m, dtype=np.float)
X_shape = linalg.pinv(X) #x的伪逆
for i in trange(self.n_iter): #对b用梯度下降法进行迭代
self.W = np.dot(X_shape, self.b) #算出此时的w*
self.err = np.dot(X, self.W) - self.b #计算误差
self.b = self.b + self.c * (self.err + np.abs(self.err)) #更新b
self.loss_saver.append(np.linalg.norm(self.err, ord=2)) #把loss加入序列
if self.loss_saver[-1] < EPS: #结束
return
def predict(self, X):
b = np.ones((X.shape[0], 1))
X = np.concatenate([X, b], axis=1) #需要加一列全1(方程的常数项)
return np.dot(X, self.W)
3 Fisher线性判别准则
3.1 推导
底层逻辑就是一个 LDA 推导:PCA主成分分析&LDA线性判别分析 - 缙云山车神 - 博客园 (cnblogs.com)
3.2 算法步骤
- 把两类样本分为
- 计算两类的均值
- 计算两类的类内散度矩阵
- 计算总的l类内散度矩阵
- 计算 Fisher 最佳投影方向
3.3 代码实现
# mnist训练集,Fisher线性判别准则实现5&8二分类
# 核心代码
class Fisher(Model):
def __init__(self, iter_n = 10):
self.c = 0.
self.iter_n = iter_n
self.loss_saver = []
@staticmethod
def _cal_cov_avg(X):
u = np.mean(X, axis=0) #均值向量
cov = np.cov(X, rowvar=False) #协方差矩阵 衡量类内的相关程度
return cov, u
def fit(self, X, Y):
Y = Y.reshape((-1, 1))
X = X / 255 #把x缩小到0~1之间
X_all = np.concatenate([X, Y], axis=1) #样本和label放一起
X_0 = X_all[X_all[:, -1] == -1] #然后判断label颜色把两类分开
X_1 = X_all[X_all[:, -1] == 1]
X_0, X_1 = X_0[:, :-1], X_1[:, :-1] #把label割掉
cov_0, u_0 = self._cal_cov_avg(X_0) #计算均值向量和协方差矩阵
cov_1, u_1 = self._cal_cov_avg(X_1)
s_w = cov_0 + cov_1
s_w_inv = linalg.pinv(s_w)
self.W = np.dot(s_w_inv, u_0 - u_1) #按公式算的投影的超平面
self.u_0 = np.dot(u_0, self.W) #把两个均值向量投影到平面上
self.u_1 = np.dot(u_1, self.W)
acc = 0.
c = 0.# 初始的分割点
for i in trange(self.iter_n): #对分割点进行迭代
self.c = i / self.iter_n
l_acc = self.loss(X * 255, Y)
self.loss_saver.append(l_acc)
if l_acc > acc: #保留正确率最高的
c = self.c
acc = l_acc
self.c = c
def loss(self, X, Y):
return metrics.accuracy_score(Y, np.sign(self.predict(X)))
def predict(self, X):
X = X / 255
return -(np.dot(X, self.W) - (self.u_0 + (self.u_1 - self.u_0) * self.c))
# 通过正负情况反映观测点在分割点的左边还是右边
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· winform 绘制太阳,地球,月球 运作规律
· AI与.NET技术实操系列(五):向量存储与相似性搜索在 .NET 中的实现
· 超详细:普通电脑也行Windows部署deepseek R1训练数据并当服务器共享给他人
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 上周热点回顾(3.3-3.9)