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 /*