Primeiros Passos com Redes Neurais — Implementação na Mão

Fernando Marcos Wittmann
Data Science BR
Published in
6 min readJul 18, 2021

OBS: Este artigo ficou na “geladeira”do meu Medium por cerca de 4 anos e originalmente escrevi quando estava aprendendo sobre o tema. Caso tenha interesse em maiores detalhes ou algo não tenha ficado claro, não deixe de conferir esta minha playlist do youtube ou o meu curso da Udemy, onde cubro os mesmos pontos com maiores detalhes.

Neste artigo vamos aprender sobre os conceitos básicos de redes neurais e implementar uma rede neural manualmente. Como metodologia, partimos de um exemplo extremamente simples e visualizável e ir adicionando complexidade aos poucos. Ao final do artigo meu objetivo é te apresentar a intuição por trás dos principais conceitos de redes neurais: perceptron, hidden layers (camadas ocultas) e otimizadores.

Perceptron

Uma rede neural nada mais é do que uma “função gigante” que busca mapear um conjunto de entradas — chamaremos de X — e saídas — chamaremos de y — a partir de parâmetros — chamaremos de w — . O bloco fundamental da construção de uma rede neural são os ‘perceptrons’ — ou unidades — representados pela seguinte figura:

Dado um conjunto de entrada X e saídas y, o objetivo das redes neurais é descobrir quais são os melhores valores dos parâmetros w que correlacionem ambos. Como saída, temos a soma do produto da entrada pelos seus respectivos pesos. Note que o primeiro parâmetro wₒ é multiplicado por 1. O mesmo é chamado de bias e tem como função fornecer a cada perceptron um valor constante e treinável (que não depende da entrada). Outra possível notação para o mesmo é bₒ. Por fim temos também a aplicação de uma função de ativação na qual converte a combinação de w com a entrada em um único número entre 0 e 1. Uma das principais funções de ativação é a função sigmóide na qual possui o seguinte formato:

Não se preocupe com a fórmula embutida. Apenas imagine que a função sigmoide nos diz o quão positivo ou negativo é um valor: quanto mais positivo, mais próximo de 1 será a saida, quanto mais negativo, mais próximo de 0. Seguem alguns exemplos em Python de saídas com as entradas 0, 25 e -5:

>>> import numpy as np
>>> sigm = lambda x: 1/(1+np.exp(-x))
>>> sigm(0)
0.5
>>> sigm(25)
0.999999999986112
>>> sigm(-5)
0.0066928509242848554

Matematicamente podemos representar a saída de um perceptron com a seguinte fórmula:

Como mencionado anteriormente, todos os pesos w são multiplicados pelas respectivas entradas x. A função sigmóide possui a notação σ(z) que nada mais é do que uma simplificação da notação 1/(1+exp(-z)). A simplificação y=σ(w x) é uma notação vetorial. Agora que já conhecemos o bloco mais básico das redes neurais, vamos utilizá-lo em um exemplo prático.

Exemplo prático: Ou-Exclusivo

Como ponto de partida, vamos criar uma rede neural que modele uma porta lógica Ou-Exclusivo (que vamos abreviar para XOR). Apesar de simples, este é um ótimo exemplo inicial pois uma fronteira de decisão linear não consegue resolver este problema. Em outras palavras, não existe uma reta que consiga dividir a classe positiva da classe negativa na seguinte figura:

Função exemplo OU-exclusivo a ser mapeada pela rede neural

Estimadores lineares como regressão logística ou linear SVM são incapazes de resolver este problema, a não ser que kernels sejam utilizados. Numericamente, a função XOR possui as seguinte tabela da verdade:

x1 x2 | y
---------
0 0 | 0
0 1 | 1
1 0 | 1
1 1 | 0

Em suma, se as entradas forem iguais, a saída será zero. Se as entradas forem diferentes, a saída será um. Observe que ambas entradas e saídas são binárias e portanto podemos considerá-lo como um problema de classificação (apesar de neste caso não haver dados de teste e preocupação com sobreajuste).

Primeira Tentativa de Solução

Intuitivamente, a primeira solução que tentaríamos neste problema seria:

Onde x e x são as entradas, y a saída e w0, w1 e w2 são os pesos a serem encontrados. A função de ativação foi omitida na imagem acima, mas continua existente. Matematicamente temos:

Nos primórdios das redes neurais, uma nas primeiras críticas foi justamente a impossibilidade de a equação acima resolver o problema XOR. Em outras palavras, não existem valores de w0, w1 e w2 que satisfazem a equação anterior. A prova é bastante simples: a equação anterior descreve a equação de uma reta e não existe reta que consiga separar a classe positiva da negativa. A seguir, veremos um aprimoramento que ajudará a resolver este problema.

Aprimoramento: Utilização de Camadas Ocultas

De forma a resolver este problema, entram as camadas ocultas ou “hidden layers”. Elas nada mais são que conjuntos de perceptrons intermediários entre a entrada e a saída. Vale ressaltar que podemos ter múltiplas camadas ocultas e cada uma com múltiplos perceptrons. A arquitetura evolui para a seguinte forma:

Note que muitos termos novos surgiram, no entanto a ideia continua a mesma. Além disso, agora estou utilizando a notação b para bias em vez de w para que fique mais intuitiva a sua identificação. Agora descobrir quais valores de pesos e vieses que precisamos para correlacionar todas as entradas e saídas torna-se mais desafiante. Será que apenas uma solução satisfaz ou existem várias possíveis soluções? Como encontrá-las? Acontece que a solução não é tão trivial (de fato, é um problema NP). Para a busca desta solução utiliza-se métodos de otimização. Existem vários métodos de otimização, como por exemplo Adam, Stochastic Gradient Descent. Buscar os valores ótimos é um pouco análogo à buscar os valores extremos (máximo ou mínimo) em uma função. O seguinte GIF ilustra alguns métodos de otimização (referência):

Cada método tem suas vantagens e desvantagens. Alguns são mais rápidos enquanto outros são mais estáveis ou precisos. Para tentar resolver na mão, criei a seguinte visualização:

Experimente trocar os pesos e ver o comportamento final. Note que cada peso tem o controle em cima de uma característica diferente da fronteira de decisão. Por fim, uma possível solução ao problema acima seria a seguinte:

Note que mesmo para um caso simples não foi tão trivial. Sem contar que mesmo para um caso simples como este, existem muitas possíveis soluções e a partir de várias possíveis tentativas. É por isso que os otimizadores estão aí para nos ajudar com essa tarefa.

Conclusão

Neste artigo nós abordamos os componentes primordiais existentes em redes neurais. Implementamos manualmente uma rede neural para resolver o problema do OU-Exclusivo. Vimos que mesmo para problemas mais simples, há vários pesos que precisam ser aprendidos, e conseguimos isso graças à utilização de otimizadores. Por fim, alguns pontos de sumário:

  • Uma rede neural nada mais é que um monte de multiplicações e somas seguidas por operações não lineares (as tais funções de ativação).
  • Cada bloco é um perceptron (ou neurônio) e combinando-os em camadas, eles podem aprender funções que representam fronteiras não lineares como o ou-exclusivo!
  • E podemos definir o aprendizado profundo (ou deep learning) como o uso de redes neurais profundas para aprender relacionamentos muito complexos.

Espero que tenham gostado, este artigo ficou na "geladeira"do meu Medium por cerca de 3 anos! Eu originalmente escrevi quando estava aprendendo sobre o tema. Caso tenha interesse em maiores detalhes ou algo não tenha ficado claro, não deixe de conferir esta minha playlist do youtube ou o meu curso da Udemy, no cubro os mesmos pontos acima com maiores detalhes.

--

--

Fernando Marcos Wittmann
Data Science BR

Head of Data Science @ Awari | Machine Learning Expert | E-Learning