← Back to list

The Adagrad Optimization Algorithm (with PyTorch)

Today I am starting a series of blog posts about optimization algorithms beyond simple gradient descent. Optimization algorithms play a…

Francesco Franco in Artificial Intelligence in Plain English · 2025-01-30 09:39 · 11 claps · 7.6 min read
#optimization-algorithms #adagrad #deep-learning #python-programming #data-science
Open on Medium ↗
Wiki topics: ML · Machine Learning EDU · Education & Learning 💻 · Programming 🔬 · Science · General

The Adagrad Optimization Algorithm (with PyTorch)

Source: https://www.youtube.com/watch?v=EGt-UOIIdDk

Source: https://www.youtube.com/watch?v=EGt-UOIIdDk

Today I am starting a series of blog posts about optimization algorithms beyond simple gradient descent. Optimization algorithms play a crucial role in training neural networks. They determine how the model’s parameters are updated during the learning process, ultimately influencing the speed and quality of convergence. Among the many optimization techniques available, Adagrad (Adaptive Gradient Algorithm) stands out as an innovative approach that adapts the learning rate for each parameter individually. This article explores the Adagrad algorithm, its mechanics, advantages, and limitations.

Let’s get started!

What is Adagrad?

Adagrad, introduced by John Duchi, Elad Hazan, and Yoram Singer in 2011, is an adaptive learning rate optimization algorithm designed to address the challenges of sparse data and varying parameter updates in neural networks. Unlike traditional gradient descent methods that use a fixed learning rate for all parameters, Adagrad dynamically adjusts the learning rate based on the historical gradients of each parameter.

The key idea behind Adagrad is to give frequently updated parameters a smaller learning rate and infrequently updated parameters a larger learning rate. This adaptation is particularly useful for dealing with sparse data, where certain features may appear rarely but carry significant importance.

How Does Adagrad Work?

Adagrad modifies the standard gradient descent update rule by incorporating a per-parameter learning rate. Here’s a step-by-step breakdown of the algorithm:

  1. Gradient Computation: For each iteration, compute the gradient of the loss function with respect to the model parameters:

where θ_t​ represents the parameters at time step t, and J(θ_t​) is the loss function.

2. Accumulate Squared Gradients: Adagrad maintains a running sum of the squares of the gradients for each parameter:

Here, G_t​ is a diagonal matrix where each diagonal element corresponds to the sum of squared gradients for a specific parameter.

3. Update Parameters: The parameters are updated using the following rule:

where:

  • η is the initial learning rate,
  • square root of G_t+ϵ​ scales the learning rate adaptively for each parameter,
  • ϵ is a small constant (e.g., 10^−8) to prevent division by zero.

Key Features of Adagrad

  1. Per-Parameter Learning Rates: Adagrad adapts the learning rate for each parameter individually, making it well-suited for problems with sparse gradients or uneven feature frequencies.
  2. Automatic Learning Rate Decay: The learning rate decreases over time as the sum of squared gradients grows. This property helps the algorithm converge more effectively, especially in convex optimization problems.
  3. No Manual Tuning: Adagrad eliminates the need to manually tune the learning rate, which can be a significant advantage for practitioners.

Advantages of Adagrad

  • Effective for Sparse Data: Adagrad performs exceptionally well on sparse datasets, where certain features are rarely active but highly informative.
  • Adaptive Learning Rates: By adjusting the learning rate for each parameter, Adagrad can navigate complex loss landscapes more efficiently than fixed learning rate methods.
  • Robustness: The algorithm is less sensitive to the choice of the initial learning rate, making it easier to use in practice.

Limitations of Adagrad

Despite its advantages, Adagrad has some notable drawbacks:

  1. Aggressive Learning Rate Decay: The accumulation of squared gradients causes the learning rate to shrink excessively over time. In non-convex optimization problems, this can lead to premature convergence or stagnation.
  2. Memory Intensive: Adagrad requires storing the historical sum of squared gradients for each parameter, which can be memory-intensive for large models.
  3. Not Ideal for All Problems: While Adagrad excels in sparse settings, it may underperform in dense or non-convex optimization scenarios.

Variants of Adagrad

To address the limitations of Adagrad, several variants have been developed that we will go into further in future posts:

  1. RMSProp: RMSProp modifies Adagrad by introducing a decay factor to the accumulation of squared gradients, preventing the learning rate from decaying too aggressively.
  2. Adam: Adam combines the ideas of momentum and RMSProp, offering a more robust and widely applicable optimization algorithm.
  3. Adadelta: Adadelta eliminates the need for an initial learning rate by using a window of past gradients to scale updates.

When to use adagrad?

Adagrad is particularly useful in the following scenarios:

  • Training models on sparse datasets, such as natural language processing (NLP) tasks.
  • Problems where feature frequencies vary significantly.
  • Situations where manual tuning of the learning rate is impractical.

However, for dense datasets or non-convex optimization problems, newer algorithms like Adam or RMSProp are often preferred.

Implementing Adagrad using PyTorch

Step 1: Import required libraries.

import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScalar

Step 2: Generate a synthetic dataset.

# Create a binary classification dataset
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)
# Convert data to PyTorch tensors
X_train = torch.tensor(X_train, dtype=torch.float32)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.long)
y_test = torch.tensor(y_test, dtype=torch.long)

Step 3: Define a simple neural network model:

class SimpleNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(SimpleNN, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        out = self.fc1(x)
        out = self.relu(out)
        out = self.fc2(out)
        return out
# Initialize the model
input_size = 20  # Number of features
hidden_size = 10  # Number of neurons in the hidden layer
output_size = 2   # Number of classes
model = SimpleNN(input_size, hidden_size, output_size)

Step 4: Define the loss function and optimizer

criterion = nn.CrossEntropyLoss()  # Loss function for classification
optimizer = optim.Adagrad(model.parameters(), lr=0.01)  # Adagrad optimizer

Step 5: Train the model

num_epochs = 50
batch_size = 32

for epoch in range(num_epochs):
    model.train()  # Set the model to training mode
    for i in range(0, len(X_train), batch_size):
        # Get mini-batch
        X_batch = X_train[i:i+batch_size]
        y_batch = y_train[i:i+batch_size]

        # Forward pass
        outputs = model(X_batch)
        loss = criterion(outputs, y_batch)

        # Backward pass and optimization
        optimizer.zero_grad()  # Clear gradients
        loss.backward()        # Compute gradients
        optimizer.step()       # Update weights

    # Print loss every 10 epochs
    if (epoch + 1) % 10 == 0:
        print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

Step 6: Evaluate the model

model.eval()  # Set the model to evaluation mode
with torch.no_grad():
    # Forward pass on the test set
    outputs = model(X_test)
    _, predicted = torch.max(outputs, 1)

    # Calculate accuracy
    accuracy = (predicted == y_test).sum().item() / y_test.size(0)
    print(f'Test Accuracy: {accuracy * 100:.2f}%')

Explanation of the code

  1. Data Preparation:
  • A synthetic binary classification dataset is generated using make_classification from sklearn.
  • The dataset is split into training and testing sets, and the features are converted to PyTorch tensors.
  1. Model Definition:
  • A simple feedforward neural network (SimpleNN) is defined with one hidden layer and ReLU activation.

3. Loss Function and Optimizer:

  • The CrossEntropyLoss is used for classification tasks.
  • The Adagrad optimizer is initialized with a learning rate of 0.01

4. Training Loop:

  • The model is trained for 50 epochs using mini-batch gradient descent.
  • The loss is printed every 10 epochs to monitor progress.

5. Evaluation:

  • The model is evaluated on the test set, and the accuracy is calculated.

Full Model code

The complete program is available below if you are just interested in getting started with that.

# Step 1: Import Required Libraries
import torch
import torch.nn as nn
import torch.optim as optim
from sklearn.datasets import make_classification
from sklearn.model_selection import train_test_split
from sklearn.preprocessing import StandardScaler

# Step 2: Generate a Synthetic Dataset
# Create a binary classification dataset
X, y = make_classification(n_samples=1000, n_features=20, n_classes=2, random_state=42)
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2, random_state=42)

# Convert data to PyTorch tensors
X_train = torch.tensor(X_train, dtype=torch.float32)
X_test = torch.tensor(X_test, dtype=torch.float32)
y_train = torch.tensor(y_train, dtype=torch.long)
y_test = torch.tensor(y_test, dtype=torch.long)

# Step 3: Define a Simple Neural Network Model
class SimpleNN(nn.Module):
    def __init__(self, input_size, hidden_size, output_size):
        super(SimpleNN, self).__init__()
        self.fc1 = nn.Linear(input_size, hidden_size)
        self.relu = nn.ReLU()
        self.fc2 = nn.Linear(hidden_size, output_size)

    def forward(self, x):
        out = self.fc1(x)
        out = self.relu(out)
        out = self.fc2(out)
        return out

# Initialize the model
input_size = 20  # Number of features
hidden_size = 10  # Number of neurons in the hidden layer
output_size = 2   # Number of classes
model = SimpleNN(input_size, hidden_size, output_size)

# Step 4: Define the Loss Function and Optimizer
criterion = nn.CrossEntropyLoss()  # Loss function for classification
optimizer = optim.Adagrad(model.parameters(), lr=0.01)  # Adagrad optimizer

# Step 5: Train the Model
num_epochs = 50
batch_size = 32

for epoch in range(num_epochs):
    model.train()  # Set the model to training mode
    for i in range(0, len(X_train), batch_size):
        # Get mini-batch
        X_batch = X_train[i:i+batch_size]
        y_batch = y_train[i:i+batch_size]

        # Forward pass
        outputs = model(X_batch)
        loss = criterion(outputs, y_batch)

        # Backward pass and optimization
        optimizer.zero_grad()  # Clear gradients
        loss.backward()        # Compute gradients
        optimizer.step()       # Update weights

    # Print loss every 10 epochs
    if (epoch + 1) % 10 == 0:
        print(f'Epoch [{epoch+1}/{num_epochs}], Loss: {loss.item():.4f}')

# Step 6: Evaluate the Model
model.eval()  # Set the model to evaluation mode
with torch.no_grad():
    # Forward pass on the test set
    outputs = model(X_test)
    _, predicted = torch.max(outputs, 1)

    # Calculate accuracy
    accuracy = (predicted == y_test).sum().item() / y_test.size(0)
    print(f'Test Accuracy: {accuracy * 100:.2f}%')

Summary

Adagrad is a pioneering adaptive learning rate algorithm that has influenced the development of many modern optimization techniques. Its ability to adjust learning rates on a per-parameter basis makes it a powerful tool for sparse data and uneven feature distributions. However, its aggressive learning rate decay and memory requirements have led to the development of more advanced variants like RMSProp and Adam.

Understanding Adagrad and its trade-offs is essential for selecting the right optimization algorithm for your neural network. While it may not always be the best choice, its contributions to the field of deep learning remain significant and enduring. Thanks for reading today’s post and keep learning!!

References

  • Duchi, J., Hazan, E., & Singer, Y. (2011). Adaptive Subgradient Methods for Online Learning and Stochastic Optimization. Journal of Machine Learning Research, 12, 2121–2159. Link to Paper-. This is the foundational paper that introduces the Adagrad algorithm and provides theoretical insights into its adaptive learning rate mechanism.
  • Goodfellow, I., Bengio, Y., & Courville, A. (2016). Deep Learning. MIT Press. Chapter 8 (Optimization for Training Deep Models) provides an overview of optimization algorithms, including Adagrad and its variants. Link to Book
  • Stanford CS231n: Convolutional Neural Networks for Visual Recognition. Optimization: Stochastic Gradient Descent. Lecture Notes. This resource provides an intuitive explanation of optimization algorithms, including Adagrad, and their role in training neural networks.
  • Towards Data Science. Understanding Optimization Algorithms in Neural Networks. Article Link. A beginner-friendly article that explains Adagrad and other optimization algorithm
  • TensorFlow Documentation. Optimizers. Link to Documentation. Provides implementation details and usage examples for Adagrad in TensorFlow.
  • PyTorch Documentation. Optimizers. Link to Documentation. Provides implementation details and usage examples for Adagrad in PyTorch.

Thank you for being a part of the community

Before you go:


메타데이터
post_id
b136c3692cb4
slug
adagrad-optimization-algorithm-for-deep-learning-b136c3692cb4
url
https://ai.plainenglish.io/adagrad-optimization-algorithm-for-deep-learning-b136c3692cb4
canonical_url
https://ai.plainenglish.io/adagrad-optimization-algorithm-for-deep-learning-b136c3692cb4
author_url
https://medium.com/@francescofranco_39234
status
ok
fetched_at
2026-07-13 06:23:13