Aprendizagem de Máquina é Divertido! Parte 3

Deep Learning e Redes Neuronais Convolutivas

Josenildo Costa da Silva
Machina Sapiens
15 min readJun 13, 2016

--

Nota: 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ê está cansado de ler inúmeras notícias sobre deep learning e não entender realmente o que significa? Vamos mudar isto!

Desta vez, vamos aprender como escrever programas que reconhecem objetos em imagens usando deep learning. Em outras palavras, vamos explicar a magia negra que permite o Google Photos encontrar suas fotos baseado no conteúdo da imagem:

Google permite procurar suas fotos por descrição — mesmo que elas não tenham anotações! Como isto funciona??

Assim como na Parte 1 e na Parte 2, este guia é para qualquer um que está curioso sobre aprendizagem de máquina mas não tem a menor ideia de por onde começar. O objetivo é ser acessível a todos — o que significa que há um monte de generalizações e omissão de detalhes. Mas quem se importa? Se este post fize com que alguém fique mais interessado em aprendizagem de máquina, a missão foi cumprida!

(Se você ainda não leu a Parte 1 e Parte 2, faça isso agora mesmo!)

Reconhecendo Objetos com Aprendizagem Profunda

xkcd #1425 (View original here)

Talvez você conheça esta tirinha do xkcd.

A piada é baseada na ideia de que qualquer criança de 3 anos de idade pode reconhecer a foto de um pássaro, mas fazer o computador reconhecer objetos tem desafiado os melhores cientistas da computação por mais de 50 anos.

Nos últimos anos, finalmente foi encontrada uma boa abordagem para reconhecimento de objetos usando deep convolutional neural networks. Isto soa como um monte de palavras inventadas de um romance de fição científica de William Gibson, mas as ideias são totalmente compreensíveis se você analisá-las um por uma em separado.

Então vamos lá — vamos escrever um programa que reconhece pássaros!

Inicio Simples

Antes de aprendermos como reconhecer fotos de pássaros, vamos aprender como reconher algo mais simples — o número “8” manuscrito.

Na Parte 2, aprendemos como redes neuronais podem resolver problemas complexos encadeando vários neuronios simples. Nós criamos uma pequena rede neuronal para estimar o preço de um imóvel baseado em quantos quartos ela possui, a área construída, e qual o bairro:

Também sabemos que a ideia de aprendizagem de máquina é que o mesmo algoritmo básico pode ser utilizado com dados diferentes para resolver problemas diferentes. Assim, vamos modificar esta mesma rede neuronal para reconhecer texto escrito. Mas para tornar a tarefa realmente simples, vamos tentar reconhecer apenas uma letra — o número “8”.

Aprendizagem de máquina só funciona se você possuir dados — de preferência uma grande quantidade de dados. Então, precisamos de um monte de “8”s manuscritos pra começo de conversa. Por sorte, pesquisadores criaram o dataset MNIST de números manuscritos exatamente para isto. MNIST possui 60.000 imagens de dígitos manuscritos, cada um no formato de 18x18 pixels. Aqui estão alguns exemplos deste dataset:

Alguns números 8 do dataset MNIST

Se você pensar bem, tudo é número

A rede neuronal que construimos na Parte 2 tinha apenas 3 números de entrada (“3” quartos, “200” metros quadrados, etc.). Mas agora queremos processar imagens com nossa rede neuronal. Como é que vamos passar imagens como entrada em uma rede neuronal ao invés de apenas números?

A resposta é incrivelmente simples. Uma rede neuronal recebe números como entrada. Para um computador, uma imagem é apenas uma grade com números que representa o nível de luminosidade de cada pixel:

Para passar uma imagem para nossa rede neuronal, vamos simplesmente tratar a imagem de 18x18 pixels como um vetor de 324 números:

Para receber 324 entradas, vamos aumentar nossa rede neuronal para ter 324 nodos de entrada:

Observe que nossa rede neuronal também tem duas saídas agora (e não apenas uma). A primeira saída prediz a probabilidade de uma imagem ser um número “8” e a segunda saída prediz a probabilidade dela não ser um “8”. Como a rede tem duas saídas separadas para cada tipo de objeto que queremos reconhecer, ela poderá ser utilizada para classificar objetos em grupos.

Nossa rede neuronal é bem maior que a última (324 entradas ao invés de 3). Mas qualquer computador moderno pode dar conta de uma rede neuronal com algumas centenas de nós sem piscar. Isto rodaria sem problemas até mesmo em nosso smatphone.

Agora é só treinar nossa rede neuronal com imagens de “8”s e de não-“8”s para que ela aprenda a distinguí-los. Quando nós passarmos um “8”, nós iremos dizer que a probabilidade da imagem ser um “8” é 100% e que a probabilidade de ser um outro dígito é 100%. E vice-versa para os exemplos contrários.

Aqui está uma amostra do nossos dados de treinamento:

Humm… dados de treinamentos!

Podemos treinar este tipo de redes neuronais em alguns minutos em um computador moderno. Quando terminar, teremos uma rede neuronal que pode reconhecer imagens de “8”s com alta acurácia. Bem-vindos ao mundo do reconhecimento de imagens (da era do final dos anos 1980)!

Visão de Túnel

É realmente impressionante que apenas alimentando a rede neuronal com pixels tenha sido suficiente para criar um reconhecedor de imagens! Aprendizagem de Máquina é mágico! … certo?

Bem, é claro que não é tão simples assim.

Primeiro, a boa notícia é que nosso reconhecedor de “8” realmente funciona bem em imagens simples onde o dígito está centralizado na imagem:

Mas agora as más notícias:

Nosso reconhecedor de “8” falha completamente quando o dígito não está perfeitamento centralizado na imagem. Basta uma pequena variação nada mais funciona:

Isto se deve ao fato de que nossa rede foi exposta apenas a padrões de “8” perfeitamente alinhados. A rede não tem a menor ideia do que seja um “8” fora do centro. Ela aprendeu exatamente um padrão, e um padrão apenas.

Isto não é muito útil no mundo real. Problemas reais nunca são limpos e simples. Então, precisamos descobrir uma maneira de fazer nossa rede neuronal funcionar em casos onde o “8” não esteja perfeitamente centralizado.

Ideia de Força Bruta n. 1: Busca com janela deslizante

Até aqui, criamos um programa realmente bom em reconhecer um “8” centralizado em uma imagem. E se varrêssemos toda a imagem em seções menores, uma seção por vez, até encontrarmos um “8”?

Esta abordagem é chamada de janela deslizante (sliding window). É uma solução de força bruta. Funciona bem apenas em casos limitados, mas é muito ineficiente. Você precisa verificar a mesma imagem repetidas vezes procurando por objetos de tamanhos diferentes. Podemos fazer melhor que isto!

Ideia de Força Bruta n. 2: Mais dados e Rede Neuronal Profunda

Quando treinamos nossa rede, mostramos a ela apenas “8”s que eram perfeitamente centralizados. E se treinarmos a rede com mais dados, incluindo “8”s em todas as posições diferentes e tamanhos de imagem?

Nós nem vamos precisar coletar novos dados de treinamento. Podemos escrever um script para gerar novas imagens de “8”s de várias posições diferentes na imagem:

We created Synthetic Training Data by creating different versions of the training images we already had. This is a very useful technique!

Utilizando esta técnica, podemos facilmente criar um suprimento infinito de dados de treinamento.

A quantidade de dados maior torna o problema mais difícil para a rede neuronal resolver, mas podemos compensar isto tornando nossa rede neuronal maior e, portanto, capaz de aprender padrões mais complexos.

Para tornar a rede maior, vamos adicionar várias novas camadas intermediárias de nodos:

Isto é chamado de “deep neural network” porque tem mais camadas que uma rede neuronal tradicional.

Esta ideia já existe desde o final dos anos 1960. Mas até recentemente, treinar uma rede neuronal muito grande era lento demais para ser útil. Mas uma vez que descobrimos como utilizar placas gráficas 3D (que foram criadas para realizar multiplicação efficiente de matrizes) ao invés de processadores normais, trabalhar com redes neuronais de repente se tornou viável. Na verdade, a mesma placa de vídeo NVIDIA GeForce GTX 1080 que você usa para jogar Overwatch pode ser utilizada para treinar uma rede neuronal bem rápido.

Mas apesar de podermos tornar nossa rede neuronal realmente grande e treiná-la rapidamente com uma placa gráfica 3D, isto ainda não é o suficiente para nos levar a uma solução. Precisamos de uma abordagem mais inteligente para processar as imagens para nossa rede neuronal.

Vamos pensar sobre isto. Não faz sentido treinar uma rede para reconhecer um “8” no topo de uma imagem separadamente de treiná-la pra reconher um “8” na parte de baixo da imagem como se fossem dois objetos totalmente diferentes.

Deve haver uma maneira de fazer a rede neuronal perceber que um “8” em qualquer lugar da figura é a mesma coisa sem treinamento extra. Felizmente … existe uma maneira!

A Solução é a Convolução

Nós humanos sabemos intuitivamente que imagens apresentam uma hierarquia ou estrutura de conceitos. Considere a imagem seguinte:

Uma criança em seu cavalo de brinquedo (fonte: Adam Geitgey)

Temos a capacidade de reconhecer instantâneamente a hieraquia nesta imagem:

  • O piso está coberto de grama e concreto
  • Há uma criança
  • A criança está sentada em um cavalinho de balanço
  • O cavalo de balanço está sobre a grama

O mais importante é que reconhecemos a ideia de uma criança não importa qual a superfície em que ela esteja. Não temos que reaprender o conceito de criança para cada possível superficie em que ela possa aparecer.

Mas por enquanto, nossa rede neuronal não pode fazer isto. Ela pensa que um “8” em uma área diferente da imagem é uma coisa totalmente diferente. Ela não entende que mover um objeto na imagem não a torna uma coisa diferente. Por isto ela tem que reaprender a identificar cada objeto em todas as posições possíveis. Isto é uma droga.

Precisamos dar a nossa rede neuroanal a compreensão de invariância de translação (translation invariance) — um “8” é um “8” não importa em qual local da imagem ele apareça.

Vamos fazer isto usando um processo chamado convolução (convolution). A ideia da convolução é inspirada parcialmente por ciência da computação e parcialmente pela biologia (i.e. cientistas malucos literalmente cutucando o cérebro de gatos com sondas estranhas para descobrir como os gatos processam imagens).

Como Funciona a Convolução

Ao invés de passar imagens inteiras para nossa rede neuronal como uma grade de números, vamos fazer algo mais inteligente que se baseia na ideia de que um objeto é o mesmo não importa onde ele apareça em uma imagem.

Aqui detalhamos a ideia geral, passo a passo.

Passo 1: Divida a imagem em recortes sobrepostos

Similar à nossa busca com janela deslizante acima, vamos passar uma janela deslizante na imagem original e salvar cada resultado como uma imagem menor em separado:

Ao fazermos isto, transformamos nossa imagem original em 77 recortes menores e de tamanho igual.

Passo 2: Passe cada recorte para uma rede neuronal menor

Antes, passamos uma imagens simples para a rede neuronal para descobrir se havia um “8”. Vamos fazer exatamente a mesma coisa aqui, mas vamos fazer isto com cada recorte de imagem individual:

Repita isto 77 vezes, uma para cada recorte de imagem.

Há, entretanto, um pulo do gato: vamos manter os mesmos pesos da rede neuronal para cada recorte da imagem original. Em outras palavras, vamos tratar cada recorte de imagem igualmente. Se alguma coisa aparecer em algum recorte, vamos marcar este recorte como interessante.

Passo 3: Salve os resultados de cada recorte em um novo vetor

Não vamos perder de vista a organização original dos recortes. Deste modo, salvamos o resultado de processar cada recorte em uma grade que possui a mesma organização que a imagem original. Como mostrado a seguir:

Ou seja, iniciamos com uma grande imagem e ao final ficamos com um vetor bem menor que registra quais seções de nossa imagem são as mais interessantes.

Passo 4: Redução por amostragem (downsampling)

O resultado do passo anterior foi um vetor que mapeia quais partes da imagem original é mais interessante. Mas o vetor é ainda muito grande:

Para reduzir o tamanho do vetor, tiramos uma amostra (downsample) com um algoritmo chamado max pooling. Parece pomposo, mas não é nada disso!

Max pooling analisa cada quadrado 2x2 do vetor e mantem os números maiores:

A intuição aqui é que se encontrarmos alguma coisa interessante em algum dos retângulos de saída que compõe cada região 2x2, vamos manter apenas a parte mais interessante. Isto reduz o tamanho do nosso vetor enquanto mantem as partes mais interessantes.

Passo final: faça uma predição

Até aqui, reduzimos uma imagem gigante a um vetor bem pequeno.

Adivinhe? Este vetor é apenas um punhado de números, então podemos utilizar estes números em uma outra rede neuronal. Esta rede neuronal final decidirá se a imagem contém um objeto ou não. Para diferenciá-lo da rede utilizada no passo da convolução, vamos chamá-la de rede “completamente conectada”.

Em resumo, do inicio até o final, nosso processo de cinco passos pode ser explicado assim:

Adicionando Mais Passos

Nosso processo possui vários passos: convolução, max-pooling, e uma rede completamente conectada ao final.

Ao resolver problemas no mundo real, estes passos podem ser combinados e empilhados tanto quanto for necessário! Você pode ter duas, três ou até mesmo dez camadas de convolução. Você pode adicionar uma max pooling onde quer que você queira reduzir o tamanho dos seus dados.

A ideia básica é começar com uma imagem grande e continuamente tranformá-la, passo a passo, até finalmente chegar a um resultado final. Quanto mais passos de convolução você adicionar, maior a capacidade da rede de aprender a reconhecer padrões complexos.

Por exemplo, o primeiro passo de convolução pode aprender a reconher bordas pontiagudas, o segundo passo de convolução pode aprender a reconhecer bicos usando o conhecimento de bordas pontiagudas, e a terceira camada de convolução pode aprender a reconher um pássaro inteiro usando o conhecimento de bicos, etc.

Um exemplo de uma rede convolutiva profunda mais realista (típica de artigos de pesquisa) é mostrada a seguir:

Neste caso, a rede recebe uma imagem de 224x224 pixels, aplica uma convolução e duas max pooling, aplica convolunção mais três vezes, aplica max pooling e então utiliza duas camadas completamente conectadas. O resultado final é que a imagem classificada em uma de 1000 categorias!

Construindo a rede mais adequada

Mas como saber quais passos são necessários combinar para ter um classificador que funcione?

Honestamente, você tem que responder isto fazendo muitos experimentos e testes. Você pode ter que treinar 100 redes antes de encontrar a estrutura ótima e os parâmetros para o problema que você está resolvendo. Aprendizagem de máquina envolve muita tentativa e erro!

Construindo Nosso Classificador de Pássaros

Agora finamente sabemos o suficiente para escrever um programa que decide se uma imagem é um pássaro ou não.

Como sempre, precisamos de dados para começar. O dataset gratuito CIFAR10 contém 6.000 imagens de pássaros e 52.000 imagens de coisas que não são pássaros. Mas para adicionar ainda mais dados, vamos também adicionar o dataset Caltech-UCSD Birds-200–2011 que tem outras 12.000 imagens de pássaros.

Aqui uma amostra dos pássaros no nosso dataset combinado:

E aqui mais 52.000 imagens que não são pássaros:

Este dataset é bom o suficiente para nossos propósitos, mas 72.000 imagens de baixa resolução é ainda muito pequeno para uma aplicação do mundo real. Se você deseja performance no nível da Google, você precisa milhões de imagens em alta resolução. Em aprendizagem de máquina, ter mais dados é quase sempre mais importante do que ter melhores algoritmos. Agora que você sabe porque o Google te oferece tão alegremente espaço ilimitado para armazenamento de fotos. Eles querem seus preciosos dados!

Para construir nosso classificador, vamos utilizar TFLearn. TFlearn é uma extensão de alto nível para a biblioteca TensorFlow de aprendizagem profunda do Google, que apresenta uma API simplificada. Ela torna a construção de redes neuronais convolutivas bem mais simples, exigindo apenas poucas linhas de código para definir as camadas da rede.

Aqui está o código para definir e treinar a rede:

Se você está utilizando uma boa placa de vídeo com suficiente memória RAM (como a Nvidia GeForce GTX 980 Ti ou superior), o treinamento deve levar pouco menos que uma hora. Se você utilizar uma CPU normal, irá levar muito mais tempo.

À medida que a rede treina, a acurácia irá aumentar. Depois da primeira iteração, obtenho 75.4% de acurácia. Depois de 10 rodadas, já atinge 91.7%. Depois de 50 iterações a rede estabiliza em torno de 95.5% de acurácia e qualquer treino adicional não ajuda, então decidi parar.

Parabéns! Nosso programa agora pode reconher pássaros em imagens!

Testando Nossa Rede

Agora que treinamos nossa rede neuronal, podemos utilizá-la! Aqui tem um script simples que recebe uma imagem e prevê se é um pássaro ou não.

Para ver realmente quão efetiva é nossa rede, precisamos testá-la com muitas imagens. O dataset que eu criei separa 15.000 imagens para a validação. Quando eu passo estas 15.000 imagens para a rede, ela prediz corretamente a resposta 95% das vezes.

Parece bom, não? Bem … depende!

Quão bom é 95% de acurácia?

Nossa rede afirma ter 95% de acurácia. Mas o diabo mora nos detalhes. Isto pode significar várias coisas diferentes.

Por exemplo, e se 5% de nossas imagens de treinamento fossem pássaros e os outros 95% fossem não-pássaros? Um programa que só respondesse “não é pássaro” iria ter 95% de acurácia! Mas também seria 100% inútil.

Precisamos analisar com mais detalhes os resultados além da acurácia. Para julgar quão bom um sistema de classificação realmente é, precisamos saber como ele falhou, não apenas a percentagem das vezes em que ele falhou.

Ao invés de pensar sobre nossas predições como “certo” e “errado”, vamos dividí-las em quatro categorias separadas.

  • Primeiro, aqui estão alguns dos pássaros que a rede identificou corretamente como pássaros. Vamos chamá-los de Verdadeiros Positivos (true positives):
Uau! Nossa rede pode identificar muitos tipos diferentes de pássaros corretamente!
  • Segundo, aqui estão as imagens que nossa rede classificou corretamente como “não-pássaros”. Estes serão chamados Verdadeiros Negativos (true negatives):
Cavalos e caminhões não nos enganam!
  • Terceiro, aqui estão algumas imagens que a rede identificou como pássaros mas não tinham pássaro algum. Estes são os Falsos Positivos (false positives):
Vários aviões são confundidos com pássaros! Isto faz sentido.
  • E finalmente, aqui estão algumas imagens de pássaros que a rede não identificou como pássaros. Estes são os Falsos Negativos (false negatives):
Estes pássaros nos fizeram de bobos! Avestruzes estúpidas! Eles realmente contam como pássaros?

Usando nosso conjunto de 15.000 imagens para validação, calculamos quantas vezes nossas predições caíram em cada categoria:

Por que detalhamos nossos resultados desta forma? Porque nem todos os erros são criados iguais.

Imagine se estivéssemos escrevendo um programa para detectar câncer a partir de uma imagem de ressonância magnética. Se nós estivéssemos detectando câncer, seria preferível ter falsos positivos que falsos negativos. Falsos negativos seria o pior dos casos possíveis — quando o programa diz a alguém que ele definitivamente não tem câncer mas ele tem.

Ao invés de simplemente observar a acurácia geral, vamos calcular as métricas Precisão e Revocação (precision e recall). Precisão e revocação (as vezes também traduzido em português como cobertura ou sensibilidade) nos dão uma visão mais clara do desempenho do classificador:

Este resultado nos diz que 97% da vezes que previmos “pássaro”, estávamos certos! Mas também nos diz que apenas encontramos 90% dos pássaros no dataset. Em outras palavras, podemos não encontrar todos os pássaros, mas temos bastante certeza quando encontramos um!

Para onde ir agora

Agora que você sabe o básico sobre redes convolutivas profundas, você pode tentar alguns exemplos que vem com o tflearn para botar a mão na massa e testar diferentes arquiteturas de redes. O tflearn traz ainda datasets prontos, para que você nem tenha que preparar suas próprias imagens.

Você também sabe o suficiente para começar a explorar outras áreas de aprendizagem de máquina. Por que não aprender como usar algoritmos para treinar computadores para jogar Atari em seguida?

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.

Nota do Tradutor: Se você quiser receber mais artigos em portugês sobre o mesmo tema, assine minha lista de emails abaixo.

--

--