顔認証AIのFaceNetは顔のどこに注目しているのか
はじめに
この記事は顔学2020アドベントカレンダーの6日目の記事です.
前回投稿したFaceNetを使って,顔認証AIが顔のどこに注目して人を判別しているのかを可視化してみます.
FaceNet
顔認証のための顔認識モデルです.512次元の空間上に顔を埋め込むいわゆるEmbedding Modelで,空間上のユークリッド距離を使って顔の類似度を計算することで顔認証を行います.
前回の記事でFaceNetの使い方を紹介しています.
GradCAM
画像認識モデルがどこに注目をしているのかをヒートマップで可視化してくれるモデルです.画像の顕著性(Saliency)の可視化と似たような分野です.画像の顕著性については人間の視覚特性(Treismanの特徴統合理論)を根拠に画像処理を行うのですが,GradCAMは画像認識モデルの出力を参考にします.
最終層の出力は基本的にクラスラベルになっているので,クラスラベルの予測値の中で最も大きな値を認識結果とします.GradCAMでは,最も大きい値の出力(予測値)を計算する上で,寄与の大きかった画像箇所を逆算することで注目箇所を推定します.
FaceNet(Embedding Model)にどう導入するか
FaceNetの出力は空間上の座標なので,何か特定のクラスを表す認識結果を出力するわけではありません.なので,どの出力の値が重要なのか判断するのが非常に難しいです.
すごく厳密に寄与した出力チャネルを決める研究もあるみたいなんですが,ここでは簡単のために全出力の絶対値の中で最も大きかった値を採用しました.
Adapting Grad-CAM for Embedding Networks
DCGANやInterFaceGANなどの論文が示唆するように,深層学習のモデルが構築する中間表現(潜在変数)には意味的軸があり,また現実世界の法則を反映したような軸同士の相関関係を持っています.(年齢を変化させると自然と眼鏡が出てきたり,白髪になったりする.つまり,意味的軸同士のcos類似度が高い.)
FaceNetも多くの顔画像をきれいに分布させる顔空間を構築しているはずです.なので,なんらかの意味的定量化がなされた空間上であれば,各要素にも固有の意味を含んでいると仮定し,各座標値の絶対値を評価すればそれなりの結果になるだろうと見当をつけました.
実装(コード)
動作環境はGoogle Colaboratoryです.前回のノートブックに追記で書いています.
データ
前回の記事で使った首相データを再利用します.
ライブラリのインストール
!pip install tf-explain tensorflow==2.0.0 mira keras-facenet
FaceNetで顔ベクトルを取得
from mira.detectors import MTCNN
from keras_facenet import FaceNet
from PIL import Image
import numpy as np
import cv2
import matplotlib.pyplot as plt
import os
detector = MTCNN() # 顔領域検出器
embedder = FaceNet() # FaceNetのモデルを持つクラス
img = img = cv2.imread(FILE_PATH) # 画像読み込み
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) # RGB形式に変換
face = detector.detect(img_rgb)[0] # 画像中に複数の顔が検出されることもある.先頭をとってくる.
embedding = embedder.embeddings([face.selection.extract(img_rgb)])
GradCAMで注目箇所を可視化
from tf_explain.core.grad_cam import GradCAM
#
model = embedder.model # FaceNetのモデル(KerasのModelクラス)
model.summary()
# 前処理
img = face.selection.extract(img_rgb)
img = cv2.resize(img, (160, 160))
X = np.float32([embedder._normalize(img)])
data = (X, None)
# 出力の重要要素を決定
abs = np.abs(embedding) # 絶対値
top_channel = np.argmax(abs) # 絶対値が最も大きい要素番号
# GradCAMで可視化
explainer = GradCAM()
grid = explainer.explain(data, model, class_index=top_channel, layer_name="Block8_6_Conv2d_1x1")
explainer.save(grid, ".", "grad_cam.png")
重要要素の決定の妥当性は置いておき,結果自体は顕著性っぽいものがとれてそうですね.主に鼻から目にかけての領域を一番重要視していると今回は判断できそうです.
自分が人の顔を見る際に真っ先に目が行くのが鼻や目のあたりなので,直感的にも正しい気がしています.
ちなみに,西洋人と東洋人で顔を観察するときの視点移動方法は違うらしいですね.今回の結果は鼻を中心に顕著性が分布したので,どちらかというと東洋人っぽい観察の特性だと思いました.
Culture Shapes How We Look at Faces
さいごに
今回はFaceNetが顔認識を行う際にどこを重視してみているのか,独自の指標で可視化してみました.この指標が本当に正しいかはちょっと担保できませんが,少し試してみる程度ならいい結果が得られたと思っています.
コードはこちらから利用できます.前回の記事のノートブックに追記する形で書いてあるので,後半まで順番に実行してください.
結局,修論のためにお休みをもらうといっておきながら記事のネタを思いついたので帰ってきてしまいました.また気が向いたら更新するくらいの気持ちでカレンダーを埋めていこうと思います.
参考
Author And Source
この問題について(顔認証AIのFaceNetは顔のどこに注目しているのか), 我々は、より多くの情報をここで見つけました https://qiita.com/Takuya-Shuto-engineer/items/66066047914286ac94c3著者帰属:元の著者の情報は、元のURLに含まれています。著作権は原作者に属する。
Content is automatically searched and collected through network algorithms . If there is a violation . Please contact us . We will adjust (correct author information ,or delete content ) as soon as possible .