[ 認証 / Python ] Face IDの仕組みと類似度について
はじめに
(最近、記事を更新できていませんでした。。)
突然ですが、FaceIDの仕組みはご存じでしょうか。
なんとなく使っているFaceIDですが、仕組みまで知らない方が多いのではないでしょうか。そんな「FaceIDの仕組み」と「FaceIDの今後」について書いていきます。
FaceIDの簡単な流れ
FaceIDが何をやっているかを簡単に紹介します。
iPhoneなどに用いられるFaceIDと、病院などにあるような顔認証の画像読み取り内容が少し違うので、難しいことは割愛します。
*今回は、イメージしやすいようiPhoneを例に解説します。
(以下「FaceID」は、iPhoneで行っているFaceIDと読み替えてください)
流れは以下のようになります。
① 顔画像を登録する
② 顔画像から特徴点を抽出し、ベクトル値を計算し数値化
③ しきい値によって類否かを判断
各処理の具体的な処理
ここでは、①から③の具体的な処理について、難しすぎないよう説明します。
① 顔画像を登録する
iPhoneUserのみなさんは、登録したことがあるのではないでしょうか??FaceIDでは、iPhoneの内カメ付近にある「ドットプロジェクタ」から、数万本の赤外線を出しユーザの顔を立体的に読み取ります。
ここでの立体的というのは、FaceIDでは平面だけでなく赤外線によって「z軸の深度」も読み取るためです。この、赤外線でのデータ取得で、顔画像の登録が完了です。
(また、ドットプロジェクタとは別に「赤外線カメラ」があり、同時に赤外線イメージを作成します。これが暗闇でもFaceIDを使用できる理由の一部ですが、今回は割愛。)
② 顔画像から特徴点を抽出し、ベクトル値を計算し数値化
①で取得したデータをもとに、数値化していきます。
ここで重要なのは特徴点の抽出です。人の目・鼻・口などは変化が大きい部分だと思います。逆に、ほっぺなどを切り取って考えると違いが出にくいとイメージできるかなと思います。そのため、目・鼻・口といった特徴点の情報に重みを乗せた上で、数値ベクトル化します。
下記のように、情報が格納されているイメージです。(あくまでイメージです。)
ベクトルなので「-」など含めた情報が入っています。
//(例:登録データ)
register_value = [0.24535164655 , -0.14564661451 , 0.514156161]
(ここは推測ですが、)valuesに対して複雑な操作をしながら、低次元の一意的な数値のようなものを出力しているかもしれません。
//(例:登録データを下記のように、してるかも??
data = [1.047519374]
③ しきい値によって類否かを判断
②であらかじめ登録された値と、FaceIDを実行した際の値を比較する。
あらかじめ、しきい値を設定し、しきい値内であればOKとする。といった処理です。
下記の例では、userが元々設定していたvalueに対して、値が近く類似性が高いと判断しています。
類似度の計算にも、様々あり代表的なものでは下記があります。
・コサイン類似度
コサイン類似度 (Cosine Similarity) 下記の定義で示されています。
結果の範囲は ([-1, 1]) で、値が 1 に近いほどベクトルが類似しています。
・ユークリッド距離
結果の範囲は0以上で、値が 0 に近いほどベクトルが類似しています。
今回、この2つの類似度計算をPythonでサクッと書きます。(モジュール使用のため、簡単です)
まず、コサイン類似度についてです。
import numpy as np
def cosine_similarity(vec1, vec2):
//コサイン類似度を計算
dot_product = np.dot(vec1, vec2) //内積を計算
norm_vec1 = np.linalg.norm(vec1) // ノルムを計算
norm_vec2 = np.linalg.norm(vec2) // ノルムを計算
return dot_product / (norm_vec1 * norm_vec2)
//定義式を、numpyで式にしただけです。
次にユークリッド距離についてです。
def euclidean_distance(vec1, vec2):
//ユークリッド距離を計算
return np.linalg.norm(np.array(vec1) - np.array(vec2))
最後にコード一覧です。
register_valueが登録したデータで、user_dataがiPhoneを開くときに毎度登録する情報だと思ってください。
# 事前に登録した数値ベクトル
register_value = [0.24535164655 , -0.14564661451 , 0.514156161]
# ロック解除時の数値ベクトル
user_data = [0.54535164655 , 0.658368 , 0.5735]
import numpy as np
def cosine_similarity(vec1, vec2):
#コサイン類似度を計算
dot_product = np.dot(vec1, vec2) #内積を計算
norm_vec1 = np.linalg.norm(vec1) #ノルムを計算
norm_vec2 = np.linalg.norm(vec2) #ノルムを計算
return dot_product / (norm_vec1 * norm_vec2)
def euclidean_distance(vec1, vec2):
#ユークリッド距離を計算
return np.linalg.norm(np.array(vec1) - np.array(vec2))
# 類似度と距離を計算
cos_sim = cosine_similarity(register_value, user_data)
euc_dist = euclidean_distance(register_value, user_data)
print(f"コサイン類似度: {cos_sim:.2f}")
print(f"ユークリッド距離: {euc_dist:.2f}")
上記のコードを実行すると、それぞれ値が出力されます。
例えば、コサイン類似度で、しきい値を0.7とすると、今回の結果は0.55で、0.7 > 0.55となり、基準の値を超えていないためFaceIDの解除はできません。
コサイン類似度:0.55
ユークリッド距離:0.86
このようにして、FaceIDが解除されるかを判断しています。
問題点
FaceID登録の流れをみてきましたが。なんとなく問題点があると思います。
そう顔が似ている双子などでは、FaceIDが通ってしまうことです
双子のAさんとBさんの特徴点が似通ってしまうため、数値ベクトルがAさんとBさんで近しいものになってしまい、どちらの顔でもしきい値内になってしまいます。
また、近年AIの発達により類似画像の生成からの解除なども問題になっています。
それでは、どのような解決策があるのかをひじょーーーに簡単に今後の展望で記載していきます。
今後の展望
最近注目を集めているのが、OpneAI社が発表した「World」です。
虹彩認証を用いているのですが、ただの虹彩認証ではなく、Worldは個人情報を極力持たないのが特徴です。このWorldは、「人間であることや固有の人であること」を確認する。というAIが発達したからこそ、「人間であること」という観点が興味深いですね。今回は、FaceIDについてのため、ここまでとします。
最後まで読んでいただきありがとうございました!
Discussion