CS/기계학습(ML)

기존의 얼굴 인식 모델들(FaceNet, VGG-Face)을 이용해 한국인 얼굴 인식해보기

hyunah 2021. 11. 24. 23:23

기존의 얼굴 인식 모델들을 이용하여 한국인 얼굴을 인식해보기

졸업프로젝트로 기획하고 있는 서비스를 구현하기 위해 기존의 얼굴 인식 모델들인 FaceNet, VGG-Face, OpenFace 등으로 한국인 얼굴 인식도 높은 정확도로 수행할 수 있는지 검증하는 절차가 필요했다.

 

만약 기존의 모델로는 동양인 특히 한국인의 얼굴 인식에서 높은 정확성을 기대할 수 없다면, 별도로 한국인 데이터셋으로 학습을 시키거나 우리가 직접 얼굴 인식 모델을 만들어야 하기 때문이다.





DeepFace 프레임워크

 

우선 여러 얼굴 인식 모델들 간의 비교를 위해 파이썬의 DeepFace 프레임워크를 사용했다. DeepFace는 다양한 검증된 모델들을 wrapping하고 있는 경량의 하이브리드 face recognition 프레임워크이다.

 

DeepFace를 사용하기 위해서는 먼저 라이브러리를 다운 받아야 한다.

pip install deepface

 

그 후에는 다음과 같이 라이브러리를 import해서 사용하면 된다. 나는 pycharm에서 실행했고, 구글 코랩이나 다른 환경에서 진행해도 무방하다. Deepface가 아니라 DeepFace란 것에 유의하자

from deepface import DeepFace






얼굴 이미지 전처리

 

DeepFace를 사용하여 얼굴인식모델을 돌려보기에 앞서서, 얼굴 인식 모델에 이미지를 넣기 위해서는 전처리과정을 거처야 한다.

 

얼굴 이미지 전처리 과정

 

우선 입력 이미지에서 얼굴을 찾고(face detection), 얼굴의 특징점을 나타내는 점을 찾아 얼굴이 수평, 정면이 되도록 얼굴을 정렬(face alignment)한다. 그 다음에는 앞서서 추출한 얼굴 특징점을 이용해 얼굴 영역을 동일한 형태와 크기로 변경하는 정규화(normalization) 과정을 거친다.






DeepFace를 이용한 얼굴 인식 모델 사용

 

프로젝트에서 하는 작업은 얼굴 인식 중에서도 face identification이다. (face identification 개념에 대해서는 이 글을 참고)

 

DeepFace에서는 find() 메서드로 face identification 작업을 할 수 있다. 참고로 find() 안에는 전처리 과정인 face detection과 face alignment, normalization이 모두 포함된다.

 

DeepFace.find() 함수의 일부

 

위의 사진을 보면 find 함수에서 represent 메서드를 호출하는 것을 볼 수 있는데, 이 함수가 다음과 같은 작업을 시행한다.

 

얼굴 인식 모델에 이미지를 넣기 전에 시행해주어야 하는 전처리 작업




다양한 모델에 대해 find 함수를 진행한 후에 결과를 출력하기 위해 반복문으로 처리해주었다.

from deepface import DeepFace

models = ["VGG-Face", "Facenet", "Facenet512", "OpenFace", "DeepFace", "DeepID", "ArcFace", "Dlib"]
metrics = ["cosine", "euclidean", "euclidean_l2"]

input_img = "img4.png"

for i in range(len(models)):
    df = DeepFace.find(img_path=input_img, db_path="./test", model_name=models[i], distance_metric=metrics[2], enforce_detection=False)
    print(df)

 

위의 코드는 input image인 'img4.png'에 해당되는 얼굴을 test 폴더 사진의 얼굴들 중에서 탐색하는 코드이다. models가 담고 있는 각각의 모델에 대해서 한 번씩 시행되며, 거리측정은 euclidean_l2를 사용하도록 지정했다.

 

 

여기서 enforce_detection 파라미터를 False로 설정해주는 이유는, face detection을 할 수 없다고 판단한 경우에도 face identification을 시행하도록 하기 위해서다. 만약 저 부분을 빼고 돌리면 다음과 같은 에러를 마주하게 될 수도 있다.

 

Face가 detect되지 않은 경우 에러가 나며, 에러코드에서 친절하게 enforce_detection을 False로 설정하라고 알려준다.

 

 

파일 구조 사진

 

위와 같은 구조로 테스트 이미지를 넣었다. 입력 이미지는 루트 폴더 바로 아래에 넘버링을 하여 넣었고, DB 이미지는 test 폴더에 각각의 입력 이미지 인물과 대응되도록 넘버링을 하여 넣어두었다. 예를 들어서 'img1.png'에 해당하는 인물 사진은 test 폴더의 'img1_1.png'와 'img1_2.png'이다.

 

 

참고로 이미지를 추가하거나 삭제한 후 다시 코드를 돌리는 경우에는 저 'representations_*.pkl' 파일을 지우고 돌려줘야 한다. 그렇지 않으면 이전 이미지 정보를 가지고 코드가 돌아간다. 이 부분에 대해서는 코드를 시행하면 프로그램 자체에서도 warning을 해준다.

 

새로운 파일을 추가한 후에는 representation_vgg_face.pkl을 지우라고 안내하고 있다.

 

 

 

 

 

그런데 이렇게 시행하였을 때, 기대했던 것보다 사진 탐색의 성능이 좋지 않았다. 조사에 따르면 DeepFace 프레임워크가 포함하고 있는 VGG-Face, FaceNet, ArcFace 등은 모두 99퍼센트에 달하는 accuracy score를 보였다고 나와있는데, 그런 것에 비해 내가 직접 얻은 결과는 시원찮았다. 정말 동양인 데이터셋이 문제인건가 싶었지만, 백인 데이터셋을 넣었을 때도 헤어스타일이나 피부색, 입술색 등의 얼굴 특징이 조금이라도 달라지면 제대로 탐색을 하지 못하였다.

 


다음은 입력 이미지와 테스트 이미지 예시로 사용한 안젤리나 졸리의 사진과 탐색 결과다. 

 

입력 이미지 img.png
DB 이미지 img_1.png와 img_2.png

 

위의 사진들과 함께 다른 인물들의 사진도 test 폴더에 넣은 후에 입력 이미지를 find() 함수에 넣고 돌렸을 때 다음과 같은 결과가 나왔다. img_1과 img_2를 모두 탐색한 모델이 하나도 없었다.



 

DeepFace 프레임워크로 전처리하기

 

전처리 과정에서 문제가 있을 수 있겠다는 생각이 들어 find() 함수에 이미지를 넣기 전에 미리 전처리를 한 후 해당 이미지를 db에 직접 저장하는 코드를 작성했다. 전처리가 제대로 이루어지고 있는지 확인하기 위해서 전처리 이후의 사진을 바로 저장하도록 했다.

 

from deepface import DeepFace
import matplotlib.pyplot as plt
import glob
import sys

models = ["VGG-Face", "Facenet", "Facenet512", "OpenFace", "DeepFace", "DeepID", "ArcFace", "Dlib"]
metrics = ["cosine", "euclidean", "euclidean_l2"]

#1. DB 이미지 리스트 불러오기
imgs = glob.glob('test/*.png')

#2. 이미지 없을 때 예외처리
if not imgs:
    print("이미지가 없습니다.")
    sys.exit()

#3. DB 이미지 리스트 전처리
for img in imgs:
    aligned_img = DeepFace.detectFace(img)
    plt.imsave(img,aligned_img)

#4. 입력 이미지 전처리
input_img = "img4.png"
aligned_face = DeepFace.detectFace(input_img)
plt.imshow(aligned_face)
plt.show()
plt.imsave(input_img, aligned_face)

#5. 모든 모델에 대해 시행

for i in range(len(models)):
    df = DeepFace.find(img_path=input_img, db_path="./test", model_name=models[i], distance_metric=metrics[2])
    print(df)

 

 

위의 코드를 자세히 살펴보면 다음과 같다.

 

  1. glob.glob()를 이용해 test 폴더 안에 있는 png 형식의 파일을 모두 가져온다.
  2. 해당 폴더에 이미지가 없는 경우를 따로 처리해준다.
  3. 1에서 받아온 이미지들에 대해 DeepFace.detectFace()를 이용해 face detection과 face alignment를 시행한다. 이때 detectFace 메서드는 앞서 살펴본 represent 메서드가 포함하고 있던 preprocess_face()를 호출한다. imsave()를 이용해 전처리된 이미지를 저장한다.
  4. 입력 이미지도 별도로 전처리 과정을 거친다. imshow()와 show()를 이용해 사진이 출력되도록 하여 제대로 전처리되었는지 확인하고, imsave()로 전처리된 이미지를 저장한다.
  5. 모든 모델에 대해 얼굴 인식을 시행한다.




이때 전처리된 이미지를 imsave로 db에 저장한 상태에서 다시 전처리를 시행하면 오류가 나므로 주의해야 한다. 물론 앞서 설명한 Face could not be detected 오류이기 때문에 모든 detectFace()와 find()의 enforce_detection을 False로 지정하면 오류가 나지 않는다.



위의 코드로 시행해보았을 때, 얼굴 탐색이 제대로 이루어지지 않은 경우는 모두 전처리 결과에서 문제가 있었다. 입력 이미지의 얼굴 정렬이 제대로 이루어지지 않았거나, face detection에서 오류가 있어 얼굴 위치가 잘못 크롭되었거나, DB 속의 이미지의 얼굴 정렬 과정에서 문제가 있었던 경우였다.

 

 

앞서 보였던 안젤리나 졸리 예시의 전처리 결과는 다음과 같았다.

 

제대로 탐색되지 않았던 img_2의 얼굴 정렬 결과에 오류가 있는 것을 확인할 수 있다.

 

전처리가 제대로 시행되는 사진으로 다시 선정했을 때에는 백인과 동양인 테스트 이미지 모두 결과가 올바르게 도출되었으며, 특히 FaceNet 512가 높은 정확도를 보였다.






결론적으로, 전처리 과정을 제대로 시행한다면 기존의 얼굴 인식 모델로도 한국인 얼굴 인식을 높은 정확도로 시행할 수 있다. 별도의 전처리 과정을 어떻게 '제대로' 시행할 것이냐는 앞으로 남은 기간동안 여러 가지를 시도하면서 찾아가야 할 부분이다.