Redes Neurais: o Cérebro Artificial
Redes neurais são inspiradas (vagamente) no cérebro humano. Mas não se deixe enganar pela analogia — o que realmente importa é a matemática por trás. Um neurônio artificial é uma função: recebe números, multiplica por pesos, soma e passa por uma não-linearidade. Empilhe milhões desses e você tem o sistema que reconhece rostos, traduz idiomas e gera texto. Neste módulo, vamos abrir essa caixa preta: do neurônio individual até backpropagation, loss functions, overfitting e as técnicas de regularização que fazem tudo funcionar.
O neurônio artificial, de verdade
Pesos (w) são os números que o modelo aprende durante o treino. Bias (b) é um deslocamento que permite ao neurônio ativar mesmo quando todas as entradas são zero. A função de ativação (f) introduz não-linearidade — sem ela, empilhar 100 camadas seria o mesmo que ter uma só (composição de lineares é linear).
Arquitetura: camadas empilhadas
A profundidade (número de hidden layers) dá nome ao deep learning. Camadas iniciais aprendem features simples (bordas, texturas); camadas profundas compõem essas features em representações abstratas (rostos, objetos, conceitos). Cada camada faz a mesma coisa: multiplicação matricial + bias + ativação.
Universal Approximation Theorem: uma rede com uma única hidden layer e neurônios suficientes pode aproximar qualquer função contínua. Na prática, redes mais profundas (deep) são mais eficientes: aprendem as mesmas funções com menos parâmetros do que redes rasas e largas.
Forward pass e loss function
O forward pass é simplesmente passar os dados pela rede da entrada até a saída, camada por camada. O resultado é uma previsão. A loss function mede quão longe essa previsão está do valor correto:
| Loss Function | Quando usar | Fórmula (intuição) |
|---|---|---|
| MSE (Mean Squared Error) | Regressão (prever um número) | Média de (predição - real)². Penaliza erros grandes mais que pequenos. |
| Cross-Entropy | Classificação (prever uma classe) | -Σ(y_real × log(y_pred)). Se a rede diz 90% gato e era gato, loss baixa. Se diz 10%, loss altíssima. |
| Binary Cross-Entropy | Classificação binária (sim/não) | Caso especial da cross-entropy com 2 classes. |
A loss é o único número que a rede tenta minimizar. Tudo que o modelo "aprende" durante o treino é ajustar os pesos para reduzir essa loss. A escolha da loss function errada pode fazer o modelo convergir para algo inútil.
Backpropagation: como o modelo aprende
Backpropagation é o algoritmo que calcula quanto cada peso contribuiu para o erro e em que direção ajustá-lo. Funciona em 3 passos:
A chain rule do cálculo é o coração: o gradiente de cada camada depende do gradiente da camada seguinte, multiplicado pelas derivadas locais. Assim o erro se propaga da saída até a entrada — cada peso sabe exatamente quanto e em que direção se mover.
Vanishing gradient: em redes muito profundas com sigmoid/tanh, os gradientes são multiplicados por valores < 1 em cada camada, encolhendo exponencialmente. Camadas iniciais mal treinam. Soluções: ReLU, skip connections (ResNet), batch normalization.
Learning rate: o passo do aprendizado
O learning rate (lr) controla o tamanho do passo em cada atualização. lr = 0.001 é um ponto de partida comum. Alto demais: o treino oscila e diverge. Baixo demais: converge tão devagar que parece não aprender. Otimizadores modernos (Adam, AdamW) adaptam o learning rate por parâmetro, mas o valor inicial ainda importa muito.
Funções de ativação comparadas
| Ativação | Fórmula | Range | Gradiente | Quando usar |
|---|---|---|---|---|
| Sigmoid | 1 / (1 + e^(-x)) | (0, 1) | Máx 0.25 — satura | Saída binária (probabilidade) |
| Tanh | (e^x - e^(-x)) / (e^x + e^(-x)) | (-1, 1) | Máx 1.0 — satura | Saída centrada em zero (raro hoje) |
| ReLU | max(0, x) | [0, ∞) | 0 ou 1 — sem saturação | Default para hidden layers ✅ |
| Leaky ReLU | max(0.01x, x) | (-∞, ∞) | 0.01 ou 1 | Quando dying ReLU é problema |
| GELU | x × Φ(x) | (-∞, ∞) | Suave | Transformers (GPT, BERT) |
| Softmax | e^xᵢ / Σe^xⱼ | (0, 1) soma=1 | — | Última camada de classificação multi-classe |
Regra prática: use ReLU nas hidden layers (ou GELU se estiver em Transformers). Use sigmoid na saída de classificação binária. Use softmax na saída multi-classe. Nunca use sigmoid em hidden layers profundas.
Skip connections: o segredo das redes profundas
Redes muito profundas (100+ camadas) sofriam com um problema fundamental: o gradiente desaparecia antes de chegar às camadas iniciais (vanishing gradient), e as camadas extras não ajudavam — ou até pioravam o desempenho. A ResNet (2015) resolveu isso com uma ideia elegante: skip connections (ou residual connections).
A insight: em vez do bloco aprender a transformação completa H(x), ele aprende apenas o resíduoF(x) = H(x) - x. Se o bloco não for necessário, F(x) → 0 e a rede simplesmente passa o input adiante (identidade). Com isso, o gradiente tem um caminho direto da saída até as camadas iniciais — sem multiplicações que o encolhem.
Skip connections são a razão pela qual LLMs funcionam com 96+ camadas. Sem elas, GPT-4 não existiria. Toda arquitetura Transformer moderna usa residual connections em cada bloco de atenção e feed-forward.
Normalização: BatchNorm vs LayerNorm
Durante o treino, as distribuições das ativações mudam a cada batch (covariate shift interno). Isso instabiliza o treino e exige learning rates menores. Normalização resolve: padroniza as ativações para média≈0, desvio≈1 em um determinado eixo.
Se você está construindo ou fine-tunando um Transformer (LLM, BERT, etc.), vai ver LayerNorm em todo lugar — geralmente antes de cada sub-camada (pre-norm), não depois. GPT-2 e versões mais antigas usam post-norm; LLaMA e modelos modernos usam pre-norm (mais estável).
Overfitting: o inimigo número 1
Overfitting é quando o modelo decora o dataset de treino — incluindo o ruído — e perde a capacidade de generalizar para dados novos. É a diferença entre um estudante que entende a matéria e um que decora as respostas da prova anterior.
Diagnóstico: loss de treino cai mas loss de validação sobe (ou estagna). Soluções:
| Técnica | Como funciona | Quando usar |
|---|---|---|
| Dropout | Desativa aleatoriamente X% dos neurônios em cada batch de treino — força redundância | Default em redes densas (p=0.2–0.5) |
| Regularização L2 (weight decay) | Adiciona penalidade λ×Σw² à loss — pesos grandes são punidos | Quase sempre, especialmente AdamW |
| Regularização L1 | Adiciona λ×Σ|w| — empurra pesos pra zero (sparsity) | Quando quer feature selection automática |
| Early stopping | Para o treino quando validation loss começa a subir | Sempre — é grátis |
| Data augmentation | Gera variações artificiais dos dados (rotação, flip, crop) | Quando tem poucos dados |
| Batch normalization | Normaliza ativações entre camadas — estabiliza treino | Redes convolucionais, redes profundas |
Train, Validation e Test: os 3 conjuntos
Nunca use o test set pra tomar decisões durante o treino. Se fizer isso, está implicitamente overfittando no test — e o número final não vale nada. O validation set existe exatamente pra isso: tomar decisões (learning rate, quando parar, qual modelo é melhor) sem contaminar a avaliação final.
Parâmetros vs hiperparâmetros
Tipos de rede neural
📋 Classificar imagens (gato, cachorro, carro)
CNNs têm camadas convolucionais que detectam padrões espaciais (bordas, texturas, formas) sem precisar de cada pixel como input independente. Muito mais eficiente que MLP para imagens.
Alt: MLP (fully connected) —
📋 Prever próxima palavra em uma sequência
Transformers processam toda a sequência em paralelo com mecanismo de atenção — superam RNNs em escala e qualidade. São a base de todos os LLMs.
Alt: RNN/LSTM —
Na prática: treino em Python
import torch
import torch.nn as nn
# Rede simples: 784 inputs → 256 hidden → 10 classes
model = nn.Sequential(
nn.Linear(784, 256), # camada 1: 784×256 + 256 = 200.960 params
nn.ReLU(), # ativação
nn.Dropout(0.3), # regularização: desliga 30% por batch
nn.Linear(256, 10), # camada de saída: 256×10 + 10 = 2.570 params
)
loss_fn = nn.CrossEntropyLoss() # loss pra classificação
optimizer = torch.optim.Adam(model.parameters(), lr=0.001)
# 1 epoch de treino
for images, labels in train_loader:
pred = model(images) # forward pass
loss = loss_fn(pred, labels) # calcula loss
loss.backward() # backpropagation (calcula gradientes)
optimizer.step() # atualiza pesos
optimizer.zero_grad() # limpa gradientes pro próximo batch São 14 linhas. É isso que acontece debaixo de todo framework de ML. loss.backward() é o backpropagation. optimizer.step() é w = w - lr × grad.
Perguntas típicas (Q&A)
❓ Mais camadas é sempre melhor?
❓ Batch normalization e dropout podem ser usados juntos?
❓ Qual a diferença entre epoch, batch e iteration?
Take-aways: (1) Um neurônio = soma ponderada + ativação. (2) Backpropagation propaga o erro da saída à entrada via chain rule. (3) A loss function define o que o modelo otimiza — escolha errada, resultado errado. (4) Overfitting é o inimigo #1 — dropout, regularização L2, early stopping e data augmentation são suas armas. (5) ReLU é o default em hidden layers; sigmoid/softmax só na saída. No próximo módulo: como tudo isso resultou nos LLMs.
Próximos passos sugeridos
Discussão
Carregando…