支持向量机学习笔记:LIBSVM应用(人脸识别)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Linoi/article/details/18327835

如果你已经看完并理解了我的上一篇SVM的博客,那么接下来你要面对的是怎么应用SVM这个实际的问题,现在SVM里面应用最广泛的就是LIBSVM这个函数库,OpenCV中也基于LIBSVM推出了CvSVM 的函数。因此下面的内容,我主要是介绍一下LIBSVM的应用方法,主要是参考文献[1,2]。

LIBSVM是国立台湾大学 Chih-Jen Lin开发的一个SVM的函数库,他不但提供了编译好的可在Windows系列系统的执行文件,还提供了源代码,方便改进、修改以及在其它操作系统上应用;该软件对SVM所涉及的参数调节相对比较少,提供了很多的默认参数,利用这些默认参数可以解决很多问题;并提供了交互检验(Cross Validation)的功能。该软件包可在http://www.csie.ntu.edu.tw/~cjlin/免费获得。该软件可以解决C-SVM、ν-SVM、ε-SVR和ν-SVR等问题,包括基于一对一算法的多类模式识别问题。

上一篇博客中谈的内容是从理论出发的东西,但是在实际应用中,我们常常无法找到一个完美无缺的判别超平面,那么为了能够在这样子的不可分的集合中学习支持向量机,需要引入软间隔(soft margin)来进行分类,即是允许一些训练模式停留在判别超平面的“错误”一侧,或者说允许其他类的模式停留在间隔内,则上一篇博客中的公式(3)修改为:


其中为松弛变量,对应数据点偏离对应的间隔面(非分类超平面)的距离(见图1)。因此,最终的结果是margin可以比1小,但是当某些点出现这种margin比1小的情况时(这些点也称离散点),意味着我们放弃啦对这些点的精确分类,而这对分类器来说是一种损失,但是放弃这些点也带来了好处,就是分类面不必向这些点的方向移动,因而可以得到更大的几何margin。显然,我们必须权衡这种损失和好处。好处是明显的,我们得到的分类间隔越大,好处就越多。


图1 松弛变量


下面还有几点需要注意:

  • 并非所有的样本点都有一个松弛变量与其对应。实际上只有“离群点”才有,或者也可以这么看,所有没离群的点松弛变量都等于0(对负类来说,离群点就是在前面图中,跑到H2右侧的那些负样本点,对正类来说,就是跑到H1左侧的那些正样本点)。
  • 松弛变量的值实际上标示出了对应的点到底离群有多远,值越大,点就越远。
  • 惩罚因子C决定了你有多重视离群点带来的损失,显然当所有离群点的松弛变量的和一定时,你定的C越大,对目标函数的损失也越大,此时就暗示着你非常不愿意放弃这些离群点,最极端的情况是你把C定为无限大,这样只要稍有一个点离群,目标函数的值马上变成无限大,马上让问题变成无解,这就退化成了硬间隔问题。
  • 惩罚因子C不是一个变量,整个优化问题在解的时候,C是一个你必须事先指定的值,指定这个值以后,解一下,得到一个分类器,然后用测试数据看看结果怎么样,如果不够好,换一个C的值,再解一次优化问题,得到另一个分类器,再看看效果,如此就是一个参数寻优的过程,但这和优化问题本身决不是一回事,优化问题在解的过程中,C一直是定值,要记住。
  • 尽管加了松弛变量这么一说,但这个优化问题仍然是一个优化问题(汗,这不废话么),解它的过程比起原始的硬间隔问题来说,没有任何更加特殊的地方。

现在,我们来看看在实际应用中的C-SVM:


文献[1]中推荐的SVM使用步骤如下:

  1. 【将数据变换成SVM格式】Transform data to the format of an SVM package
  2. 【数据规范化(scale)】Conduct simple scaling on the data
  3. 【考虑使用RBF核】Consider the RBF Kernel 
  4. 【使用交叉验证获取最优参数C和Gamma】Use Corss-validation to find the best parameter C and Gamma
  5. 【使用最优参数来训练整个训练集】Use the best parameter C and Gamma to train the whole training set
  6. 【新来数据的测试】Test

描述如下:

Data Preprocessing

Categorical Feature

SVM要求数据实例是实数向量,因此,我们必须先把它的类别特征转换成数值特征。这里推荐使用m个值去代表m类的特征。例如,一个三类特征{red,green,blue}可以表示成(0,0,1)(0,1,0)(1,0,0)。经验表明,当类别不是非常大时,这种特征类别编码方式更稳定

Scaling

Scaling在SVM中非常重要,这里推荐使用linearly scaling each attribute to the range [-1,+1] or [0,1]。

Model Selection

RBF Kernel 


一般情况下,RBF Kernel 是一个合理的第一选择,可以首先尝试这个核函数。

Cross-validation and Grid-search

RBF核函数有两个参数:C和Gamma。针对一个给定的问题,需要通过参数搜索方法来获取他们的最优值。一个常用的方法是将训练数据分成2个部分,其中一部分为“未知的”,通过对未知数据的分类效果来反映系统分类性能。该方法的一个提升版本就是Cross-validation交叉验证。在v-fold交叉验证中,我们首先将数据分成v组,将每个子集分别做一次测试集,其余v-1组作为训练集,这样就会得到v个模型,用这v个模型最终的测试集的分类准确率作为v-fold cross-validation分类性能的指标。这里我们推荐使用“grid-search”,即尝试各个参数对(C,gamma),我们发现使用指数增长能更快找到最佳参数值。如

            C = 2^(-5)   2^(-3) .... 2^15

gamma = 2^(-15) 2^(-13) ... 2^3

————————————————————————————————————————————————————————————


下面,我贴一个用SVM进行人脸识别的例子(效果很不好,特征和参数没细调)


close all;
clc;
clear;
num = 25;
M = 112;N = 92;accu = 0;
suma = zeros(28,28);
Gt = zeros(28,28);
for ii = 1:1:num
    for k = 1:9
        name1 = strcat('s',num2str(ii));
        name2 = strcat(name1,'\');
        name3 = strcat(num2str(k),'.bmp');
        name4 = strcat(name2,name3);
        name = strcat('E:\快盘\文献阅读\DATAbase\ORLFACE\',name4);
        I = imread(name);
        if ndims(I)==3
            I = rgb2gray(I);
        end
        I_re = imresize(I,[112 112]);
        temp = double(I_re(1:4:112,1:4:112));
        suma = suma+temp;
    end
end
aver_A = suma/(num*9);

for ii = 1:1:num
   for k =1:9
    name1 = strcat('s',num2str(ii));
    name2 = strcat(name1,'\');
    name3 = strcat(num2str(k),'.bmp');
    name4 = strcat(name2,name3);
    name = strcat('E:\快盘\文献阅读\DATAbase\ORLFACE\',name4);
    I=imread(name);
    if ndims(I)==3
        I = rgb2gray(I);
    end
    I_re = imresize(I,[112 112]);
    temp = double(I_re(1:4:112,1:4:112));
    Gt = Gt+(temp-aver_A)'*(temp-aver_A);
   end
end

Gt = Gt/(num*9);
[v,d] = eigs(Gt,25);
[eigenvalues, index] = sort(diag(d),'descend');

ratio = cumsum(eigenvalues)/sum(eigenvalues);
xnum = find(ratio>.98);
D_num = xnum(1);
index_select = index(1:D_num);
V_select = zeros(size(v,1),D_num);
V_select(:,1:D_num) = v(:,index_select(1:D_num));

i_oo=1;
for ii = 1:1:num
    for k = 1:9
    name1 = strcat('s',num2str(ii));
    name2 = strcat(name1,'\');
    name3 = strcat(num2str(k),'.bmp');
    name4 = strcat(name2,name3);
    name = strcat('E:\快盘\文献阅读\DATAbase\ORLFACE\',name4);
    I = imread(name);
    if ndims(I)==3
        I = rgb2gray(I);
    end
    I_re = imresize(I,[112 112]);
    temp = double(I_re(1:4:112,1:4:112));
    temp2 = temp*V_select;
    Y_matrix(i_oo,:) = reshape(temp2,1,588);
    i_oo=i_oo+1;
    end
end
t_label=[];
for ii = 1:1:num
    for jj = 1:9
        t_label =[t_label,ii];
        Y_label = t_label';
    end
end
%% 现在准备开始建立model,为predict做准备
model = svmtrain(Y_label,Y_matrix);
%% 测试部分
for ii = 1:1:num
    k = 10;
    name1 = strcat('s',num2str(ii));
    name2 = strcat(name1,'\');
    name3 = strcat(num2str(k),'.bmp');
    name4 = strcat(name2,name3);
    name = strcat('E:\快盘\文献阅读\DATAbase\ORLFACE\',name4);
    I = imread(name);
    if ndims(I)==3
        I = rgb2gray(I);
    end
    I_re = imresize(I,[112 112]);
    temp = double(I_re(1:4:112,1:4:112));
    tempY = temp*V_select;
    X_test(ii,:) = reshape(tempY,1,588);
end
label_temp = [1:num];X_label=label_temp';
[predict_label, accuracy, dec_values] = svmpredict(X_label,X_test,model);


参考文献

[1] Hsu C W, Chang C C, Lin C J. A practical guide to support vector classification[J]. 2003.

[2] Chang C C, Lin C J. LIBSVM: a library for support vector machines[J]. ACM Transactions on Intelligent Systems and Technology (TIST), 2011, 2(3): 27.


没有更多推荐了,返回首页