Transfer Learning com Tensorflow? Mais fácil do que você imagina…

Arnaldo Gualberto
Ensina.AI
Published in
6 min readOct 16, 2018

Talvez a maneira mais fácil, rápida e utilizada para você treinar modelos de Deep Learning em bancos de dados pequenos é a Transferência de Aprendizado (Transfer Learning). Semana passada, eu trabalhei num problema que se encaixa perfeitamente nessa descrição. Acredite ou não, eu tinha que treinar um classificador que adivinhasse se um pessoa estava usando chapéu/boné ou não.

"Hã??? Qual a utilidade disso???"

Nesse artigo, além de descobrir a utilidade de um classificador de chapéu/boné, a gente também vai ver:

  • o que é Transfer Learning (TL) afinal de contas;
  • como fazer Transfer Learning com o Tensorflow nos modelos mais conhecidos (MobileNet, Inception, etc…) com o Tensorflow Hub; e
  • como testar o seu classificador final.

Transfer Learning? Como assim?

Transfer Learning é o processo de aproveitar uma rede treinada para um dada tarefa em uma outra tarefa similar

A melhora maneira de entender essa definição é na prática. Imagine que você precisa treinar uma rede para detectar gatos. Infelizmente, você tem poucas imagens de gatos e sabe que treinar uma rede do zero não vai funcionar muito bem. Porém, você conhece uma rede muito boa para detectar cachorros. Então, você pensa: "Ora, cachorros e gatos são bem parecidos — ambos tem 4 patas, rabo, focinho, pêlos, etc… Então, eu acho que eu posso aproveitar de alguma forma essa rede treinada com cachorros para achar meus gatos também!".

E isso, meus amigos, é exatamente o que a transferência de aprendizado faz!

Para fazer o TL, nós vamos pegar uma rede já treinada em uma tarefa similar, remover a última camada (camada de classificação) e adicionar uma camada com a quantidade de neurônios necessários ao nosso problema. No meu caso, como tinha um problema de classificação binária, eu adicionei uma camada com 2 neurônios na saída. Além disso, somente essa camada adicionada será treinada, ou seja, o restante da rede não é afetada pela backpropagation.

A grade sacada do TL está justamente no treinamento da rede. Como somente a camada adicionada é treinada, em geral, para economizar tempo de treinamento, calcula-se a saída da penúltima camada (anterior aos neurônios adicionados) para todas as imagens de treinamento. Esse vetor de saída é conhecido como bottleneck features e é geralmente salvo em arquivo antes do treinamento. Quando formos treinar a rede, nós vamos passando as mesmas bottleneck features para a camada final adicionada, que vai sendo treinada normalmente. Por conta disso, o treinamento é bem rápido e costuma gerar bons resultados.

De maneira geral, você deve aplicar transfer learning quando:

  • os dados das duas tarefas são do mesmo tipo: é meio óbvio dizer isso, mas não adianta muita coisa você utilizar uma rede treinada com imagens e querer aplicar em dados de voz, por exemplo. Não é só por que a rede original foi projetada para detectar cachorros que você vai conseguir fazer com que ela aprenda a reconhecer quando alguém diz “cachorro”, por exemplo.
  • a tarefa original foi treinada com muito mais dados do que você tem: imagine que a nossa rede original foi treinada para detectar apenas uma raça de cachorro e você agora quer treinar uma rede para detectar todas as raças. Provavelmente, você vai ter que usar muito mais dados que a rede original e a sua transferência de aprendizado não vai funcionar tão bem como a gente espera.
  • o domínio dos dados é parecido: no nosso exemplo, é fácil perceber que cachorros e gatos pertencem ao mesmo domínio de dados. Logo, a transferência de aprendizagem tem tudo para funcionar. Porém, se você tem uma rede treinada inicialmente para detectar carros e quer usar a mesma rede para detectar pessoas, não há transfer learning que faça milagre! Carros e pessoas tem estruturas bem diferentes entre si, então não faz sentido aplicar TL nesse caso. Faria mais sentido, por exemplo, utilizar a rede de carros para detectar caminhões. Obviamente, tudo vai depender dos seus dados!

O Problema

Como eu disse lá em cima, eu tive que treinar um modelo para saber se uma pessoas estava usando chapéu ou não. Apesar de parecer um problema simples, resolvê-lo com visão computacional ou até mesmo machine learning clássico pode ser bem complicado. Pare para pensar um pouco e me diga como você resolveria esse problema (sem usar Deep Learning) nas imagens abaixo:

Além de diferentes modelos de boné/chapéu, repare também nas diferenças de iluminação, pose, qualidade da imagem, background, etc…

É… eu sei. É mais difícil do que parece mesmo. Mas por que, afinal, esse problema é relevante? A empresa que trabalho, dentre outras coisas, é responsável por emitir as carteiras de identidade (RG) aqui da Paraíba e alguns outros estados do Nordeste. Para isso, nós temos que garantir que a foto que uma pessoa tira para emitir no documento obedeça a +20 requisitos, entre eles: boca fechada, olhos abertos, sem óculos de sol, iluminação uniforme, ausência de sombra, etc. Dentre eles, nós também temos que garantir que a pessoa não está usando chapéu/boné (acredite, tem gente que tira foto de boné pro RG 🤦🏻‍♂️).

Por fim, antes de começar a treinar a rede, eu resolvi aplicar um pré-processamento nas imagens para facilitar o treinamento. Basicamente, eu detecto alguns pontos na face, normalizo a distância/ângulo dos olhos e recorto uma região de tamanho pré-definido acima da região dos olhos. Assim, aquelas imagens lá em cima, ficam dessa forma:

imagens normalizadas para facilitar o treinamento

Vale ressaltar que nem sempre você vai precisar aplicar um pré-processamento nas imagens. No meu caso, eu resolvi aplicar para facilitar o treinamento. Além disso, o meu pré-processamento eu tirei da minha cabeça mesmo, não foi nada baseado na literatura ou algo assim. Nos seus dados, pode ser que você nem precise aplicar um pré-processamento. Novamente: tudo depende dos seus dados!

Treinando o classificador

⚠️ O restante do tutorial é baseado no meu problema de chapéu/não-chapéu. Porém, você pode facilmente adaptá-lo pro seu problema. É só seguir as instruções e adaptá-las quando necessário.

Com os dados em mãos, vamos agora treinar o nosso modelo. Para isso, basta seguir as instruções abaixo:

  1. Crie uma pasta data que conterá as nossas imagens de treinamento. Organize as imagens de cada classe em uma pasta separada. No meu problema de chapéu/não-chapéu, minha pasta ficou assim:
data/
hat/
non-hat/

2. Baixe os scripts retrain.py e label_image.py. Coloque-os na mesma pasta que a pasta data.

3. Rode o seguinte comando:

$ python tensorflow/examples/image_retraining/retrain.py \
--image_dir data/ \
--tfhub_module https://tfhub.dev/google/imagenet/mobilenet_v1_100_224/classification/1

Dica: o script retrain.py têm diversos parâmetros de treinamento que você pode conferir executando o comando $ python retrain.py --help

A última linha do comando acima especifica o modelo que você utilizará para fazer o tranfer learning. Nesse site aqui, você pode conferir a lista completa de modelos disponibilizados pelo Tensorflow Hub. Altere a URL para o modelo que você desejar.

Dica: se seu banco de imagens tem arquivos que não são JPEG, antes de rodar o comando acima, adicione os formatos de imagem adicionais na linha 176 do arquivo retrain.py. Por exemplo:

extensions = sorted(set(os.path.normcase(ext) for ext in ['JPEG', 'JPG', 'jpeg', 'jpg', 'png', 'PNG']))

Pronto! Se tudo deu certo, em pouco tempo você verá seu classificador sendo treinado e atingindo altas taxas de acurácia em poucas epochs 🤞

Será que ficou bom?

Chegou a hora de testarmos o nosso modelo! O jeito mais fácil para testarmos em uma imagem qualquer é utilizando o script label_image.py que baixamos no começo desse tutorial.

$ python3 tensorflow/examples/label_image/label_image.py \ 
--graph=/tmp/mobilenet_0.50_192.pb \
--labels=/tmp/output_labels.txt \
--image=/path/to/image_file.jpg \
--input_mean=0 \
--input_std=255 \
--input_width=224 \
--input_height=224

⚠️ Confira os caminhos para os arquivos acima, bem como o tamanho da entrada do seu modelo. Dica: esse tamanho está no próprio nome do arquivo do modelo que você utilizou para treinar com o script retrain.py. Por exemplo: no meu caso, utilizei o modelo mobilenet_v1_100_224. Portanto, o tamanho da entrada é 224.

Quer conferir como ficou o meu modelo final? Dá uma olhada no vídeo abaixo rodando o modelo em um banco de imagens que não foi visto no treinamento:

Se tiver alguma dúvida ou sugestão, comenta aí embaixo. Estou aqui para ajudar! ✌️

Referências

--

--