Uma leve explicação sobre Redes Neurais e a matemática por trás dela.
Introdução
Redes Neurais são sistemas de computação com nós interconectados que funcionam como os neurônios do cérebro humano. Usando algoritmos, elas podem reconhecer padrões escondidos e correlações em dados brutos, agrupá-los e classificá-los, e — com o tempo — aprender e melhorar continuamente.
Elas são aplicadas em diversos tópicos, como : visão computacional, processamento de linguagem natural e otimização, ou seja, é uma ferramenta que possui uma grande abrangência em seu uso.
Vamos começar com o exemplo de um neurônio biológico(figura 1) e posteriormente de um neurônio artificial (NA) (figura 3).
Neurônio Biológico
Os estímulos se propagam sempre no mesmo sentido: são recebidos pelos dendritos, seguem pelo corpo celular, percorrem o axônio e, da extremidade desse, são passados à célula seguinte (dendrito — corpo celular — axônio). A figura abaixo ilustra a transmissão desses impulsos nervosos
O Neurônio artificial (NA) funciona de forma similar, uma informação chega, é processada e por fim é retornado um valor, o resultado.
Neurônio Artificial
O NA é chamado de Perceptron, com apenas ele, é possível construir a “Rede” mais simples possível, porém, infelizmente, ela é muito limitada para resolver problemas. Todo o Perceptron possui pesos, uma função de ativação e um bias associado. Esse exemplo possui apenas 3 pesos, todavia isso muda dependendo da quantidade de entradas.
1.As entradas podem ser resultados de outros neurônios, assim são formadas as Redes Neurais
2.O bias sempre vai ter o valor 1 e um peso, visto que é considerado uma entrada.
3.Os pesos são iniciados de maneira aleatória, normalmente entre -1 e 1.
Matemática do “impulso nervoso”
Nesse processo, os valores de entrada são multiplicados pelos seus respectivos pesos (conexões) e depois são somados (soma ponderada), após isso, a soma será usada em uma função de ativação retornando a nossa resposta !.
Na figura 3 as entradas são 1(bias), 2 e 4 e os pesos 0.3, 0.4 e 0.2, respectivamente, multiplicamos os pesos pelas entradas e depois somamos, o resultado é 1.9. Por fim, utilizamos esse valor, 1.9, em uma função de ativação (que nesse caso é a step function) e teremos o resultado, 1.
Rede Neural (RN)
A partir do Perceptron, podemos formar RNs, apenas precisamos agrupar os neurônios em camadas e depois ligá-los com os pesos, esse tipo de rede é bastante conhecida como Multilayer Perceptron.
1.Não confunda essas 2 bolinhas da camada de entrada com neurônios !, é apenas uma forma ilustrativa para os valores de entrada.
2.Nesse exemplo não está incluso os bias, mas, se tivesse, seriam 3 ( 1 para cada camada intermediária e 1 para a de saída).
Feedforward
Todo esse processo matemático explicado anteriormente acontece para todos os neurônios da nossa RN e é chamado de feedforward , seriam os “impulsos nervosos”, sempre tomando esse sentido, da esquerda para a direita.
O processo de “aprendizagem” da RN
Até agora, apenas vimos como funciona a propagação das informações da nossa Rede e quais são os seus componentes (entradas, camadas, pesos, função de ativação e bias).
O processo de aprendizagem consiste em encontrar o melhor conjunto de pesos que generalizem os nossos dados, mas como fazer isso ?
Usaremos um otimizador bastante conhecido para RNs, o Gradiente descendente, juntamente com o backpropagation e uma função de perda para fazermos a atualização dos nossos pesos e encontrar o melhor conjunto.
Função de perda
Essa função é utilizada para sabermos como o nosso algoritmo esta se saindo nas predições e como devemos atualizar os nossos pesos, ou seja, ela é de suma importância para o aprendizado da rede.
Existem vários tipos de funções de perda e cada uma é melhor em determinados problemas e situações.
Gradiente descendente
Se você esta usando uma função que indica o erro de cada previsão de sua rede, qual o valor que você mais deseja que ela retorne ? o mínimo, é claro. Então é ai que entra o nosso otimizador.
O gradiente é um vetor contendo todas as derivadas parciais de suas variáveis e ele indica em que sentido e direção devemos ir para ter o maior valor resultante da função. Tendo isso em vista, cada derivada parcial indica em que direção e sentido aquela determinada variável deve seguir para aumentarmos a resultante.
Mas, se precisamos chegar ao menor valor da função de perda, como ele vai nos ajudar ? É simples, apenas indo para o sentido e direção contrários ao gradiente, isto é, apenas seguir o valor negativo das derivadas parciais, que no nosso caso são as parciais dos pesos.
Nesse gráfico, os eixos X e Y seriam 2 pesos da nossa rede e Z o nosso erro.
A cada treinamento, os valores dos pesos são atualizados e o erro diminui seguindo essa “descida”, ganhando assim outro nome , descida do gradiente.
O alfa se chama taxa de aprendizagem e serve pra controlar o quanto atualizaremos os pesos. Dessa forma, você pode interpretar como sendo o tamanho dos “passos” até chegar no valor mínimo.
1.O valor da taxa de aprendizagem é escolhido pela pessoa, porém é normal começar com valores pequenos.
Vamos colocar em prática utilizando um Perceptron e a tabela AND.
Os valores de entrada serão os elementos da coluna 1 e 2 e o resultado esperado será a ultima coluna, por exemplo, daremos os números 0 e 0 como entrada e esperamos que a rede retorne 0.
Elementos do nosso Perceptron
Função de ativação
Existem várias funções de ativação e cada uma é empregada em determinadas situações e camadas, por exemplo, a função sigmoide é muito usada na ultima camada e quando temos um problema de classificação binária, pois ela retorna valores de 0 a 1, o que se encaixa perfeitamente em nosso problema.
Função de perda
Utilizaremos a função chamada de mean squared error ( erro quadrático médio) em que “n” é a quantidade de exemplos que a rede irá utilizar antes de atualizar os pesos. Ela é muito utilizada para problemas de regressão, situações em que precisamos predizer um valor numérico.
1.Nos atualizaremos os pesos a cada exemplo, ou seja, o valor de “n” será 1. Esse método é chamado de Descida do Gradiente Estocástica.
Cálculo das parciais
Para fazer os cálculos necessários você precisa ter noção sobre : derivadas, derivadas parciais e regra da cadeia (as 2 primeiras são um pouco óbvias).
Como “n” é igual a 1, então a nossa função de perda ficará assim: (y — ý)², em que “y” e é resposta da rede e “ý” é a resposta correta.
1.Tenha em mente que Y = g(x1 * w1 + x2 * w2 + w3)
Veja que precisamos aplicar a regra da cadeia, pois existem 2 funções : a principal ,( )², e a secundária, y — ý.
Aplicando a regra da cadeia:
Lembre-se que estamos calculando a derivada parcial em relação a um peso, logo o ý’ irá sair , pois é considerado uma constante.
Teremos que aplicar a regra da cadeia novamente, porém na função g(x).
Derivando em relação ao peso w1:
Pronto, encontramos a parcial do peso w1.
As derivadas dos outros pesos ficarão assim:
São as derivadas parciais dos pesos w2 e w3, respectivamente.
Antes de colocar a “mão na massa”, vamos deixar essas contas com um melhor visual utilizando a regra delta. Se você olhar com um pouco de atenção ,perceberá que o seguinte termo se repete.
Chamaremos esse termo de Delta, então ficará assim:
Criando o algoritmo
Começaremos importando a biblioteca numpy, pois ajudará na manipulação de matrizes e na criação da nossa base de dados:
Base de Dados
Nossa base de dados possui 4 linhas e 3 colunas. As duas primeiras colunas são nossas entradas e a ultima é o resultado esperado que a rede retorne.
Pesos
Iniciaremos os pesos de forma aleatória entre -1 e 1.
Função de ativação
Treinamento
Na descida do gradiente estocástica é recomendado que você embaralhe os seus dados a cada atualização de peso, pois evita que sua rede sofra algum viés, por exemplo, “se acostumar” com a sequência dos dados.
Impulso e backpropagation
A parte da atualização se chama backpropagation, pois é como se estivéssemos fazendo uma retro propagação calculando o nosso erro e atualizando os pesos.
1.Utilizei erro = y — ý para não calcularmos novamente no Delta.
2.O valor que escolhi para a taxa de aprendizagem foi 0.5.
Código do “treinamento” completo:
Perceba que o nosso erro esta diminuindo :).
Decidi fazer esse tópico, pois a maioria dos sites, vídeos e livros estão em inglês e são abordados, as vezes, de uma forma complexa, então eu resolvi falar sobre o assunto para ajudar outras pessoas que queiram aprender e estão começando como eu.
Referências
- https://www.sas.com/pt_br/insights/analytics/neural-networks.html#:~:text=Redes%20neurais%20s%C3%A3o%20sistemas%20de,tempo%20%E2%80%93%20aprender%20e%20melhorar%20continuamente.
- https://pt.khanacademy.org/math/multivariable-calculus/multivariable-derivatives/partial-derivative-and-gradient-articles/a/the-gradient
- https://matheusfacure.github.io/2017/02/20/MQO-Gradiente-Descendente/
- https://medium.com/@davivc/um-mergulho-profundo-na-matem%C3%A1tica-por-tr%C3%A1s-das-redes-neurais-77994b87a2ab