Otimizadores#

Os otimizadores são o “motor de convergência” de uma rede neural. Enquanto a função de perda nos diz o quão errado o modelo está, o otimizador dita a estratégia exata de como os parâmetros (pesos e vieses) devem ser ajustados para corrigir esse erro.

Através das derivadas calculadas no Backpropagation, o algoritmo de otimização define as regras para descer a superfície de erro passo a passo, em busca do mínimo global da função objetivo.

Note

O hiperparâmetro mais crítico em qualquer otimizador é a Taxa de Aprendizado ($eta$). Um valor muito alto pode fazer o modelo divergir e “explodir”, enquanto um valor muito baixo fará o treinamento demorar uma eternidade ou travar em mínimos locais.

Interface Base (Optimizer)#

class Optimizer#

Classe base abstrata para todos os algoritmos de otimização.

  • Define a interface para os métodos que atualizam os parâmetros treináveis (pesos e vieses) da rede neural com o objetivo de minimizar a função de perda \( L \).

  • A regra geral de otimização baseada em gradiente ajusta um parâmetro genérico \( \theta \) na direção oposta ao seu gradiente:

    \[ \theta_{t+1} = \theta_t - \eta \cdot \nabla_{\theta} L \]
    Onde \( \eta \) é a taxa de aprendizado. Algoritmos derivados (como Momentum, Adam) estendem essa regra introduzindo conceitos físicos (inércia) ou estatísticos (momentos).

Subclassed by GDMomentum, GradientDescent, NAG

Public Functions

inline Optimizer(float learning_rate = 0.01f)#

Construtor padrão do otimizador.

Parameters:

learning_rate – Valor inicial para a taxa de aprendizado \( \eta \). O padrão é 0.01.

virtual ~Optimizer() = default#

Destrutor virtual padrão.

  • Garante a liberação correta de memória caso otimizadores derivados (que podem alocar matrizes de estado, como velocidades) sejam destruídos.

virtual void Update(Eigen::MatrixXf &weights, Eigen::MatrixXf &biases, const Eigen::MatrixXf &grad_weights, const Eigen::MatrixXf &grad_biases) = 0#

Atualiza os parâmetros de uma camada baseando-se nos gradientes calculados.

  • Esta função aplica a regra de otimização específica para atualizar as matrizes originais de pesos ( \( W \)) e vieses ( \( b \)). Em sua forma mais canônica (Gradiente Descendente Padrão), a operação executada nas classes filhas será:

    \[ W = W - \eta \frac{\partial L}{\partial W} \]
    \[ b = b - \eta \frac{\partial L}{\partial b} \]

Parameters:
  • weights – Referência para a matriz de pesos da camada \( W \).

  • biases – Referência para o vetor de vieses da camada \( b \).

  • grad_weights – Referência constante para a matriz de gradientes dos pesos \( \frac{\partial L}{\partial W} \).

  • grad_biases – Referência constante para o vetor de gradientes dos vieses \( \frac{\partial L}{\partial b} \).

Gradiente Descedente (GradientDescent)#

class GradientDescent : public Optimizer#

Implementa o algoritmo de otimização Gradiente Descendente (Standard Gradient Descent).

  • É o método fundamental de otimização de primeira ordem para redes neurais. Ele atualiza os parâmetros do modelo iterativamente na direção oposta ao gradiente da função de perda, buscando o mínimo da função objetivo. A regra matemática de transição de estado para um parâmetro genérico \( \theta \) é definida como:

    \[ \theta_{t+1} = \theta_t - \eta \nabla_{\theta} L \]
    Onde \( \eta \) representa a taxa de aprendizado (learning rate).

Public Functions

inline GradientDescent(float learning_rate = 0.01f)#

Construtor do otimizador Gradiente Descendente.

Parameters:

learning_rate – O tamanho do passo \( \eta \) dado na direção do gradiente negativo. O valor padrão é 0.01.

virtual ~GradientDescent() = default#

Destrutor padrão.

inline virtual void Update(Eigen::MatrixXf &weights, Eigen::MatrixXf &biases, const Eigen::MatrixXf &grad_weights, const Eigen::MatrixXf &grad_biases) override#

Executa a atualização dos pesos e vieses da camada.

  • Aplica a regra algébrica clássica do Gradiente Descendente diretamente subtraindo o gradiente escalonado das matrizes de parâmetros originais:

    \[ W = W - \eta \frac{\partial L}{\partial W} \]
    \[ b = b - \eta \frac{\partial L}{\partial b} \]

Parameters:
  • weights – Referência para a matriz de pesos \( W \) da camada, que será atualizada in-place.

  • biases – Referência para o vetor de vieses \( b \) da camada, que será atualizado in-place.

  • grad_weights – Matriz constante contendo os gradientes da perda em relação aos pesos \( \frac{\partial L}{\partial W} \).

  • grad_biases – Vetor constante contendo os gradientes da perda em relação aos vieses \( \frac{\partial L}{\partial b} \).

Exemplo de Aplicação#

Abaixo está um exemplo completo de como instanciar e treinar uma rede utilizando o gradiente descendente como otimizador:

 1    Model model;
 2
 3    // Camada Oculta: 784 entradas (pixels 28x28) para 128 neurônios
 4    model.AddLayer(new DenseLayer(784, 128));
 5    model.AddLayer(new Sigmoid());
 6
 7    // Camada de Saída: 128 entradas para 10 neurônios (classes de 0 a 9)
 8    model.AddLayer(new DenseLayer(128, 10));
 9    model.AddLayer(new Softmax());
10
11    /*
12     * 3. Configurando a função de perda e o otimizador
13     */
14
15    CategoricalCrossEntropy loss_function;
16    GradientDescent optimizer(0.01f);
17
18    /*
19     * 4. Configurando os parâmetros de treinamento do modelo
20     */
21
22    int epochs = 3;
23    int batch_size = 64;
24
25
26    model.Fit(epochs, batch_size, X_train, Y_train, loss_function, optimizer);

Gradiente Descendente com Momento (GDMomentum)#

class GDMomentum : public Optimizer#

Implementa o otimizador Gradiente Descendente com Momento (Momentum).

  • Este algoritmo introduz o conceito físico de “inércia” na atualização dos parâmetros. Em vez de depender apenas do gradiente atual, ele acumula uma média móvel exponencial dos gradientes passados (velocidade). Isso ajuda a acelerar a convergência em direções consistentes e a amortecer oscilações em ravinas muito íngremes da função de perda.

  • A regra de atualização matemática para um parâmetro genérico \(\theta\) e sua respectiva velocidade \(v\) é dada por:

    \[ v_{t+1} = \gamma v_t + \eta \nabla_{\theta} L\]
    \[\theta_{t+1} = \theta_t - v_{t+1}\]
    Onde \(\eta\) é a taxa de aprendizado e \(\gamma\) é o coeficiente de momento.

Public Functions

inline GDMomentum(float learning_rate = 0.01f, float momentum = 0.01f)#

Construtor do otimizador GDMomentum.

Note

Na literatura padrão de Deep Learning, valores comuns para o momento são maiores, como 0.9 ou 0.99.

Parameters:
  • learning_rate – A taxa de aprendizado \(\eta\). O padrão é 0.01.

  • momentum – O coeficiente de momento \(\gamma\).

virtual ~GDMomentum() = default#

Destrutor padrão.

inline virtual void Update(Eigen::MatrixXf &weights, Eigen::MatrixXf &biases, const Eigen::MatrixXf &grad_weights, const Eigen::MatrixXf &grad_biases) override#

Executa a atualização dos pesos e vieses utilizando inércia.

  • Caso os parâmetros estejam sendo atualizados pela primeira vez (não existam no mapa de velocidades), uma matriz de inércia zerada é inicializada preguiçosamente (lazy initialization). Em seguida, as seguintes equações são aplicadas:

    \[v_W = \gamma v_W + \eta \frac{\partial L}{\partial W}\]
    \[W = W - v_W\]
    (O mesmo é aplicado aos vieses \(b\)).

Parameters:
  • weights – Referência para a matriz de pesos \(W\).

  • biases – Referência para o vetor de vieses \(b\).

  • grad_weights – Matriz contendo os gradientes da perda em relação aos pesos \(\frac{\partial L}{\partial W}\).

  • grad_biases – Vetor contendo os gradientes da perda em relação aos vieses \(\frac{\partial L}{\partial b}\).

Exemplo de Aplicação#

Abaixo está um exemplo completo de como instanciar e treinar uma rede utilizando o gradiente descendente com momento como otimizador:

 1    Model model;
 2
 3    // Camada Oculta: 784 entradas (pixels 28x28) para 128 neurônios
 4    model.AddLayer(new DenseLayer(784, 128));
 5    model.AddLayer(new Tanh());
 6
 7    // Camada de Saída: 128 entradas para 10 neurônios (classes de 0 a 9)
 8    model.AddLayer(new DenseLayer(128, 10));
 9    model.AddLayer(new Softmax());
10
11    /*
12     * 3. Configurando a função de perda e o otimizador
13     */
14
15    CategoricalCrossEntropy loss_function;
16    GDMomentum optimizer(0.01f, 0.01f);
17
18    /*
19     * 4. Configurando os parâmetros de treinamento do modelo
20     */
21
22    int epochs = 20;
23    int batch_size = 64;
24
25
26    model.Fit(epochs, batch_size, X_train, Y_train, loss_function, optimizer);

Gradiente Acelerado de Nesterov (NAG)#

class NAG : public Optimizer#

Implementa o otimizador Nesterov Accelerated Gradient (NAG).

  • Uma melhoria sobre o Gradiente Descendente com Momento. Enquanto o Momento padrão calcula o gradiente na posição atual e então adiciona a inércia, o Nesterov teoricamente calcula o gradiente em uma posição futura (lookahead), o que proporciona uma correção de curso mais rápida e evita oscilações excessivas ao redor de mínimos.

  • Como o cálculo do gradiente ocorre antes da etapa de otimização em nossa arquitetura, implementamos a forma algebricamente rearranjada do NAG. Para um parâmetro genérico $\theta$, velocidade $v$, taxa de aprendizado $\eta$ e momento $\gamma$, a atualização é:

    \[v_{t+1} = \gamma v_t + \eta \nabla_{\theta} L\]
    \[\theta_{t+1} = \theta_t - (\gamma v_{t+1} + \eta \nabla_{\theta} L)\]

Note

Essa formulação permite aplicar o conceito de “lookahead” do Nesterov utilizando o gradiente calculado na posição atual \(\theta_t\), mantendo o desacoplamento entre o cálculo das derivadas (camadas) e a atualização (otimizador).

Public Functions

inline NAG(float learning_rate = 0.01f, float momentum = 0.01f)#

Construtor do otimizador Nesterov Accelerated Gradient.

Parameters:
  • learning_rate – A taxa de aprendizado \(\eta\). O padrão é 0.01.

  • momentum – O coeficiente de momento \(\gamma\). O padrão é 0.01.

virtual ~NAG() = default#

Destrutor padrão.

inline virtual void Update(Eigen::MatrixXf &weights, Eigen::MatrixXf &biases, const Eigen::MatrixXf &grad_weights, const Eigen::MatrixXf &grad_biases) override#

Executa a atualização dos parâmetros utilizando a inércia de Nesterov.

  • Semelhante ao Momento padrão, a velocidade é inicializada preguiçosamente (lazy initialization). A atualização segue a variante vetorizada onde aplicamos a correção de Nesterov diretamente utilizando o gradiente recém-calculado e a nova velocidade:

    \[v_{nova} = \gamma v_{atual} + \eta \frac{\partial L}{\partial W}\]
    \[W = W - (\gamma v_{nova} + \eta \frac{\partial L}{\partial W})\]

Parameters:
  • weights – Referência para a matriz de pesos \(W\).

  • biases – Referência para o vetor de vieses \(b\).

  • grad_weights – Matriz contendo os gradientes da perda em relação aos pesos \(\frac{\partial L}{\partial W}\).

  • grad_biases – Vetor contendo os gradientes da perda em relação aos vieses \(\frac{\partial L}{\partial b}\).

Exemplo de Aplicação#

Abaixo está um exemplo completo de como instanciar e treinar uma rede utilizando o gradiente acelerado de Nesterov como otimizador:

 1    Model model;
 2
 3    // Camada Oculta: 784 entradas (pixels 28x28) para 128 neurônios
 4    model.AddLayer(new DenseLayer(784, 128));
 5    model.AddLayer(new ReLU());
 6
 7    // Camada de Saída: 128 entradas para 10 neurônios (classes de 0 a 9)
 8    model.AddLayer(new DenseLayer(128, 10));
 9    model.AddLayer(new Softmax());
10
11    /*
12     * 3. Configurando a função de perda e o otimizador
13     */
14
15    CategoricalCrossEntropy loss_function;
16    NAG optimizer(0.01f, 0.01f);
17
18    /*
19     * 4. Configurando os parâmetros de treinamento do modelo
20     */
21
22    int epochs = 20;
23    int batch_size = 64;
24
25    model.Fit(epochs, batch_size, X_train, Y_train, loss_function, optimizer);
26
27    /*