Back-End

4 out, 2018

Implementação e análise de RNA com Python

100 visualizações
Publicidade

Tenho percebido duas pequenas dificuldades quando falamos de IA. A primeira advém da matemática e a dificuldade de entender um algoritmo de IA e sua manipulação dada a sua natureza. A segunda é a própria implementação da matemática em forma de código. Hoje, faremos uma simples implementação de RNA em Python e levantaremos alguns pontos de discussão.

Matemática

Nas outras edições da revista, vocês puderam observar que os algoritmos de IA são baseados, por exemplo, em equações integrais e diferenciais, álgebra linear, matrizes e funções trigonométricas. O ideal é entender o conceito de todos estes subterfúgios matemáticos, porém, graças a funções computacionais já prontas, você consegue implementar sem saber exatamente como essa base de cálculo funciona.

Embora o conhecimento matemático não seja imprescindível, é altamente recomendável que você estude estes conceitos. Abordaremos esta necessidade no tópico discussão.

Classes e bibliotecas Python

Para facilitar a criação da nossa RNA em Python, utilizaremos as seguintes classes e bibliotecas. Como vimos no tópico anterior, para desenvolver um algoritmo de RNA precisamos utilizar álgebra linear, e no Python temos uma biblioteca chamada Numpy que é utilizada para este fim. Caso seu compilador não tenha, basta instalar o pacote.

Outro ponto muito utilizado em RNA é a própria construção da rede, que como já vimos anteriormente, é baseada em neurônios artificiais, camadas e pesos. Temos vários exemplos de codificação de RNA pronta na internet, é importante sabermos como estes códigos funcionam para fazemos as modificações necessárias para nosso problema ou mesmo para iniciarmos do zero, caso tenhamos algum problema específico a ser resolvido. Abaixo vamos explicar um modelo comum.

No Python, temos uma classe chamada Network.

No constructor temos o parâmetro syze que recebe o número de neurônios de cada camada.

Sendo assim, para criarmos uma rede com cinco neurônios na primeira camada, dois na segunda e quatro na última, basta instanciarmos o seguinte objeto da classe Network

Rede = Network([5,2,4])

Também neste constructor podemos observar que o bias e os pesos são inicializados aleatoriamente por meio da função: np.random.randn.

Esta função gerará distribuições gaussianas com 0 de média e desvio padrão de 1. Este não é o modo ideal de inicializarmos os pesos e o bias, mas é um ponto inicial. Na sequência é necessário utilizar uma função de ativação.

Implementação

Existem várias arquiteturas de RNA, Deep Feed Forward, Radial Basis Network, Perceptron, Feed Forward, Sparse AE e muitas outras. Neste algoritmo será utilizada a arquitetura Feed Forward. Para termos ideia da complexidade de cálculos realizados para cada tipo de arquitetura, seguem dois exemplos diferentes.

Feed Forward
Deep Feed Forward

Agora é necessário aplicar esta rede feed forward à classe Network. O método feed forward aplica a equação sigmoid em cada camada da nossa rede neural.

Até este ponto, a RNA já está basicamente implementada, entretanto, ela ainda não é capaz de aprender, pois falta o dataset e a descida estocástica do gradiente (SGD) que é o algoritmo padrão de aprendizagem para RNA. Existem outros algoritmos que podem ser utilizados.

Segue abaixo a implementação do SGD e a implementação do data set por meio do training_data.

O training_data é uma série de tuplas com entradas e saídas esperadas (aprendizagem supervisionada). Epochs e mini_batch_size são as variáveis que representam os resultados esperados e eta é a taxa de aprendizagem. Nos argumentos você também pode ver o test_data, que é opcional.

Caso o argumento seja fornecido, o algoritmo imprimirá o resultado parcial após cada período de treinamento. É extremamente útil esse tipo de utilização, caso você queira inserir rastreabilidade no seu processo de aprendizagem, porém, a performance é severamente afetada.

Neste código, os dados de treinamento são arrastados e particionados em mini batches. Para cada mini_batch, um passo de descida no gradiente SGD é aplicado. Então, os pesos e o bias são atualizados pelo update_mini_batch.

Nesta atualização do mini_batch você consegue identificar o algoritmo backpropagation funcionando. Este algoritmo calcula o gradiente da função de custo. Mas não estudaremos isso neste momento.

Discussão

Durante o artigo nós falamos sobre uma chamada função de ativação e propositadamente não a explicamos. Aqui, é importante nos atentarmos ao fato de porque precisamos entender a matemática, mesmo sabendo que muitas das funções já estão prontas e implementadas nas próprias bibliotecas.

Funções de ativação são necessárias para ajustarmos a saída de nossos neurônios. Você pode pensar que alterar o valor do peso manualmente seja suficiente para corrigir uma saída inesperada para uma que seja esperada.

Entretanto, este tipo de alteração pode fazer com que a saída do neurônio correspondente aja de forma correta, entretanto, todo o resto da rede pode agir de maneira incorreta. Sendo assim, utilizamos a função de ativação da seguinte maneira:

Esta função de ativação basicamente define se um neurônio deve ou não ser ativado. Esta decisão é tomada baseada na relevância da informação que o neurônio produz. Dada função de ativação, nada mais é que outra camada matemática adicionada ao processo.

Porém, esta camada matemática é imprescindível para que seu algoritmo tenha realmente uma inteligência e não esteja apenas aplicando uma regressão linear. Regressões lineares não são técnicas ruins, muito pelo contrário; sua importância é fundamental em várias aplicações de IA, porém, apenas a implementação da regressão linear não pode ser chamada de IA.

Agora, imagine: se você souber como manipular matematicamente esta função e não apenas utilizá-la matemagicamente, você será capas de alterá-la ou até mesmo criar outra função e, assim, desenvolver um algoritmo que trará maior assertividade para o seu programa.

As bibliotecas e as classes nos auxiliam (e muito!) no desenvolvimento dos nossos modelos. Porém, quanto maior o seu conhecimento em matemática, maior será a sua facilidade de manipular estas bibliotecas e, assim, melhorar a performance da sua aplicação.

***

Artigo publicado na revista iMasters, edição #27: https://issuu.com/imasters/docs/imasters_27_issuu