Inteligência Artificial

Redes neurais do zero com NumPy: entendendo backpropagation na prática

Redes neurais do zero com NumPy: entendendo backpropagation na prática

Frameworks como PyTorch e TensorFlow abstraem a complexidade das redes neurais, mas entender o que acontece por baixo é o que separa quem usa IA de quem entende IA. Vamos construir uma rede neural do zero usando apenas NumPy — sem frameworks, sem magia, apenas matemática e Python.

O neurônio artificial

Um neurônio recebe inputs, multiplica cada um por um peso (weight), soma tudo, adiciona um bias, e passa o resultado por uma função de ativação. Matematicamente: output = activation(sum(inputs * weights) + bias). Os pesos determinam a importância de cada input, o bias permite ajustar o limiar de ativação, e a função de ativação introduz não-linearidade — sem ela, a rede inteira seria equivalente a uma única transformação linear, incapaz de modelar relações complexas.

A função sigmoid transforma qualquer valor em um número entre 0 e 1, interpretável como probabilidade. ReLU (Rectified Linear Unit) retorna 0 para valores negativos e o próprio valor para positivos — simples, eficiente e resolve o problema de vanishing gradients que plagava redes profundas com sigmoid. Tanh é similar a sigmoid mas vai de -1 a 1, útil quando outputs negativos fazem sentido.

Forward pass: do input ao output

O forward pass propaga dados pela rede camada por camada. A entrada é multiplicada pela matriz de pesos da primeira camada, o bias é adicionado, a ativação é aplicada, e o resultado vira input para a próxima camada. Com NumPy, isso é uma sequência de operações matriciais: np.dot para multiplicação de matrizes, soma vetorial para bias, e aplicação element-wise da função de ativação.

Uma rede com uma hidden layer de 4 neurônios e output de 1 neurônio é implementada em menos de 20 linhas de NumPy. O forward pass inteiro é: hidden = sigmoid(np.dot(X, W1) + b1); output = sigmoid(np.dot(hidden, W2) + b2). Simples, legível, e exatamente o que frameworks fazem internamente — só que sem a mágica invisível.

Loss function: medindo o erro

A loss function quantifica quão longe as predições estão dos valores reais. Para classificação binária, binary cross-entropy é a escolha padrão: -mean(y * log(pred) + (1-y) * log(1-pred)). Ela penaliza predições confiantes e erradas muito mais que predições incertas — se o modelo diz 0.99 para algo que é 0, a penalidade é enorme, incentivando calibração.

Para regressão, mean squared error (MSE) é o padrão: mean((y – pred)^2). A escolha da loss function impacta diretamente como o modelo aprende — ela é o feedback que o gradiente descendente usa para ajustar os pesos na direção certa.

Backpropagation: o coração do aprendizado

Backpropagation calcula o gradiente da loss em relação a cada peso da rede, aplicando a regra da cadeia do cálculo diferencial de trás para frente. Para o output layer: calcula-se o erro (predição – real), multiplica-se pela derivada da função de ativação, e obtém-se o gradiente dos pesos dessa camada. Para camadas anteriores: o erro é propagado para trás usando os pesos da camada seguinte, multiplicado pela derivada da ativação local.

A derivada de sigmoid é elegantemente simples: sigmoid(x) * (1 – sigmoid(x)). A derivada de ReLU é ainda mais simples: 1 se x > 0, 0 caso contrário. Com NumPy, toda a backpropagation é implementável em poucas linhas de operações matriciais: dW2 = np.dot(hidden.T, d_output); dW1 = np.dot(X.T, d_hidden). Os pesos são atualizados subtraindo o gradiente multiplicado pela learning rate.

Treinamento e convergência

O loop de treinamento repete forward pass, cálculo da loss, backpropagation e atualização dos pesos por N epochs. A learning rate controla o tamanho de cada passo — muito alta e o modelo oscila sem convergir, muito baixa e o treinamento é lento demais. Valores como 0.01 a 0.001 são pontos de partida razoáveis.

Monitore a loss a cada 100 epochs: ela deve diminuir consistentemente. Se estagna, experimente uma learning rate maior ou uma arquitetura com mais neurônios. Se oscila, reduza a learning rate. Se cai drasticamente e depois sobe, você tem overfitting — reduza a complexidade ou adicione regularização.

Do NumPy ao PyTorch

Depois de entender cada componente, migrar para PyTorch é natural. Tudo que fizemos manualmente — forward pass, cálculo de gradientes, atualização de pesos — é exatamente o que PyTorch faz com autograd, nn.Module e optim.SGD. A diferença é que PyTorch calcula gradientes automaticamente, roda em GPU, e oferece camadas pré-implementadas e otimizadas. Mas agora você sabe o que essas abstrações escondem — e esse conhecimento é o que permite debugar, otimizar e inovar quando os frameworks não resolvem sozinhos.

Tem um projeto em mente?

Somos especialistas em transformar ideias em produtos digitais. Apps, sites, automações e IA — vamos construir juntos.

Resposta rápida Orçamento sem compromisso +100 projetos entregues
Compartilhar: