Machine Learning - PCA (Principal Component Analysis) and Face Recognition

    For details of Yiru’s complete project/code, please refer to github: https://github.com/yiru1225 (reprinted and marked with the source, do not star for projects thanks)

Table of contents

Series Article Directory

1. The concept and principle of PCA

1. Introduction to PCA

2. PCA algorithm model

2. PCA is applied to face recognition

1. Pretreatment

1.1 Data import and processing

1.2 Dataset averaging and data centering

1.3 Find and sort the covariance matrix, eigenvalues ​​and eigenvectors

2. Face reconstruction

3. Face recognition

4. Face image dimensionality reduction and visualization

5. Other

5.1 Internal function definition

5.2 Datasets and resources

Summarize


Series Article Directory

This series of blogs focuses on the concepts, principles and code practices of machine learning, and does not include tedious mathematical derivations (if you have any questions, please discuss and point them out in the comment area, or contact me directly by private message).

The code can be copied in full, and it makes sense for everyone to understand the principle and process to reproduce it! ! ! Chapter 1 PCA and Face Recognition    


synopsis

This blog mainly introduces the PCA (Principal Component Analysis) algorithm and uses PCA for face reconstruction, recognition, and image dimensionality reduction visualization (with data sets and matlab codes included)


1. The concept and principle of PCA

1. Introduction to PCA

PCA (Principal Component Analysis) is a mainstream linear dimensionality reduction algorithm. Guided by the goal of " minimum reconstruction error ", through dimensionality reduction (projection), the relatively important (most important) information in the data is used to express (replace) the original data, so as to achieve the purpose of dimensionality reduction.

2. PCA algorithm model

The classic PCA problem solving can be divided into the following steps

① Data import and processing (eg. In face recognition, each face needs to be pulled into a column or row)

② Calculate the mean of the data and centralize the data

③ Calculate the covariance matrix (scatter matrix)

④ Decompose the covariance matrix to obtain the eigenvectors sorted by eigenvalues ​​​​from large to small (SVD decomposition can also be used)

⑤ Take out the first k eigenvectors as projections, reduce the dimensionality of the original data to the corresponding projection direction, and realize the reduction from the original n-dimensional data to k-dimensional

2. PCA is applied to face recognition

1. Pretreatment

Tips: Preprocessing includes data import processing, mean value decentralization, decomposing covariance matrix to obtain eigenvectors (eigenfaces)

1.1 Data import and processing

Use imread to import the face database in batches, or directly load the corresponding mat file, and continuously pull the faces into column vectors to form reshaped_faces when importing. In this experiment, the first 30% of each person is taken as test data, and the last 70% is used as training data.

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 Dataset averaging and data centering

Use the mean function to average the training set to get the average face (as shown in Figure 1), and subtract the average face from all the data in the training set to achieve centralization (some faces after centralization are shown in Figure 2, compared to the grayscale of the original image lower value).

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

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

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

Figure 1 Average face in AR dataset

Figure 2 Partial faces after centralization 

1.3 Find and sort the covariance matrix, eigenvalues ​​and eigenvectors

According to mathematical derivation, the covariance matrix can be obtained by cov_matrix = centered_face (centralized face dataset) * centered_face' , and then use the eig function to decompose the covariance matrix based on the eigenvalues ​​(or use SVD), and use the sort function to sort the eigenvectors Sort them in descending order and get all the eigenfaces (some eigenfaces are shown in Figure 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));

Figure 3 Partial eigenface (eigenface)

Tips: An eigenface is an eigenvector. All faces in the data set are obtained by combining certain eigenfaces. Therefore, the use of eigenvectors (eigenfaces) is the key to the subsequent realization of face reconstruction, recognition, and dimensionality reduction visualization.

2. Face reconstruction

Significance of reconstruction: Detect the relationship between the reduction degree of eigenfaces to human faces and the dimensionality (how many dimensions can the data be reduced to better restore the original data)

Take a face from the centered_faces, use 20, 40, 60, 80,..., 160 projections (the first n feature vectors) according to the formula rebuild_face = eigen_faces * (eigen_faces' * single_face) + mean_face Reconstruct the face and observe the degree of restoration under different numbers of projections. The reconstruction effect is shown in Figure 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

Figure 4 Face restoration (reconstruction) effect in different dimensions 

3. Face recognition

Tips: There are two variables in this experiment, k is from 1 to 6, and the dimension is from 10 to 160, to explore the joint influence of k value and dimension on the recognition rate

Respectively reduce the dimensionality of the test set and training set, project the face into 10, 20, 30, ..., 160-dimensional space, calculate the distance between the unknown face and all known faces (Euclidean distance), and then use The nearest neighbor classifier KNN is used for identification (the common influence is shown in Figure 5, only the dimension influence is considered as shown in Figure 6, and the abscissa is dimension/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));

 Figure 5 Face recognition rate of PCA under different k values ​​and dimensions

  Figure 6 Face recognition rate of PCA in different dimensions (abscissa is dimension/10)

4. Face image dimensionality reduction and visualization

Take out the corresponding number of eigenfaces (take n in n dimensions), use the formula projected_test_data = eigen_faces' * (test_data - mean_face) to project the test set or other subsets, and color after projection (same color as the same person) and use scatter to draw for visualization (The distribution of two-dimensional faces is shown in Figure 7, and the distribution of three-dimensional faces is shown in Figure 8).

Tips: This experiment takes the 2D and 3D visualization of the test set as an example

% 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

Figure 7 The dimensionality reduction of the test set to the two-dimensional image distribution

 Figure 8 Test set dimensionality reduction to 3D image distribution

5. Other

5.1 Internal function definition

In this experiment, the face image display is abstracted into a function, and the function is defined as follows:

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

% 输入向量,显示脸
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 Datasets and resources

This experiment is demonstrated with the AR50_40 dataset, and the code can be applied to multiple datasets.

The commonly used face data sets are as follows (don't prostitute hahaha)

Link: https://pan.baidu.com/s/12Le0mKEquGMgh5fhNagZGw 
Extraction code: yrnb

PCA Complete Code: Li Yiru/Yiru's Machine Learning - Gitee.com

5.3 References

1. Lai Zhihui's class

2. Principle of PCA_PiggyGaGa's Blog-CSDN Blog_pca

3. Face recognition method based on PCA - eigenface method [2] - Zhihu (zhihu.com)

4. "Machine Learning" by Zhou Zhihua


Summarize

As a classic linear dimensionality reduction algorithm, PCA achieves dimensionality reduction by projecting data with the goal of "minimum reconstruction error". It still has excellent performance in many fields of machine learning (language image processing, data visualization). However, as an unsupervised learning method (without labeling the training samples), PCA cannot obtain better retention of data information in the case of complete ignorance of the data, and the analysis and judgment of PCA on the principal components affect the experimental results. Important factors (it is difficult to define the main information). In addition, PCA is less effective for nonlinear data dimensionality reduction. Subsequent blogs will analyze other algorithm optimizations or solve the above problems.

Guess you like

Origin blog.csdn.net/weixin_51426083/article/details/123795028