Ir para o conteúdo

7. Optimization

O Gradiente Descendente é um algoritmo de otimização usado para minimizar a função de perda em modelos de aprendizado de máquina. Ele funciona ajustando iterativamente os parâmetros do modelo na direção do declive mais acentuado da função de perda, definida pelo gradiente negativo.

A ideia principal é atualizar os parâmetros do modelo na direção oposta ao gradiente:

\[\theta_{t+1} = \theta_t - \eta \nabla J(\theta_t)\]

Gradiente Descendente Puro (Vanilla)

onde:

  • \(\theta\) representa os parâmetros do modelo,
  • \(\eta\) é a taxa de aprendizado (hiperparâmetro que controla o tamanho do passo),
  • \(\nabla J(\theta)\) é o gradiente da função de perda em relação aos parâmetros.

Um Método Baseado em Gradiente é um algoritmo que encontra os mínimos de uma função, assumindo que se pode calcular facilmente o gradiente dessa função. Assume que a função é contínua e diferenciável quase em todo lugar1.

Intuição do Gradiente Descendente: Imagine estar em uma montanha em uma noite com neblina. Como você quer descer ao vale e tem visibilidade limitada, olha ao redor para encontrar a direção de descida mais acentuada e dá um passo nessa direção1.

Variantes do Gradiente Descendente

Existem várias variantes do gradiente descendente, cada uma com suas características:

  1. Batch Gradient Descent: Calcula o gradiente usando todo o conjunto de dados. Fornece uma estimativa estável do gradiente, mas pode ser lento para grandes conjuntos de dados:

    \[\theta = \theta - \eta \frac{1}{N} \sum_{i=1}^{N} \nabla J(\theta; x^{(i)}, y^{(i)})\]
    for epoch in range(num_epochs):
        gradients = compute_gradients(X, y, model)
        model.parameters -= learning_rate * gradients
    
  2. Stochastic Gradient Descent (SGD): Calcula o gradiente usando um único ponto de dados por vez. Introduz ruído no processo de otimização, o que pode ajudar a escapar de mínimos locais:

    \[\theta_{t+1} = \theta_t - \eta \nabla J(\theta_t; x^{(i)}, y^{(i)})\]
    for epoch in range(num_epochs):
        for i in range(len(X)):
            gradients = compute_gradients(X[i], y[i], model)
            model.parameters -= learning_rate * gradients
    
  3. Mini-Batch Gradient Descent: Combina as vantagens do batch e do SGD usando um pequeno subconjunto aleatório dos dados (mini-batch) para calcular o gradiente:

    \[\theta_{t+1} = \theta_t - \eta \frac{1}{B} \sum_{i=1}^{B} \nabla J(\theta_t; x^{(i)}, y^{(i)})\]
    for epoch in range(num_epochs):
        for batch in get_mini_batches(X, y, batch_size):
            gradients = compute_gradients(batch.X, batch.y, model)
            model.parameters -= learning_rate * gradients
    

Momentum

O Momentum é uma variante do gradiente descendente que ajuda a acelerar a otimização usando gradientes passados para suavizar as atualizações. Introduz um termo de "momento" que acumula os gradientes passados:

\[V_{t+1} = \beta V_t + (1 - \beta) \nabla J(\theta_t)\]
\[\theta_{t+1} = \theta_t - \eta V_{t+1}\]

\(V\) pode ser visto como uma média móvel dos gradientes. Moveremos \(\theta\) na direção do novo momento \(V\) 1.

O termo de momentum ajuda a amortecer oscilações e pode levar a uma convergência mais rápida, especialmente em cenários com gradientes ruidosos ou vales na superfície de perda.

RMSProp

RMSProp (Root Mean Square Propagation) é um algoritmo de otimização com taxa de aprendizado adaptativa que mantém uma média móvel dos gradientes ao quadrado:

\[V_{t+1} = \beta V_t + (1 - \beta) \nabla (\theta_t)^2\]
\[\theta_{t+1} = \theta_t - \eta\frac{\nabla (\theta_t)}{\sqrt{V_{t+1} + \epsilon}}\]

onde: - \(V_t\) é a média móvel dos gradientes ao quadrado, - \(\epsilon\) é uma pequena constante para estabilidade numérica.

Otimizador ADAM

ADAM (Adaptive Moment Estimation) é um algoritmo de otimização avançado que combina os benefícios do AdaGrad e do RMSProp. Mantém dois momentos para cada parâmetro:

  1. Calcular os gradientes: \(g_t = \nabla J(\theta_t)\)

  2. Atualizar o primeiro momento: \(m_t = \beta_1 m_{t-1} + (1 - \beta_1) g_t\)

  3. Atualizar o segundo momento: \(v_t = \beta_2 v_{t-1} + (1 - \beta_2) g_t^2\)

  4. Estimativas com correção de viés:

\[\hat{m}_t = \frac{m_t}{1 - \beta_1^t}, \quad \hat{v}_t = \frac{v_t}{1 - \beta_2^t}\]
  1. Atualizar os parâmetros:
\[\theta_{t+1} = \theta_t - \eta \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon}\]

Os valores padrão dos hiperparâmetros são \(\beta_1 = 0.9\), \(\beta_2 = 0.999\) e \(\epsilon = 10^{-8}\)23.

Comparison

Here's a tabular comparison to highlight key differences:

Gradient Descent (GD) Stochastic Gradient Descent (SGD) Momentum ADAM
Computational Cost per Update High (full dataset) Low (mini-batch) Low (similar to SGD) Medium (stores moments)
Convergence Speed Slow (few updates) Medium (many noisy updates) Fast (accelerates in consistent directions) Fast (adaptive + momentum)
Stability/Noise High stability, low noise Low stability, high noise Medium stability, reduced oscillations High stability, low effective noise
Adaptivity None (fixed η) None (fixed η, but can schedule) Low (momentum helps indirectly) High (per-parameter adaptation)
Best For Small datasets, convex problems Large datasets, online learning Noisy gradients, ravine-like landscapes Complex MLPs, sparse data
Common Hyperparameters Learning rate (η) Learning rate (η), batch size Learning rate (η), momentum (β ~0.9) Learning rate (η ~0.001), β1 (0.9), β2 (0.999), ε
Limitations Scalability issues; stuck in local minima Oscillations; requires tuning Can overshoot; still fixed η Potential overfitting; higher memory

In summary,

  • GD is basic but inefficient;
  • SGD adds speed at the cost of noise;
  • Momentum smooths SGD;
  • and, ADAM offers the most automation and efficiency for MLPs, though SGD/Momentum may edge out in generalization for fine-tuned tasks.

Choice depends on dataset size, computational resources, and problem complexity—experiment with validation sets for best results.


Visualização Interativa: Comparação de Otimizadores

Os otimizadores percorrem diferentes trajetórias em uma superfície de perda com um vale estreito e elíptico — um cenário clássico que desafia SGD mas favorece métodos adaptativos.

━━ SGD ━━ SGD + Momentum ━━ Adam ━━ RMSProp

Por que Adam converge mais rápido?

Adam adapta a taxa de aprendizado por parâmetro: dimensões com gradientes grandes recebem passos menores; dimensões com gradientes pequenos (como o eixo Y elíptico) recebem passos maiores. Isso corrige a anisotropia da superfície de perda automaticamente.

AdamW — Adam com Weight Decay

AdamW[^5] separa o weight decay da atualização dos momentos, o que é matematicamente mais correto:

\[\theta_{t+1} = \theta_t - \eta \cdot \frac{\hat{m}_t}{\sqrt{\hat{v}_t} + \epsilon} - \lambda \theta_t\]

onde \(\lambda\) é o coeficiente de weight decay aplicado diretamente nos pesos (não no gradiente). É o padrão em treinamento de Transformers e LLMs.

Recursos Adicionais