基于支持向量机SVM的人脸识别
Posted 野鹿的博客
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了基于支持向量机SVM的人脸识别相关的知识,希望对你有一定的参考价值。
一、线性SVM
1. 背景:
1.1 最早是由 Vladimir N. Vapnik 和 Alexey Ya. Chervonenkis 在1963年提出
1.2 目前的版本(soft margin)是由Corinna Cortes 和 Vapnik在1993年提出,并在1995年发表
1.3 深度学习(2012)出现之前,SVM被认为机器学习中近十几年来最成功,表现最好的算法
2. 机器学习的一般框架:
训练集 => 提取特征向量 => 结合一定的算法(分类器:比如决策树,KNN)=>得到结果
3. 介绍:
3.1 例子:
两类?哪条线最好?
3.2 SVM寻找区分两类的超平面(hyper plane), 使边际(margin)最大
总共可以有多少个可能的超平面?无数条
如何选取使边际(margin)最大的超平面 (Max Margin Hyperplane)?
超平面到一侧最近点的距离等于到另一侧最近点的距离,两侧的两个超平面平行
3. 线性可区分(linear separable) 和 线性不可区分 (linear inseparable)
4. 定义与公式建立
超平面可以定义为:
W: weight vectot, , n 是特征值的个数
X: 训练实例
b: bias
4.1 假设2维特征向量:X = (x1, X2)
把 b 想象为额外的 wight
超平面方程变为:
所有超平面右上方的点满足:
所有超平面左下方的点满足:
调整weight,使超平面定义边际的两边:
综合以上两式,得到: (1)
所有坐落在边际的两边的的超平面上的被称作”支持向量(support vectors)"
分界的超平面和H1或H2上任意一点的距离为 1/||W|| (i.e.: 其中||W||是向量的范数(norm))
所以,最大边际距离为: 2/||W||
5. 求解
5.1 SVM如何找出最大边际的超平面呢(MMH)?
利用一些数学推倒,以上公式 (1)可变为有限制的凸优化问题(convex quadratic optimization)
利用 Karush-Kuhn-Tucker (KKT)条件和拉格朗日公式,可以推出MMH可以被表示为以下“决定边
界 (decision boundary)”
其中,
yi 是支持向量点Xi (support vector)的类别标记(class label)
Xt是要测试的实例
ai和b0都是单一数值型参数,由以上提到的最有算法得出
l是支持向量点的个数
5.2 对于任何测试(要归类的)实例,带入以上公式,得出的符号是正还是负决定
5.2 对于任何测试(要归类的)实例,带入以上公式,得出的符号是正还是负决定
6. 例子:
7、代码测试
1 2 7、代码测试 3 4 #!/usr/bin/python 5 # encoding: utf-8 6 7 8 """ 9 @author : 杜函敏 10 @contact : [email protected] 11 @File : SVMImplementation.py 12 @time : 2017/7/24 23:14 13 14 """ 15 import numpy as np 16 import pylab as pl 17 from sklearn import svm 18 19 20 np.random.seed(0) 21 X = np.r_[np.random.randn(20, 2) - [2, 2], np.random.randn(20, 2) + [2, 2]] 22 Y = [0] * 20 + [1] * 20 23 24 25 clf = svm.SVC(kernel=‘linear‘) 26 clf.fit(X, Y) 27 28 #得到的是几何形式,我们要转化为点斜式方程 29 w = clf.coef_[0] 30 a = -w[0] / w[1] 31 xx = np.linspace(-5, 5) 32 yy = a * xx - (clf.intercept_[0]) / w[1] 33 34 b = clf.support_vectors_[0] 35 yy_down = a * xx + (b[1] - a * b[0]) 36 b = clf.support_vectors_[-1] 37 yy_up = a * xx + (b[1] - a * b[0]) 38 39 40 print ("w: ", w) 41 print ("a: ", a) 42 print ("support_vectors_: ", clf.support_vectors_) 43 print ("clf.coef_: ", clf.coef_) 44 45 pl.plot(xx, yy, ‘k-‘) 46 pl.plot(xx, yy_down, ‘k--‘) 47 pl.plot(xx, yy_up, ‘k--‘) 48 49 pl.scatter(clf.support_vectors_[:, 0], clf.support_vectors_[:, 1], 50 s=80, facecolors=‘none‘) 51 pl.scatter(X[:, 0], X[:, 1], c=Y, cmap=pl.cm.Paired) 52 53 pl.axis(‘tight‘) 54 pl.show()
结果截图
二、非线性SVM
1. SVM算法特性:
1.1 训练好的模型的算法复杂度是由支持向量的个数决定的,而不是由数据的维度决定的。所以SVM不太容易产生overfitting
1.2 SVM训练出来的模型完全依赖于支持向量(Support Vectors), 即使训练集里面所有非支持向量的点都被去除,重复训练过程,结果仍然会得到完全一样的模型。
1.3 一个SVM如果训练得出的支持向量个数比较小,SVM训练出的模型比较容易被泛化。
2. 线性不可分的情况 (linearly inseparable case)
2.1 数据集在空间中对应的向量不可被一个超平面区分开
2.2 两个步骤来解决:
2.2.1 利用一个非线性的映射把原数据集中的向量点转化到一个更高维度的空间中
2.2.2 在这个高维度的空间中找一个线性的超平面来根据线性可分的情况处理
2.2.3 视觉化演示 https://www.youtube.com/watch?v=3liCbRZPrZA
2.3 如何利用非线性映射把原始数据转化到高维中?
2.3.1 例子:
3维输入向量:
转化到6维空间 Z 中去:
新的决策超平面: 其中W和Z是向量,这个超平面是线性的
解出W和b之后,并且带入回原方程:
2.3.2 思考问题:
2.3.2.1: 如何选择合理的非线性转化把数据转到高纬度中?
2.3.2.2: 如何解决计算内积时算法复杂度非常高的问题?
2.3.3 使用核方法(kernel trick)
3. 核方法(kernel trick)
3.1 动机
在线性SVM中转化为最优化问题时求解的公式计算都是以内积(dot product)的形式出现的
,其中 是把训练集中的向量点转化到高维的非线性映射函数,因为内积的算法复杂
度非常大,所以我们利用核函数来取代计算非线性映射函数的内积
3.1 以下核函数和非线性映射函数的内积等同
3.2 常用的核函数(kernel functions)
h度多项式核函数(polynomial kernel of degree h):
高斯径向基核函数(Gaussian radial basis function kernel):
S型核函数(Sigmoid function kernel):
如何选择使用哪个kernel?
根据先验知识,比如图像分类,通常使用RBF,文字不使用RBF
尝试不同的kernel,根据结果准确度而定
3.3 核函数举例:
假设定义两个向量: x = (x1, x2, x3); y = (y1, y2, y3)
定义方程:f(x) = (x1x1, x1x2, x1x3, x2x1, x2x2, x2x3, x3x1, x3x2, x3x3)
K(x, y ) = (<x, y>)^2
假设x = (1, 2, 3); y = (4, 5, 6).
f(x) = (1, 2, 3, 2, 4, 6, 3, 6, 9)
f(y) = (16, 20, 24, 20, 25, 36, 24, 30, 36)
<f(x), f(y)> = 16 + 40 + 72 + 40 + 100+ 180 + 72 + 180 + 324 = 1024
K(x, y) = (4 + 10 + 18 ) ^2 = 32^2 = 1024
同样的结果,使用kernel方法计算容易很多
4. SVM扩展可解决多个类别分类问题
对于每个类,有一个当前类和其他类的二类分类器(one-vs-rest)
5、人脸分类识别
实验采用的数据集,数据集叫做Labeled Faces in the Wild。大约200M左右。整个有10000张图片,5700个人,1700人有两张或以上的照片。相关的网址:http://vis-www.cs.umass.edu/lfw/index.html
1 #!/usr/bin/python 2 # encoding: utf-8 3 4 5 """ 6 @author : 杜函敏 7 @contact : [email protected] 8 @File : SVMImplementation.py 9 @time : 2017/7/24 23:14 10 """ 11 12 from __future__ import print_function 13 14 from time import time 15 import logging 16 import matplotlib.pyplot as plt 17 18 from sklearn.model_selection import train_test_split 19 from sklearn.datasets import fetch_lfw_people 20 from sklearn.model_selection import GridSearchCV 21 from sklearn.metrics import classification_report 22 from sklearn.metrics import confusion_matrix 23 from sklearn.decomposition import PCA 24 from sklearn.svm import SVC 25 26 plt.rcParams[‘font.sans-serif‘] = [‘SimHei‘] #指定默认字体 27 plt.rcParams[‘axes.unicode_minus‘] = False #解决保存图像是负号‘-‘显示为方块的问题 28 29 30 #在控制台上显示日志 31 logging.basicConfig(level=logging.INFO, format=‘%(asctime)s %(message)s‘) 32 33 ############################################################################### 34 # 下载数据,如果尚未在磁盘上,并将其作为numpy数组加载 35 36 lfw_people = fetch_lfw_people(min_faces_per_person=70, resize=0.4) 37 38 # shape求图片矩阵的维度大小 39 # n_samples图数量 h,w图的大小 40 n_samples, h, w = lfw_people.images.shape 41 42 # data中为每个图片矩阵的特征向量(列) 43 X = lfw_people.data 44 n_features = X.shape[1] 45 46 # 提取不同人的身份标记 47 y = lfw_people.target 48 49 # 提取人的名字 50 target_names = lfw_people.target_names 51 n_classes = target_names.shape[0] 52 53 print("*************总数据集大小**********************") 54 print("**图数量: %d" % n_samples) 55 print("**特征向量数: %d" % n_features) 56 print("**人数: %d" % n_classes) 57 print("*************总数据集大小**********************") 58 59 60 ############################################################################### 61 # 分训练和测试集 62 X_train, X_test, y_train, y_test = train_test_split( 63 X, y, test_size=0.25) 64 ############################################################################### 65 # 特征提取/降维 66 n_components = 150 67 print("从 %d 个维度中提取到 %d 维度" % (X_train.shape[0],n_components)) 68 #主成分分析建模 69 pca = PCA(n_components=n_components, whiten=True).fit(X_train) 70 eigenfaces = pca.components_.reshape((n_components, h, w)) 71 print("根据主成分进行降维开始") 72 X_train_pca = pca.transform(X_train) 73 X_test_pca = pca.transform(X_test) 74 print("降维结束") 75 ############################################################################### 76 # 训练SVM 77 print("训练SVM分类模型开始") 78 t0 = time() 79 #构建归类精确度5x6=30 80 param_grid = {‘C‘: [1e3, 5e3, 1e4, 5e4, 1e5], 81 ‘gamma‘: [0.0001, 0.0005, 0.001, 0.005, 0.01, 0.1], } 82 #图片用rbf核函数,权重自动选取 83 clf = GridSearchCV(SVC(kernel=‘rbf‘, class_weight=‘balanced‘), param_grid) 84 clf = clf.fit(X_train_pca, y_train) 85 print("SVM训练结束,结果如下:" "SVM训练用时 %0.3fs" % (time() - t0)) 86 print(clf.best_estimator_) 87 88 # ############################################################################### 89 print("测试集SVM分类模型开始") 90 91 t0 = time() 92 y_pred = clf.predict(X_test_pca) 93 print("测试集用时 %0.3fs" % (time() - t0)) 94 95 print("误差衡量") 96 # 数据中1的个数为a,预测1的次数为b,预测1命中的次数为c 97 # 准确率 precision = c / b 98 # 召回率 recall = c / a 99 # f1_score = 2 * precision * recall / (precision + recall) 100 101 print(classification_report(y_test, y_pred, target_names=target_names)) 102 print("预测值和实际值对角矩阵") 103 print(confusion_matrix(y_test, y_pred, labels=range(n_classes))) 104 105 106 # ############################################################################### 107 # 画图 108 def plot_gallery(images, titles, h, w, n_row=3, n_col=4): 109 plt.figure(figsize=(1.8 * n_col, 2.4 * n_row)) 110 plt.subplots_adjust(bottom=0, left=.01, right=.99, top=.90, hspace=.35) 111 for i in range(n_row * n_col): 112 plt.subplot(n_row, n_col, i + 1) 113 plt.imshow(images[i].reshape((h, w)), cmap=plt.cm.gray) 114 plt.title(titles[i], size=12) 115 plt.xticks(()) 116 plt.yticks(()) 117 118 # 绘制一部分测试集上的预测结果 119 def title(y_pred, y_test, target_names, i): 120 ##以空格为分隔符,把y_pred分成一个list。分割的次数1。[-1]取最后一个 121 pred_name = target_names[y_pred[i]].rsplit(‘ ‘, 1)[-1] 122 true_name = target_names[y_test[i]].rsplit(‘ ‘, 1)[-1] 123 return ‘预测值: %s\n 实际值: %s‘ % (pred_name, true_name) 124 125 prediction_titles = [title(y_pred, y_test, target_names, i) 126 for i in range(y_pred.shape[0])] 127 128 plot_gallery(X_test, prediction_titles, h, w) 129 130 # 画人脸咯,eigenfaces主成分特征脸 131 eigenface_titles = ["特征脸 %d" % i for i in range(eigenfaces.shape[0])] 132 plot_gallery(eigenfaces, eigenface_titles, h, w) 133 134 plt.show()
结果截图-预测效果
结果截图人脸