机器学习——SVM(支持向量机)与人脸识别

    忆如完整项目/代码详见github:https://github.com/yiru1225(转载标明出处 勿白嫖 star for projects thanks)

目录

系列文章目录

一、SVM的概念与原理

1.SVM简介

2.SVM基本流程

3.SVM在多分类中的推广

二、经典SVM运用于图像识别分类

三、SVM运用于人脸识别

1.预处理

1.1 数据导入与处理

扫描二维码关注公众号,回复: 15445238 查看本文章

1.2 数据降维

2.人脸识别

2.1 OVO实现SVM

2.2 OVR实现SVM

3.PCA与LDA分别结合SVM在各维度、各数据集的人脸识别率及其与KNN的对比

3.1 ORL下比较SVM与KNN对于PCA和LDA的人脸识别率随维度的改变

3.2  各种方法在不同数据集下的平均人脸识别率

4.OVO与OVR实现SVM的人脸识别率比较

4.1 ORL下比较OVO与OVR实现SVM + PCA的人脸识别率随维度的改变                      

4.2 OVO与OVR实现SVM + PCA在不同数据集下的平均人脸识别率           

四、创新SVM算法设计

五、其他

1. 数据集及资源

2. 参考资料

总结


系列文章目录

本系列博客重点在机器学习的概念原理与代码实践,不包含繁琐的数学推导(有问题欢迎在评论区讨论指出,或直接私信联系我)。

代码可以全抄    大家搞懂原理与流程去复现才是有意义的!!!

第一章 机器学习——PCA(主成分分析)与人脸识别_@李忆如的博客-CSDN博客

第二章 机器学习——LDA (线性判别分析) 与人脸识别_@李忆如的博客-CSDN博客

第三章 机器学习——LR(线性回归)、LRC(线性回归分类)与人脸识别_@李忆如的博客​​​​​

第四章 机器学习——SVM(支持向量机)与人脸识别


梗概

本篇博客主要介绍SVM(支持向量机)算法,利用经典SVM实现图像识别二分类,并将SVM(OVO与OVR均实现)+ 降维方法(PCA与LDA)用于人脸识别,并将SVM与KNN进行比较,OVO与OVR进行比较(内附数据集与matlab、python代码)


一、SVM的概念与原理

1.SVM简介

支持向量机(SVM)是在分类与回归中分析数据的有监督学习模型与相关的学习算法。本质上是一种二分类模型,它的经典模型是定义在特征空间的间隔最大的线性分类器,学习策略是间隔最大化

2.SVM基本流程

SVM模型将实例表示为空间(超平面、超空间)中的点,这样映射就使得单独类别的实例被尽可能宽的明显的间隔分开。然后,将新的实例映射到同一空间,并基于它们落在间隔的哪一侧来预测所属类别。

3.SVM在多分类中的推广

由于SVM是一种二分类器,即用一条线或一个平面分开两类不同数据,一般用如下两个方法使其推广到多分类。

① OVR:对于K个类别的情况,训练K个SVM,第j个SVM用于判断任意条数据是属于类别j还是类别非j。预测的时候,具有距超空间i最大值的表示给定的数据x属于类别i。

② OVO:对于K个类别的情况,训练K*(K-1)/2个SVM,每一个SVM只用于判断任意条数据是属于K中的特定两个类别。预测的时候,使用K*(K-1)/2个SVM做K*(K-1)/2次预测,使用计票的方式决定数据被分类为哪个类别的次数最多,就认为数据x属于此类别。

Tips:SVM详细推导可见:svm原理详细推导_weixin_42001089的博客-CSDN博客_svm推导

二、经典SVM运用于图像识别分类

① 问题描述:识别图片属于森林还是房间

② 算法实现核心:使用mapminmax实现划分后的数据集归一化,利用函数fitcsvm训练归一化后训练集,通过求解二次规划与准备参数,得到a并找到支持向量,predict用刚刚训练出的模型预测,求b得到f(x)与预测类别。

③ 代码如下:

clear;
% dataset是将bedroom和forest合并;dataset = [bedroom;forset];这行代码可以实现合并
load forest.mat                  %导入要分类的数据集
load bedroom.mat
dataset = [bedroom;MITforest];
load labelset.mat                %导入分类集标签集

% 选定训练集和测试集

% 将第一类的1-5,第二类的11-15做为训练集
train_set = [dataset(1:5,:);dataset(11:15,:)];
% 相应的训练集的标签也要分离出来
train_set_labels = [lableset(1:5);lableset(11:15)];
% 将第一类的6-10,第二类的16-20,做为测试集
test_set = [dataset(6:10,:);dataset(16:20,:)];
% 相应的测试集的标签也要分离出来
test_set_labels = [lableset(6:10);lableset(16:20)];
 
% 数据预处理,将训练集和测试集归一化到[0,1]区间
 
[mtrain,ntrain] = size(train_set);
[mtest,ntest] = size(test_set);
 
test_dataset = [train_set;test_set];
% mapminmax为MATLAB自带的归一化函数
[dataset_scale,ps] = mapminmax(test_dataset',0,1);
dataset_scale = dataset_scale';
 
train_set = dataset_scale(1:mtrain,:);
test_set = dataset_scale( (mtrain+1):(mtrain+mtest),: );
 
% SVM网络训练
model = fitcsvm(train_set,train_set_labels);
 
% SVM网络预测
[predict_label] = predict(model,test_set);
%[predict_label] = model.IsSupportVector;

 
% 结果分析
 
% 测试集的实际分类和预测分类图
% 通过图可以看出只有一个测试样本是被错分的
figure;
hold on;
plot(test_set_labels,'o');
plot(predict_label,'r*');
xlabel('测试集样本','FontSize',12);
ylabel('类别标签','FontSize',12);
legend('实际测试集分类','预测测试集分类');
title('测试集的实际分类和预测分类图','FontSize',12);
grid on;

④ 识别效果如下:

 分析:分析上图可知,预测分类与实际分类均相等,预测效果很好。

三、SVM运用于人脸识别

1.预处理

1.1 数据导入与处理

利用imread批量导入人脸数据库,或直接load相应mat文件,并在导入时不断将人脸拉成一个个列向量组成reshaped_faces,并取出n%作为测试数据,剩下100-n%作为训练数据,重复此步骤,将导入数据抽象成框架,可以匹配不同数据集的导入(本实验框架适配ORL、AR、FERET数据集)。

Tips:代码可见本系列第二篇文章(LDA与人脸识别),基本一致。

1.2 数据降维

使用LDA或PCA对数据降维(具体原理与详细代码见本系列一二篇文章)

% LDA
% 算每个类的平均
k = 1; 
class_mean = zeros(dimension, people_num); 
for i=1:people_num
    % 求一列(即一个人)的均值
    temp = class_mean(:,i);
    % 遍历每个人的train_pic_num_of_each张用于训练的脸,相加算平均
    for j=1:train_pic_num_of_each
        temp = temp + train_data(:,k);
        k = k + 1;
    end
    class_mean(:,i) = temp / train_pic_num_of_each;
end

% 算类类间散度矩阵Sb
Sb = zeros(dimension, dimension);
all_mean = mean(train_data, 2); % 全部的平均
for i=1:people_num
    % 以每个人的平均脸进行计算,这里减去所有平均,中心化
    centered_data = class_mean(:,i) - all_mean;
    Sb = Sb + centered_data * centered_data';
end
Sb = Sb / people_num;

% 算类内散度矩阵Sw
Sw = zeros(dimension, dimension);
k = 1; % p表示每一张图片
for i=1:people_num % 遍历每一个人
    for j=1:train_pic_num_of_each % 遍历一个人的所有脸计算后相加
        centered_data = train_data(:,k) - class_mean(:,i);
        Sw = Sw + centered_data * centered_data';
        k = k + 1;
    end
end
Sw = Sw / (people_num * train_pic_num_of_each);

% 目标函数一:经典LDA(伪逆矩阵代替逆矩阵防止奇异值)
% target = pinv(Sw) * Sb;

% PCA
centered_face = (train_data - all_mean);
cov_matrix = centered_face * centered_face';
target = cov_matrix;

% 求特征值、特征向量
[eigen_vectors, dianogol_matrix] = eig(target);
eigen_values = diag(dianogol_matrix);

% 对特征值、特征向量进行排序
[sorted_eigen_values, index] = sort(eigen_values, 'descend'); 
eigen_vectors = eigen_vectors(:, index);
eigen_vectors = real(eigen_vectors); % 处理复数,会导致一定误差(LDA用)

2.人脸识别

实现核心流程:使用PCA/LDA先对数据进行预处理与降维,SVM使用OVO/OVR对划分好的数据集进行模型训练与测试集预测,最终记录识别率并与比较。

2.1 OVO实现SVM

%使用SVM人脸识别
    % SVM(OVO)
rate = []; %用于记录人脸识别率
for i=10:10:160
    right_num = 0;
    % 降维得到投影矩阵
    project_matrix = eigen_vectors(:,1:i);
    projected_train_data = project_matrix' * (train_data - all_mean);
    projected_test_data = project_matrix' * (test_data - all_mean);

    % SVM训练过程
           model_num = 1;
       for j = 0:1:people_num - 2
         train_img1 = projected_train_data(:,j * train_pic_num_of_each + 1 : j * train_pic_num_of_each + train_pic_num_of_each); % 取出每次SVM需要的训练集
         train_label1 = ones(1,train_pic_num_of_each)*(j + 1); % 给定训练标签
         test_img1 = projected_test_data(:,j * test_pic_num_of_each + 1 : j * test_pic_num_of_each + test_pic_num_of_each); % 取出每次SVM需要的测试集
         for z = j + 1:1:people_num - 1
         train_img2 = projected_train_data(:,z * train_pic_num_of_each + 1 : z * train_pic_num_of_each + train_pic_num_of_each); % 取出每次SVM需要的训练集
         train_label2 = ones(1,train_pic_num_of_each)*(z + 1); % 给定训练标签
         train_imgs = [train_img1,train_img2];
         train_label = [train_label1,train_label2];
         
         test_img2 = projected_test_data(:,z * test_pic_num_of_each + 1 : z * test_pic_num_of_each + test_pic_num_of_each); % 取出每次SVM需要的测试集
         test_imgs = [test_img1,test_img2];
         
          % 数据预处理,将训练集和测试集归一化到[0,1]区间 
        [mtrain,ntrain] = size(train_imgs); %m为行数,n为列数
        [mtest,ntest] = size(test_imgs);
 
        test_dataset = [train_imgs,test_imgs];
        % mapminmax为MATLAB自带的归一化函数
        [dataset_scale,ps] = mapminmax(test_dataset,0,1);
 
        train_imgs = dataset_scale(:,1:ntrain);
        test_imgs = dataset_scale( :,(ntrain+1):(ntrain+ntest) );
 
        % SVM网络训练
        train_imgs = train_imgs';
        train_label = train_label';
        expr = ['model_' num2str(model_num) ' = fitcsvm(train_imgs,train_label);']; % fitcsvm默认读取数据为按行,一张一脸为一列,需要转置
        eval(expr);
        model_num = model_num + 1;
         end
       end
       model_num = model_num - 1;
       
       % 人脸识别
       test = []; % 测试用
    for k = 1:1:test_pic_num_of_each * people_num
        test_img = projected_test_data(:,k); % 取出待识别图像
        test_real_label = fix((k - 1) / test_pic_num_of_each) + 1; % 给定待测试真实标签
        predict_labels = zeros(1,people_num); %用于OVO后续投票
      
       % SVM网络预测
       for t = 1:1:model_num
       predict_label = predict(eval(['model_' num2str(t)]),test_img');
       % test = [test,predict_label]; % 测试用
       predict_labels(1,predict_label) = predict_labels(1,predict_label) + 1;
       end
         [max_value,index] = max(predict_labels);
       if(index == test_real_label)
           right_num = right_num + 1;   
       end
    end
       
       recognition_rate = right_num / (test_pic_num_of_each * people_num); 
       rate = [rate,recognition_rate];
end    

2.2 OVR实现SVM

           % SVM(OVR)
rate = []; %用于记录人脸识别率
for i = 10:10:160
        right_num = 0;
    % 降维得到投影矩阵
    project_matrix = eigen_vectors(:,1:i);
    projected_train_data = project_matrix' * (train_data - all_mean);
    projected_test_data = project_matrix' * (test_data - all_mean);
         model_num = 1;
             % SVM训练过程(每次训练都要使用整个数据集)
         for j = 0:1:people_num - 1
         
         train_imgs = circshift(projected_train_data,-j * train_pic_num_of_each ,2); %使训练集始终在前几行
         train_label1 = ones(1,train_pic_num_of_each) * (j + 1);
         train_label2 = zeros(1,train_pic_num_of_each * (people_num - 1));
         train_label = [train_label1,train_label2];
         
         test_imgs = circshift(projected_test_data,-j * test_pic_num_of_each ,2); %使测试集始终在前几行

        % 数据预处理,将训练集和测试集归一化到[0,1]区间 
        [mtrain,ntrain] = size(train_imgs); %m为行数,n为列数
        [mtest,ntest] = size(test_imgs);
 
        test_dataset = [train_imgs,test_imgs];
        % mapminmax为MATLAB自带的归一化函数
        [dataset_scale,ps] = mapminmax(test_dataset,0,1);

        train_imgs = dataset_scale(:,1:ntrain);
        test_imgs = dataset_scale( :,(ntrain+1):(ntrain+ntest) );
 
        % SVM网络训练
        train_imgs = train_imgs';
        train_label = train_label';
        expr = ['model_' num2str(model_num) ' = fitcsvm(train_imgs,train_label);']; % fitcsvm默认读取数据为按行,一张一脸为一列,需要转置
        eval(expr);
        model_num = model_num + 1;
         end
        model_num = model_num - 1;
         % 人脸识别
       for k = 1:1:test_pic_num_of_each * people_num
        test_img = projected_test_data(:,k); % 取出待识别图像
        test_real_label = fix((k - 1) / test_pic_num_of_each) + 1; % 给定待测试真实标签
        predict_labels = zeros(1,people_num); %用于OVR预测
      
       % SVM网络预测
       for t = 1:1:model_num
       [predict_label,possibility] = predict(eval(['model_' num2str(t)]),test_img');
       if predict_label ~= 0
       predict_labels(1,predict_label) = predict_labels(1,predict_label) + possibility(1,1); 
       end
       end
         [min_value,index] = min(predict_labels); % 若一张图片被预测为多类,选择离超平面最远的作为最终预测类
       if(index == test_real_label)
           right_num = right_num + 1;   
       end
       end
       recognition_rate = right_num / (test_pic_num_of_each * people_num); 
       rate = [rate,recognition_rate];
        
end

3.PCA与LDA分别结合SVM在各维度、各数据集的人脸识别率及其与KNN的对比

运行SVM.m,比较在ORL(或其他数据集下)SVM(OVO实现为例)+降维方法与KNN+降维方法的人脸识别率随维度的变化,并在多个数据集下比较不同方法的人脸识别率,结果与分析如下:

3.1 ORL下比较SVM与KNN对于PCA和LDA的人脸识别率随维度的改变

3.2  各种方法在不同数据集下的平均人脸识别率

 Tips:数据集后为训练集与测试集的划分比

分析:分析以上两组图可知,各方法的人脸识别率与维度、数据集、参数选择均存在巨大关系,并没有某种方法组合在所有维度所有数据集下均具有优越性。

4.OVO与OVR实现SVM的人脸识别率比较

分别用OVO与OVR的思想训练SVM不同分类器并应用于人脸识别,在不同维度、不同数据集下的人脸识别率如下:

4.1 ORL下比较OVO与OVR实现SVM + PCA的人脸识别率随维度的改变                      

4.2 OVO与OVR实现SVM + PCA在不同数据集下的平均人脸识别率           

分析:分析以上两组图可知,OVR实现SVM时在低维度时识别率低于OVO实现SVM,随着维度增加,OVR的识别率逐渐稳定地优于OVO,且在实验的三个数据集中,OVR的平均识别率均高于OVO。另外,OVR训练的分类器数量少,在小数据集下效率更高,但随着数据规模增大,OVR每次训练数据过大,效率会逐渐低于OVO。 

5.方法与函数的补充

对于多分类SVM,matlab可以使用fitcecoc函数,python可以使用svm.SVC搭配fit与predict直接实现多分类SVM,而不需要多次训练二分类SVM。

四、创新SVM算法设计

① 经典SVM不足:无法处理非线性数据,对大规模训练样本难以实施。

已有改进:软间隔SVM/SVM/ CSVM

③ 创新SVM算法简述:

(1)SMO后通过对核函数的缓存可以大大增加算法效率。因为在经典SVM中,空间消耗主要在模型的训练,时间消耗主要在各种核函数与其他模型、函数的调用。

(2)对于最优化问题中f(x)的计算需要不断循环,代价很高,在此定义并缓存一个g(x)如下,让我们可以随时计算误差:

3)优化数据集划分,实现冷热数据分离。热数据在前(大于0小于Calpha值),冷数据在后(小于等于0 或者大于等于 C alpha)在后。随着迭代加深,大部分时候只需要在热数据里求解,并且热数据的大小会逐步不停的收缩,所以区分了冷热以后SVM 大部分都在针对有限的热数据迭代。

4)传入外部分类“权重”修正结果,提高识别率。用原始的 C 乘以各自分类的权重,得到 Cp Cn,然后迭代时,不同的样本根据它的 y 值符号,用不同的 C 值带入计算。

(5)同时支持稀疏和非稀疏,针对不同数据,选择合适的方式求解。

五、其他

1. 数据集及资源

本实验所用数据集:ORL5646、AR5040、FERET_80,代码框架可适用多个数据集。

常用人脸数据集如下(不要白嫖哈哈哈)

链接:https://pan.baidu.com/s/12Le0mKEquGMgh5fhNagZGw 
提取码:yrnb

SVM完整代码与二分类所需数据集:李忆如/忆如的机器学习 - Gitee.com

2. 参考资料

1.支持向量机(SVM)的推导(线性SVM、软间隔SVM、Kernel Trick) - liuyang0 - 博客园 

2.手撕SVM公式——硬间隔、软间隔、核技巧_Dominic_S的博客-CSDN博客_硬间隔

3.手写SVM算法(Matlab实现) - 知乎 (zhihu.com)

4.SVM支持向量机+实例展示_Snippers的博客-CSDN博客_svm支持向量机

5.周志华《机器学习》


总结

SVM作为经典的线性二分类器,通过”最大化间隔“为目标导向对数据进行超空间(平面)投影并划分。如今仍然在机器学习许多领域(数据分类、语言图像处理、推荐系统)有优异表现。且作为一种有监督学习方法(利用了数据的原有信息),SVM能得到较好的保留数据信息。但SVM仍存在处理高维数据大计算代价问题、不好刻画非线性问题等等,另外,SVM假设的数据属性在现实世界的问题中往往难以达到,从而影响实验结果,后续博客会分析其他算法优化或解决上述问题。

猜你喜欢

转载自blog.csdn.net/weixin_51426083/article/details/124396497