Optimization2011intermediate12 min read
Adaptive Subgradient Methods for Online Learning and Stochastic Optimization
أساليب التدرّج الفرعي التكيُّفية للتعلّم عبر الإنترنت والأمثَلة العشوائية
Duchi, J. · Hazan, E. · Singer, Y. — JMLR
The problem
Standard uses a single for all parameters. In problems with sparse features — natural language, recommender systems, click-through prediction — some features appear in nearly every example while others show up once in a million. A learning rate tuned for the frequent features is far too small for the rare ones, and vice versa. Practitioners spent enormous effort hand-tuning learning rate schedules per group, with no theoretical guidance.
The contribution
AdaGrad: an that gives every its own adaptive learning rate. It accumulates the sum of squared past gradients for each parameter; parameters with large accumulated gradients get smaller steps, parameters with small or rare gradients get larger steps. This is equivalent to preconditioning the by the inverse square root of a diagonal approximation to the empirical Fisher information matrix. The method comes with provable regret bounds that match the best fixed learning rate chosen in hindsight, and it requires essentially no learning rate tuning.
The impact
AdaGrad opened the era of adaptive optimizers. fixed the monotonic decay by using an exponential moving average; combined that fix with and became the default optimizer for . Shampoo extended AdaGrad's full-matrix version to practical scales. Every modern adaptive optimizer traces its lineage to AdaGrad's core insight: let the gradient history shape the geometry of the update step.
Standard is like a coach who shouts the same instruction to every player on the field — "run faster!" — regardless of whether they're a sprinter who's been running all game or a goalkeeper who just got the ball for the first time.
AdaGrad replaces that one-size-fits-all coaching with a personal diary for each player. The sprinter's diary is full of entries, so the coach whispers "small adjustments now." The goalkeeper's diary is nearly empty, so the coach shouts "big move — make it count!"
The result: every player gets exactly the guidance their history warrants. Frequent features converge smoothly; rare but informative features catch up fast.
The problem: one learning rate cannot serve all parameters
In standard SGD, every parameter gets the same learning rate . The update rule is simple:
where is the gradient at step . This works well when all parameters receive gradients of similar magnitude at similar frequencies. But in the real world, parameters live very different lives.
Consider a language learning word embeddings. The word "the" appears in almost every sentence — its gets updated thousands of times. The word "serendipity" might appear once in the entire corpus. With a shared learning rate, you face a dilemma: set high enough for "serendipity" to learn, and "the" oscillates wildly. Set it low enough for stability, and "serendipity" barely moves.
This is the sparse feature problem: in NLP, recommender systems, and click-through prediction, most of the predictive power lives in rare features — but a uniform learning rate starves them of the updates they need.
The insight: let gradient history shape the step size
AdaGrad's core idea is deceptively simple: keep a running sum of squared gradients for each parameter, then divide the learning rate by the square root of that sum.
Think of the squared gradient sum as a "mileage counter" for each parameter. A parameter that has been updated many times with large gradients has high mileage — it's already close to where it needs to be, so take smaller steps. A parameter with low mileage has barely been explored — give it a bigger step to compensate.
This is the essence of per-parameter adaptive learning rates: instead of one global , each parameter effectively has its own that shrinks in proportion to how much gradient signal it has accumulated.
The algorithm: three lines that changed optimization
Before we see symbols, let's trace the logic step by step. At each training step, AdaGrad does three things:
Step 1 — Compute the gradient for each parameter, exactly as in standard SGD.
Step 2 — Accumulate: add the square of each gradient component to a running sum. This sum grows monotonically — it never forgets.
Step 3 — Scale the update: divide the gradient by the square root of the accumulated sum, then multiply by the global learning rate. Parameters with large accumulated gradients get smaller effective learning rates; parameters with small accumulated gradients get larger ones.
Notice what happened: we started with a single global learning rate and ended with a different effective learning rate for every parameter . The adaptation is fully automatic — no manual schedule, no per-feature tuning. The only that matters is the initial , and AdaGrad is far more robust to its choice than SGD.
Geometric view: reshaping the loss landscape
There's a deeper way to understand AdaGrad. Standard SGD takes the gradient and steps in that direction with a fixed stride. Geometrically, it treats the surface as if it curves equally in all directions — using the identity matrix as a .
But real loss surfaces are anisotropic: they curve steeply in some directions and gently in others. Think of a long, narrow valley — SGD bounces off the steep walls while crawling along the valley floor.
AdaGrad implicitly builds a diagonal approximation to the curvature from gradient history. The accumulated acts like the diagonal of the : large values mean the surface curves sharply there (take shorter steps), small values mean it's flat (take longer steps). The effect is to stretch the narrow valley into a rounder bowl where gradient descent converges naturally.
The full-matrix version of AdaGrad uses the outer product as a preconditioner — a complete second-order approximation. The diagonal version approximates this with just the diagonal, trading some accuracy for memory instead of .
Why it shines: sparse features get their due
The magic of AdaGrad becomes clearest with sparse data. Consider a feature that appears in only 0.1% of training examples. In standard SGD, its gradient is zero 99.9% of the time, so its accumulated stays small. When the feature finally does appear and produces a nonzero gradient, AdaGrad divides by a small number — giving it a large effective learning rate. The rare feature gets a proportionally larger update, compensating for its infrequent appearances.
Conversely, a feature present in every example accumulates a large quickly. Its effective learning rate drops, preventing the oscillation that would occur with a fixed high learning rate.
This is why AdaGrad was transformative for NLP and recommender systems: these domains are dominated by sparse, high-dimensional feature spaces where the frequency of features varies by orders of magnitude.
The limitation: a learning rate that only shrinks
AdaGrad has a critical drawback: the accumulated sum only grows. Every step adds a non-negative value to it, so the effective learning rate can only decrease — it never recovers. In convex this is fine: as you approach the minimum, you want to take smaller and smaller steps. In non-convex deep learning, however, the loss landscape has many regions, and a learning rate that decayed in a plateau region can't speed back up when it enters a steep descent.
After many iterations, the effective learning rate can become so small that the model essentially stops learning — the updates become negligible. This is why AdaGrad on its own struggles with deep neural networks that require thousands of epochs.
The same idea in code
Simplified to show the idea — not the real implementation.
import numpy as np
class AdaGrad:
"""Per-parameter adaptive learning rate optimizer."""
def __init__(self, lr=0.01, eps=1e-8):
self.lr = lr # global learning rate (the only hyperparameter that matters)
self.eps = eps # small constant to avoid division by zero
self.cache = {} # accumulated squared gradients per parameter
def step(self, params, grads):
"""Update params in-place given their gradients."""
for name in params:
g = grads[name]
# First time seeing this parameter? Initialize its diary to zeros
if name not in self.cache:
self.cache[name] = np.zeros_like(g)
# Step 2: accumulate squared gradients (the diary grows, never shrinks)
self.cache[name] += g ** 2
# Step 3: scale each gradient component by its accumulated history
params[name] -= self.lr * g / (np.sqrt(self.cache[name]) + self.eps)
# That's it. Three lines of math, one powerful idea:
# frequent-gradient parameters → large cache → small step
# rare-gradient parameters → small cache → large stepFull-matrix AdaGrad: the ideal we approximate
The paper actually proposes a more general form: instead of tracking only the diagonal, accumulate the full outer product of gradients:
The update then uses (the matrix square root) as the preconditioner:
This is the optimal preconditioning — it captures correlations between parameters, not just individual magnitudes. But computing and inverting a matrix every step is infeasible for millions of parameters. The diagonal version is the practical compromise that became "AdaGrad" in common usage.
The full-matrix idea didn't die, though — it re-emerged years later in Shampoo, which finds efficient ways to approximate the full preconditioner for large-scale training.
Theoretical guarantee: regret that matches hindsight
AdaGrad comes with a formal guarantee from theory. The regret measures how much worse the performs compared to the single best fixed decision in hindsight. For standard SGD with a fixed learning rate, the regret bound depends on knowing the scale of the gradients in advance. Pick a rate too high and regret explodes; too low and is slow.
AdaGrad's regret bound is:
where is the cumulative gradient for parameter . This bound is dimension-dependent but data-adaptive: if most parameters have small gradients (sparse data), the bound is small even in very high dimensions. For sparse problems, this can be dramatically better than SGD's bound.
In plain language: AdaGrad is provably as good as the best learning rate schedule you could have chosen if you could see the future.
The family tree: from AdaGrad to modern optimizers
AdaGrad planted the seed, but its descendants grew taller:
RMSProp (Hinton, 2012) — Replaced the ever-growing sum with an exponential moving average of squared gradients: . This "forgets" old gradients, so the learning rate stabilizes instead of decaying to zero. Think of it as AdaGrad with a leaky memory.
AdaDelta (Zeiler, 2012) — Similar to RMSProp but also adapts the numerator using an exponential average of squared parameter updates, eliminating the global learning rate entirely.
Adam (Kingma & Ba, 2014) — Combined RMSProp's adaptive second moment with momentum's first-moment moving average, plus bias correction for the initial steps. Became the default optimizer for deep learning.
Shampoo (Gupta et al., 2018) — Resurrected AdaGrad's full-matrix preconditioner, making it practical for large-scale training through Kronecker-product approximations.
Every one of these is a direct answer to AdaGrad's question: how should gradient history shape the update step? They differ only in how much history to remember and how to structure the preconditioner.
Timeline: how one idea reshaped optimization
2011
AdaGrad
Duchi, Hazan, and Singer introduce per-parameter adaptive learning rates based on accumulated squared gradients. Dominates sparse NLP tasks immediately.
2012
RMSProp
Hinton proposes replacing the cumulative sum with an exponential moving average, preventing the learning rate from decaying to zero in deep networks.
2012
AdaDelta
Zeiler eliminates the global learning rate hyperparameter entirely by using a ratio of running averages. No manual tuning needed at all.
2014
Adam
Kingma and Ba combine RMSProp's second moment with momentum's first moment, plus bias correction. Becomes the default optimizer for deep learning.
2018
Shampoo
Gupta et al. revive AdaGrad's full-matrix preconditioner using Kronecker-product factorizations, making it practical for large-scale training.
Practical guide: when to use AdaGrad today
Despite its age, AdaGrad remains the right choice in specific settings:
Use AdaGrad when your features are sparse and high-dimensional — click-through rate prediction, large-vocabulary NLP, recommender systems with millions of items. The automatic per-feature adaptation handles the frequency imbalance perfectly, and the monotonic decay is actually a feature: in convex problems, it guarantees convergence.
Use Adam or RMSProp instead when training deep neural networks on dense data (images, audio, continuous signals). The non-convex landscape benefits from a learning rate that can recover after flat regions.
The key intuition: if your problem has features that vary wildly in frequency and your loss is (approximately) convex, AdaGrad is still hard to beat. If you're in deep learning territory with dense gradients and non-convex loss, reach for Adam.
CitationDuchi, Hazan, Singer. Adaptive Subgradient Methods for Online Learning and Stochastic Optimization. JMLR, 2011.
Terms in this paper
- Learning Rateمعدل التعلم
- Gradient Descentالانحدار التدريجي
- Stochastic Gradient Descent (SGD)الانحدار التدريجي العشوائي
- Optimizerالـمُحسِّن
- Adamخوارزمية آدام
- RMSPropخوارزمية آر إم إس بروب
- Convergenceالتقارب الحسابي
- Sparsityالتناثر البنيوي للمصفوفات
- Regularizationالضبط الهيكلي
- Weight Decayاضمحلال الأوزان
- Lossالفقد
- Gradientالتدرج التفاضلي
- Parameterالمعلمة البنيوية
- Featureميزة / سمة
- Embeddingالتضمين