Coletânea Python do ZERO às Redes Neurais Artificiais
Classificação de Imagens de Animais – Bichos Dataset
Classificação de Imagens de Animais – Bichos
Dataset
Avançando um pouco mais com nossos estudos sobre redes neurais convolucionais, foi entendido o processo de transformação de uma imagem para formatos de arquivos suportados pelas ferramentas de redes neurais. Também fiemos um breve entendimento sobre a forma como podemos treinar um modelo para que este aprenda a identificar características e a partir desse aprendizado, realizar previsões, porém até o momento estávamos nos atendo a modelos de exemplo das bibliotecas em questão.
Na prática, quando você precisar criar um identificador e classificador de imagem este será de uma base de objetos muito diferente dos exemplos anteriores. Em função disso neste tópico vamos abordar o processo de aprendizado de máquina com base em um conjunto de imagens de gatos e cachorros, posteriormente nossa rede será treinada para a partir de seu modelo, identificar novas imagens que fornecermos classificando-as como gato ou cachorro. Note que agora para tentarmos trazer um modelo próximo a realidade, dificultaremos de propósito esse processo, uma vez que estamos classificando 2 tipos de animais esteticamente bastante parecidos.
O primeiro grande diferencial deste modelo que estudaremos agora é que o mesmo parte do princípio de classificar gatos e cachorros a partir de imagens separadas de gatos e cachorros obviamente, mas completamente aleatórias, de diferentes tamanhos com diferentes características, e não padronizadas como nos exemplos anteriores, dessa forma, essa base de dados que criaremos se aproxima mais das aplicações reais desse tipo de rede neural. No mesmo diretório onde criamos nosso arquivo de código extraímos a base de dados.
Dentro de dataset podemos verificar que temos duas pastas referentes a base de treino e de teste.
Abrindo training_set podemos verificar que existem as categorias cachorro e gato.
Abrindo cachorros note que temos um conjunto de dados de imagens de cachorros diversos (2000 imagens para ser mais exato) com características diversas (tamanho, formato, pelagem, etc...) e em ações diversas (posição na foto).
O interessante desse tipo de dataset é que existe muita coisa desnecessária em cada foto, objetos, pessoas, legenda, etc... e nossa rede neural terá de identificar o que é característica apenas do cachorro na foto, para dessa forma realizar previsões posteriormente.
Outro ponto interessante é que esse modelo é facilmente aplicável para classificação de qualquer tipo de objeto, e para classificação de diferentes tipos de objeto (mais de 2), a nível de base de dados a única alteração seria a criação de mais pastas (aqui temos duas, gatos e cachorros) referentes a cada tipo de objeto a ser classificado.
Como sempre, o processo se dá iniciando com as importações das bibliotecas, módulos e ferramentas que estaremos usando ao longo do código. Dessa forma criamos um novo arquivo de código de nome Bichos Dataset e damos início as importações das bibliotecas já conhecidas, única diferença é que para este modelo importamos do módulo preprocessing da biblioteca keras a ferramenta ImageDataGenerator. Esta ferramenta por sua vez será usada para gerar dados a partir de padrões reconhecidos.
Em outras palavras, estaremos usando uma base de dados relativamente pequena, a medida que a rede for encontrando padrões que ela tem certeza ser de gato ou certeza ser de cachorro, ela irá gerar uma nova imagem com indexamento próprio com tais características, facilitando o processo de reforço de aprendizado.
A ideia desta ferramenta é compensar a alta complexidade encontrada em processamento de imagens, identificar caracteres como no modelo anterior é muito fácil, identificar características minúsculas, a partir de imagens tão variadas de animais (que por sua vez possuem muitas características variáveis) é um processo bastante complexo até mesmo para redes neurais, sendo assim, nas etapas onde são aplicados métodos de aprendizagem por reforço, a rede usará de características identificadas e separadas para ganhar eficiência em seu processamento.
Na fase de executar a rede propriamente dita você verá que este modelo de rede neural sempre começa com uma margem de acertos bastante baixa e época a época ela aumenta e muito sua precisão, isto se dá por funções internas de ferramentas como a ImageDataGenerator.
Feitas as importações de forma correta podemos dar início diretamente na criação de nosso gerador, em algumas literaturas essa fase é chamada Augmentation, pois estamos justamente junto ao nosso polimento inicial dos dados, realizando o aumento de nossa base para que se tenha melhor precisão no processamento das imagens.
Para isso criamos nossa variável gerador_treino que inicializa a ferramenta ImageDataGenerator que por sua vez recebe uma série de parâmetros. O primeiro deles rescale = 1.0/255 nada mais é do que o escalonamento da imagem, rotation_range diz respeito ao fator de rotação (no sentido de angular a imagem nos dois sentidos por um ângulo pré-determinado e salvar também essas informações, horizontal_flip = True, que irá espelhar a imagem e guardar as informações da mesma espelhada, height_shift_range irá encontrar e salvar as informações referentes a possível distorção vertical da imagem e zoom_range por sua vez irá aplicar um zoom de 2% e salvar essa informação.
Note que dessa forma, não são apenas convertidos os dados brutos referentes a cada mapeamento de pixel normal, mas essas informações adicionais, quando salvas em blocos, ajudarão o interpretador e eliminar distorções e encontrar padrões mais precisos. Já para nossa variável gerador_teste é feito simplesmente a conversão de escala.
Em seguida são criadas as variáveis referentes as nossas variáveis de entradas e saídas com base nas importações das imagens. Inicialmente criamos a variável base_treino que instancia e executa nosso gerador_treino executa sua função .flow_from_directory( ) que por sua vez é capaz de ler os arquivos que estão dentro de um diretório específico, lembre-se que nossa base de dados está dividida em imagens de gatos e cachorros divididas para treino e teste dentro de pastas separadas.
Como parâmetros, inicialmente é passado o caminho da pasta onde se encontram os arquivos, em nosso caso, ‘dataset/training_set’, na sequência target_size realiza a primeira conversão para uma matriz de mapeamento 64x64, onde batch_size define a criação de blocos de 32 em 32 pixels, convertendo para binário via class_mode. Exatamente o mesmo processo é feito para nossa base_teste, apenas modificando o caminho do diretório onde se encontram as imagens separadas para teste.
Prosseguindo com nosso código hora de criar a estrutura de rede neural, onde codificamos todo aquele referencial teórico para um formato lógico a ser processado. Inicialmente criamos nosso classificador que inicializa Sequential sem parâmetros.
Em seguida é criada a primeira parte de nossa etapa de convolução, onde adicionamos uma camada onde parametrizamos que como neurônios da camada de entrada, temos uma estrutura matricial de 54 por 64 pixels em 3 camadas, que será dividida em blocos de 3x3 resultando em uma primeira camada oculta de 32 neurônios, passando pela ativação relu. Em seguida é adicionada uma camada de normalização por meio da função BatchNormalization( ), sem parâmetros mesmo.
Logo após é adicionada uma camada de polimento onde a matrix anterior 3x3 passa a ser um mapa 2x2. A seguir é repetida esta primeira etapa até o momento da dição da camada Flatten, que por sua vez irá pegar todo resultado da fase de convolução e converter para uma indexação em forma de lista onde cada valor da lista se tornará um neurônio da camada subsequente.
Na sequência é criada a fase de camadas densas da rede, onde a primeira camada delas possui em sua estrutura 128 neurônios e é aplicada a função de ativação relu.
Subsequente é feito o processo de seleção de uma amostra desses neurônios aleatoriamente para serem descartados do processo, apenas a fim de filtrar essa camada e poupar processamento, isto é feito por meio da ferramenta Dropout, parametrizada para descartar 20% dos neurônios da camada.
Finalmente é criada a camada de saída, onde haverá apenas 1 neurônio, passando pela função de ativação sigmoid em função de estarmos classificando de forma binária (ou gato ou cachorro), se fossem usadas 3 ou mais amostras lembre-se que a função de ativação seria a softmax.
Então é criada a estrutura de compilação da rede, nada diferente do usual usado em outros modelos e por fim é criada a camada que alimenta a rede e a coloca em execução, note que agora, em um modelo de rede neural convolucional, este processo se dá pela função .fit_generator( ) onde passamos como parâmetros os dados contidos em base_treino, steps_per_epoch define o número de execuções sobre cada amostra (se não houver 4000 amostras a rede irá realizar testes sobre amostras repetidas ou geradas anteriormente), epochs como de costume define que a toda a rede neural será executada 5 vezes (reforçando seu aprendizado), validation_data irá, como o próprio nome dá a ideia, fazer a verificação para ver se os dados encontrados pela rede conferem perfeitamente com os da base de teste em estrutura e por fim é definido que essa validação será feita sobre 1000 amostras aleatórias.
Selecionando e executando todo esse bloco de código, se não houve nenhum erro de sintaxe você verá a rede em execução via console.
Você irá notar duas coisas a partir desse modelo, primeira delas é que mesmo realizadas todas as conversões, o processamento da mesma é relativamente lento, uma vez que internamente existe um enorme volume de dados a ser processado.
Segundo, que este modelo de rede neural se inicia com uma margem de acertos bastante baixa (78% na primeira época de execução) e à medida que vai avançando em épocas essa margem sobe consideravelmente (na quarta época a margem de acertos era de 96%).
Por fim na última época a margem de acertos final foi de 97%, lembrando que aqui, apenas como exemplo, executamos este modelo apenas 5 vezes, em aplicações reais é possível aumentar e estabilizar essa margem ainda mais, executando a rede por mais épocas, fazendo valer mais seu aprendizado por reforço.
Uma vez realizada a execução de nossa rede neural artificial convolucional, temos em mãos um modelo pronto para ser usado para testes. Como de costume, para não nos estendermos muito aqui no livro, podemos realizar um simples teste sobre uma amostra, algo próximo da aplicação real justamente por uma rede dessa ser usada para classificar um animal a partir de uma imagem fornecida.
Para isso realizamos a importação da numpy que até o momento não havíamos utilizado nesse modelo, também realizamos a importação da ferramenta image do módulo preprocessing da biblioteca keras. Em seguida é criada a variável imagem_teste que por meio da função image.load_img( ) faz a leitura de um arquivo escolhido definido pelo usuário, apenas complementando, é parametrizado que esta imagem no processo de leitura, independentemente de seu tamanho original, será convertida para 64x64.
A imagem em questão é essa, escolhida aleatoriamente (e lembrando que apesar de sua nomenclatura “cat...” o interpretador fará a leitura, as conversões e a identificação com base nas características da imagem. Na sequência é feita a conversão da imagem propriamente dita para uma array do tipo numpy por meio da função img_to_array( ).
Em seguida é parametrizado que expand_dims permite que tais dados sejam empilhados em forma de lista por meio do parâmetro axis = 0, lembre-se que na fase onde os dados passam pela camada Flatten, eles serão convertidos para dados sequenciais que se tornarão neurônios de uma camada da rede.
Por fim, por meio da função .predict( ) é passada esta imagem pelo processamento de nossa rede para que seja identificada como tal.
O retorno neste caso foi, como esperado, que a imagem fornecida foi de fato classificada como uma imagem de um gato.
Código Completo: