Aprendizagem de Máquina é Divertido! Parte 4

Reconhecimento Facial Moderno com Deep Learning

Nota do tradutor: Este post é a tradução de um artigo por Adam Geitgey, de uma série de artigos originalmente em inglês. Leia a série completa original: Part 1, Part 2, Part 3, Part 4, Part 5, Part 6, Part 7 and Part 8!

Você pode ler em português a Parte 1, Parte 2, Parte 3, Parte 4, Parte 5, Parte 6, Parte 7 e Parte 8.


Você já notou que o Facebook desenvolveu uma capacidade impressionante de reconhecimento dos seus amigos nas suas fotos? Antigamente, Facebook solicitava que você marcasse os amigos clicando e digitando os seus nomes. Agora, assim que você adiciona uma foto, Facebook marca todos da foto para você como num passe de mágica:

Facebook marca pessoas automaticamente nas suas fotos pessoas que você já marcou anteriormente. Não tenho certeza se isto é útil ou assustador!

Esta tecnologia é chamada de reconhecimento facial. O algoritmo do Facebook é capaz de reconhecer o rosto dos seus amigos depois que eles tenham sido marcados algumas vezes. É uma tecnologia incrível — Facebook consegue reconhecer com acurácia de 98%, o que é bem próximo da performance humana!

Vamos aprender como reconhecimento facial moderno funciona! Mas apenas reconhecer amigos seria muito fácil. Vamos até os limites desta tecnologia para resolver um problema mais desafiador — diferenciar entre Will Ferrel (o ator) e Chad Smith (o roqueiro)

Um destes dois é Will Ferrell. O outro é Chad Smith. Eu juro que eles são duas pessoas diferentes!

Como usar Aprendizagem de Máquina em um Problema bem Complicado

Na Parte 1, Parte 2 e Parte 3, usamos aprendizagem de máquina para resolver problemas isolados que representam apenas um passo — estimar o preço de um imóvel, gerar novos dados baseado em dados existentes, e predizer se uma imagem contém um determinado objeto. Todos estes problemas podem ser resolvidos escolhendo um algoritmo de aprendizagem de máquina, alimentando-o com dados e recebendo o resultado.

Reconhecimento facial de fato é uma série de problemas inter-relacionados:

  1. Primeiro, encontre um rosto em uma imagem
  2. Segundo, focar em um rosto de cada vez e entender que mesmo que o rosto esteja inclinado de modo estranho ou com iluminação ruim, ainda é a mesma pessoa.
  3. Terceiro, ser capaz de identificar características únicas no rosto que você possa utilizar para diferenciá-lo de outras pessoas — como o tamanho dos olhos, comprimento do rosto, etc.
  4. E finalmente, compare as caractarísticas únicas do rosto em foco com todas as pessoas já conhecidas e determine o nome da pessoa.

O cérebro humano realiza todas estas funções automaticamente e instântaneamente. Os humanos são tão bons em identificar rostos que acabam vendo faces em objetos comuns:

Computadores não são capazes deste tipo de generalização de alto nível (pelo menos não ainda …). Portanto, temos que ensiná-los como fazer cada passo deste processo separadamente.

Precisamos criar um pipeline onde tratamos cada etapa do reconhecimento facial individualmente e passamos o resultado do passo atual para o próximo passo. Em outras palavras, vamos encadear vários algoritmos de aprendizagem de máquina:

Como funciona um pipeline básico para detecção de faces.

Reconhecimento Facial — Passo a Passo

Vamos resolver este problema passo a passo. Para cada passo, vamos discutir um algoritmo de aprendizagem diferente. Eu não vou explicar detalhadamente o algoritmo para evitar que este post vire um livro, mas você vai entender a ideia geral de cada um e vai aprender como criar seu próprio sistema de reconhecimento facial em Python usando OpenFace e dlib.

Passo 1: encontrar as faces na imagem

O primeiro passo no nosso pipeline é detecção de rosto. Obviamente precisamos localizar os rostos em uma foto antes que poder analisá-los.

Se você utilizou uma câmera nos ultimos 10 anos, provavelmente você já viu detecção de rosto em ação:

Detecção de rosto é uma ótima função para câmeras. Se a câmera pode detectar automaticamente os rostos, ela pode garantir que todos estão em foco antes de fazer a foto. Mas vamos utilizar esta função com outra finalidade — encontrar as áreas na imagem que queremos passar para o próximo passo do nosso pipeline.

A popularização da detecção de rosto aconteceu no inicio dos anos 2000 quando Paul Viola e Michal Jones inventaram uma maneira de detectar rostos que era rápido o suficiente para rodar em câmeras baratas. Contudo, existem soluções mais confiáveis atualmente. Nós iremos utilizar um método inventado em 2005 chamado Histogramas de Gradientes Orientados (histogram of oriented gradients) — ou apenas HOG.

Para encontrar um rosto em uma imagem, vamos começar tornando a imagem preto e branco, pois não precisamos de cores para encontrar o rosto:

Analizamos, então, cada um dos pixels na imagem, observando os pixels que estão na vizinhança imediata de cada pixel:

Nosso objetivo é descobrir quão escuro é o pixel atual comparado aos seus vizinhos diretos. Então, desenhamos uma seta (vetor) mostrando a direção em que a imagem fica mais escura:

Considerando apenas estes pixel e seus vizinhos, a imagem está ficando mais escura na direção do canto superior direito.

Se repetirmos este processo para cada pixel na imagem, cada pixel será substituído por uma seta. Estas setas são chamadas gradientes e eles mostram o fluxo da parte mais clara para a mais escura por toda a imagem:

Isto pode parecer um procedimento aleatório, mas há uma boa razão para substituirmos pixels por gradientes. Se analizarmos pixels diretamente, imagens muito escuras e as muito claras da mesma pessoa vão apresentar valores de pixels completamente diferentes. Mas apenas considerando a direção da mudança da luminosidade, tanto imagens escuras quanto claras terão a mesma representação. Assim, o problema fica muito mais fácil de resolver!

Entretanto, guardar o gradiente de cada pixel resulta em detalhes demais. Vamos deixar de ver a floresta devido às árvores. Seria melhor se pudéssemos ver o fluxo básico de luz e sombra em um nível maior, de modo que o padrão básico da imagem ficasse aparente.

Para fazer isto vamos dividir a imagem em pequenos quadrados de 16x16 pixels cada. Em cada quadrado vamos contar quantos gradientes apontam em cada direção principal (para cima, superior direito, direita, etc.). Depois vamos substituir o quadrado na imagem pela seta de direção que tenha maior contagem.

Com este procedimento, transformamos a imagem original em uma representação que captura a estrutura básica do rosto de modo simplificado:

A imagem original é transformada em uma representação HOG, que captura as principais características da imagem independente das condições de iluminação.

Para detectar faces em uma imagem HOG tudo que temos que fazer é encontrar a parte da nossa imagem que mais se pareça com um padrão HOG conhecido que tenha sido extraído de um monte de outras faces de treinamento:

Utilizando esta técnica podemos detectar facilmente faces em uma imagem:

Se você quiser tentar este passo por você mesmo utilizando Python e dlib, aqui está o código mostrando como gerar e visualizar a representação HOG de imagens.

Passo 2: Posicionar e projetar faces

Pronto, já sabemos como isolar faces na nossa imagem. Mas agora temos que lidar com o problema de que quando um rosto pode parecer totalmente diferente para um computador quando muda a direção:

Humanos podem facilmente reconhecer que ambas imagens são de Will Ferrel, mas computadores verão estas duas imagens como como duas pessoas completamente diferentes.

Para tratar isto, vamos tentar torcer cada imagem de tal modo que os olhos e os lábios estejam sempre no mesmo lugar na imagem. Isto tornará a comparação de imagens bem mais fácil nos próximos passos.

Vamos utilizar um algoritmo chamado estimação de marcas da face (face landmark estimation). Há várias maneiras de fazer isto, mas utilizaremos uma abordagem inventada em 2014 por Vahid Kazemi e Josephine Sullivan.

A ideia básica é identificar 68 pontos específicos que existem em todo rosto (chamados marcas — landmarks), a ponta do queixo, a borda externa de cada olho, a borda interna de cada sobrancelha, etc. Iremos então treinar um algoritmo de aprendizagem para encontrar estes 68 pontos no rosto:

Os 68 pontos do rosto que iremos localizar em cada rosto. Esta imagem foi criada por Brandon Amos do CMU, que trabalha no OpenFace.

Aqui está o resultado da identificação dos 68 pontos na nossa imagem de teste:

DICA: Você pode usar esta mesma técnica para implementar suas próprias versões dos filtros de rosto 3d do Snapchat!

Agora que sabemos onde estão os olhos e a boca, podemos simplesmente rotacionar, escalar e cisalhar a imagem para que os olhos e boca fiquem o mais centralizado quanto possível. Não vamos fazer nenhuma operação 2d complicada porque isto introduziria distorções na imagem. Vamos utilizar apenas transformações básicas para que linhas paralelas sejam preservadas (chamadas tranformações afins):

Não importa como o rosto esteja inclinado, seremos capazes de centralizar os olhos e a boca para as mesmas posições nas imagens. Isto tornará mais preciso nosso próximo passo.

Se você quiser testar este passo você mesmo usando Python e dlib, aqui está o código para encontrar os 68 pontos em um rosto e aqui está o código para transformar a imagem utilizando estes pontos.

Passo 3: Codificar rostos

Agora estamos no cerne do problema — realmente identificando cada rosto. É agora que vai ficar realmente interessante!

A abordagem mais simples para o problema de reconhecimento de rosto é comparar o rosto desconhecido que foi encontrado no passo 2 com todas as imagens de pessoas que já foram previamente identificadas. Quando encontramos um rosto previamente identificado que se parece muito similar com nosso rosto desconhecido, deve ser a mesma pessoa. Parece uma boa ideia, certo?

Infelizmente há um grande problema com esta abordagem. Um site como Facebook com bilhões de usuários e um trilhão de fotos não pode varrer em tempo hábil todas as fotos pré-identificadas para compará-las com uma nova foto que tenha sido adicionada. Isto iria demorar tempo demais. Eles precisam poder reconhecer um rosto em milisegundos, não em horas.

O que precisamos é uma maneira de extrair algumas características básicas de cada rosto. Assim, poderíamos mensurar o rosto desconhecido do mesmo modo e encontrar os rostos que tenham as medidas básicas mais similares. Por exemplo, poderíamos medir o tamanho de cada orelha, o espaço entre os olhos, o tamanho do nariz, etc. Se você já assitiu séries de TV como CSI, você sabe do que estou falando:

Igual à TV! tão real! #ciencia

A maneira mas confiável de mensurar rostos

Ok, então qual características devemos coletar de cada rosto para criar nosso banco de dados de rostos? tamanho da orelha? tamanho do nariz? ou outra coisa?

Acontece que as características que parecem tão óbvias para nós (como cor dos olhos) não fazem sentido para o computador que está considerando pixels individuais em uma imagem. Pesquisadores descobriram que a abordagem mais precisa é deixar o computador encontrar ele mesmo as características a serem coletadas. Deep learning tem um desempenho melhor que humanos na descoberta de quais características do rosto são mais importantes para se medir.

A solução, então, é treinar uma Rede Neural Convolutiva Profunda (Deep Convolutional Neural Network), como fizemos na Parte 3. Mas ao invés de treinar uma rede para reconhecer objetos, desta vez vamos treiná-la para gerar 128 medidas para cada rosto.

O processo de treinamento utiliza 3 imagens por vez:

  1. Carregue uma imagem de treinamento de uma pessoa conhecida
  2. Carregue uma outra imagem da mesma pessoa conhecida
  3. Carregue uma imagem de uma pessoa totalmente diferente

O algoritmo irá extrar as medidas para cada uma das três imagens. Ele então irá modificar a rede levemente de modo que as medidas para imagens 1 e 2 sejam mais similares e ao mesmo tempo que medidas para imagens 2 e 3 sejam diferentes:

Depois de repetir este passo milhões de vezes para milhões de imagens e milhares de pessoas diferentes, a rede neural aprende a gerar de modo confiável 128 medidas para cada pessoa. Quaisquer 10 fotos diferentes da mesma pessoa deve gerar aproximadamente as mesmas medidas.

Em aprendizagem de máquina, esta técnica é conhecida como embedding. Reduzir dados complexos como fotos a um punhado de números gerados por computador é uma abordagem muito utilizada em aprendizagem de máquina (especialmente em tradução de linguagem natural). A abordagem exata para idenficação de rostos que estamos utilizando aqui foi inventada em 2015 por pesquisadores do Google, mas há muitas outras abordagens similares.

Codificando a nossa imagem de teste

Este processo de treinar uma rede neural convolutiva para produzir embeddings de rosto exige uma grande quantidade de dados e muito poder computacional. Mesmo com uma placa gráfica NVidia Tesla, leva cerca de 24 horas de treinamento contínuo para se obter boa precisão.

Apesar disso, uma vez treinada a rede pode gerar medidas para qualquer rosto, mesmo os que ela nunca viu antes! Portanto, o treinamento só precisa ser realizado uma vez. Felizmente pra nós, os caras legais da OpenFace já fizeram isto e publicaram várias redes treinadas prontas para serem utilizadas. Obrigado Brando Amos e sua equipe!

Tudo que temos que fazer, então, é analisar nossas imagens com as redes pré-treinadas e obter as 128 medidas para cada rosto. Aqui está a lista de medidas para nossa imagem de teste:

Mas quais partes do rosto estes 128 números estão medido exatamente? De verdade, não temos a menor ideia. E isto realmente não importa. Tudo que precisamos é que a rede gere os mesmos números para fotos diferentes da mesma pessoa.

Se você quiser testar este passo você mesmo, OpenFace disponibiliza um script em lua que irá gerar os embeddings para todas as imgens em um determinado diretório e os salva em um arquivo csv. Detalhes de como executar neste link.

Passo 4: Encontrar o nome da pessoa a partir da codificação

Este ultimo passo é o mais fácil de todo o processo. Tudo que precisamos fazer é encontrar a pessoa na nossa base de dados que seja mais similar à nossa imagem de teste de acordo com as medidas feitas pela rede.

Você pode fazer isto utilizando qualquer algoritmo básico de classificação. Não precisamos de nenhum truque requintado de deep learning. Vamos utilizar um simples classificador SVM linear, mas qualquer outro classificador poderia ser utilizado.

Precisamos treinar o classificador que receba as medidas de entrada para uma nova imagem de teste e responda qual é a pessoa mais similar. Executar este classificador leva alguns milisegundos. O resultado do classificador é o nome da pessoa!

Agora é hora de testar nosso sistema. Primeiro, treinei o classificador com os embeddings de imagens cada Will Ferrel, Chad Smith e Jimmy Falon, 20 imagens para cada pessoa:

Dados, dados, dados!

Após o treinamento, apliquei o classificador em cada frame do famoso vídeo do YouTube onde Will Ferrell e Chad Smith fingem ser o outro no prograda do Jimmy Fallon:

Funciona! E observe que funciona bem mesmo com o rosto em diferentes ângulos — mesmo quando o rosto está de lado!

Executando o script você mesmo

Vamos revisar os passos que seguimos:

  1. Codifique a imagem usando o algoritmo HOG para criar uma versão simplificada da mesma. Usando a versão simplificada, encontre uma parte da imagem que seja mais similar a um HOG genérico de uma face.
  2. Descubra a pose do rosto através dos 68 pontos da face. Uma vez encontrados estes pontos, use-os para modificar a imagem de modo que olhos e boca estejam centralizados.
  3. Use a imagem centralizada como entrada para uma rede neural que tenha sido treinada para gerar medidas de faces. Salve estas 128 medidas.
  4. Utilizando todas as faces que já mensuramos antes, veja qual pessoa tem as medidas mais similares à medidas do rosto desconhecido. Esta é a pessoa!

Agora que você já sabe como tudo funciona, aqui estão as instruções do inicio ao fim para executar todo o processo de reconhecimento facial no seu próprio computador:

Atualização 4/9/2017: Você ainda pode seguir os passos abaixo para utilizar o OpenFace. Contudo, eu publiquei uma nova biblioteca de reconhecimento facial em Python chamada face_recognition que é muito mais fácil de instalar e utilizar. Então, recomendo que você tente o face_recognition primiro, antes de continuar com os passos abaixo!

Eu até preparei uma máquina virtual pré-configurada com o face_recognition, OpenCV, TensorFlow e vários outras ferramentas de deep learning pré-instaladas. Você pode fazer download e executá-la no seu computador facilmente. Tente utilizar esta máquina virtual se você não quer instalar todas estas bibliotecas por você mesmo!

Segue abaixo as instruições originais para utilzar o OpenFace:


Nota do autor: Se você gostou deste artigo, considere assinar a minha lista de emails Machine Learning is Fun! Só irei enviar mensagens quando eu tiver alguma coisa nova e interessante para compartilhar. Esta é a melhor maneira de ficar sabendo quando eu escrever mais artigos iguais a este.

Você pode me seguir no Twitter em @ageitgey, me enviar email diretamente ou me encontrar no linkedin. Eu vou adorar poder ajudá-lo ou a sua equipe com aprendizagem de máquina.

Agora, continue a jornada com Aprendizagem de Máquina é Divertida Parte 5!