机器学习——LDA(线性判别分析)与人脸识别

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

目录

系列文章目录

一、LDA的概念与原理

1.LDA简介

2.LDA算法模型

3.LDA的不足与优化

二、LDA运用于人脸识别

1.预处理

1.1 数据导入与处理

1.2 算各类均值、类间散度Sb、类内散度Sw

2.LDA核心(构造目标函数并对其进行特征分解)

3.人脸识别

4.LDA与PCA图像降维与可视化对比

5.LDA与PCA的异同总结

6.其他

6.1 内部函数定义

6.2 数据集及资源

6.3 参考资料

总结


系列文章目录

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

代码可以全抄    大家搞懂原理与流程去复现才是有意义的!!!
第一章 机器学习——PCA(主成分分析)与人脸识别_@李忆如的博客-CSDN博客

第二章 LDA与人脸识别


梗概

本篇博客主要介绍LDA(线性判别分析)算法并将LDA及其各种等价模型用于人脸的识别、图像降维可视化,并将LDA与PCA进行比较(内附数据集与matlab代码)


一、LDA的概念与原理

1.LDA简介

LDA(线性判别分析)为主流的一种线性降维算法。以”最小化类内方差,最大化类间方差“为目标导向,通过降维(投影),达到降维的目的更好地将样本分类。

2.LDA算法模型

经典的LDA解决问题可划分为以下步骤

1.将数据集分类,计算每个类的均值(LDA利用了样本的类别(数据)标签,为有监督学习)。

2.计算类间散度矩阵Sb与类内散度矩阵Sw。

3.构造目标函数(多种不同的目标函数)并对其进行特征分解。

4.取出一定数量的特征向量得到投影矩阵。

5.将测试数据投影到子空间中,使用KNN进行分类(实际问题中)。

3.LDA的不足与优化

1.有限投影轴问题(≤类别数 - 1)

2.小样本问题

3.处理高维数据时,计算代价很大

优化:先用PCA进行预处理再使用LDA,或在目标函数中加入正则化扰动

4.不能较好地刻画非线性问题

优化:使用核属性的LDA升维处理数据

二、LDA运用于人脸识别

1.预处理

1.1 数据导入与处理

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

clear;
% 1.人脸数据集的导入与数据处理框架
reshaped_faces=[];
% 声明数据库名
database_name = "ORL";

% ORL5646
if (database_name == "ORL")
  for i=1:40    
    for j=1:10       
        if(i<10)
           a=imread(strcat('C:\Users\hp\Desktop\face\ORL56_46\orl',num2str(i),'_',num2str(j),'.bmp'));     
        else
            a=imread(strcat('C:\Users\hp\Desktop\face\ORL56_46\orl',num2str(i),'_',num2str(j),'.bmp'));  
        end          
        b = reshape(a,2576,1);
        b=double(b);        
        reshaped_faces=[reshaped_faces, b];  
    end
  end
row = 56; 
column = 46;
people_num = 40;
pic_num_of_each = 10;
train_pic_num_of_each = 7; % 每张人脸训练数量
test_pic_num_of_each = 3;  % 每张人脸测试数量
end

%AR5040
if (database_name == "AR")
    for i=1:40    
      for j=1:10       
        if(i<10)
           a=imread(strcat('C:\AR_Gray_50by40\AR00',num2str(i),'-',num2str(j),'.tif'));     
        else
            a=imread(strcat('C:\AR_Gray_50by40\AR0',num2str(i),'-',num2str(j),'.tif'));  
        end          
        b = reshape(a,2000,1);
        b=double(b);        
        reshaped_faces=[reshaped_faces, b];  
      end
    end
row = 50;
column = 40;
people_num = 40;
pic_num_of_each = 10;
train_pic_num_of_each = 7;
test_pic_num_of_each = 3;
end

%FERET_80
if (database_name == "FERET")
    for i=1:80    
      for j=1:7       
        a=imread(strcat('C:\Users\hp\Desktop\face\FERET_80\ff',num2str(i),'_',num2str(j),'.tif'));              
        b = reshape(a,6400,1);
        b=double(b);        
        reshaped_faces=[reshaped_faces, b];  
      end
    end
row = 80;
column = 80;
people_num = 80;
pic_num_of_each = 7;
train_pic_num_of_each = 5;
test_pic_num_of_each = 2;
end

% 取出前30%作为测试数据,剩下70%作为训练数据
test_data_index = [];
train_data_index = [];
for i=0:people_num-1
    test_data_index = [test_data_index pic_num_of_each*i+1:pic_num_of_each*i+test_pic_num_of_each];
    train_data_index = [train_data_index pic_num_of_each*i+test_pic_num_of_each+1:pic_num_of_each*(i+1)];
end

train_data = reshaped_faces(:,train_data_index);
test_data = reshaped_faces(:, test_data_index);
dimension = row * column; %一张人脸的维度

1.2 算各类均值、类间散度Sb、类内散度Sw

样本的类间散度矩阵Sb和类内散度矩阵Sw分别定义为:

图1 Sb与Sw的定义

 将人脸数据集按人数n分为n类,算各类均值,并按Sb与Sw的定义与数学推导求出相应矩阵。

% 算每个类的平均
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);

2.LDA核心(构造目标函数并对其进行特征分解)

Tips:本实验使用pinv(矩阵伪逆)代替inv(矩阵的逆),消除部分奇异值对实验带来的影响

每个目标函数对应不同LDA的等价模型(除法的、减法的及其调换位置的等)以及PCA模型(目标函数以及具体原理可以查看对应博客),确定目标函数后对其进行特征分解。

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

% 目标函数二:不可逆时需要正则项扰动
%   Sw = Sw + eye(dimension)*10^-6;
%   target = Sw^-1 * Sb;

% 目标函数三:相减形式
% target = Sb - Sw;

% 目标函数四:相除
% target = Sb/Sw;

% 目标函数五:调换位置
% target = Sb * pinv(Sw);

%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);

3.人脸识别

降维过程LDA与PCA基本一致,在按特征值排好序的特征向量中取出前n大的特征向量来构建投影矩阵,实现降维(降维到n维),并用KNN进行分类预测,实现人脸识别,并比较PCALDA的各种等价模型与正则模型在不同数据集下的人脸识别精度。

Tips:单次运行为选定目标函数对应的人脸识别率。

% 人脸识别

index = 1;
X = [];
Y = [];
% i为降维维度
for i=1:5:161

    % 投影矩阵
    project_matrix = eigen_vectors(:,1:i);
    projected_train_data = project_matrix' * (train_data - all_mean);
    projected_test_data = project_matrix' * (test_data - all_mean);

    % KNN的k值
    K=1;

    % 用于保存最小的k个值的矩阵
    % 用于保存最小k个值对应的人标签的矩阵
    minimun_k_values = zeros(K,1);
    label_of_minimun_k_values = zeros(K,1);

    % 测试脸的数量
    test_face_number = size(projected_test_data, 2);

    % 识别正确数量
    correct_predict_number = 0;

    % 遍历每一个待测试人脸 
    for each_test_face_index = 1:test_face_number

        each_test_face = projected_test_data(:,each_test_face_index);

        % 先把k个值填满,避免在迭代中反复判断
        for each_train_face_index = 1:K
            minimun_k_values(each_train_face_index,1) = norm(each_test_face - projected_train_data(:,each_train_face_index));
            label_of_minimun_k_values(each_train_face_index,1) = floor((train_data_index(1,each_train_face_index) - 1) / pic_num_of_each) + 1;
        end

        % 找出k个值中最大值及其下标
        [max_value, index_of_max_value] = max(minimun_k_values);

        % 计算与剩余每一个已知人脸的距离
        for each_train_face_index = K+1:size(projected_train_data,2)

            % 计算距离
            distance = norm(each_test_face - projected_train_data(:,each_train_face_index));

            % 遇到更小的距离就更新距离和标签
            if (distance < max_value)
                minimun_k_values(index_of_max_value,1) = distance;
                label_of_minimun_k_values(index_of_max_value,1) = floor((train_data_index(1,each_train_face_index) - 1) / pic_num_of_each) + 1;
                [max_value, index_of_max_value] = max(minimun_k_values);
            end
        end

        % 最终得到距离最小的k个值以及对应的标签
        % 取出出现次数最多的值,为预测的人脸标签
        predict_label = mode(label_of_minimun_k_values);
        real_label = floor((test_data_index(1,each_test_face_index) - 1) / pic_num_of_each)+1;

        if (predict_label == real_label)
            correct_predict_number = correct_predict_number + 1;
        end
    end

    correct_rate = correct_predict_number/test_face_number;

    X = [X i];
    Y = [Y correct_rate];

    fprintf("k=%d,i=%d,总测试样本:%d,正确数:%d,正确率:%1f\n", K, i,test_face_number,correct_predict_number,correct_rate);

    if (i == 161)
        waitfor(plot(X,Y));
    end
end

图2 pinv改进的经典LDA在ORL下的人脸识别率与维数的关系

图3  LDA的各模型与PCA在FERET人脸识别率对比

分析:在FERET较大的数据集时,调换LDA、除法LDA、PCA的识别率波动较大,较其他三个模型识别率较低,而正则LDA与经典LDA在各数据集下表现相对稳定(其他图未展示),识别率均高于经典PCA,特别是在大数据集下,LDA相对PCA有明显优势。 

4.LDA与PCA图像降维与可视化对比

分别使用PCA与LDA对人脸图像进行降维至2与3维,并取前三类的分布作图,将每类第一幅图作为代表图。

Tips:本实验以测试集的二三维可视化为例

% 二三维可视化
class_num_to_show = 3;
pic_num_in_a_class = pic_num_of_each;
pic_to_show = class_num_to_show * pic_num_in_a_class;
for i=[2 3]

    % 取出相应数量特征向量
    project_matrix = eigen_vectors(:,1:i);

    % 投影
    projected_test_data = project_matrix' * (reshaped_faces - all_mean);
    projected_test_data = projected_test_data(:,1:pic_to_show);

    color = [];
    for j=1:pic_to_show
        color = [color floor((j-1)/pic_num_in_a_class)*20];
    end

    % 显示
    if (i == 2)
        subplot(1, 7, [1, 2, 3, 4]);
        scatter(projected_test_data(1, :), projected_test_data(2, :), [], color, 'filled');
        for j=1:3
            subplot(1, 7, j+4);
            fig = show_face(test_data(:,floor((j - 1) * pic_num_in_a_class) + 1), row, column);
        end
        waitfor(fig);
    else
        subplot(1, 7, [1, 2, 3, 4]);
        scatter3(projected_test_data(1, :), projected_test_data(2, :), projected_test_data(3, :), [], color, 'filled');
        for j=1:3
            subplot(1, 7, j+4);
            fig = show_face(test_data(:,floor((j - 1) * pic_num_in_a_class) + 1), row, column);
        end
        waitfor(fig);
    end
end

                             图4 LDA在ORL数据集下二三维可视化                                      

图5 PCA在ORL数据集下二三维可视化

分析:图4 图5(其他数据集与模型可自己更改目标函数或框架尝试)展示了LDAPCA对图像的降维后分布,可以清晰地看出LDA降维同类图像较聚集,不同类图像较分散。而PCA则相对混杂,无明显规律。根据两算法的目的与原理,以此可以比较出PCALDA的不同(即eigenfacefisherface的不同

5.LDA与PCA的异同总结

参考其它作者图

                                           PCA                                                                                                                    LDA

分析:PCA与LDA都是常见的线性降维算法,但两算法的降维原理与目的不同,LDA的核心思想是“最小化类内方差,最大化类间方差”,从而更好地完成数据的分类与识别,而PCA的核心思想是“最小化协方差矩阵(最小化重构误差)”,从而实现数据的压缩与主成分重构,一般在小数据集下PCA与LDA效果相近甚至超过LDA,但在大数据集中,LDA明显优于PCA。另外,LDA使用了数据的标签(类别)信息,为有监督学习,而PCA则未使用,为无监督学习。

6.其他

6.1 内部函数定义

本实验中将人脸图像展示抽象为函数,函数定义如下:

% 输入向量,显示脸
function fig = show_face(vector, row, column)
    fig = imshow(mat2gray(reshape(vector, [row, column])));
end

6.2 数据集及资源

本实验以ORL5646数据集做展示,代码可适用多个数据集。

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

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

LDA完整代码:李忆如/忆如的机器学习 - Gitee.com

6.3 参考资料

1.赖志辉的课

2.LDA算法原理及matlab实现_dulingtingzi的博客-CSDN博客_lda matlab

3.基于LDA的人脸识别方法--fisherface - 知乎 (zhihu.com)

4.周志华《机器学习》


总结

LDA作为经典的线性降维算法,通过”最小化内类方差,最大化类间方差“为目标导向对数据进行投影实现降维,更好地完成数据的分类。如今仍然在机器学习许多领域(数据分类、语言图像处理、推荐系统)有优异表现。且作为一种有监督学习方法(利用了数据的原有信息),LDA能得到较好的保留数据信息。但LDA仍存在上文提到的有限投影轴问题、小样本问题、处理高维数据大计算代价问题、不好刻画非线性问题等等,另外,LDA是假设每个类的数据都是高斯分布的情况下开发的,这个属性在现实世界的问题中往往不存在。如果没有这个属性,不同类的可分离性就不能很好地通过类间散射来描述,从而影响实验结果,后续博客会分析其他算法优化或解决上述问题。

  • 34
    点赞
  • 132
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 12
    评论
现在我们回到LDA的原理上,我们在第一节说讲到了LDA希望投影后希望同一种类别数据的投影点尽可能的接近,而不同类别的数据的类别中心之间的距离尽可能的大,但是这只是一个感官的度量。现在我们首先从比较简单的二类LDA入手,严谨的分析LDA的原理。     假设我们的数据集D={(x1,y1),(x2,y2),...,((xm,ym))}D={(x1,y1),(x2,y2),...,((xm,ym))},其中任意样本xixi为n维向量,yi∈{0,1}yi∈{0,1}。我们定义Nj(j=0,1)Nj(j=0,1)为第j类样本的个数,Xj(j=0,1)Xj(j=0,1)为第j类样本的集合,而μj(j=0,1)μj(j=0,1)为第j类样本的均值向量,定义Σj(j=0,1)Σj(j=0,1)为第j类样本的协方差矩阵(严格说是缺少分母部分的协方差矩阵)。     μjμj的表达式为: μj=1Nj∑x∈Xjx(j=0,1) μj=1Nj∑x∈Xjx(j=0,1)     ΣjΣj的表达式为: Σj=∑x∈Xj(x−μj)(x−μj)T(j=0,1) Σj=∑x∈Xj(x−μj)(x−μj)T(j=0,1)     由于是两类数据,因此我们只需要将数据投影到一条直线上即可。假设我们的投影直线是向量ww,则对任意一个样本本xixi,它在直线ww的投影为wTxiwTxi,对于我们的两个类别的中心点μ0,μ1μ0,μ1,在在直线ww的投影为wTμ0wTμ0和wTμ1wTμ1。由于LDA需要让不同类别的数据的类别中心之间的距离尽可能的大,也就是我们要最大化||wTμ0−wTμ1||22||wTμ0−wTμ1||22,同时我们希望同一种类别数据的投影点尽可能的接近,也就是要同类样本投影点的协方差wTΣ0wwTΣ0w和wTΣ1wwTΣ1w尽可能的小,即最小化wTΣ0w+wTΣ1wwTΣ0w+wTΣ1w。综上所述,我们的优化目标为: argmaxwJ(w)=||wTμ0−wTμ1||22wTΣ0w+wTΣ1w=wT(μ0−μ1)(μ0−μ1)TwwT(Σ0+Σ1)w argmax⏟wJ(w)=||wTμ0−wTμ1||22wTΣ0w+wTΣ1w=wT(μ0−μ1)(μ0−μ1)TwwT(Σ0+Σ1)w     我们一般定义类内散度矩阵SwSw为: Sw=Σ0+Σ1=∑x∈X0(x−μ0)(x−μ0)T+∑x∈X1(x−μ1)(x−μ1)T Sw=Σ0+Σ1=∑x∈X0(x−μ0)(x−μ0)T+∑x∈X1(x−μ1)(x−μ1)T     同时定义类间散度矩阵SbSb为: Sb=(μ0−μ1)(μ0−μ1)T Sb=(μ0−μ1)(μ0−μ1)T     这样我们的优化目标重写为: argmaxwJ(w)=wTSbwwTSww argmax⏟wJ(w)=wTSbwwTSww     仔细一看上式,这不就是我们的广义瑞利商嘛!这就简单了,利用我们第二节讲到的广义瑞利商的性质,我们知道我们的J(w)J(w)最大值为矩阵S−12wSbS−12wSw−12SbSw−12的最大特征值,而对应的ww为S−12wSbS−12wSw−12SbSw−12的最大特征值对应的特征向量! 而S−1wSbSw−1Sb的特征值和S−12wSbS−12wSw−12SbSw−12的特征值相同,S−1wSbSw−1Sb的特征向量w′w′和S−12wSbS−12wSw−12SbSw−12的特征向量ww满足w′=S−12www′=Sw−12w的关系!     注意到对于二类的时候,SbwSbw的方向恒为μ0−μ1μ0−μ1,不妨令Sbw=λ(μ0−μ1)Sbw=λ(μ0−μ1),将其带入:(S−1wSb)w=λw(Sw−1Sb)w=λw,可以得到w=S−1w(μ0−μ1)w=Sw−1(μ0−μ1), 也就是说我们只要求出原始二类样本的均值和方差就可以确定最佳的投影方向ww了。
### 回答1: LDA(Linear Discriminant Analysis)是一种常用的统计学习方法,可以应用于人脸识别中。Python提供了丰富的机器学习库和人脸识别库,可以很方便地实现LDA人脸识别算法。 LDA人脸识别算法的基本思想是在低维空间中最大化类间散布而最小化类内散布,从而实现良好的分类效果。在Python中,可以使用sklearn库中的LDA模块来实现LDA人脸识别。 首先,我们需要准备一些标记好的人脸图像作为训练样本。然后,使用OpenCV库中的人脸检测器将人脸图像进行检测和裁剪。接着,将裁剪后的人脸图像转化为灰度图像,并将每个图像转化为一个一维向量。 接下来,我们可以使用sklearn库中的LDA模块进行训练。将训练样本输入LDA模型,该模型会自动对训练样本进行降维,得到一组最能区分不同人脸的特征。这些特征向量可以用于人脸的分类和识别。 对于待识别的人脸图像,我们需要将其进行与训练样本相同的处理,即人脸检测、裁剪、灰度化和转化为一维向量。然后,使用训练好的LDA模型将待识别图片映射到降维后的特征空间中。最后,比较待识别人脸特征向量与训练样本特征向量的距离,找到最接近的训练样本,即可判断其所属的人脸类别。 在Python中,除了LDA算法,还可以使用其他的人脸识别算法,如PCA(Principal Component Analysis)和人脸识别库如OpenCV和dlib。这些工具和库的使用方法和函数也是非常丰富和成熟的,可以根据实际需求选择合适的方法进行人脸识别的实现。 总之,通过Python的机器学习库和人脸识别库,我们可以方便地实现LDA人脸识别算法,并将其应用于人脸识别的任务中。 ### 回答2: LDA线性判别分析)是一种常用的机器学习算法,用于进行特征提取和降维。在人脸识别领域,LDA可以用于提取人脸图像的有效特征,并用于分类和识别。 在Python中,我们可以使用一些库来实现LDA人脸识别。其中,scikit-learn是一个广泛使用的机器学习库,可以提供LDA算法的实现。 首先,我们需要导入所需的库和数据集。对于人脸识别,我们可以使用公共人脸数据集,如LFW(Labeled Faces in the Wild)数据集。 ```python from sklearn.discriminant_analysis import LinearDiscriminantAnalysis as LDA from sklearn.datasets import fetch_lfw_people ``` 然后,我们可以加载人脸数据集,并进行预处理,如归一化和降维。 ```python lfw_dataset = fetch_lfw_people(min_faces_per_person=70, resize=0.4) X = lfw_dataset.data y = lfw_dataset.target # 归一化 X = (X - X.mean()) / X.std() # 使用LDA进行降维 lda = LDA(n_components=100) X_lda = lda.fit_transform(X, y) ``` 在上面的代码中,我们使用了fetch_lfw_people函数加载LFW数据集,并设置了每个人至少有70张脸的限制,并将图像大小调整为原来的0.4倍。然后,我们对数据进行了归一化处理,确保输入的值范围相对一致。接下来,我们使用LDA算法进行特征提取和降维,通过指定n_components参数来设定降维后的维度。 最后,我们可以使用降维后的数据进行分类或识别。 ```python # 进行分类或识别 # ... ``` 根据具体的应用需求,我们可以选择不同的分类算法,如SVM、KNN等,来进行人脸识别任务。 以上就是使用LDA进行人脸识别的简单示例。在实际应用中,还要考虑一些额外的处理步骤,如数据增强、交叉验证等,以提高模型的性能和鲁棒性。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 12
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

@李忆如

感谢!!! 有什么问题欢迎交流

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值