感知机(Perception)原理小结

本博客中使用到的完整代码请移步至: 我的github:https://github.com/qingyujean/Magic-NLPer,求赞求星求鼓励~~~


感知机是二类分类的 线性分类模型,对应于特征空间中将实例划分为正负两类的 分离超平面,属于判别模型。感知机学习算法有 原始形式对偶形式

  • 适用问题:二类分类
  • 模型特点:分离超平面
  • 模型类型:判别模型
  • 损失函数:误分类点到超平面的总距离
  • 学习策略:极小化误分类点到超平面的总距离
  • 学习算法:随机梯度下降 SGD

1. 感知机模型

输入 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(wx+b)

其中sign为符号函数, s i g n ( x ) = { + 1 x ≥ 0 − 1 x < 0 sign(x)=\begin{cases}+1&x\ge 0 \\-1&x\lt0 \end{cases} sign(x)={+11x0x<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 w\cdot x+b=0 wx+b=0对应于特征空间的一个超平面,w为超平面的法向量,b为截距,感知机的学习就是利用训练集求得感知机模型参数w和b,这样就确定了分离超平面

2. 感知机学习策略

确定学习策略,即定义(经验)损失函数(经验风险或者经验损失:模型关于训练集的平均损失),并极小化损失函数。误分类点的总数可以表示损失,但是其不是w,b的连续可导函数,不易优化。感知机采用的损失函数是:误分类点到超平面的总距离

L ( w , b ) = − ∑ x i ∈ M y i ( w ⋅ x + b ) L(w,b)=-\sum\limits_{x_i\in M}y_i (w\cdot x +b) L(w,b)=xiMyi(wx+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 w\cdot x+b=0 wx+b=0,输入空间中任意一点 x 0 x_0 x0到超平面的距离是 ∣ w ⋅ x 0 + b ∣ ∣ ∣ w ∣ ∣ \frac{|w\cdot x_0+b|}{||w||} wwx0+b,而对于误分类点来说, y i y_i yi w ⋅ x i + b w\cdot x_i+b wxi+b 异号,所以误分类点 x i x_i xi到超平面的距离可表示为: − y i ( w ⋅ x 0 + b ) ∣ ∣ w ∣ ∣ \frac{-y_i(w\cdot x_0+b)}{||w||} wyi(wx0+b),所有误分类点到超平面的距离就可以表示为: − 1 ∣ ∣ w ∣ ∣ ∑ x i ∈ M y i ( w ⋅ x + b ) -\frac{1}{||w||}\sum\limits_{x_i\in M}y_i (w\cdot x +b) w1xiMyi(wx+b) 1 ∣ ∣ w ∣ ∣ \frac{1}{||w||} w1为常数因子,去掉后对求解无影响,所以得到最终的损失函数: L ( w , b ) = − ∑ x i ∈ M y i ( w ⋅ x + b ) L(w,b)=-\sum\limits_{x_i\in M}y_i (w\cdot x +b) L(w,b)=xiMyi(wx+b)

3. 感知机学习算法

感知机学习问题,就是损失函数 L ( w , b ) L(w,b) L(w,b)的最优化问题,最优化方法采用:随机梯度下降法,即极小化过程不是一次使M中所有点的梯度下降,而是一次随机选取一个误分类点,使其梯度下降。

3.1 感知机学习算法的原始形式

损失函数 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)=-\sum\limits_{x_i \in M}y_i x_i \\ \nabla_b L(w,b)=-\sum\limits_{x_i \in M}y_i wL(w,b)=xiMyixibL(w,b)=xiMyi

原始形式

算法的直观理解:当一个实例被误分类时,就调整w,b的值,使得分离超平面向该误分类点的一侧移动,以减少该点与超平面的距离,直至超平面越过该点,使其被正确分类

【注意】解不是唯一的!感知机采用不同的初值(参数w和b的初值)、或选取不同的误分类点(依赖于误分类点的选择顺序),可以得到不同的解。当对分离超平面增加约束时,可得到唯一解,例如线性支持向量机SVM。

算法的收敛性

  • 对于一个线性可分的训练集集,感知机学习算法的原始形式是收敛的。即经过有限次迭代,一定能求得一个超平面,将训练数据及完全正确的分开。
  • 当训练集线性不可分时,感知机学习算法不收敛,迭代结果会发生震荡

3.2感知机学习算法的对偶形式

对偶形式就是间接求得模型参数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 = \sum\limits_{i=1}^N\alpha_i y_i x_i \\ b = \sum\limits_{i=1}^N\alpha_i y_i w=i=1Nαiyixib=i=1Nαiyi

其中 α i = n i η \alpha_i=n_i\eta α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(w\cdot x_i+b)=y_i (\sum\limits_{j=1}^N\alpha_jy_jx_j \cdot x_i+b)\le0 yi(wxi+b)=yi(j=1Nαjyjxjxi+b)0时,就需要对 α i \alpha_i αi b b b 增加一次修改,即 △ α = η \bigtriangleup\alpha=\eta α=η △ b = η y i \bigtriangleup b=\eta y_i b=ηyi,为一次更新,最终对于第i个样本, α i = n i η \alpha_i=n_i\eta αi=niη b = n i η y i = α i y i b=n_i\eta 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]_{N\text{x}N} G=[xixj]NxN

4. 手动实现感知机算法

手动实现感知机学习算法的原始形式,其中将参数 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 w\cdot x+b wx+b
就可简写为: w ⋅ x w\cdot x wx,实现时更方便。

准备鸢尾花数据集:

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):
         self.eta = eta
         self.n_iter = n_iter
         self.random_state = random_state

     def 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_ = rgen.normal(loc=0.0, scale=0.01, size=1 + X.shape[1])
         self.errors_ = []
         for _ in range(self.n_iter):
             errors = 0
             for 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*\eta
                 update = self.eta * (target - self.predict(xi))
                 self.w_[1:] += update * xi # 更新w
                 self.w_[0] += update # 更新b
                 errors += int(update != 0.0)
             self.errors_.append(errors)
         return self

     def 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.net_input(X) >= 0.0, 1, -1)

训练感知机模型,并绘制学习曲线(误分类实例数随着迭代次数的变化曲线):

ppn = Perceptron(eta=0.1, n_iter=10)
ppn.fit(X, y)
plt.plot(range(1, len(ppn.errors_) + 1), ppn.errors_, 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 map
     markers = ('s', 'x', 'o', '^', 'v')
     colors = ('red', 'blue', 'lightgreen', 'gray', 'cyan')
     cmap = ListedColormap(colors[:len(np.unique(y))])

     # plot the decision surface
     x1_min, x1_max = X[:, 0].min() - 1, X[:, 0].max() + 1
     x2_min, x2_max = X[:, 1].min() - 1, X[:, 1].max() + 1
     xx1, 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.shape)
     plt.contourf(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 samples
     if test_idx:
         # plot all samples
         X_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()

分类决策边界

5. 模型评价

  • 感知机算法简单直观易懂。
  • 由于内积形式的优势,在实践应用中对偶形式比原始形式的求解更快。
  • 虽然现在已经很少在使用感知机了,不过理解感知机是理解支持向量机SVM神经网络深度学习的基础!

完整代码地址

完整代码请移步至: 我的github:https://github.com/qingyujean/Magic-NLPer,求赞求星求鼓励~~~

最后:如果本文中出现任何错误,请您一定要帮忙指正,感激~

参考

[1] 统计学习方法(第2版) 李航
[2] Python_Machine_Learning_2nd_Edition

  • 4
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值