기계 학습(Machine Learning, 머신 러닝)은 즐겁다! Part 4

딥러닝(Deep Learning)을 사용한 최신 얼굴 인식(Face Recognition)


Facebook이 당신의 사진 속에서 친구들을 인식하는 신기한 기능을 이미 개발한 것을 알고 계셨나요? 이전 Facebook에서는 사진을 클릭하고 이름을 입력해야만 친구들에 대한 태그를 달 수 있었습니다. 이제 사진을 업로드하자마자 Facebook은 마술처럼 사람들에 대한 태그를 달아줍니다:

Facebook에서 이전에는 태그를 추가해야만 했지만 이제는 사진에 사람들에 대한 태그를 자동으로 달아줍니다. 이것이 도움을 주는것인지 오싹한 일인지 확실하진 않네요!

이 기술을 얼굴 인식(face recognition)이라고 합니다. 페이스북의 알고리즘은 친구사진에 단 몇 번 만 태그를 달아도 바로 그 얼굴을 인식 할 수 있습니다. 이것은 꽤 놀라운 기술입니다 — 페이스북은 인간이 할 수 있는 만큼이나 좋은 98%의 정확도로 얼굴을 인식할 수 있습니다!

이제 최신의 얼굴 인식이 어떻게 동작하는지 알아보겠습니다! 그런데 단지 당신의 친구들을 인식하는 것은 너무 쉬울지도 모릅니다. 우리는 이 기술을 한계까지 밀어붙여서 Will Ferrell(유명 배우)와 Chad Smith(유명한 록 뮤지션)을 구분하는 것과 같은 더욱 도전적인 문제를 해결해 볼 수도 있습니다

이 중 한 명은 Will Farrell이고 다른 사람은 Chad Smith입니다. 맹세컨데 정말 다른 사람입니다!
* 역자주: 여기서 Chad SmithWill Ferrell 사진을 구분하는 것을 어려운 예로 드는 이유는, 이 두 사람이 닮은 꼴로 유명해서 도플갱어로 불리고 유명한 The Tonight Show라는 토크쇼에도 출연했었기 때문입니다. 구글에서 검색해 보면 이 두사람을 비교하는 사진과 글을 많이 확인하실 수 있습니다.

매우 복잡한 문제에 기계 학습을 사용하는 방법

지금까지 Part 1, Part 2, Part 3에서, 우리는 주택 가격 예측하기, 기존 데이터를 기반으로 새로운 데이터 생성하기 그리고 이미지에 특정 객체가 있는지 여부를 알려 주기와 같은 단 한 가지 단계(step)만 있는 독립된 문제를 해결하기 위해 기계학습을 사용해 봤습니다. 이러한 종류의 문제는 하나의 기계 학습 알고리즘을 선택하고 데이터를 제공(feed)해서 결과를 얻으면 해결할 수 있습니다.

그러나 얼굴 인식은 일련의 여러가지 관련된 문제들을 해결하는 과정입니다:

1. 먼저 사진을 보고 그 안에 있는 모든 얼굴을 찾아야 합니다.

2. 둘째, 각 얼굴에 초점을 맞추고 얼굴이 이상한 방향으로 틀어졌거나 또는 조명이 안좋은 상황이라도, 여전히 같은 사람이라는 것을 이해할 수 있어야 합니다.

3. 셋째, 눈이 얼마나 큰지, 얼굴은 얼마나 긴지 등과 같이 다른 사람들과 구분하는데 사용하는 얼굴의 고유한 특징을 찾아 낼 수 있어야 합니다.

4. 마지막으로, 그 얼굴의 고유한 특징을 기존에 알고 있는 모든 사람들과 비교해서 그 사람의 이름을 결정해야 합니다.

인간으로서, 당신의 두뇌는 이 모든 것을 자동적으로 또 즉시 수행하도록 연결되어 있습니다. 사실 인간은 일상의 모든 사물의 얼굴 또는 표면을 발견하고 인식하는 일을너무나도 잘 합니다.

컴퓨터는 이러한 높은 수준의 일반화를 (적어도 아직까지는…) 할 수 없기 때문에, 이 프로세스를 분리해서 각 단계별로 수행하는 방법을 가르쳐야 합니다.

우리는 얼굴 인식을 분리해서 각 단계별로 문제를 해결하고, 현 단계의 결과를 다음 단계로 넘겨주는 경로(pipeline)를 만들어야 합니다. 다시 말해서, 몇가지 기계 학습 알고리즘을 함께 연결할 것입니다.

얼굴을 인식하기 위한 기본 경로(pipeline)의 동작 방식

단계별 얼굴 인식

한 번에 한 단계씩 이 문제를 해결해 보겠습니다. 각 단계마다 다른 기계 학습 알고리즘에 대해 배우게 됩니다. 이 글이 책처럼 되지 않도록 하기 위해서 모든 알고리즘을 하나 하나 완전하게 설명하진 않을 것입니다. 하지만, 전체적인 중요 아이디어를 배우고 나서 OpenFacedlib을 사용해 Python으로 자신 만의 얼굴인식 시스템을 만드는 방법을 배우게 될 것입니다.

Step 1: 모든 얼굴 찾기

우리의 경로(pipeline)에서 첫 번째 단계는 얼굴 검출(face detection)입니다. 당연하게도 우리가 얼굴을 구별하기 위해서는 먼저 사진 상에서 얼굴을 찾아야 합니다!

지난 10년 사이 아무 카메라나 사용해 봤다면, 얼굴 인식 기능이 들어있는걸 본적이 있을겁니다:

얼굴 인식은 카메라의 중요한 기능입니다. 카메라가 얼굴을 자동으로 인식할 수 있다면, 사진을 찍기 전에 모든 얼굴에 확실하게 초점을 맞춰줄 수 있습니다. 그런데 우리는 이 기능을 다른 목적으로 사용할 것입니다 — 즉, 이 기능을 우리의 경로(pipeline)의 다음 단계로 넘길 이미지 영역을 찾는데 사용할 것입니다.

Paul Viola와 Michael Jones가 값싼 카메라에도 사용할 정도로 빠른 얼굴 인식 방법을 발명한 2000년대 초반부터 얼굴 인식은 대세가 되었습니다. 그런데, 현재는 훨씬 더 신뢰할 수 있는 솔루션이 존재합니다. 우리는 Histogram of Oriented Gradients(또는 줄여서 HOG)라 불리는 2005년에 발명 된 방식을 사용할 것입니다.

이미지에서 얼굴을 찾기위해 우리는 이미지를 흑백으로 바꾸는 것부터 시작할 것입니다. 왜냐하면 얼굴을 찾는데 색상 데이터는 필요 없기 때문입니다:

그런 다음 한번에 하나씩 이미지의 모든 단일 픽셀을 살펴 보겠습니다. 모든 단일 픽셀에 대해 이를 직접 둘러싸고 있는 픽셀들 또한 살펴볼 것입니다:

우리의 목표는 해당 픽셀이 이를 직접 둘러싸고 있는 픽셀들과 비교해서 얼마나 어두운지 알아내는 것입니다. 이를 통해서 이미지가 어두워지는 방향을 나타내는 화살표를 그리고자 합니다:

이 한개의 픽셀과 이 픽셀에 인접한 픽셀들을 살펴 보면, 이미지는 오른쪽 상단으로 갈수록 어두워집니다.

이미지의 모든 픽셀에 대해 이 프로세스를 반복하면 결국 모든 픽셀이 화살표로 바뀌게 됩니다. 이러한 화살표들을 그래디언트(gradients)라고 부르고, 이를 통해 전체 이미지에서 밝은 부분으로부터 어두운 부분으로의 흐름을 알 수 있습니다:

* 역자주: gradients를 번역할 단어를 찾지 못해 영어 발음 그대로 씁니다. 일반적으로 쓰는 기울기, 변화도, 그라데이션은 절대 아니며, 여기서는 방향성을 갖는 Vector의 특징이 있습니다. 정확한 단어 알고 계시는 분 연락바랍니다.

이것은 아무것도 아닌 일처럼 보일지 모릅니다. 그런데, 픽셀을 그래디언트(gradients)로 바꿔야 하는 정말 좋은 이유가 있습니다. 픽셀을 직접 분석하면, 동일한 사람의 정말 어두운 이미지와 정말 밝은 이미지는 전혀 다른 픽셀값을 갖게 될 것입니다. 그러나 밝기가 변하는 방향 만 고려하면 정말 어두운 이미지와 정말 밝은 이미지에 대한 완전히 동일한 표현(representation)을 얻게 됩니다. 이렇게 하면 문제를 훨씬 더 쉽게 해결할 수 있습니다!

그러나 모든 단일 픽셀에 대해 그래디언트를 저장하면 너무 자세합니다. 이렇게 되면 결국 우리는 나무를 보고 숲을 보지 못하게 됩니다. 이미지의 기본 패턴을 알 수 있도록, 높은 수준에서 밝음/어둠의 기본 흐름만을 보는 것이 더 좋습니다.

이를 위해, 이미지를 각각 16x16 픽셀의 작은 정사각형들으로 분해합니다. 각 정사각형에서, 우리는 얼마나 많은 그래디언트가 주요 방향(윗쪽, 우상쪽, 오른쪽, 등)을 얼마나 가리키고 있는지 세어 볼 것입니다 . 그런 다음 이 사각형을 가장 강한 화살표 방향으로 바꿀 것입니다.

결과적으로, 우리는 원본 이미지를 얼굴의 기본 구조가 심플한 방법으로 표시되는 매우 간단한 표현(representation)으로 변환하게 됩니다:

원본 이미지는 이미지 밝기에 관계없이 이미지의 주요 특징들을 캡처한 HOG 표현로 바뀝니다.

이 HOG 이미지에서 얼굴을 찾기위해서 우리가 해야 할 일은 많은 훈련 얼굴 이미지로부터 추출 된 잘 알려진 HOG 패턴과 가장 유사하게 보이는 부분을 이미지에서 찾는 것입니다:

이 테크닉을 사용하면 어떠한 이미지에서도 얼굴을 쉽게 찾을 수 있습니다:

Python과 dlib을 사용해서 이 단계를 직접 해보고 싶다면, 여기 이미지로부터 HOG 표현을 생성하고 확인할 수 있는 코드가 있습니다.

Step 2: 얼굴의 위치교정(Posing)과 투영(Projection)

휴유, 드디어 이미지에서 얼굴들만을 분리해 냈습니다. 그러나 이제 얼굴이 다른 방향을 보고 있으면 컴퓨터에게는 전혀 다르게 보이게 되는 새로운 문제를 해결해야 합니다:

인간은 두 이미지 모두 Will Ferrell이라는 것을 쉽게 인식할 수 있지만, 컴퓨터는 이 사진들을 완전히 다른 두 사람으로 보게됩니다.

이를 해결하기 위해, 각각의 사진을 비틀어 눈과 입술이 항상 표준 위치에 올 수 있도록 해보려고 합니다. 이렇게하면 다음 단계들에서 얼굴을 좀 더 쉽게 비교할 수 있습니다.

이렇게 하기 위해서, 우리는 face landmark estimation이라고 하는 알고리즘을 사용할 것입니다. 여러 방법이 많이 있지만, 2014년에 Vahid Kazemi와 Josephine Sullivan이 발명 한 접근 방법을 사용하려고합니다.

기본적인 아이디어는 모든 얼굴에 존재하는 68개의 랜드마크(landmarks)라 부르는 특정 포인트(턱의 상단, 눈 바깥의 가장자리, 눈썹 안쪽의 가장자리, 등)를 찾아 내는 것입니다. 이제 우리는 기계 학습 알고리즘을 훈련시켜 어떤 얼굴에서든 이러한 68개의 특정 포인트들을 찾을 수 있도록 할 것입니다:

모든 얼굴에 표시할 68개의 랜드마크(landmarks). 이 이미지는 OpenFace에서 일하는 CMU의 Brandon Amos가 만들었습니다.

우리의 테스트 이미지에 68개의 얼굴 랜드마크를 표시한 결과입니다:

전문가 팁 :이 기술을 동일하게 사용해서 Snapchat의 실시간 3D 얼굴 필터를 당신만의 버전으로 구현할 수도 있습니다.

눈과 입이 어디에 있는지 알게되었으므로, 이제 눈과 입이 최대한 가운데로 올 수 있도록 이미지를 간단하게 회전(rotate)하고, 크기를 조절(scale)하고 비틀(shear) 것입니다. 여기서 우리는 환상적인 3d 변형(3d warps)를 사용하지는 않을 것입니다. 그렇게 하면 이미지에 왜곡이 생기기 때문입니다. 여기서 우리는 평행선을 보존하는 회전(rotation) 및 크기 조절(scale)과 같은 기본적인 이미지 변환방법(affine transformations이라 부름) 만을 사용할 것입니다:

* 역자주: 여기서 3d 변형(3d warps)는 이미지를 3차원 상에서 변형하거나 뒤트는 것을 말합니다. 다음과 같은 이미지를 참고하세요.

이제 얼굴이 옆으로 돌아가 있어도, 우리는 눈과 입을 이미지상에서 대략 동일한 위치에 맞출 수 있습니다. 이렇게 함으로써 다음 단계가 훨씬 더 정확해질 것입니다.

Python과 dlib을 사용해 이번 단계를 직접 해보고 싶다면, 여기 얼굴 랜드마크(landmarks)을 찾는 코드와 랜트마크를 사용해 이미지를 변형하는 코드가 있습니다.

Step 3 : 얼굴 인코딩

이제 문제의 핵심인 실제로 얼굴을 구별하는 단계에 이르렀습니다. 이 단계는 정말 재미있는 곳입니다!

얼굴 인식을 가장 간단하게 접근하는 방법은 앞서 Step 2에서 찾아낸 모르는 얼굴을 이미 태그가 달린 사람들의 모든 사진과 직접 비교하는 것입니다. 모르는 얼굴과 매우 비슷하게 보이는 이미 태그가 달린 얼굴을 찾게되면, 분명히 같은 사람일 것입니다. 꽤 괜찮은 아이디어 같아 보이죠?

그런데 이 접근 방법에는 큰 문제가 있습니다. 수십억 명의 사용자와 1조 개의 사진이 있는 Facebook과 같은 사이트는 이미 태그가 달린 모든 얼굴과 새롭게 업로드된 사진을 일일이 반복해서 비교할 수는 없습니다. 너무 오래 걸릴 것입니다. 시간 단위가 아닌 밀리초 단위로 얼굴을 인식 할 수 있어야 합니다.

우리에게 필요한 것은 각 얼굴에서 몇 가지 기본 측정값을 추출하는 방법입니다. 그런 다음에 모르는 얼굴을 이 방법으로 측정하면 이 측정값과 가장 가까운 값을 가지는 얼굴을 찾을 수 있습니다. 예를 들어, 각 귀의 크기, 눈 사이의 간격, 코의 길이 등을 측정해 볼 수 있을 겁니다. CSI와 같은 범죄 드라마를 본 적이 있다면, 무슨 말을하고 있는지 알 것입니다:

TV에서 하는 것처럼! 이거 진짜입니다! #science

가장 신뢰할 수 있는 얼굴 측정 방법

좋습니다, 그런데 아는 얼굴의 데이터베이스를 만들기 위해 얼굴에서 어떤 측정값을 수집해야 할까요? 귀의 크기? 코의 길이? 눈의 색깔? 아니면 다른 어딘가?

눈의 색깔과 같이 인간에게는 분명한 것으로 보이는 측정값들이 이미지의 개별 픽셀을 보는 컴퓨터에게는 전혀 의미가 없습니다. 최근에 연구자들은 컴퓨터가 수집할 측정값을 스스로 파악하도록 하는 것이 가장 정확한 접근 방법임을 알게 되었습니다. 딥러닝은 얼굴의 어느 부분이 측정에 있어 중요한 것인지 파악하는 일을 인간보다 더 잘 수행합니다.

해결책은 바로 Part 3에서 했던 것처럼 딥 컨볼루션 신경망(Deep Convolutional Neural Network)을 훈련시키는 것입니다. 그러나 우리가 마지막으로 했던 것처럼 사진에서 객체를 인식하도록 신경망을 훈련시키는 대신, 각 얼굴에 대해 128개의 측정값을 생성하도록 훈련시킬 것입니다.

훈련 과정은 3 개의 얼굴 이미지를 차례 대로 확인하는 것입니다.

1. 훈령용 아는 사람의 얼굴 사진 적재(load)

2. 동일한 아는 사람의 다른 사진 적재

3. 전혀 다른 사람의 사진 적재

그리고 알고리즘은 세 개의 이미지 각각에 대해 현재 생성하고 있는 측정값을 확인합니다. 그런 다음에, #1 과 #2 이미지에 대해 생성한 측정값은 서로 좀더 가깝게 하고 #2와 #3의 측정값은 좀더 멀어지도록 신경망을 조금 조정합니다:

수천 명의 다른 사람들의 수백만 개의 이미지에 대해 이 단계를 수백만 번 반복 하면, 신경망은 각 사람에 대한 128개의 측정값을 신뢰성 있게 생성하는 방법을 배우게 됩니다. 동일한 사람의 10개의 다른 사진에 대해서 대략적으로 동일한 측정값을 제공해야 합니다.

기계 학습을 하는 사람들은 각 얼굴에 대한 128개의 측정값을 임베딩(embedding)이라고 부릅니다. 사진과 같이 복잡한 원시 데이터(raw data)를 컴퓨터가 생성한(computer-generated) 숫자값의 목록으로 축소한다는 아이디어는 기계 학습(특히 언어 번역)에서 많이 사용되고 있습니다. 우리가 지금 사용하고 있는 얼굴 인식의 정확한 접근 방법은 2015년에 Google의 연구원에 의해 발명된 것이지만 이와 비슷한 접근 방법은 많이 있습니다.

우리의 얼굴 이미지 인코딩 하기

임베딩(embeddings)을 생성할 수 있도록 컨볼루션 신경망을 훈련시키는 프로세스는 많은 양의 데이터와 컴퓨터 자원을 필요로 합니다. 비싼 NVidia Telsa 비디오 카드를 사용하더라도, 좋은 정확도를 얻기위해서는 대략 24시간의 지속적인 훈련이 필요합니다.

그러나 일단 신경망이 훈련을 마치면, 이전에 절대 본적도 없는 얼굴에 대해서도 측정값을 생성할 수 있습니다! 따라서 이 단계는 딱 한 번만 수행하면됩니다. 운좋게도, OpenFace의 훌륭한 사람들이 이미 이 작업을 진행한 다음, 우리가 바로 사용할 수 있는 몇 가지 훈련 된 신경망을 공개했습니다. Brandon Amos와 그의 팀에게 감사드립니다!

따라서 우리가 직접 해야 할 일은 사전 훈련된 신경망을 사용해서 우리의 얼굴 이미지로부터 각 얼굴에 대한 128개의 측정 값을 얻는 것입니다. 다음은 우리의 테스트 이미지에 대한 측정값입니다:

그런데, 이러한 128개의 숫자들이 정확히 얼굴의 어느 부분을 측정한 것일까요? 우리는 전혀 알 수가 없습니다. 하지만, 전혀 문제가 되지 않습니다. 우리가 신경써야 할 것은 동일한 사람의 다른 두개의 사진에 대해 거의 같은 숫자들을 생성한다는 것입니다.

이 단계를 직접 해보고 싶다면, 폴더 안의 모든 이미지에 대한 임베딩(embeddings)를 생성해주는 OpenFace의 lua 스크립트를 사용하면 됩니다. 이런식으로 실행하면 됩니다.

Step 4: 인코딩에서 사람의 이름 찾기

이 마지막 단계는 사실 전체 프로세스에서 가장 쉬운 단계입니다. 우리가 해야할 일은 테스트 이미지에 가장 근접한 측정값을 갖고 있는 사람을 우리의 아는 사람에 대한 데이터베이스에서 찾아내는 것입니다.

기본적인 기계 학습 분류 알고리즘을 사용해서 이 작업을 수행 할 수 있습니다. 대단히 멋진 딥러닝 기술이 필요하지 않습니다. 다양한 분류 알고리즘을 사용할 수 있겠지만, 우리는 간단한 선형 SVM 분류기(classifier)를 사용하겠습니다.

우리가 해야 할 일은 새로운 테스트 이미지로부터 측정값을 가져와 가장 매칭되는 아는 사람이 누구인지 알려주는 분류기(classifier)를 훈련시키는 것입니다. 이 분류기의 실행시간은 밀리초 밖에 되지 않습니다. 이 분류기의 결과물은 바로 그 사람의 이름입니다!

이제 우리 시스템을 시험해 보겠습니다. 먼저, Will Ferrell, Chad Smith 그리고 Jimmy Falon 각각에 대한 20장 정도의 사진들에 대한 임베딩으로 분류기를 훈련시켰습니다:

아주 멋진 훈련 데이터!

그런 다음에 Will Ferrell과 Chad Smith가 Jimmy Fallon 쇼에서 서로 같은 사람인척 하는 유명한 유튜브 비디오의 모든 프레임에서 분류기를 실행해 봤습니다.

정말 동작합니다! 그리고 다른 포즈의 얼굴에 대해서도 얼마나 잘 동작하는지 보세요 — 심지어 옆 모습에서도!

직접 실행해 보기

지금까지 진행한 단계들을 검토해보겠습니다:

1. 이미지의 단순화된 버전을 만들어 주는 HOG 알고리즘을 사용해 사진을 인코딩합니다 . 이 단순화된 이미지에서 얼굴의 일반 HOG 인코딩(generic HOG encoding)과 가장 유사하게 보이는 부분을 찾습니다.

2. 얼굴의 주요 랜드마크(landmarks)를 찾아 얼굴의 포즈(pose)를 알아냅니다. 이 랜드마크를 찾으면, 이를 이용해서 눈과 입이 중앙에 오도록 이미지를 변형시킵니다.

3. 얼굴의 특징들을 측정하는 방법을 알고 있는 신경망에 중심을 맞춘 얼굴 이미지를 전달합니다. 그리고 128개의 측정값을 저장합니다.

4. 과거에 측정해 놓은 모든 얼굴에 대해, 이 얼굴의 측정값에 가장 가까운 사람이 누구인지 확인합니다. 이 사람이 바로 그 사람입니다!

이제 모든 것이 어떻게 동작하는지 알게되었습니다. 다음은 당신의 컴퓨터에서 OpenFace를 사용해 얼굴 인식의 전체 경로(pipeline)를 실행하는 방법에 대한 처음부터 끝까지 모든 단계별 설명입니다:


이 글이 마음에 들었다면, 제 Machine Learning is Fun! 이메일 리스트에 가입하는 것도 좋습니다! 새롭고 멋진 소식이있을 때만 이메일을 보내 드리겠습니다. 제가 이런 종류의 추가 글을 올릴때가 언제인지 알 수 있는 가장 좋은 방법입니다.

Twitter의 @ageitgey인 저를 팔로우하거나, 직접 이메일을 보내거나 또는 linkedin에서 저를 찾을 수도 있습니다. 기계 학습으로 제가 당신이나 당신의 팀을 도울 수 있다면 언제든 연락 주십시오.

*역자주: 번역글과 관련해 의견 주시려면, 저에게 직접 이메일을 보내시거나 LinkedIn에서 저를 찾으셔도 됩니다.