Deep Face Recognition with ArcFace in Keras and Python
아크페이스(ArcFace)는 Imperial College London의 연구자들이 개발하였다. 이것은 InsightFace 얼굴 분석 툴박스의 모듈이다. 원래 연구는 MXNet과 파이썬에 기초한다. 그러나, 여기서는 3rd 파티에서 케라스로 재구현한 것을 사용한다. 원래 연구가 LFW 데이터셋에서 99.83%의 정확도 점수인 반면 케라스 재구현은 99.4% 정확도이다. 따라서 재구현도 강력해 보인다. 게다가 MXNet 모델도 케라스로 재생산 가능한 것으로 보인다. 따라서 이 글에서는 ArcFace모델을 설계에서부터 구축해 본다.
Apple Face Id launch
Face recognition pipeline
일반적인 파이프라인은 탐지(detect), 정렬(align), 표현(represent), 검증(verify)의 4단계로 구성된다. 여기서 아크페이스는 표현에 대한 일반적인 얼굴 인식 알고리즘이다.
Source code
이 글에서 사용된 소스코드는 쥬피터노트북으로 여기에 저장되어 있다. 계속 진행하기 전에 이 소스와 ResNet archetecture building 종속성과 pre-trained weights를 clone한다.
Pre-trained model
아크페이스의 케라스 재구축은 그것의 저장소에 사전 훈련된 모델을 공유하지만 한덩어리이다. 즉 모델 구조(model structure)와 사전훈련된 가중치가 하나의 h5파일로 여기에 저장되었다는 의미이다. 그러나 모델은 tensorflow2로 저장되어서 다른 텐서플로 버전에서 이 모델을 로드하면 문제가 발생할 수 있다. 그렇기 때문에 버전문제를 피하기 위해 수작업으로 코드에 모델 구조를 구축하고 단지 사전훈련된 가중치만을 저장하는 것을 선호한다.
Model structure
아크페이스는 아래 그림과 같이 주로 ResNet32 모델 기반이다.
ResNet34 Architecture
이미 네트워크 아키텍쳐가 설계되어 있는 것이 있기 때문에 여기에서 ArcFace.py를 다운로드 받아 아래와 같이 load model 함수를 호출하기만 하면 된다. 아래 코드는 ArcFace.py와 동일한 디렉토리에 있어야만 한다.
#https://github.com/serengil/deepface/blob/master/deepface/basemodels/ArcFace.py
import ArcFace
ArcFace.loadModel()
아크페이스 모델은 (112, 112, 3) 모양의 입력을 받고 512차원 벡터 표현을 반환한다.
Pre-trained weights
친절한 다른 블로거가 여기에 사전훈련된 가줓치만을 저장하여 공유하였다(133MB). 앞에서 이미 모델을 구축했기 때문에 이제 아래 코드로 사전훈련된 가중치를 로드할 수 있다.
#Google Drive Link: https://drive.google.com/uc?id=1LVB3CdVejpmGHM28BpqqkbZP5hDEcdZY
model.load_weights("arcface_weights.h5")
Early stages of pipeline
아크페이스는 얼굴인식 파이프라인의 표현 단계를 담당하는 반면 탐지와 정렬은 앞선 단계이다. 운좋게도 deepface는 이러 앞선 단계를 다룰 수 있다. 딥페이스는 얼굴 탐지를 위한 opencv, ssd, mtcnn, dlib를 포함한다.
(저자의) 실험은 MTCNN이 가장 강력한 탐지기지만 가장느리고 SSD는 가장 빠르지만 정렬이 mtcnn만큼 좋지 않다는 것을 보여준다.
Preprocessing
#!pip install deepface
from deepface.commons import functions
img1_path = "img1.jpg"
img2_path = "img2.jpg"
img1 = functions.preprocess_face(img1_path, target_size = (112, 112))
img2 = functions.preprocess_face(img2_path, target_size = (112, 112))
왕좌의 게임에서 두명의 대표 캐릭터(Emilia Clarke (Daenerys Targaryen) and Lena Headey (Cersei Lannister))에 대해 모델을 테스트해 본다. 특히 에밀리아의 일상적인 모습과 그녕의 역할은 매우 달라 보인다. 유사하게 레나도 그녀의 짧고 긴 머리에 따라 매우 달라 보인다.
Game of Thrones ladies
Representation
우리는 이미 얼굴 이미지에 탐지와 정렬을 적용했고 또한 필요한 크기로 만들었다. 이제 아크페이스에 전처리된 얼굴 이미지를 전달할 수 있다.
img1_embedding = model.predict(img1)[0]
img2_embedding = model.predict(img2)[0]
Verification
CNN모델에 이미지를 전달하면 512차원 벡터로 얼굴 이미지 쌍을 표현한다. 여기서 이미지간 거리 표현은 동일 인물에 대해서는 낮지만 다른 인물에 대해서는 더 높아야 한다.
from deepface.commons import distance as dst
metric = 'euclidean'
if metric == 'cosine':
distance = dst.findCosineDistance(img1_embedding, img2_embedding)
elif metric == 'euclidean':
distance = dst.findEuclideanDistance(img1_embedding, img2_embedding)
elif metric == 'euclidean_l2':
distance = dst.findEuclideanDistance(dst.l2_normalize(img1_embedding), dst.l2_normalize(img2_embedding))
Threshold
거리값을 구했지만 어떻게 거리값이 높은지 낮은지를 결정할까? 이를 결정하는 가장 쉬운 방법은 대량의 긍정(positive)과 부정(negative) 인스턴스를 전달하는 것이다. 그러면 결정트리 알고리즘은 최고의 분할점을 찾을 수 있다. Fine Tuning the Threshold in Face Recognition에서 자세한 내용을 찾을 수 있다. 여기서는 딥페이스의 unit test images를 사용했다. 여기서 'master.csv'는 이미지 쌍과 동일인물인지 아닌지를 저장한다. 37개의 긍정과 239의 부정, 총 276개의 인스턴스가 있다.
Distributions
yes와 no 분류가 별개로 분포된 것같아 보인다. 목표(target) 레이블은 불균형하다. 그렇기 때문에 no 분류가 y축에서 더 높은 값으로 보인다.
거리값과 목표 분류를 C4.5 알고리즘에 전달하면 정보 이익(information gain)이 최대일때 최고의 임계치값을 찾는다.
def findThreshold(metric):
if metric == 'cosine':
return 0.6871912959056619
elif metric == 'euclidean':
return 4.1591468986978075
elif metric == 'euclidean_l2':
return 1.1315718048269017
Accuracy
이전에 언급된 바와 같이 케라스 재구축은 LFW 데이터셋에서 99.40% 정확도를 갖는다. (필자는) 딥페이스 unit test 인스턴스를 전달하여 최고의 임계치도 찾았다. 여기서는 찾은 임계치를 기초로 각 지표에 대한 정확도, 정밀도, 재현률 값이다.
metirc | precision | recall | f1-score | accuracy |
---|---|---|---|---|
cosine | 0.98 | 0.89 | 0.93 | 0.97 |
euclidean | 0.98 | 0.86 | 0.91 | 0.96 |
eudlieean_l2 | 0.98 | 0.89 | 0.93 | 0.97 |
Decision
각 거리 지표에 대한 거리와 임계치 모두를 구했다. 이제는 결정을 찾는다.
threshold = findThreshold(metric)
if distance <= threshold:
print("they are same person")
else:
print("they are different persons")
True positive pairs
아크페이스는 높랍게도 에밀리아 클라크(Emilia Clarke)와 레나 헤디(Lena Headey)의 신원을 검증한다. 에밀리아는 그녕의 일생생활과 왕좌의 게임에서의 역할에서 매우 다른 모습을 보인다. 유사하게 레나의 모습도 장발일때와 장발일 때 매우 다르지만 여전히 아크페이스 모델은 그들을 구분한다.
True positives
True negative pairs
아크페이스는 true negative 쌍에 대한 검증도 성공했다.
True negatives
Running ArcFace in deepface
단계별로 설게부터 아크페이스 모델을 만들고 파이프라인의 모든 단계를 적용했다. 한편으로는 단지 몇줄의 코드를 사용한 딥페이스로 아크페이스 모델을 만들어 실행할 수 있다. 우리는 데이터베이스에서 얼굴 검증 또는 식별을 할 수 있다. 단지 모델 이름 인자를 Arcface로 설정하기만 하면 된다.
#!pip install deepface
from deepface import DeepFace
#face verification
obj = DeepFace.verify("img1.jpg", "img2.jpg", model_name = 'ArcFace')
print(obj)
#face recognition
df = DeepFace.find("img1.jpg", db_path = "C:/my_db", model_name = 'ArcFace')
print(df.head())
** 중간의 Youtube 영상들은 중복되어 나오는 것이어서 건너 뛴다.
Conclusion
이 글에서는 최신 얼굴 인식 모델을 다뤘다.
여기에 사용된 소스코드는 여기에서 찾을 수 있다.