本博客中使用到的完整代码请移步至: 我的github:,求赞求星求鼓励~~~
感知机是二类分类的 线性
分类模型
,对应于特征空间中将实例划分为正负两类的 分离超平面
,属于判别模型。感知机学习算法有 原始形式
和 对偶形式
。
误分类点到超平面的总距离
随机梯度下降
SGD输入 x ∈ χ ( χ ∈ R n ) x in chi;(chi in R^n) x∈χ(χ∈Rn) 表示实例的特征向量, y ∈ { − 1 , 1 } y in {-1,1} y∈{−1,1} 表示输入实例的类别,则感知机模型为如下函数:
f ( x ) = s i g n ( w ⋅ x + b ) f(x)=sign(w cdot x+b) f(x)=sign(w⋅x+b)
其中sign为符号函数, s i g n ( x ) = { + 1 x ≥ 0 − 1 x < 0 sign(x)=begin{cases}+1&xge 0 \-1&xlt0 end{cases} sign(x)={+1−1x≥0x<0 。感知机的学习,就是在训练集
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)}上学得感知机模型 f ( x ) f(x) f(x)。
感知机的几何解释:分离超平面
线性方程 w ⋅ x + b = 0 wcdot x+b=0 w⋅x+b=0对应于特征空间的一个超平面
,w为超平面的法向量
,b为截距
,感知机的学习就是利用训练集求得感知机模型参数w和b,这样就确定了分离超平面
。
确定学习策略
,即定义(经验)损失函数
(经验风险或者经验损失:模型关于训练集的平均损失),并极小化损失函数
。误分类点的总数可以表示损失,但是其不是w,b的连续可导函数,不易优化。感知机采用的损失函数是:误分类点到超平面的总距离
:
L ( w , b ) = − ∑ x i ∈ M y i ( w ⋅ x + b ) L(w,b)=-sumlimits_{x_iin M}y_i (wcdot x +b) L(w,b)=−xi∈M∑yi(w⋅x+b)
其中M表示误分类点的集合,且 L ( w , b ) L(w,b) L(w,b)是w和b的连续可导函数。感知机学习策略就是极小化 L ( w , b ) L(w,b) L(w,b)求得对应的w和b,得到感知机模型。
如何得到该损失函数的?
超平面: w ⋅ x + b = 0 wcdot x+b=0 w⋅x+b=0,输入空间中任意一点 x 0 x_0 x0到超平面的距离是 ∣ w ⋅ x 0 + b ∣ ∣ ∣ w ∣ ∣ frac{|wcdot x_0+b|}{||w||} ∣∣w∣∣∣w⋅x0+b∣,而对于误分类点来说, y i y_i yi和 w ⋅ x i + b wcdot x_i+b w⋅xi+b 异号,所以误分类点 x i x_i xi到超平面的距离可表示为: − y i ( w ⋅ x 0 + b ) ∣ ∣ w ∣ ∣ frac{-y_i(wcdot x_0+b)}{||w||} ∣∣w∣∣−yi(w⋅x0+b),所有误分类点到超平面的距离就可以表示为: − 1 ∣ ∣ w ∣ ∣ ∑ x i ∈ M y i ( w ⋅ x + b ) -frac{1}{||w||}sumlimits_{x_iin M}y_i (wcdot x +b) −∣∣w∣∣1xi∈M∑yi(w⋅x+b), 1 ∣ ∣ w ∣ ∣ frac{1}{||w||} ∣∣w∣∣1为常数因子,去掉后对求解无影响,所以得到最终的损失函数: L ( w , b ) = − ∑ x i ∈ M y i ( w ⋅ x + b ) L(w,b)=-sumlimits_{x_iin M}y_i (wcdot x +b) L(w,b)=−xi∈M∑yi(w⋅x+b)。
感知机学习问题,就是损失函数 L ( w , b ) L(w,b) L(w,b)的最优化问题,最优化方法采用:随机梯度下降法,即极小化过程不是一次使M中所有点的梯度下降,而是一次随机选取一个误分类点,使其梯度下降。
损失函数 L ( w , b ) L(w,b) L(w,b)的梯度:
∇ w L ( w , b ) = − ∑ x i ∈ M y i x i ∇ b L ( w , b ) = − ∑ x i ∈ M y i nabla_w L(w,b)=-sumlimits_{x_i in M}y_i x_i \ nabla_b L(w,b)=-sumlimits_{x_i in M}y_i ∇wL(w,b)=−xi∈M∑yixi∇bL(w,b)=−xi∈M∑yi
算法的直观理解:当一个实例被误分类时,就调整w,b的值,使得分离超平面向该误分类点的一侧移动,以减少该点与超平面的距离,直至超平面越过该点,使其被正确分类
。
【注意】
:解不是唯一的!
感知机采用不同的初值(参数w和b的初值)、或选取不同的误分类点(依赖于误分类点的选择顺序),可以得到不同的解
。当对分离超平面增加约束时,可得到唯一解,例如线性支持向量机SVM。
算法的收敛性
对偶形式就是间接求得模型参数w和b,将w和b表示为 x i x_i xi和 y i y_i yi以及 α i alpha_i αi的线性组合形式,通过求解 α alpha α从而间接求得模型参数。
从原始形式能看到,w和b在不断的被修改,一次修改的增量分别是 η y i x i eta y_i x_i ηyixi和 η y i eta y_i ηyi。假设一共修改了 n 次,设w和b 关于样本 ( x i , y i ) (x_i,y_i) (xi,yi)由于误分类而进行修改的次数为 n i n_i ni次,那么最后学习得到的w和b可分别表示为:
w = ∑ i = 1 N α i y i x i b = ∑ i = 1 N α i y i w = sumlimits_{i=1}^Nalpha_i y_i x_i \ b = sumlimits_{i=1}^Nalpha_i y_i w=i=1∑Nαiyixib=i=1∑Nαiyi
其中 α i = n i η alpha_i=n_ieta αi=niη, n i n_i ni表示对第i个样本更新的次数,对 α i alpha_i αi的一次修改的增量是 η eta η。实例点更新次数越多,意味着其距离分离超平面越近,也就越难正确分类。换句话说,这些实例对学习的结果影响也最大
。
在对偶形式的学习算法中, α i alpha_i αi均初始化为0,相当于对每个样本 x i x_i xi的修改次数 n i n_i ni都初始化为0,而每次当 x i x_i xi被误分类时,即满足 y i ( w ⋅ x i + b ) = y i ( ∑ j = 1 N α j y j x j ⋅ x i + b ) ≤ 0 y_i(wcdot x_i+b)=y_i (sumlimits_{j=1}^Nalpha_jy_jx_j cdot x_i+b)le0 yi(w⋅xi+b)=yi(j=1∑Nαjyjxj⋅xi+b)≤0时,就需要对 α i alpha_i αi, b b b 增加一次修改,即 △ α = η bigtriangleupalpha=eta △α=η, △ b = η y i bigtriangleup b=eta y_i △b=ηyi,为一次更新,最终对于第i个样本, α i = n i η alpha_i=n_ieta αi=niη, b = n i η y i = α i y i b=n_ieta y_i=alpha_iy_i b=niηyi=αiyi。
【注意】
:在对偶形式
中,训练实例仅以 内积
的形式出现,可预先将训练集中实例间的内积计算出来并以矩阵形式存储,这样在算法学习过程中会更快捷更方便
。这个矩阵称为Gram矩阵(Gram Matrix):
G = [ x i ⋅ x j ] N x N G=[x_i cdot x_j]_{Ntext{x}N} G=[xi⋅xj]NxN
手动实现感知机学习算法的原始形式,其中将参数 w 和 b 合并为一个参数向量,方便实现:
w ⃗ = < w ( 1 ) , w ( 2 ) , . . . , w ( n ) , b > vec{w}=<w^{(1)},w^{(2)},...,w^{(n)},b> w =<w(1),w(2),...,w(n),b>, x i ⃗ = < x i ( 1 ) , x i ( 2 ) , . . . , x i ( n ) > vec{x_i}=<x_i^{(1)}, x_i^{(2)},...,x_i^{(n)}> xi =<xi(1),xi(2),...,xi(n)>,那么 w ⋅ x + b wcdot x+b w⋅x+b
就可简写为: w ⋅ x wcdot x w⋅x,实现时更方便。
准备鸢尾花数据集:
iris = datasets.load_iris()
print(iris['data'].shape, iris['target'].shape) # (150, 4) (150,) 一共有4个特征
print(iris['target'][:5], iris['target'][50:55], iris['target'][100:105])X = iris.data[:100,[0,2]] # 只使用2个特征:sepal length 和 petal length 以及2个类别
y = iris.target[:100]
y = np.where(y==1, 1, -1) # 1表示setosa杂色鸢尾,-1表示负例
print('Class labels:', np.unique(y))
print(X.shape, y.shape)
输出:
(150, 4) (150,)
[0 0 0 0 0] [1 1 1 1 1] [2 2 2 2 2]
Class labels: [-1 1]
(100, 2) (100,)
绘制数据点的分布:
plt.scatter(X[:50, 0], X[:50, 1], color='red', marker='o', label='setosa')
plt.scatter(X[50:100, 0], X[50:100, 1], color='blue', marker='x', label='versicolor')
plt.xlabel('sepal length [cm]')
plt.ylabel('petal length [cm]')
plt.legend(loc='upper left')
plt.show()
实现感知机:
class Perceptron(object):"""Perceptron classifier.Parameters------------eta : float 学习率 (between 0.0 and 1.0)n_iter : int 迭代次数. 整个训练迭代完一次叫一次iter(或epoch)random_state : int 用于初始化参数的随机数种子Attributes-----------w_ : 1d-array 模型权重参数 需要通过训练求得errors_ : list 每次迭代中,误分类点个数"""def __init__(self, eta=0.01, n_iter=50, random_state=1):a = etaself.n_iter = n_iterself.random_state = random_statedef fit(self, X, y):"""Fit training data.Parameters----------X : {array-like}, shape = [n_samples, n_features] 训练集样本shape [样本数,样本特征数]y : array-like, shape = [n_samples], 真实类别标记Returns-------self : object"""rgen = np.random.RandomState(self.random_state) # 用于初始化w# # 使用正态分布初始化w, 注意w 是考虑了bias的增广向量<w,b>self.w_ = al(loc=0.0, scale=0.01, size=1 + X.shape[1])s_ = []for _ in range(self.n_iter):errors = 0for xi, target in zip(X, y):# uodate用于计算 eta*yi# 注意,当x_i被正确分类时,target - self.predict(xi)=0,即update=0,不更新# 当target - self.predict(xi)不等于0时,update = +2*eta 或者 -2*eta# 这样实现是为了代码更简洁。当然也可以直接先判断target * self.predict(xi)的符号# 只有异号时才进行update的计算:update = eta* target即+1*eta 或者-1*etaupdate = a * (target - self.predict(xi))self.w_[1:] += update * xi # 更新wself.w_[0] += update # 更新berrors += int(update != 0.s_.append(errors)return selfdef net_input(self, X):"""Calculate net input"""return np.dot(X, self.w_[1:]) + self.w_[0]def predict(self, X):"""Return class label after unit step"""return np.where(self_input(X) >= 0.0, 1, -1)
训练感知机模型,并绘制学习曲线(误分类实例数随着迭代次数的变化曲线):
ppn = Perceptron(eta=0.1, n_iter=10)
ppn.fit(X, y)
plt.plot(range(1, s_) + 1), s_, marker='o')
plt.xlabel('Epochs')
plt.ylabel('Number of updates')
plt.xlim(0)
plt.show()
绘制决策边界:
# 绘制分类决策边界:
def plot_decision_regions(X, y, classifier, test_idx=None, resolution=0.02):# setup marker generator and color mapmarkers = ('s', 'x', 'o', '^', 'v')colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')cmap = ListedColormap(colors[:len(np.unique(y))])# plot the decision surfacex1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1xx1, xx2 = np.meshgrid(np.arange(x1_min, x1_max, resolution),np.arange(x2_min, x2_max, resolution))Z = classifier.predict(np.array([xx1.ravel(), xx2.ravel()]).T)Z = Z.reshape(xx1.urf(xx1, xx2, Z, alpha=0.3, cmap=cmap)plt.xlim(xx1.min(), xx1.max())plt.ylim(xx2.min(), xx2.max())for idx, cl in enumerate(np.unique(y)):plt.scatter(x=X[y == cl, 0], y=X[y == cl, 1],alpha=0.8, c=colors[idx],marker=markers[idx], label=cl,edgecolor='black')# highlight test samplesif test_idx:# plot all samplesX_test, y_test = X[test_idx, :], y[test_idx]plt.scatter(X_test[:, 0], X_test[:, 1],c='', edgecolor='black', alpha=1.0,linewidth=1, marker='o',s=100, label='test set')
plot_decision_regions(X, y, classifier=ppn)
plt.xlabel('sepal length [cm]')
plt.ylabel('petal length [cm]')
plt.legend(loc='upper left')
plt.show()
内积形式
的优势,在实践应用中对偶形式比原始形式的求解更快。支持向量机SVM
、神经网络
和深度学习
的基础!完整代码请移步至: 我的github:,求赞求星求鼓励~~~
最后:如果本文中出现任何错误,请您一定要帮忙指正,感激~
[1] 统计学习方法(第2版) 李航
[2] Python_Machine_Learning_2nd_Edition
本文发布于:2024-01-28 10:34:55,感谢您对本站的认可!
本文链接:https://www.4u4v.net/it/17064093006808.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
留言与评论(共有 0 条评论) |