3.2 感知器
3.2.1 原理概述
感知器可以看作极简的线性前馈型神经网络,它通过对输入数据x(列向量)的线性运算实现物体分类。具体来说,感知器计算输入向量x各个元素的加权和,并和给定门限比较来确定x对应的数据类别。对于二分类器,通过下面的公式计算函数f(x),并根据f(x)的值大于0或者小于0来决定x的类别:
其中w是加权重系数构成的(列)向量,b是给定门限。符号<*,*>代表两个向量的内积,即
比如我们用机器根据重量和体积区分西瓜和苹果这两类水果,把输入写成向量,其中和分别代表重量和体积数值。用坐标系下的点表示向量x,如图3-1所示。
可以看到对于西瓜,其重量和体积数值较大,对应的点在右上角,而对于苹果,根据其重量和体积,对应的点大多落在图的左下角,于是可以用图3-2中所示的直线将其分离。
图3-1 西瓜和苹果两类水果特征数据在特征空间的位置示意图
图3-2 通过分类边界线分割特征平面,西瓜和苹果两类水果特征数据在分类边界两侧
假设图中直线对应的方程是
分类器就是相对应的方程
对照式(3-5)得到,b=-10。对于某种水果的重量和体积数据,我们计算,如果它大于0则分类为西瓜,小于0则分类为苹果。分类器的设计其实就是寻找合适的分界线,使得不同类型的数据对应的特征分别在直线的两侧。
前面给出的算法用于二分类器设计,当需要分类数据有多个类别时,使用“一对所有”(One-Versus-All,OVA)的方法设计分类器。下面通过一个例子说明它的分类原理。
假设需要分类的数据有3种类别,分别记作,于是我们训练3个分类器,对其中的分类器,通过训练使得当数据的确属于类别A时,,对于其他类别的数据,。同样对于,我们希望当数据的确属于类别B时,,对于其他类别的数据;对,训练分类器使得当数据的确属于类别C时,,对于其他类别的数据。对于未知类别的输入数据,我们分别计算,根据这三个值中最大的那一个作为数据x的分类结果,比如时,将x分为类别B。
感知器执行的主要运算是向量乘法,即式(3-6)中的向量内积运算,向量内积进一步可以看成一系列乘加运算。在第6章将介绍对这一运算的优化。
3.2.2 模型训练和推理
下面给出基于Python的Scikit-Learn软件包库构建和训练线性感知器分类器,它使用和之前一样的鸢尾花分类数据。代码的总体结构和之前类似,如代码清单3-1所示。
代码清单3-1 感知器模型训练例程
from sklearn.model_selection import train_test_split from sklearn.linear_model import Perceptron from sklearn import datasets # 加载数据集 iris = datasets.load_iris() # 数据拆分为训练集和测试集 x_train, x_test, y_train, y_test = \ train_test_split(iris.data, iris.target, test_size = 0.3, # 数据划分比例,test数据占30% random_state = 1, # 随机数"种子" stratify = iris.target )# 划分数据中类别比例 # 构建感知机分类器 model = Perceptron() # 利用训练数据集训练分类器 model.fit(x_train, y_train)
上述代码中使用API train_test_split将原始训练数据分为两部分,x_train/y_train和x_test/y_test。其中x_train和x_test来自原始数据中的iris.data,即鸢尾花特征测量数据,而y_train和y_test是对应的鸢尾花分类的标准答案。上面的代码中Perceptron用于构建感知器分类器对象,而model.fit函数用于训练,得到感知器的参数。训练完成后通过下面的API调用计算数据分类:
y_pred = model.predict(x_test)
其中x_test是存放测试数据的矩阵,每一行对应一朵花的4个测量数据,y_pred是分类器分类结果,它的每个元素和x_test行对应。
如果需要提取训练结果中每个分类器的参数,即式(3-5)中的权重系数w和偏置b,可以分别从model.coef_和model.intercept_得到,代码如下,我们可以用这两个数据手动计算y_pred。
b=model.intercept_ W=model.coef_ f=x_test.dot(W.T)+b y_pred=np.argmax(f,axis=1)