Skip to content

感知机-了解即可

一、前置

1、来源

感知机(Perceptron) 是由美国学者 Frank·Rosenblatt 在 1957 年提出来的。

感知机是作为神经网络(深度学习)的起源的算法。 因此,学习感知机的构造也就是学习通向神经网络和深度学习的一种重要思想。

感知机接收多个输入信号,输出一个信号。这里所说的“信号”可以想象成电流或河流那样具备“流动性”的东西。像电流流过导线,向前方输送电子一样,感知机的信号也会形成流,向前方输送信息。但是,和实际的电流不同的是,感知机的输出信号只有两种:

  • 1:传递信号
  • 0:抑制信号,不传递信号
js
// 模型
y = (w1 * x1 + w2 * x2) + b

2、知识储备

感知机是解决线性可分的问题

线性可分: 一个 N 维空间中,如果可以通过 N - 1 维超平面分割,则表示该成为线性可分。

线性可分的空间分类:

  • 一维是一条直线,可以用一个点(零维)进行分类;
  • 二维是一个平面,可以用一条直线(一维)进行分类;
  • 三维是一个立体空间,可以用一个平面(二维)进行分类;
  • ......

3、生活案例

如何判断一个人是胖是瘦子?我们现在有一堆用户的信息如下:

用户身高体重类型
1181。130
2160160
3170120
............

将这些人的信息用坐标表示,如下所示。

然后,找到一条直线,能够将胖人和瘦人区分开来。

js
// 直线模型
y = wx + b

这样,就建立了一个二分类的数学模型,当再次输入一个人的身高和体重,即可根据该模型输出该人是胖还是瘦。

二、感知机概念

感知机(Perceptron)对应于输入空间(特征空间)中将实例划分为正负两类的分离超平面,属于判别模型旨在求出将训练数据进行线性划分的分离超平面,为此,导入基于误分类的损失函数,利用梯度下降法对损失函数进行极小化求最优解,从而得到感知机模型。

总结,感知机(perceptron)是二类分类的线性分类模型

感知机接收多个输入信号 x,一个输出信号 y。

感知机用来处理分类问题的,但是只能用来处理二分问题,即非此即彼这样的问题。

分类方式也很简单,是线性划分:

  • x是二维数据:感知机为一条一维直线。
  • x是三维数据:感知机是一个二维平面。
  • x是n维数据:感知机是一个 n−1 维超平面。

注意,感知机的信号只有(0 / 1)两种取值。

上述模型必须加入 截距 b ,否则直线过原点,不能适配复杂情况

  • 上图是一个接收两个输入信号的感知机的流程图。
  • x是输入信号,y是输出信号,w是权重,〇称为“神经元”或者“节点”。

首先,我们会根据输入的 x,来计算信号总和,得到如下关于 x 的求和函数公式:

在深度学习和机器学习中,通常我们把 b 称为偏置(bias),以便能够让我们的超平面在空间中可以随意移动,否则所有的超平面都要经过坐标原点。

对于上面的公式,我们还可以使用矩阵表示,如下所示:

使用向量的点乘来表示感知机模型,并没有特殊含义,仅仅是因为向量点乘的形式和感知机运算规则相似。

那么,什么时候输出信号的取值是-1,什么时候输出信号的取值是+1 呢?我们接下来就可以把计算出来的 f(x) 传入激活函数中,来进行判断。

首先,我们可以认为设定给一个阈值θ。如果某个样本的输出值大于定义的θ,则为 1,反之为-1。即:

  • f(x) − θ ≥ 0,则预测结果为 +1,代表正类
  • f(x) − θ < 0,则预测结果为 -1,代表负类

最终,我们就可以使用向量点乘来表示出最终的决策函数,如下所示:

其中,sign是激活函数,根据规则只会返回 ±1 这两种结果。

三、数学模型

1、常规定义

如果存在一个超平面将所有实例正确的分在平面两侧,称线性可分数据集,否则线性不可分。

感知机是线性分类模型,即判别模型。

如下例子,w^T ⋅ x + b = 0 对应n维空间的一个超平面,w是其法向量,b为其截距,将点(特征向量)分为正、负两类。

所以,我们得到一个假设空间是一个输入变量x的线性函数,函数表达如下所示:

  • x:是一个二维的输入向量(x1, x2)
  • w:是一个二维的权重向量(w1, w2)
  • b:偏置
  • sign:激活函数
  • y:最终输出结果,为+1 或-1

2、其他定义

很多书上对于感知机公式直接用 f(x) = w^T . x表达,对于新手可能看起来很难理解,为什么不写偏置 b 呢?

其实,因为这是因为,偏置 b已经写到了 w 矩阵中。

已知,我们的f(x)使用矩阵表示,如下:

我们可以令w0 = b,x0 = 1 那么得到新的公式,如下:

新的矩阵表达式如下所示:

然后,可以转换为如下的简化公式,即可写成如下形式:

四、学习策略

如果存在一个超平面,能够将所有实例正确的分在平面两侧,则成为线性可分,否则线性不可分

上面我们已经知道感知机模型就是解决线性可分数据的,而且,我们也知道他的主要任务是解决二分类问题

简单来说,感知机的目标就是找到一个超平面,将数据集线性分为正类和负类。

那么下面关键是如何学习找出超平面的参数w,b,这就需要用到我们的学习策略,即定义损失函数,并极小化损失函数

1、定义损失函数

我们知道机器学习模型,需要首先找到损失函数,然后转化为最优化问题,用梯度下降等方法进行更新,找到损失函数的最小值,最终学习到我们模型的参数w,b

那么,我们开始来定义损失函数,并极小化损失函数。感知机损失函数的定义,我们有两种方式:

  • 自然选择:计算误分类点的个数 ,即误分类点越少约好。但是,这样定义的损失函数不是关于w,b的连续可导函数,不易优化。
  • 优化选择:计算误分类点到超平面 S 的总距离,即距离越小越好。而且,距离是一个关于w,b的连续可导函数,优化方便。

比如上面的图,误分类点一共有 3 个,我们可以计算每个误分类点到超平面的总距离,即

  • S = S​1 + S2 + S3

2、空间点到超平面距离

首先,我们要知道平面上任意一个点 x0 到超平面 S 的距离。

假设 x0 到超平面 S 的投影是 x1,如下图所示:

我们在超平面上取两个点分别是 x1,x2 那么可以得到:

然后,我们从 x0 出发,做出两条向量指向 x1 和 x2 两向量夹角为 θ, 如下图所示:

空间中,x0 与 x1 之间的距离,我们记为 d,则得到如下公式:

根据向量夹角公式:

两个式子整合,可以得到:

因为 x1,x2 为超平面上的点,因而有:


L2 范数通常用于表示向量的长度或模,它的值永远是非负的。

3、误分类点确定

如何确定误分类点?

首先,我们看分类正确的点:


4、误分类点的距离

我们可以确定误分类点 xi 到超平面的距离公式为:

5、误分类点总距离

对于空间中所有的误分类点,可以假设在集合 M 中,则可以得到如下公式,即损失函数:

我们可以不考虑

,因为我们并不关心误分类点到超平面点的总距离是多少,我们只关心误分类点到超平面的总距离最小就可以了。

所以,可以得到最终的损失函数公式为:

6、最优化求解

因为,我们需要计算损失函数的最小值,即:

五、学习算法

定了了损失函数,接下来就需要计算损失函数的最小值,一般在深度学习中,采用梯度下降法(Random Gradient Descent),步骤如下:

  • Step1:初始化超平面(参数为 w0 和 b0 );
  • Step2:采用梯度下降算法,不断及消化损失函数;

极小化过程中不是一次性使误分类中的所有点的梯度下降,而是一次随机选取一个误分类点使其梯度下降!

六、鸢尾花实战

1、问题描述

  • 给定鸢尾花的特征数据集(花萼、花瓣的长和宽尺寸)
  • 预测其属于哪个品种,如山鸢尾(Setosa)、变色鸢尾(Versicolor)、维吉尼亚鸢尾(Virginical)等。

2、数据描述

python
from sklearn import datasets
iris = datasets.load_iris() # 加载鸢尾花数据集

鸢尾花的数据集如下所示:

  • SepalLength:花萼长度
  • SepalWidth:花萼宽度
  • PetalLength:花瓣长度
  • PetalWidth:花瓣宽度
  • Species:鸢尾花标签
    1. 0 表示山鸢尾(Setosa)
    2. 1 变色鸢尾(Versicolor)
    3. 2 维吉尼亚鸢尾(Virginical)

3、数据可视化

首先,我们来观察一下数据。

1、花萼特征可视化

由于平面只能展示 2 维特征,我们取 2 个花萼的长度和宽度这两个特征进行进行分析。

python
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
from sklearn.linear_model import Perceptron
import matplotlib.pyplot as plt

def show_data_set(X, y, data):
      # 使用 plot 函数绘制二维坐标图
      # 使用红方块绘制 Setosa 的点(rs: red square)
    plt.plot(X[y == 0, 0], X[y == 0, 1], 'rs', label=data.target_names[0])
    # 使用蓝叉号绘制 Versicolor 的点(bx: blue x)
    plt.plot(X[y == 1, 0], X[y == 1, 1], 'bx', label=data.target_names[1])
    # 使用绿圆圈绘制 Virginical 的点(go: green circle)
    plt.plot(X[y == 2, 0], X[y == 2, 1], 'go', label=data.target_names[2])
    # x轴坐标显示
    plt.xlabel(data.feature_names[0])
    # y轴坐标显示
    plt.ylabel(data.feature_names[1])
    plt.title("鸢尾花二维数据可视化")
    plt.legend()
    plt.rcParams['font.sans-serif'] = 'Songti SC'  # 消除中文乱码
    plt.show()

if __name__ == '__main__':
    # 读取鸢尾花数据
    iris = load_iris()
    print(dir(iris))        # 查看data所具有的属性或方法
    print(iris.data[:5])    # 显示前5数据
    print(iris.DESCR)       # 数据描述
    X = iris.data[:, :2]    # 取前2列花萼(长宽)特征
    y = iris.target         # 目标类别
    show_data_set(X, y, iris)

绘制出来的图像如下所示:

从图中,我们可以发现,如果对于花萼的长和宽两个属性:

  • Setosa 和 Versicolor 是线性可分的
  • Setosa 和 Virginical 是线性可分的
  • Versicolor 和 Virginical 是线性不可分的

2、花瓣特征可视化

然后,我们再从花瓣的长和宽两个特征来分析。只需将代码中X的取值改为下面的代码即可。

python
# 取后2列花瓣(长宽)特征
X = iris.data[:, 2:4]

最终,运行的结果如下所示:

通过观察,我们可以发现,其实花瓣的长和宽对于鸢尾花的分类影响并不大。

  • Setosa 的花瓣长和宽都比较小
  • Virginical 的花瓣长和宽都比较大

4、数据处理

数据采用 sklearn 内置的鸢尾花数据。

python
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
from sklearn.linear_model import Perceptron
import matplotlib.pyplot as plt

# 读取鸢尾花数据
iris = load_iris()
# 将鸢尾花4个特征,以4列存入pandas的数据框架
df = pd.DataFrame(iris.data, columns=iris.feature_names)
# 在最后一列追加lab列,表示目标分类数据
df['lab'] = iris.target

# 选取前两种花的花瓣特征绘制散点图(scatter: 绘制散点图函数)
# 选择0~49条数据的 花瓣长和宽 特征,标签是
plt.scatter(df[:50][iris.feature_names[0]], df[:50][iris.feature_names[1]], label=iris.target_names[0])

plt.scatter(df[50:100][iris.feature_names[0]], df[50:100][iris.feature_names[1]], label=iris.target_names[1])

plt.xlabel(iris.feature_names[0])
plt.ylabel(iris.feature_names[1])

# 选取数据,前100行,前两个特征,最后一列标签
data = np.array(df.iloc[:100, [0, 1, -1]])
# X是除最后一列外的所有列,y是最后一列
X, y = data[:, :-1], data[:, -1]
# 生成感知机的标签值,+1, -1, 第一种-1,第二种+1
y = np.array([1 if i == 1 else -1 for i in y])

5、完整代码

python
# -*- coding:utf-8 -*-
import pandas as pd
import numpy as np
from sklearn.datasets import load_iris
from sklearn.linear_model import Perceptron
import matplotlib.pyplot as plt

if __name__ == '__main__':
    # 读取鸢尾花数据
    iris = load_iris()
    # 将鸢尾花4个特征,以4列存入pandas的数据框架
    df = pd.DataFrame(iris.data, columns=iris.feature_names)
    # 在最后一列追加 加入标签(分类)列数据
    df['lab'] = iris.target

    # 选取数据,前100行,前两个特征,最后一列标签
    data = np.array(df.iloc[:100, [0, 1, -1]])
    # X是除最后一列外的所有列,y是最后一列
    X, y = data[:, :-1], data[:, -1]
    # 生成感知机的标签值,+1, -1, 第一种-1,第二种+1
    y = np.array([1 if i == 1 else -1 for i in y])

    # ------------------sklearn实现----------------------------
    classify = Perceptron(fit_intercept=True, max_iter=10000, shuffle=False, eta0=0.5, tol=None)
    classify.fit(X, y)
    print("特征权重:", classify.coef_)  # 特征权重 w
    print("截距(偏置):", classify.intercept_)  # 截距 b

    # 可视化
    plt.scatter(df[:50][iris.feature_names[0]], df[:50][iris.feature_names[1]], label=iris.target_names[0])
    plt.scatter(df[50:100][iris.feature_names[0]], df[50:100][iris.feature_names[1]], label=iris.target_names[1])
    plt.xlabel(iris.feature_names[0])
    plt.ylabel(iris.feature_names[1])

    # 绘制分类超平面
    x_points = np.linspace(4, 7, 10)
    y = -(classify.coef_[0][0] * x_points + classify.intercept_) / classify.coef_[0][1]
    plt.plot(x_points, y, 'r', label='sklearn Perceptron Classify')

    plt.title("sklearn classify")
    plt.legend()
    plt.show()

最终,程序执行的代码结果如下所示:

可以看出在这两个特征下,两种花线性可分,感知机将两类花分类成功。

七、感知机与SVM

  • 相同点:解决分类问题
  • 不同点: 感知机目标是最小化分类错误,SVM目标是最大化分类间隔

八、感知机的缺陷

感知器本质上是一种线性模型(linear model),只能处理线性分类问题,就连最简单的 XOR(异或)问题都无法正确分类。——马文·明斯基

1958 年,罗森布拉特提出感知机,掀起了人工智能领域的第一次浪潮。但是,在 1969 年,马文·明斯基的上述评价,又直接宣判了感知器的死刑,也使得神经网络的研究也陷入了将近 20 年的停滞。

那什么是异或问题呢?

1、与门问题

首先,我们来看「与问题」的分类。

有x1,x2两个数据做与操作,得到如下表格。

x1x2y(与操作)
000
100
010
111

将其在坐标系中表示,如下所示(红色代表 0,绿色代表 1):

下面考虑用感知机来表示这个与门。

需要做的就确定能满足上图真值表 w1、w2和θ的值,那么设定什么样的值才能制作出满足上图真值表的感知机呢?

我们初中学过的直线表达式:ax+by+c=0

  • 当某一点(x0,y0)在直线下方时,有 ax0 + by0 + c < 0
  • 当某一点(x0,y0)在直线上方时,有 ax0 + by0 + c > 0

回到感知机的计算法则:

也就是说,当点(x1,x2)在w1x1 + w2x2 − θ = 0这条线的下方时,z取值为 0,反之为 1。

因此,我们就是找寻一条直线,将图中的两类点分开。

事实上,这样的直线有无数条。

2、或门问题

同样的,或门问题,我们得到如下表格。

x1x2y(与操作)
000
101
011
111

我们得到的模型如下所示。

3、与非门问题

与非门 是 Not 与门的意思,颠倒了与门的输出,仅在两个输入均为 1 时输出 0,其他时候输出 1

用真值表表示为:

x1x2y(与操作)
001
101
011
110

同样,与非问题也可以找到这条直线。

4、异或问题

异或问题的真值表如下所示:

x1x2y(与操作)
000
101
011
110

模型图如下所示:

从图中可以看出,对于异或门而言,无论如何,都找不到一条直线能够将两类点分开

这就是单层感知机的局限性或缺陷。

单层感知机的局限性就在于它只能表示由一条直线分割的空间。

由此,我们引入两个概念:

线性可分: 表示像与门、或门、与非门等这些能够由直线分割而成的空间,也称为线性空间。 线性不可分: 表示像异或门这样不能由直线分割而成的空间,只能由曲线分割而成的空间,也称为非线性空间。

Released under the MIT License.