机器学习——PCA(主成分分析)与人脸识别

目录

Numpy学习

系列文章目录

go语言

一、PCA的概念与原理

IPv6

1.PCA简介

RepVGG

2.PCA算法模型

CAN协议

二、PCA运用于人脸识别

consul

1.预处理

排名

1.1 数据导入与处理

云原生实战

1.2 数据集求均值与数据中心化

express

1.3 求协方差矩阵、特征值与特征向量并排序

FreeMarker

2.人脸重构

企业微信

3.人脸识别

mint

4.人脸图像降维与可视化

模块化程序设计

5.其他

代码封装

5.1 内部函数定义

GIS

5.2 数据集及资源

微信公众平台

总结

高并发


wincc

系列文章目录

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

Python

代码可以全抄    大家搞懂原理与流程去复现才是有意义的!!!
第一章 PCA与人脸识别

license


队列

梗概

装饰器

本篇博客主要介绍PCA(主成分分析)算法并将PCA用于人脸的重构、识别、图像降维可视化(内附数据集与matlab代码)

tcp


内存越界

一、PCA的概念与原理

1.PCA简介

PCA(主成分分析)为主流的一种线性降维算法。以”最小重构误差“为目标导向,通过降维(投影),用数据中相对重要(最主要)的信息表达(代替)原数据,从而达到降维的目的。

UGUI

stylegan

2.PCA算法模型

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

去中心化

① 数据的导入与处理(eg.人脸识别中需要将每一张人脸拉成一列或一行)

qt教程

② 计算数据均值并对数据中心化

机顶盒ROM

③ 计算协方差矩阵(散度矩阵)

书籍

④ 分解协方差矩阵得到按特征值从大到小排序的特征向量(也可用SVD分解)

⑤ 取出前k个特征向量作为投影,使原数据降维到对应投影方向,实现由原本n维数据降到k维

二、PCA运用于人脸识别

1.预处理

Tips:预处理包括数据导入处理、求均值去心化、分解协方差矩阵得到特征向量(特征脸)

1.1 数据导入与处理

利用imread批量导入人脸数据库,或直接load相应mat文件,并在导入时不断将人脸拉成一个个列向量组成reshaped_faces,本实验取出每个人的前30%作为测试数据,后70%作为训练数据。

clear;
% 1.人脸数据集的导入与数据处理(400张图,一共40人,一人10张)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
reshaped_faces=[];
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); %utf-8转换为double类型,避免人脸展示时全灰的影响       
        reshaped_faces=[reshaped_faces, b];  
    end
end

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

train_data = reshaped_faces(:,train_data_index);
test_data = reshaped_faces(:, test_data_index);

1.2 数据集求均值与数据中心化

利用mean函数对训练集求平均值,得出平均脸(如图1),将训练集中所有数据减去平均脸,实现中心化(中心化后某些人脸如图2,相对原图灰度值更低)。

% 2.图像求均值,中心化
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% 求平均脸
mean_face = mean(train_data,2);
%waitfor(show_face(mean_face)); %平均脸展示,测试用

% 中心化
centered_face = (train_data - mean_face);
%用于展示中心化后某些训练图片 测试用
%waitfor(show_faces(centered_face));

图1 AR数据集中的平均脸

图2 中心化后的部分人脸 

1.3 求协方差矩阵、特征值与特征向量并排序

根据数学推导,协方差矩阵可由cov_matrix = centered_face(中心化人脸数据集) * centered_face'求得,再利用eig函数基于特征值对协方差矩阵进行分解(或使用SVD),并用sort函数将特征向量按从大到小排序好,得到所有特征脸(部分特征脸如图3)。

% 3.求协方差矩阵、特征值与特征向量并排序
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

% 协方差矩阵
cov_matrix = centered_face * centered_face';
[eigen_vectors, dianogol_matrix] = eig(cov_matrix);

% 从对角矩阵获取特征值
eigen_values = diag(dianogol_matrix);

% 对特征值按索引进行从大到小排序
[sorted_eigen_values, index] = sort(eigen_values, 'descend'); 

% 获取排序后的征值对应的特征向量
sorted_eigen_vectors = eigen_vectors(:, index);

% 特征脸(所有)
all_eigen_faces = sorted_eigen_vectors;

%用于展示某些特征脸 测试用
waitfor(show_faces(all_eigen_faces));

图3 部分特征脸(eigenface)

Tips:一个特征脸即一个特征向量,数据集中所有人脸都是由某些特征脸组合得到,故利用特征向量(特征脸)是后续实现人脸重构、识别、降维可视化的关键。

2.人脸重构

重构的意义:检测特征脸对人脸的还原度与维数的关系(数据降到多少维才能较好还原原始数据)

从已中心化的centered_faces中取出某人脸,用20,40,60,80,…,160个投影(前n个特征向量)按公式rebuild_face = eigen_faces * (eigen_faces' * single_face) + mean_face来重构此人脸,并观察在不同数量的投影下的还原度,重构效果如图4。

%%人脸重构

% 取出第一个人的人脸,用于重构
single_face = centered_face(:,1);

index = 1;
for dimensionality=20:20:160

    % 取出相应数量特征脸(前n大的特征向量,用于重构人脸)
    eigen_faces = all_eigen_faces(:,1:dimensionality);

    % 重建人脸并显示
        rebuild_face = eigen_faces * (eigen_faces' * single_face) + mean_face;
        subplot(2, 4, index); %两行四列
        index = index + 1;
        fig = show_face(rebuild_face);
        title(sprintf("dimensionality=%d", dimensionality));    
        if (dimensionality == 160)
            waitfor(fig);
        end
end

图4 不同维度下人脸还原(重构)效果 

3.人脸识别

Tips:本实验中有两个变量,k从1~6取值,维度从10~160,探究k值及维度对识别率的共同影响

分别对测试集、训练集进行降维,将人脸投影到10,20,30,…,160维空间中,计算未知人脸与所有已知人脸的距离(欧几里得距离),然后使用最近邻分类器KNN进行识别(共同影响如图5 只考虑维度影响如图6 横坐标为维度/10)

% 5.人脸识别
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

index = 1;       
Y = [];
% KNN
for k=1:6

    for i=10:10:160
    % 取出相应数量特征脸
   eigen_faces = all_eigen_faces(:,1:i);
    % 测试、训练数据降维
    projected_train_data = eigen_faces' * (train_data - mean_face);
    projected_test_data = eigen_faces' * (test_data - mean_face);
        % 用于保存最小的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) / 10) + 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) / 10) + 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) / 10)+1;

            if (predict_label == real_label)
                %fprintf("预测值:%d,实际值:%d,正确\n",predict_label,real_label);
                correct_predict_number = correct_predict_number + 1;
            else
                %fprintf("预测值:%d,实际值:%d,错误\n",predict_label,real_label);
            end
        end
        % 单次识别率
        correct_rate = correct_predict_number/test_face_number;

        Y = [Y correct_rate];

        fprintf("k=%d,i=%d,总测试样本:%d,正确数:%d,正确率:%1f\n", k, i,test_face_number,correct_predict_number,correct_rate);
    end
end
% 求不同k值不同维度下的人脸识别率及平均识别率
Y = reshape(Y,k,16);
waitfor(waterfall(Y));
avg_correct_rate=mean(Y);
waitfor(plot(avg_correct_rate));

 图5 不同k值与维度下PCA的人脸识别率

  图6 不同维度下PCA的人脸识别率(横坐标为维度/10)

4.人脸图像降维与可视化

取出对应数量的特征脸(n维取n个),利用公式projected_test_data = eigen_faces' * (test_data – mean_face)对测试集或其他子集进行投影,投影后上色(同人同色)并使用scatter画图实现可视化(二维人脸分布如图7,三维人脸分布如图8)。

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

% 6.人脸数据二三维可视化(可推广到不同数据集)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

for i=[2 3]

    % 取出相应数量特征脸
    eigen_faces = all_eigen_faces(:,1:i);

    % 投影
    projected_test_data = eigen_faces' * (test_data - mean_face);

    color = [];
    for j=1:120
        color = [color floor((j-1)/4)*5];
    end

    % 显示
    if (i == 2)
        waitfor(scatter(projected_test_data(1, :), projected_test_data(2, :), [], color));
    else
        waitfor(scatter3(projected_test_data(1, :), projected_test_data(2, :), projected_test_data(3, :), [], color));
    end

end

图7 测试集降维至二维图像分布

 图8 测试集降维至三维图像分布

5.其他

5.1 内部函数定义

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

%内用函数定义
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

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

% 显示矩阵中某些脸
function fig = show_faces(eigen_vectors)
    count = 1;
    index_of_image_to_show = [1,5,10,15,20,30,50,70,100,150];
    for i=index_of_image_to_show
        subplot(2,5,count);
        fig = show_face(eigen_vectors(:, i));
        title(sprintf("i=%d", i));
        count = count + 1;
    end
end

5.2 数据集及资源

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

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

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

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

5.3 参考资料

1.赖志辉的课

2. PCA原理_PiggyGaGa的博客-CSDN博客_pca

3.基于 PCA 的人脸识别方法——特征脸法[2] – 知乎 (zhihu.com)

4.周志华《机器学习》


总结

PCA作为经典的线性降维算法,通过”最小重构误差“为目标导向对数据进行投影实现降维,如今仍然在机器学习许多领域(语言图像处理、数据可视化)有优异表现。但作为一种无监督学习方法(没有对训练样本做标注),在对数据完全无知的情况下,PCA并不能得到较好的保留数据信息,且PCA对于主成分的分析判断是影响实验结果的重要因素(不好界定主要信息),另外,PCA对于非线性的数据降维效果较差,后续博客会分析其他算法优化或解决上述问题。

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注