Descida do Gradiente
O que é a descida do gradiente (gradient descent)
Descida do gradiente é um método iterativo de otimização de primeira ordem (first-order) para minimizar uma função objetivo (f(\theta)), onde (\theta) representa os parâmetros que você quer aprender (por exemplo, os pesos (weights) de um modelo). “De primeira ordem” significa que ele usa apenas informação de gradiente (primeiras derivadas), e não segundas derivadas como a Hessiana (Hessian).
No aprendizado de máquina (machine learning), o treinamento frequentemente se reduz ao problema:
[ \min_{\theta} ; f(\theta) ;=; \frac{1}{n}\sum_{i=1}^n \ell(\theta; x_i, y_i) ;+; \lambda,R(\theta) ]
onde:
- (\ell) é uma perda (loss) por exemplo (por exemplo, erro quadrático (squared error), entropia cruzada (cross-entropy)),
- (R(\theta)) é um regularizador (regularizer) (por exemplo, L2),
- (\lambda) controla a força da regularização.
A descida do gradiente dá passos repetidos na direção de maior decréscimo de (f), conforme indicado pelo gradiente negativo.
A descida do gradiente é fundamental para o aprendizado de máquina moderno, especialmente para treinar Redes Neurais (Neural Networks) via Retropropagação (Backpropagation), e está no núcleo de muitos métodos discutidos em Otimização Estocástica (Stochastic Optimization) e Otimização Convexa (Convex Optimization).
Regra central de atualização (update rule)
Dados os parâmetros atuais (\theta_t), a descida do gradiente atualiza:
[ \theta_{t+1} = \theta_t - \eta , \nabla f(\theta_t) ]
- (\nabla f(\theta_t)) é o gradiente (um vetor de derivadas parciais).
- (\eta > 0) é a taxa de aprendizado (learning rate) (tamanho do passo (step size)).
Por que o gradiente negativo?
O gradiente (\nabla f(\theta)) aponta na direção de maior aumento. Mover-se na direção oposta diminui a função mais rapidamente para passos pequenos.
Uma aproximação linear local de (f) em torno de (\theta_t) dá:
[ f(\theta_t + \Delta) \approx f(\theta_t) + \nabla f(\theta_t)^\top \Delta ]
Se você escolher (\Delta = -\eta \nabla f(\theta_t)), obtém:
[ f(\theta_t + \Delta) \approx f(\theta_t) - \eta |\nabla f(\theta_t)|^2 ]
Então, para (\eta) suficientemente pequeno, o objetivo diminui.
Um exemplo simples (1D)
Minimizar:
[ f(w) = (w - 3)^2 \quad\Rightarrow\quad \nabla f(w) = 2(w - 3) ]
Atualização:
[ w_{t+1} = w_t - \eta \cdot 2(w_t - 3) ]
Se (w_0 = 0) e (\eta = 0.1):
- (w_1 = 0 - 0.1 \cdot 2(0-3) = 0.6)
- (w_2 = 0.6 - 0.1 \cdot 2(0.6-3) = 1.08)
- (w_3 = 1.464), …
Isso converge para (w=3). Se (\eta) for grande demais, as atualizações podem ultrapassar o ponto e oscilar ou divergir.
Taxa de aprendizado (\(\eta\)): escolha e orientação prática
A taxa de aprendizado frequentemente importa mais do que quase qualquer outro hiperparâmetro (hyperparameter). Ela controla o compromisso entre:
- Velocidade: (\eta) grande avança rápido.
- Estabilidade: (\eta) pequeno evita ultrapassagens.
Modos comuns de falha
- (\eta) pequeno demais: o treinamento é dolorosamente lento; pode parecer “travado”.
- (\eta) grande demais: o objetivo oscila, fica instável ou diverge (a perda explode / NaNs).
Estratégias práticas
Ajuste de taxa de aprendizado (busca simples)
- Tente valores em escala logarítmica (por exemplo, (10^{-4}, 10^{-3}, 10^{-2}, 10^{-1})).
- Monitore as curvas de perda de treinamento para divergência ou estagnação.
Agendas de taxa de aprendizado (learning rate schedules)
- Decaimento em degraus (step decay): reduza (\eta) por um fator em marcos.
- Decaimento exponencial (exponential decay): (\eta_t = \eta_0 \cdot \gamma^t).
- Decaimento cosseno (cosine decay) (comum em aprendizado profundo (deep learning)).
- Aquecimento (warmup): comece pequeno e aumente no início do treinamento.
Busca linear (line search) (otimização mais clássica)
- Escolha (\eta) a cada passo para satisfazer condições como Armijo/Wolfe.
- Menos comum em aprendizado profundo em larga escala devido a custo/ruído, mas importante conceitualmente.
Normalizar/escalar entradas
- O escalonamento de atributos (feature scaling) pode melhorar drasticamente o condicionamento (conditioning) efetivo, permitindo (\eta) maiores e estáveis.
- Isso se conecta ao motivo de a otimização poder ser mais fácil em problemas bem condicionados (veja Otimização Convexa).
Intuição de convergência (o que acontece ao longo do tempo)
Geometria: vales e condicionamento
Se o objetivo tiver direções estreitas e íngremes e direções largas e planas (um “vale alongado”), a descida do gradiente básica (vanilla gradient descent) tende a:
- quicar através da direção íngreme,
- progredir lentamente ao longo da direção plana.
Por isso o condicionamento (grosso modo, o quanto as curvas de nível são “esticadas”) importa. Condicionamento ruim torna a convergência lenta e sensível a (\eta).
Objetivos convexos vs não convexos (non-convex)
- Em problemas convexos, todo mínimo local é global. A descida do gradiente tem garantias fortes (sob suposições padrão de suavidade).
- Em problemas não convexos, (por exemplo, redes profundas), a descida do gradiente pode convergir para:
- mínimos locais,
- pontos de sela (muito comuns em altas dimensões),
- regiões planas/platôs.
Mesmo sem garantias globais, métodos de gradiente funcionam bem na prática para muitos modelos de aprendizado de máquina devido à estrutura, sobreparametrização (overparameterization) e efeitos estocásticos.
Garantias teóricas típicas (alto nível)
Assuma que (f) é convexa e tem gradiente (L)-Lipschitz (L-Lipschitz gradient) (“(L)-suave (L-smooth)”). Então, com (\eta \le 1/L), a descida do gradiente produz um objetivo não crescente e converge.
Taxas comuns (informais):
- Convexa, suave: a suboptimalidade (suboptimality) frequentemente diminui como (O(1/t)).
- Fortemente convexa (strongly convex), suave: diminui geometricamente (convergência linear (linear convergence)), como (O(\rho^t)) para algum (\rho<1).
Em cenários não convexos, uma garantia comum é a convergência para um ponto estacionário (stationary point) (um ponto onde (|\nabla f(\theta)|) é pequeno), não necessariamente um mínimo global.
Descida do gradiente em lote, estocástica e por mini-lotes
Em aprendizado de máquina, (f(\theta)) geralmente é uma média sobre pontos de dados. As três variantes principais diferem em quanto dado elas usam para estimar o gradiente.
Descida do gradiente em lote (batch gradient descent) (descida do gradiente completa)
Usa o conjunto de dados inteiro (dataset) a cada passo:
[ \nabla f(\theta) = \frac{1}{n}\sum_{i=1}^n \nabla \ell(\theta; x_i, y_i) ]
Prós
- Atualizações estáveis, com baixa variância.
- O objetivo diminui suavemente (em cenários determinísticos).
Contras
- Cada passo é caro para (n) grande.
- Não é ideal para dados em fluxo (streaming data).
- Pode ser lenta em tempo de relógio (wall-clock time) mesmo que exija menos passos.
Uso típico
- Conjuntos de dados pequenos a médios.
- Objetivos convexos em que progresso preciso é valioso.
Descida do gradiente estocástica (stochastic gradient descent, SGD)
Usa um exemplo amostrado aleatoriamente (ou um conjunto muito pequeno) por passo:
[ \theta_{t+1} = \theta_t - \eta , \nabla \ell(\theta_t; x_{i_t}, y_{i_t}) ]
Prós
- Atualizações muito rápidas; escala para conjuntos de dados enormes.
- O ruído pode ajudar a escapar de mínimos locais rasos ou pontos de sela.
- Funciona naturalmente em cenários online/streaming.
Contras
- Curvas de treinamento ruidosas; o objetivo pode não diminuir monotonicamente.
- Frequentemente requer agendas de taxa de aprendizado cuidadosas.
SGD é um tópico central em Otimização Estocástica.
Descida do gradiente por mini-lotes (mini-batch gradient descent) (mais comum em aprendizado profundo)
Usa um lote de (B) exemplos:
[ g_t = \frac{1}{B}\sum_{i \in \mathcal{B}t}\nabla \ell(\theta_t; x_i, y_i), \quad \theta{t+1} = \theta_t - \eta, g_t ]
Prós
- Eficiente em GPUs/TPUs devido à vetorização (vectorization).
- Menor variância do que SGD, mais barata do que o lote completo.
- Muitas vezes, o melhor compromisso prático.
Contras
- O tamanho do lote (batch size) interage com taxa de aprendizado e generalização (generalization).
- Lotes muito grandes podem exigir ajustes especiais (por exemplo, regras de escalonamento da taxa de aprendizado (learning-rate scaling rules)).
Tamanhos típicos de lote
- Aprendizado profundo: 32–1024 (às vezes muito maior com receitas especializadas).
Exemplo prático: regressão linear com GD em lote vs por mini-lotes
Considere regressão linear (linear regression) com erro quadrático médio (mean squared error):
[ \hat{y} = Xw,\quad f(w) = \frac{1}{n}|Xw - y|^2 ]
O gradiente é:
[ \nabla f(w) = \frac{2}{n}X^\top(Xw - y) ]
Exemplo em NumPy
import numpy as np
def batch_gradient_descent(X, y, lr=0.1, steps=1000):
n, d = X.shape
w = np.zeros(d)
for _ in range(steps):
grad = (2.0/n) * X.T @ (X @ w - y)
w -= lr * grad
return w
def minibatch_gradient_descent(X, y, lr=0.1, steps=1000, batch_size=32, seed=0):
rng = np.random.default_rng(seed)
n, d = X.shape
w = np.zeros(d)
for _ in range(steps):
idx = rng.integers(0, n, size=batch_size)
Xb, yb = X[idx], y[idx]
grad = (2.0/batch_size) * Xb.T @ (Xb @ w - yb)
w -= lr * grad
return w
O que você normalmente observará:
- GD em lote: convergência mais suave em termos de perda por passo, mas cada passo é mais caro.
- GD por mini-lotes: progresso por passo mais ruidoso, mas frequentemente mais rápido até uma boa solução em tempo de relógio.
Critérios de parada (quando parar de iterar)
Na prática, você raramente executa a descida do gradiente “até a convergência” em um sentido matemático estrito. Regras comuns de parada incluem:
- Número fixo de passos/épocas (epochs)
- Norma do gradiente pequena o suficiente: (|\nabla f(\theta_t)| < \epsilon)
- Melhora pequena na perda: (f(\theta_{t-1}) - f(\theta_t) < \epsilon)
- Parada antecipada (early stopping) na perda de validação (comum em aprendizado de máquina para evitar sobreajuste (overfitting))
A parada antecipada é especialmente relevante em aprendizado profundo, onde você otimiza a perda de treinamento, mas se importa com generalização.
Armadilhas comuns e dicas de depuração (debugging)
1) Escalonamento ruim de atributos
Se um atributo tem valores em ([0, 1]) e outro em ([0, 10^6]), o relevo da perda fica mal condicionado (ill-conditioned) e o treinamento fica instável ou lento.
Correção: padronize as entradas (média zero, variância unitária), use camadas de normalização (normalization layers) em redes profundas.
2) Gradientes explosivos/desaparecendo (exploding/vanishing gradients)
Especialmente em redes profundas (por exemplo, perceptrons multicamadas (multilayer perceptrons, MLPs) profundos, redes neurais recorrentes (recurrent neural networks, RNNs)), os gradientes podem ficar extremamente pequenos ou grandes.
Correções (dependendo do modelo):
- melhor inicialização (initialization),
- normalização (BatchNorm/LayerNorm),
- recorte de gradiente (gradient clipping),
- mudanças arquiteturais (conexões residuais (residual connections)),
- otimizadores adaptativos (adaptive optimizers) (veja abaixo).
3) Taxa de aprendizado errada
Se a perda diverge rapidamente: diminua (\eta).
Se a perda quase não diminui: aumente (\eta) ou melhore o condicionamento.
4) Objetivos não suaves (non-smooth)
Alguns objetivos não são diferenciáveis em todos os pontos (por exemplo, valor absoluto, perda hinge (hinge loss)). A descida do gradiente generaliza via subgradientes (subgradients), mas o comportamento pode ser mais traiçoeiro.
Além da descida do gradiente básica (extensões comuns)
Embora este artigo foque na descida do gradiente e em suas formas em lote/SGD/por mini-lotes, a maior parte do treinamento moderno usa variantes aprimoradas que mantêm a mesma ideia central (passos iterativos usando informação de gradiente):
- Momento (momentum): acumula um vetor de velocidade para reduzir oscilações em ravinas.
- Momento de Nesterov (Nesterov momentum): momento com um gradiente de “antecipação”.
- AdaGrad: taxas de aprendizado por parâmetro, útil para atributos esparsos.
- RMSProp: média móvel de gradientes ao quadrado para estabilizar o comportamento do AdaGrad.
- Adam: momento + escalonamento no estilo RMSProp; amplamente usado como padrão em aprendizado profundo.
Ainda são métodos de primeira ordem baseados em gradiente; eles principalmente mudam como a direção do passo e as taxas de aprendizado efetivas são calculadas.
Onde a descida do gradiente se encaixa no panorama de otimização
- Em comparação com métodos de segunda ordem (second-order methods) (Newton, quase-Newton (quasi-Newton)), a descida do gradiente é mais barata por passo e escala para dimensões muito altas.
- Em comparação com métodos com restrições (constrained methods), a descida do gradiente básica assume parâmetros sem restrições. Quando restrições importam, você pode usar projeções (projections) ou técnicas baseadas em Lagrangiano/KKT (Lagrangian/KKT-based techniques) (veja Otimização com Restrições (Constrained Optimization)).
- Muitas tarefas de aprendizado de máquina são convexas (por exemplo, algumas formas de regressão linear/logística (linear/logistic regression)), mas o aprendizado profundo moderno é amplamente não convexo — ainda assim, métodos baseados em gradiente continuam sendo o cavalo de batalha.
Resumo
- Descida do gradiente minimiza um objetivo ao iterar passos na direção do gradiente negativo: [ \theta_{t+1} = \theta_t - \eta \nabla f(\theta_t) ]
- A taxa de aprendizado (\eta) controla estabilidade e velocidade; agendas e ajuste fino frequentemente são essenciais.
- O comportamento de convergência depende da geometria do objetivo (condicionamento), suavidade e se ele é convexo.
- As principais variantes práticas são:
- descida do gradiente em lote (conjunto de dados completo por passo),
- SGD (um exemplo por passo),
- descida do gradiente por mini-lotes (pequeno lote por passo; mais comum em aprendizado profundo).
- Em sistemas reais de aprendizado de máquina, a descida do gradiente frequentemente é combinada com melhor condicionamento, pré-processamento cuidadoso e extensões do otimizador (métodos estilo momento/Adam) para treinar modelos grandes com eficiência.