顔認識ライブラリ「InsightFace」で顔認証と実用的なAI開発の基礎を学ぶ (3)

ArchFaceONNXをinsightfaceで実装し顔認識

前回のコースで顔検出を実装しました。今回は顔認識を実装してみましょう。

前回のコースはこちら

顔検出の準備

顔検出のコードは以下の通りです。前回のコースと同じです。モデルのパスは任意ですので、各自の環境に合わせて変更してください。

face detection code
1import cv2
2import numpy as np
3import insightface
4from insightface.app.common import Face
5
6# load detection model for face detection
7detector = insightface.model_zoo.get_model("models/buffalo_l/det_10g.onnx") # 任意のパスに変更してください
8detector.prepare(ctx_id=-1, input_size=(640, 640))
9

顔認識の準備

insightfaceを使って認識モデルをロードします。モデルのパスは任意ですので、各自の環境に合わせて変更してください。

face recognition code
1
2# 認識モデルの準備
3ONNX_MODEL_PATH = "models/buffalo_l/w600k_r50.onnx"
4# Use InsightFace to load model
5model = insightface.model_zoo.get_model(ONNX_MODEL_PATH)
6model.prepare(ctx_id=-1, input_size=(640, 640)) # ctx_id is computing device id

画像から顔を検出し顔認識を行うためのベクトルを推論する関数を作成

画像はファイルパスを引数として渡し、関数内でcv2.imread()で読み込んでいます。この関数では、便宜上画像の中に必ず1つの顔が存在することを前提としています。顔が画像内にない場合や複数顔を検出したい場合はコードを変更する必要がありますので注意してください。

face recognition code
1
2def get_embedding_from_img_path(img_path):
3 rgb_img = cv2.cvtColor(cv2.imread(img_path), cv2.COLOR_BGR2RGB)
4 bboxes, kpss = detector.detect(rgb_img)
5 if bboxes.shape[0] == 0:
6 return None
7 i = 0 # take only the first face
8 bbox = bboxes[i, 0:4]
9 det_score = bboxes[i, 4]
10 kps = None
11 if kpss is not None:
12 kps = kpss[i]
13 face = Face(bbox=bbox, kps=kps, det_score=det_score)
14 embedding = model.get(rgb_img, face)
15 return embedding
16

顔認識のためのベクトル(embedding)とは?

ところで上の関数で顔認識モデルが推論するベクトル(embedding)とは一体何でしょうか。これを理解するためにはまず顔認識にメカニズムを知ることが大事です。顔認識は以下のようなステップで行います。

  1. 画像から顔を検出
  2. 検出した顔を別の顔と比較する
  3. 類似度が一定の閾値以上なら同一人物と判定する

顔の比較方法

ここで重要になるのが2番目の手順である顔画像の比較です。コンピューターは顔画像を直接比較することはできませんから顔画像をコンピューターが理解可能な数値に変換する必要があります。それが顔の特徴を数値化した高次元ベクトルというわけです。高次元のベクトルというと非常に難しく聞こえますが要は数字の配列です。例えば [5,,6,8,9,1...] といった形です。512次元のベクトルなら512個の数値が格納されています。これを比較するといっても分かりにくいかもしれませんが、私たちがなじみのある二次元で考えると分かりやすいです。2次元ですからたとえば[2,4]のようなベクトルになります。つまりこれは平面世界(2次元)の[x,y]ですね。横がx縦がyとしたとき、座標A[2,2] 座標B[90,71] 座標C[7,5] があるとし、座標Aに近いのは座標Bより座標Cであるということは分かると思います。このようにしてベクトルどうしの距離を計算すればそれを類似度として扱うことが可能なのです。

顔の類似度を計算

顔の類似度を計算するために今回はコサイン類似度を使います。コサイン類似度はベクトルどうしの角度を計算するための指標で、-1から1の値を取ります。1に近いほど類似度が高いということになります。コサイン類似度は以下のコードのように計算されます。

face recognition code
1
2def calc_cos_sim(embedding1, embedding2):
3 return np.dot(embedding1, embedding2) / (np.linalg.norm(embedding1) * np.linalg.norm(embedding2))
4

この関数は2つのベクトルを引数として受け取ります。そしてそれらのベクトルの内積を計算し、それをそれぞれのベクトルのノルム(ベクトルの長さ)の積で割ります。これがコサイン類似度です。

コサイン類似度

コサイン類似度はベクトル間の角度のコサインを測定することによって、それらのベクトルがどれだけ似ているかを数値で表します。この類似度はベクトルの長さに依存せず、方向性のみに基づいています。したがって2つのベクトルがまったく同じ方向を向いている場合、コサイン類似度は1になります。逆に2つのベクトルがまったく逆の方向を向いている場合、コサイン類似度は-1になります。この計算ではベクトルの長さに依存せず、方向性のみを基にした類似度が得られます。ベクトルの長さも考慮したい場合は、ベクトルの大きさと方向の両方が結果に影響する「ユークリッド距離」というものが使われることが多いです。

なんだか、難しい説明がたくさんできてきましたが、ここで完全に理解している必要はありません。今なんとなく分かっていればいいことは、顔画像を取り出した後、AIをつかって(ArchFaceONNXモデルをつかって)顔をベクトルに変換する、それを比較するためにコサイン類似度を使うということでOKです。この流れは数々のAIで使われている基本的な手法です。

作成したコードをつかって顔認識をしてみよう

顔が映っている2枚の画像の人物が同一人物か認識してみましょう。いつもと同じように、画像ファイルへのパスは各自の環境に合わせて変更してください。

face recognition code
1
2# 入力画像1
3embedding1 = get_embedding_from_img_path("data/images/maya/maya_1.jpg")
4# 入力画像2
5embedding2 = get_embedding_from_img_path("data/images/maya/maya_3.jpg")
6# 類似度を計算
7cos_sim = calc_cos_sim(embedding1, embedding2)
8# 結果を表示
9print(cos_sim)
10# 類似度が0.6以上なら同一人物と判定
11
12

実にシンプルに顔認証ができるようになりました。このコードを使えば、顔認証を簡単に実装することができますね。また、最後の同一人物かどうかの判定閾値を0.6としていますが、これは実際のアプリケーションによって変更する必要があります。

セッション3のまとめ

今回は顔認証を「顔の検出」、「顔画像のベクトル化」、「ベクトルの比較」、という3つのモジュールに分けて実装することを学びました。これは顔認証の基本的な流れですし、様々なAI構築において使われている基本的な手法です。このコースを通じて、AIの基本的な手法を学ぶことができましたね。このコースはinsightfaceという学習済みモデルが提供されているライブラリを使用しましたので「顔の検出」には det_10g.onnx、「顔画像のベクトル化」にはw600k_r50.onnxという学習済みのモデルを使用することができ、サクッと顔認証を実装することができましたが、現実世界の個々の問題解決のためAI開発においては、学習済みモデルが存在しないことも多く、自分でモデルを構築・学習させる必要に迫られることがおおいです。今後公開するコースでは、自分で学習させるための手法を学んでいきたいと思います。