機械学習 - LDA (線形判別分析) と顔認識

    Yiru の完全なプロジェクト/コードの詳細については、github を参照してください: https://github.com/yiru1225 (転載され、ソースが示されています。プロジェクトにはスターを付けないでください)

目次

シリーズ記事ディレクトリ

1. LDAの概念と原理

1. LDA の概要

2. LDAアルゴリズムモデル

3. LDA の不足と最適化

2.LDAは顔認識に使用されます

1. 前処理

1.1 データのインポートと処理

1.2 各種平均値、クラス間ばらつきSb、クラス内ばらつきSwの計算

2. LDA コア (目的関数を構築し、それに対して固有分解を実行します)

3. 顔認識

4. LDA と PCA 画像の次元削減と視覚化の比較

5. LDA と PCA の類似点と相違点のまとめ

6. その他

6.1 内部関数の定義

6.2 データセットとリソース

6.3 参考文献

要約する


シリーズ記事ディレクトリ

このブログ シリーズは、機械学習の概念、原則、コードの実践に焦点を当てており、面倒な数学的導出は含まれません (質問がある場合は、コメント エリアで議論するか、プライベート メッセージで直接私に連絡してください)

コードは完全にコピーでき、    誰もがそれを再現するための原理とプロセスを理解するのが理にかなっています。
第 1 章機械学習 - PCA (主成分分析) と顔認識_@李忆如的博客-CSDN 博客

第 2 章 LDA と顔認識


概要

このブログでは主に LDA (線形判別分析) アルゴリズムを紹介し、顔認識、画像の次元削減、視覚化に LDA とそのさまざまな同等モデルを使用し、LDA と PCA (囲まれたデータセットおよび Matlab コード) を比較します。


1. LDAの概念と原理

1. LDA の概要

LDA (線形判別分析) は、主流の線形次元削減アルゴリズムです。クラス内分散を最小化し、クラス間分散を最大化する」という目標に導かれ、次元削減 (射影) を通じて、サンプルをより適切に分類するという次元削減の目的が達成されます。

2. LDAアルゴリズムモデル

古典的な LDA 問題解決は次のステップに分割できます。

1. データセットを分類し、各クラスの平均値を計算します (LDA は教師あり学習であるサンプルのカテゴリ (データ) ラベルを使用します)。

2. クラス間散乱行列 Sb とクラス内散乱行列 Sw を計算します。

3. 目的関数 (さまざまな異なる目的関数) を構築し、それに対して固有分解を実行します。

4. 一定数の固有ベクトルを取り出して射影行列を取得します。

5. テスト データを部分空間に射影し、(実際の問題で) 分類に KNN を使用します。

3. LDA の不足と最適化

1. 有限射影軸問題 (≤ カテゴリ数 - 1)

2. 小さなサンプル問題

3. 高次元データを扱う場合、計算コストが非常に高くなります

最適化: LDA を使用する前に PCA で前処理するか、目的関数に正則化摂動を追加します。

4. 非線形問題をうまく説明できない

最適化: カーネル属性を持つ LDA を使用したデータの処理

2.LDAは顔認識に使用されます

1. 前処理

1.1 データのインポートと処理

imread を使用して顔データベースをバッチでインポートするか、対応するマット ファイルを直接ロードし、インポート時に顔を継続的に列ベクトルにプルして reshape_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 コア (目的関数を構築し、それに対して固有分解を実行します)

ヒント: この実験では、実験に対するいくつかの特異値の影響を排除するために、inv (行列逆行列) の代わりに pinv (行列擬似逆行列) を使用します。

各目的関数は、異なる 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を利用します。顔認識を実現するための分類予測を行い、異なるデータセットの下でのPCAおよびLDAのさまざまな等価モデルと通常モデルの顔認識精度を比較します。

ヒント: 1 回の実行は、選択した目的関数に対応する顔認識率です。

% 人脸识别

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 顔認識率と ORL のもとで pinv によって改善されたクラシック LDA の次元の関係

図3 FERETにおけるLDAとPCAの各モデルの顔認識率の比較

分析: FERET が大規模なデータセットを持つ場合、転置 LDA、除算 LDA、および PCA の認識率は大きく変動し、他の 3 つのモデルよりも低くなりますが、通常の LDA とクラシック LDA のパフォーマンスは各データセットで比較的安定しています。 (その他の図は示されていません)、認識率は従来の PCA よりも高く、特に大規模なデータセットでは、LDA は PCA よりも明らかな利点があります。 

4. LDA と PCA 画像の次元削減と視覚化の比較

PCA と LDA を使用して顔画像の次元を 2 次元と 3 次元に削減し、最初の 3 つのカテゴリの分布を取得し、各カテゴリの最初の画像を代表画像として使用します。

ヒント: この実験では、例としてテスト セットの 2D および 3D 視覚化を取り上げます。

% 二三维可视化
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 ORL データセットにおける LDA の 2D および 3D 視覚化                                      

図 5 ORL データセットにおける PCA の 2 次元および 3 次元の視覚化

分析:図 4 と図5 (他のデータセットやモデルの目的関数やフレームワークを自分で変更できます) は、LDAPCAによる次元削減後の画像の分布を示しています。一方、 PCA は比較的混合されており、明確なルールはありません。2 つのアルゴリズムの目的と原理に従って、 PCALDAの違い(つまり、 eigenfacefisherfaceの違い)を比較できます。

5. LDA と PCA の類似点と相違点のまとめ

他の著者への参照

                                           PCA LDA

分析: PCA と LDA はどちらも一般的な線形次元削減アルゴリズムですが、2 つのアルゴリズムの次元削減の原理と目的は異なります。LDA の中心的な考え方は、「クラス内の分散を最小化し、クラス間の分散を最大化する」ことです。 PCA の分類と識別、および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 完全なコード: Li Yiru/Yiru の機械学習 - Gitee.com

6.3 参考文献

1.頼志暉先生の授業

2. LDA アルゴリズムの原理と matlab 実装_dulingtingzi のブログ - CSDN blog_lda matlab

3. LDA ベースの顔認識手法 --fisherface - Zhihu (zhihu.com)

4. 周志華著「機械学習」


要約する

古典的な線形次元削減アルゴリズムとして、LDA は「クラス内分散を最小化し、クラス間分散を最大化する」ことを目標として次元削減を達成するようにデータを投影し、データ分類をより完全に完了します。機械学習の多くの分野 (データ分類、言語画像処理、推奨システム) で依然として優れたパフォーマンスを発揮します。また、教師あり学習方法 (データの元の情報を使用) として、LDA はデータ情報をより適切に保持できます。しかし、LDA には、前述した射影軸の制限問題、サンプル数の少なさの問題、高次元データの処理、計算コストの多さの問題、非線形問題の記述の困難などが依然として存在します。また、LDA は各クラスのデータが 1 つのクラスであると仮定しています。ガウス分布 のコンテキストで開発されましたが、このプロパティは現実の問題には存在しないことがよくあります。このプロパティがなければ、異なるクラスの分離可能性はクラス間散乱によってうまく説明できず、実験結果に影響を及ぼします。後続のブログでは、他のアルゴリズムの最適化を分析するか、上記の問題を解決します。

おすすめ

転載: blog.csdn.net/weixin_51426083/article/details/123885066