首页 > 代码库 > 基于支持向量机SVM的人脸识别

基于支持向量机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 : duhanmin@foxmail.com
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 : duhanmin@foxmail.com
  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()

 

 
结果截图-预测效果
技术分享
结果截图人脸
技术分享
        
            
          
     
 
 
 
 
 
 
 
               
                                        
     
 
     
 

基于支持向量机SVM的人脸识别