PCA+支持向量机-人脸识别(五)

一):实验准备

  本篇可以接上篇:PCA实验人脸库-人脸识别(四)

对于上篇中数据库ORL人脸库和AR人脸库(下载地址在上篇中有),在上篇中讨论的单纯的PCA算法对两个数据库进行了准确率计算,本篇为了提高识别准确率,特采用一种新方法,并结合PCA一起实现识别,实验结果发现该方法能明显提高两者数据库的识别率。

二):关于支持向量机

一直以来感觉支持向量机是一个神奇的算法,当然里面的原理相应来说也比较难懂,感觉能把支持向量机原理理解并讲明白的估计对其他大多数的算法似乎都能理解,对于使用级的,这里能大概明白并会用支持向量机工具箱的就可以了。

关于原理,贴几个比较好的,学了一段时间感觉稍微能明白点,如果一点原理都不懂,硬着头皮先看吧,总会明白的。

大神博客:支持向量机通俗导论(理解SVM的三层境界)

一个SVM网站:

http://see.xidian.edu.cn/faculty/chzheng/bishe/index.htm

一个系列SVM知识集合:

http://www.blogjava.net/zhenandaci/category/31868.html

支持向量机SVM(Support Vector Machine)

三):关于支持向量机工具箱—LIBSVM

LIBSVM工具箱是台湾国立大学的一些人研究制作的,这里面把SVM的用法都集成化了,想怎么用,用哪个核函数等等只需要修改相应的参数就可以了,可以说使用起来非常方便的。像LIBSVM在matlab下的工具箱只有四个函数,其中通常情况下就用其中的两个函数,svmtrain训练模型函数和svmpredict预测数据函数,至于选择SVM算法中的哪个核函数直接写相应的参数就可以了。虽然新版的matlab也集成了SVM函数,但是感觉使用起来特麻烦,需要自己规定核函数,核函数参数等等。况且matlab自带的算法功能少,有些问题不适用。

关于LIBSVM在matlab下的使用,Matlab下安装LIBSVM:Matlab安装使用libsvm

LIBSVM使用

其他平台:libsvm使用步骤:libsvm使用步骤


四):LIBSVM中函数的简短说明

目前版LIBSVM(3.2.0)在matlab下编译完后只有四个函数,libsvmread,Libsvmwrite,svmtrain(matlab自带的工具箱中有一个同名的函数),svmpredict

  libsvmread主要用于读取数据,这里的数据是非matlab下的.mat数据,比如说是.txt,.data等等,这个时候需要使用libsvmread函数进行转化为matlab可识别数据,比如自带的数据是heart_scale数据,那么导入到matlab有两种方式,一种使用libsvmread函数,在matlab下直接libsvmread(heart_scale);第二种方式为点击matlab的‘导入数据’按钮,然后导向heart_scale所在位置,直接选择就可以了。个人感觉第二种方式超级棒,无论对于什么数据,比如你在哪个数据库下下载的数据,如何把它变成matlab下数据呢?因为有的数据libsvmread读取不管用,但是‘导入数据’后就可以变成matlab下数据。

libsvmwrite写函数,就是把已知数据存起来,使用方式为:libsvmwrite('filename',label_vector, instance_matrix);

label_vector是标签,instance_matrix为数据矩阵(注意这个数据必须是稀疏矩阵,就是里面的数据不包含没用的数据(比如很多0),有这样的数据应该去掉再存)。

svmtrain训练函数,训练数据产生模型的,一般直接使用为:

model=svmtrain(label,data,cmd); label为标签,data为训练数据(数据有讲究,每一行为一个样本的所有数据,列数代表的是样本的个数),每一个样本都要对应一个标签(分类问题的话一般为二分类问题,也就是每一个样本对应一个标签)。cmd为相应的命令集合,都有哪些命令呢?很多,-v,-t,-g,-c,等等,不同的参数代表的含义不同,比如对于分类问题,这里-t就表示选择的核函数类型,-t=0时线性核。-t=1多项式核,-t=2,径向基函数(高斯),-t=3,sigmod核函数,新版出了个-t=4,预计算核(还不会用);-g为核函数的参数系数,-c为惩罚因子系数,-v为交叉验证的数,默认为5,这个参数在svmtrain写出来使用与不写出来不使用的时候,model出来的东西不一样,不写的时候,model为一个结构体,是一个模型,可以带到svmpredict中直接使用,写出来的时候,出来的是一个训练模型的准确率,为一个数值。一般情况下就这几个参数重要些,还有好多其他参数,可以自己参考网上比较全的,因为下面的这种方法的人脸识别就用到这么几个参数,其他的就不写了。

svmpredict训练函数,使用训练的模型去预测来的数据类型。使用方式为:

[predicted_label,accuracy,decision_values/prob_estimates]= svmpredict(testing_label_vector,testing_instance_matrix,model,'libsvm_options')

或者:

[predicted_label]=svmpredict(testing_label_vector,testing_instance_matrix, model, 'libsvm_options')

第一种方式中,输出为三个参数,预测的类型,准确率,评估值(非分类问题用着),输入为测试类型(这个可与可无,如果没有,那么预测的准确率accuracy就没有意义了,如果有,那么就可以通过这个值与预测出来的那个类型值相比较得出准确率accuracy,但是要说明一点的是,无论这个值有没有,在使用的时候都得加上,即使没有,也要随便加上一个类型值,反正你也不管它对不对,这是函数使用所规定的的),再就是输入数据值,最后是参数值(这里的参数值只有两种选择,-p和-b参数),曾经遇到一个这样的问题,比如说我在训练函数中规定了-g参数为0.1,那么在预测的时候是不是也要规定这个参数呢?当你规定了以后,程序反而错误,提醒没有svmpredict的-g参数,原因是在svmtrain后会出现一个model,而在svmpredict中你已经用了这个model,而这个model中就已经包含了你所有的训练参数了,所以svmpredict中没有这个参数,那么对于的libsvm_options就是-p和-b参数了。对于函数的输出,两种方式调用的方法不一样,第一种调用把所有需要的数据都调用出来了,二第二种调用,只调用了predicted_label预测的类型,这里我们可以看到,在单纯的分类预测模型中,其实第二种方式更好一些吧,既简单有实用。

致此,四个函数在分类问题中的介绍大概如此,当然还有很多可以优化的细节就不详细说了,比如可以再使用那些参数的时候,你如果不规定参数的话,所有的-参数都是使用默认的,默认的就可能不是最好的吧,这样就涉及到如何去优化这个参数了。


五):SVM+PCA识别人脸的实现步骤

5.1:人脸数据库的准备

这里还是以AR人脸库 和ORL人脸库来作为样本进行检测,对于上一篇的单纯PCA方法可以看出,pca方法对于ORL人脸库的识别率已经很高了,但是对于AR人脸库的识别率那是相当的低,原因在那里说了,ORL人脸库样本间差异小,而AR人脸库样本间的差异大。这里使用SVM来挑战AR这个样本差异大的人脸库。首先也是对样本进行分类,随机抽取一些作为训练集,另一些作为测试集。同样使到函数[train_face,test_face] = imgdata(filedata,num) 具体程序见上篇:PCA实验人脸库-人脸识别(四)

5.2:对训练集与测试集进行降维

为什么需要降维?原始一张图片转化成一行数据后有10000多维,对于这个维度来说,里面很多维可能都是无关的,这样去进行SVM训练虽然也可以,可是会导致效率低下,速度上没测试,维度高势必计算量也会增加的。所以适当的降维取其主成分从理论上来讲非常合适。首先对训练集进行降维,同样直接使用上篇的[img_new,img_mean,V] = PC
A(img,k)函数。降维得到训练集的特征向量V后,用这个V去乘以测试集就可以把也降维了。这里有上篇的具体程序假设得到了[img_new,img_mean,V]这三个参数,现在怎么去给测试集也去降维呢?

简短程序如下:

[train_facepca,train_mean,V] = PCA(train_face,k);
num_test = size(test_face,1);
img_mean_all = repmat(train_mean,num_test,1);%复制m行平均值至整个矩阵
test_face = double(test_face) - img_mean_all;
test_facepca = test_face*V;

得到的test_facepca就是降维后的测试数据。

5.3:对训练集与测试集进行数据归一化

数据归一化的目的就是去除不同数量级之间的不匹配关系,有的数据集归不规范化对结果影响不大,而有的影响就很大,这里我试了不规范化的数据,对结果的影响确实很大。所以正常来说最好都规范化一下吧,大部分情况规范化总是好的。这里就是对上述得到的降维后的训练集train_facepca和test_facepca进行规范化。程序如下:

<span style="font-size:14px;">function scaledface = scaling( faceMat,lowvec,upvec )
%特征数据规范化
%输入——faceMat需要进行规范化的图像数据,
upnew=1;
lownew=-1;
[m,n]=size(faceMat);
scaledface=zeros(m,n);
for i=1:m
    scaledface(i,:)=lownew+(faceMat(i,:)-lowvec)./(upvec-lowvec)*(upnew-lownew);
end</span>

这样把所有数据规范化到-11之间了。整个规范化程序为:

%% 对训练集于测试集都进行数据归一化
low = min(train_facepca);
up = max(train_facepca);
scaled_trainface = scaling(train_facepca,low,up);
scaled_testface = scaling(test_facepca,low,up);

5.4:对训练集训练得到模型

由于libsvm处理的分类问题是两类问题,而我们这里可以看到,有50个不同的人脸,每个人又有26张样本,按照分类来说,就是每一张图片对应于50个类中的一个类。这就是50类分类问题了。那么如何由两类问题转化成50类问题呢?这里就把50个类划分成很多个2类问题,每两两一分,比如1-2,1-3,1-4...1-50;2-3,2-4,2-5...2-50,等等等等最后是49-50;这么些类,总共就有50*49/2个两类分类了,对每一个两类问题,都训练一次,产生一个model,就有50*49/2个model,每一类都和其他的49个类有一次联系吧。现在假设来了一个样本,比如是第10类吧,那么把这个样本依次带到所有的model中,循环50*49/2次,对于每一个model都会出现一个预测的类吧,比如现在理论上是第10类,依次带1-2,可能结果是个预测是个1(因为是在1-2两个类中预测,不是1就是2),1-3可能结果是个3,等等,当到了10-1(其实是1-10)至10-50这些个含有10的类时,由于样本本身是10,那么这些结果预测出来的肯定(90%以上)是10吧,这样把所有的二分类分循环完,也就是50*49/2次后,我们就可以统计出这个10落在第1类可能是30次,第二类可能是20次,第三类可能是27次等等等等,直到第10类是50次(接近50),在往后11类可能是30次,等等等等,第50类可能是10次。这样我们只要统计出这些个数中的最大者,那么这个类就是最大者对应的那个类了。

这个过程就是这样,现在的问题是怎么得到这些model?每一个model需要其中两类的训练集,每一个训练集又可能不止一个样本,并且好要标签标上类型。

我是这样处理的,比如现在求model{1,2},就是1与2类做一个model,每类假设选3个样本,这样训练样本就有6个样本,对应的标签分别是[1;1;1;2;2;2]就可以了吧。然后把这个标签价样本拿去svmtrain训练,好了,1-3,1-4等等等等都采用同样的方法就可以得到所有的model了。具体程序如下:

%---------------------
%     img_new--输入的train_face脸
%     num:每个类(人)中选取num个样本
function model = Model_Find(img_new,num)
%  用法:   model = Model_Find(img_new,num);
m = size(img_new,1);
class_all = m/num;  %总共的类数
%%  将训练集划分成SVM能够处理的形式(包括标签与数据)
for i = 1:class_all-1    %1到k-1
    for j = i+1:class_all  %2到k
        train_label_all{i,j} = [i*ones(1,num),j*ones(1,num)]';%标上标签
        train_data_all{i,j} = [img_new((i-1)*num+1:i*num,:);img_new((j-1)*num+1:j*num,:)];
    end   %把对应的类上的数据提取出来
end
%%  调用SVM分类,对于k类共需要k*(k-1)/2 次划分
for i = 1:class_all-1
    for j = i+1:class_all
        model{i,j} = svmtrain(train_label_all{i,j},train_data_all{i,j},'-t 0');
    end   %训练得到所有的model
end

5.5:对测试集进行测试得到准确率

  有了上面的model,用这些model去分类测试集就可以了。先写一个子程序,来处理随机来了一个样本时它是属于哪个类的,在处理所有的测试样本。

function class = find_class(model,test)
class_all = size(model,2); %注意model的大小为k*(k+1)
belong = zeros(1,class_all);
for i = 1:class_all-1
    for j = i+1:class_all
        predict = svmpredict(1,test,model{i,j});
%标签任意写假设为1,因为需要预测的就是标签分类,不需要知道test的标签
        belong(predict) = belong(predict) + 1;
     end
end
class = find(belong == max(belong));
%如果存在多个最大值,取第一个为准
%调试半天终于知道错误了,这个必须考虑
m = size(class,2);
if m > 1
    class = class(1);
End

这个函数中的test可以认为是scaled_testface中的任意一行(一个样本),只对这个样本进行分类。

基于此,再对所有的scaled_testface一一进行分类并计算准确率:

function accurary = facefind_svm(model,test_facepca,num)
% num:训练集中的每个人选取num个样本
%  用法:   class = facefind_svm(model,test_face,img_mean,V);
test_num = size(test_facepca,1); 
for i = 1:test_num
    class(i) = find_class(model,test_facepca(i,:));
end
%%
numtrue = 0;
for i = 1:test_num
    if ceil(i/(26-num)) == class(i) 
        numtrue = numtrue+1;
    end
end
accurary = numtrue/test_num;

六):整体main程序

clc,clear;
load('face_AR_50.mat');
%%定义每个人选取num个样本,划分样本
num = 3;
[train_face,test_face] = imgdata(filedata,num);
%% 对训练集于测试集求取PCA,都转化到PCA数据
k = 140;  %降维数
[train_facepca,train_mean,V] = PCA(train_face,k);
num_test = size(test_face,1);
img_mean_all = repmat(train_mean,num_test,1);%复制m行平均值至整个矩阵
test_face = double(test_face) - img_mean_all;
test_facepca = test_face*V;
%% 对训练集于测试集都进行数据归一化
low = min(train_facepca);
up = max(train_facepca);
scaled_trainface = scaling(train_facepca,low,up);
scaled_testface = scaling(test_facepca,low,up);
%% 训练与计算准确率
model = Model_Find(scaled_trainface,num);
accurary = facefind_svm(model,scaled_testface,num);

七):实验结果记录

  首先贴一下上一次PCA方法下对AR数据库的识别结果:

(AR人脸库(包含50位男性和50位女性每人26张人脸共2600张人脸图片 ),这里只选取了50位男性样本)

每个人选取num个样本 降维数k 准确率accuracy
num=5 K=40 0.28
num=10 K=40 0.44
num=15 K=40 0.54

可以看出效果是很差的。


    现在来看一下PCA+SVM的效果;

实验中存在的可变变量:

svmtrain 参数 :-t参数(这个是选择核函数的)其他的-g等等参数都是采   用默认的。

      系统参数:  num:每个人选取num个样本(最大26)

                   K :PCA中的降维数

首先k一定,k选30;

accuracy num=15;k = 30 num=10;k = 30 num=8;k = 30 num=2;k = 30
-t=0 0.84 0.79 0.6438 0.3717
-t=1 0.2782 0.2538 0.19 0.10
-t=2 0.65 0.6438 0.5210 0.3083
-t=3 0.68 0.6175 0.4886 0.3458


最好的,并且在num=15的时候准确率达到0.84,相比同等条件下的PCA只有0.54左右。
从上面可以看出,核函数参数-t=0,也就是选择线性核函数的时候的效果始终是

由此也可以断定线性核函数非常适合这个人脸识别库。下面就选的-t=0不变,改变降维数k看看结果如何:

accuracy k = 50 k = 80 k = 140
num=15 0.9309 0.9618 0.9618
num=10 0.8713 0.9075 0.9238
num=8 0.8422 0.8029 0.9267
num=5 0.7552 0.8143 0.8400
num=3 0.6183 0.6765 0.8052
num=2 0.4917 0.6217 维度过大

从上述可以看到,在num=15,k = 140的时候准确率可以达到0.9618,应该很高了。另外,每次实验的数据会不一样,原因在于样本的选择是随机的。Num在往上加就没有试验了,每个人总共才26个样本,用到15个作为训练已经很多了。再看看在num=3的时候,最大准确率也可以达到0.8052,也就是说每个人26个样本中用3个就可以使准确率达到0.8052,这是PCA怎么也不可能达到的。而且这个AR数据库的差异性在以前讨论过的很大,在这种情况下支持向量机的优点显而易见。(上述最后一个维度过大的原因在于这个时候最大降维为50*2=100)


相关代码下载: http://download.csdn.net/detail/on2way/8689529

你可能感兴趣的:(matlab,libsvm,人脸识别,主成分分析)