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…
The Adagrad Optimization Algorithm (with PyTorch)

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:
- 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
- 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.
- 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.
- 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:
- 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.
- Memory Intensive: Adagrad requires storing the historical sum of squared gradients for each parameter, which can be memory-intensive for large models.
- 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:
- RMSProp: RMSProp modifies Adagrad by introducing a decay factor to the accumulation of squared gradients, preventing the learning rate from decaying too aggressively.
- Adam: Adam combines the ideas of momentum and RMSProp, offering a more robust and widely applicable optimization algorithm.
- 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
- Data Preparation:
- A synthetic binary classification dataset is generated using
make_classificationfromsklearn. - The dataset is split into training and testing sets, and the features are converted to PyTorch tensors.
- Model Definition:
- A simple feedforward neural network (
SimpleNN) is defined with one hidden layer and ReLU activation.
3. Loss Function and Optimizer:
- The
CrossEntropyLossis used for classification tasks. - The
Adagradoptimizer is initialized with a learning rate of0.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:
- Be sure to clap and follow the writer ️👏️️
- Follow us: **X | [LinkedIn](https://www.linkedin.com/company/inplainenglish/) | [YouTube](https://www.youtube.com/channel/UCtipWUghju290NWcn8jhyAw) | [Newsletter](https://newsletter.plainenglish.io/) | [Podcast](https://open.spotify.com/show/7qxylRWKhvZwMz2WuEoua0)**
- **Check out CoFeed, the smart way to stay up-to-date with the latest in tech 🧪**
- **Start your own free AI-powered blog on Differ** 🚀
- **Join our content creators community on Discord** 🧑🏻💻
- For more content, visit **plainenglish.io + [stackademic.com](https://stackademic.com/)**
메타데이터
- 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