Face Recognition with Eigenfaces

顔認識はSFではよくある話で、主人公がカメラを見て、カメラがその人の顔をスキャンして認識する、というものです。 より正式には、顔認識は分類タスクとして定式化でき、入力は画像、出力は人名となります。 今回は、顔認識の代表的な手法である「固有顔」について説明します。 固有顔料の中心は、主成分分析(PCA)と呼ばれる教師なし次元削減技術であり、この一般的な技術を顔認識という特定のタスクにどのように適用できるかを見ていくことにする。

フルコードのダウンロードはこちら。
  • 200以上のコースにアクセス
  • 毎月追加される新しいコース
  • いつでもキャンセル可能
  • 修了証

Face Recognition

主成分分析について述べる前に、まず問題を定義しなければならないでしょう。 顔認識とは、入力画像に誰の顔が写っているかを分類する課題である。 これは、入力画像に顔があるかどうかを判断する顔検出とは異なる課題である。 顔認識では、既存の顔のデータベースが必要です。 これを達成するナイーブな方法は、新しい画像を取り、それをベクトルに平らにし、データベース内の他のすべての平らにした画像との間のユークリッド距離を計算することである

このアプローチにはいくつかの欠点がある。 まず、顔の大規模なデータベースがある場合、各顔に対してこの比較を行うには時間がかかります。 リアルタイムで使用する顔認識システムを構築していると想像してください。 データセットが大きければ大きいほど、アルゴリズムは遅くなります。 しかし、顔の数が多ければ多いほど、より良い結果が得られるのです 高速かつ高精度なシステムが欲しい。 そのためにニューラルネットワークを使います。 データセットでネットワークを訓練し、それを顔認識タスクに使用することができます。

ニューラルネットワークを直接使用することには、画像が大きいという問題があります! 1 つの m\times n

イメージがあった場合、それを 1 つのm\dot ntimes 1ベクトルにフラット化して、入力としてニューラルネットワークに与えなければならないでしょう。 画像サイズが大きい場合、これはスピードの低下につながります。 これは、ナイーブなアプローチで画像をそのまま使う場合の2つ目の問題に関連しています。 (Anmtimes nimage is really amdot ntimes 1vector) 新しい入力には大量のノイズがあり、行列減算とユークリッド距離を使って一つ一つのピクセルを比較すると、高いエラーと誤分類を与えるかもしれません!

これらの問題は、我々がナイーブ手法を使用しない理由でもあります。

次元削減

前節では、次元削減技術を使用する理由を説明しました。 次元削減とは、教師なし学習の一種で、画像のような高次元のデータを、より低次元の空間で表現することである。 次の画像を例にして説明します。

これらのプロットは同じデータを示していますが、下のグラフはゼロセンタリングしています。 これは教師なし学習であるため、データにラベルが関連付けられていないことに注意してください! この単純なケースでは、次元削減により、これらのデータは2Dの平面から1Dの線になります。

すべての次元削減技術は、点を投影するための高次元の線である超平面を見つけることを目的としています。 投影は、投影する超平面に垂直な懐中電灯を持ち、その超平面上のどこに影が落ちるかをプロットすることと想像することができます。 例えば、上のデータで、点をx軸に投影したい場合、各点をボールに見立てて、懐中電灯を真下または真上に向けると(x軸に垂直)、点の影がx軸に落ちることになります。 これが投影です。 scikit-learn がこの投影を適用してくれるので、この背後にある正確な数学については心配しません。

この単純な 2D のケースでは、ポイントを投影する線を見つけたいと思います。 点を投影した後、2D ではなく 1D のデータが得られます! 同様に、3次元のデータがあった場合、3次元から2次元にデータの次元を減らすために、点を投影する平面を探します。 次元削減のさまざまなタイプは、これらの超平面のうちどれを選択するかを見つけ出すことにあります:超平面は無限にあります!

主成分分析

次元削減の1つのテクニックは主成分分析(PCA)と呼ばれます。 PCAの背後にある考え方は、すべての点を超平面に投影したとき、それらが最大に広がるような超平面を選択したいということです。 言い換えれば、分散が最大になるような軸が欲しいのです。 上のプロットの例を見てみましょう。 軸の候補はX軸かY軸ですが、どちらの場合も最適な軸ではありません。 しかし、データを斜めに切る線を選ぶと、それがデータが最も広がる軸になります!

長い青い軸が正しい軸です。 もし私たちのポイントをこの軸に投影すると、それらは最大に広がることになります! しかし、この軸はどのように決定するのでしょうか。 線形代数学の固有ベクトルと呼ばれる用語を借りることができます! これが固有値面という名前の由来です! 基本的には、データの共分散行列を計算し、その共分散行列の最大の固有ベクトルを検討します。 これが主軸であり、次元を減らすためにデータを投影する軸となる。 このアプローチを使用して、共分散行列の最大の固有ベクトルを選択し、それらの固有ベクトルに投影することにより、高次元のデータを低次元にすることができます。

最大分散の軸を計算するので、データの最も重要な側面を保持することができます。

(教師あり学習を使用する線形判別分析のような他の次元の手法もあり、顔認識にも使用されますが、PCA は本当によく機能します!)

これが顔認識という課題にどう関係するのでしょうか。 mttps n

画像は、mdot n次元空間の点として概念化することができます。 そこでPCAを用いてmdot nの空間をより小さくすることができる。

顔検出の余談

ここまでは、入力画像は顔の画像だけと仮定しましたが、実際には、カメラ画像は完全に顔の中心である必要はないはずです。 そこで、顔に学習させたカスケード分類器などの顔検出アルゴリズムを実行し、入力画像のどの部分に顔が写っているのかを把握します。 このバウンディングボックスがあれば、入力画像のその部分を簡単にスライスして、そのスライスに対して固有顔を利用することができます。 (通常、このスライスをスムージングし、顔が斜めに表示されている場合はアフィン変換を行い、顔の歪みを解消します)。

固有顔コード

さて、PCAと固有顔について説明したので、scikit-learnを使って顔認識アルゴリズムをコーディングしてみましょう! まず、データセットが必要です。 ここでは、Labeled Faces in the Wild (LFW) と呼ばれるマサチューセッツ大学によるすぐに使えるデータセットを使用します。 もし自分で顔のデータセットを作りたいなら、各人の顔の写真(角度と照明を変えたもの)が数枚と、真偽のラベルが必要です。 顔の種類が多ければ多いほど、認識性能は向上します。 顔認識用のデータセットを作る最も簡単な方法は、各人物のフォルダを作り、そこに顔画像を入れることです。 それぞれ同じ大きさであることを確認し、大きな画像にならないようにリサイズしてください。 PCAによって画像の次元が小さくなるので、大きな画像や高解像度の画像を使っても意味がありませんし、アルゴリズムの速度も遅くなります。 各画像のサイズは512×512が適当です。 画像はすべて同じサイズであるべきで、寸法(num_examples, height, width)を持つ1つのnumpy配列に格納することができます. (グレースケール画像を想定しています)。 そして、フォルダ名を使ってクラスを曖昧さなくします。 この方法を使えば、自分の画像を使うことができます。

ただし、今回はLFWデータセットを使用します。 幸いなことに、scikit-learnは自動的に正しいフォーマットでデータセットを読み込むことができます。 データを読み込むための関数を呼び出すことができます。 もしデータがディスクにない場合は、scikit-learn がマサチューセッツ大学のウェブサイトから自動的にダウンロードしてくれます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19

import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_lfw_people
from sklearn.dataets import fetch_lfw_people from sklearn.model_selection import train_test_split from sklearn.dataets import train_test_peoplemetrics import classification_report
from sklearn.decomposition import PCA
from sklearn.neural_network import MLPClassifier
# Load data
lfw_dataset = fetch_lfw_people(min_faces_per_person=100)
_, h, w = lfw_dataset.images.shape
X = lfw_dataset.data
y = lfw_dataset.data.X
。target
target_names = lfw_dataset.target_names
# split into a training and testing set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)

この関数の引数は、少なくとも100の顔を持たないすべての人々をプルーンするだけなので、クラスの数が減ります。 そして、データセットとその他の補助的な情報を抽出することができます。

ここで、scikit-learn の PCA クラスを使って、次元削減を行うことができます! 成分数、つまり出力次元(投影する固有ベクトルの数)を選択する必要がありますが、最良の結果を得るためにこのパラメータを自由にいじってみてください ここでは、100成分を使用します。 さらに、データを白くします。これは簡単なブーリアン・フラグでできます! (ホワイトニングは、結果のデータの分散を単位にするだけです。

1
2
3
4
5
6
7

#PCAの計算
n_components = 100
pca = PCA(n_components=n_components.X)

# PCA(n_components)の計算。 whiten=True)。fit(X_train)

# apply PCA transformation
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)

変換をかけて画像を100次元空間に落とせばいいんだよ。 我々はデータセット全体ではなく、学習データのみに対してPCAを行っていることに注意してください。

次元を減らしたベクトルができたので、ニューラルネットワークを訓練することができます!

1
2
3

# train a neural network
print(“Fitting the classifier to the training set”)
clf = MLPClassifier(hidden_layer_sizes=(1024,), batch_size=256, verbose=True, early_stopping=True).fit(X_train_pca, y_train)

ネットワークの学習状況を見るには、verposeフラグを設定すればよいでしょう。 さらに、早期停止を使用します。

簡単な余談として、早期停止について説明しましょう。 基本的に、我々のオプティマイザーは、各エポックの検証セットの平均精度を監視します。 もし、あるエポック数の間、検証精度が著しく向上していないことに気づいたら、学習を停止します。 これは、モデルがオーバーフィットするのを防ぐ正則化のテクニックです!

上のグラフを考えてみてください。 検証セットの精度が低下し始めると、オーバーフィッティングに気づきます。 その時点で、オーバーフィッティングを防ぐために、直ちに学習を停止します。

最後に、予測を行い、各クラスの品質レポート全体をプリントアウトする関数を使用することができます。

1
2

y_pred = clf.predict(X_test_pca)
print(classification_report(y_test, y_pred, target_names=target_names))

以下は分類レポートの例です。

1
2
3
4
5
6
7
8
9

精度 リコール f1- の場合スコア サポート
Colin Powell 0.86 0.89 0.87 66
Donald Rumsfeld 0.85 0.61 0.71 38
George W Bush 0.88 0.94 0.91 177
Gerhard Schroeder 0.67 0.69 0.68 26
トニー・ブレア 0.86 0.71 0.78 35
avg / total 0.85 0.85 342

正確性の指標はないことに注意してください。 精度は、そもそも最も具体的な種類の指標ではありません。 その代わりに、precision、recall、f1-score、および support があります。 例えば、テストセットでは、Tony Blairの画像は実際には35枚ありました。 F1-Scoreは実際にはprecisionとrecallのスコアから計算されるだけです。 精度と再現率は、単一の精度スコアよりも、より具体的な指標です。

分類器を学習した後、分類するためにいくつかの画像を与えることができます。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

# Visualization
def plot_gallery(images, titles, h, w, rows=3, cols=4):
plt.figure()
for i in range(rows * cols):
plt.subplot(rows, cols, i + 1)
plt.imshow(images.reshape((h, w)), cmap=plt.cm.gray)
plt.title(titles)
plt.xticks(( ))
plt.yticks(())
def titles(y_pred, y_test, target_names):
for i in range(y_pred.shape):
pred_name = target_names].split(‘ ‘)
true_name = target_names].split(‘ ‘)
yield ‘predicted: {0}NTrue: {1}’.format(pred_name, true_name)
prediction_titles = list(titles(y_pred, y_test, target_names))
plot_gallery(X_test, prediction_titles, h, w)

(plot_gallery and titles functions modified from scikit-learn documentation)

各画像についてネットワークの予測値とグランドトゥルース値を見ることができます。

視覚化するもうひとつの興味深いことは、固有顔そのものです。 PCAが固有ベクトルを生成することを思い出してください。 これらの固有ベクトルを画像に再形成し、固有顔を視覚化できます。

これらは、私たちのデータセットの「一般的な」顔を表しています。 直感的には、これらは「顔空間」での方向を表すベクトルで、ニューラルネットワークが分類を助けるために使用するものです。 固有顔のアプローチについて説明したので、この顔認識アルゴリズムを使用するアプリケーションを構築できます!

固有顔という顔認識への一般的なアプローチについて説明しました。 固有顔の本質は、主成分分析 (PCA) と呼ばれる教師なし次元削減アルゴリズムで、画像の次元をより小さなものに削減するために使用します。 こうして顔の表現が小さくなったところで、次元削減された入力を受けて、クラスラベルを生成する分類器を適用します。 分類器には、単層ニューラルネットワークを使用しました。

顔認識は、コンピュータビジョンと機械学習を融合した魅力的な例であり、多くの研究者が今日もこの難題に取り組んでいます!

現在、深い畳み込みニューラルネットワークが顔認識に使用されており、開発キャリア世界の観点から膨大な意味合いを持っています。 このデータセットで1度試してみてください!

コメントを残す

メールアドレスが公開されることはありません。