AdamW › Visualizing AdamW's Regularization Behavior on Embeddings

Michael BrenndoerferApril 20, 20253 min read
Language AI HandbookAll chapters
Part 10 of 67Neural Network Foundations
Chapter 69AdamW › Visualizing AdamW's Regularization Behavior on Embeddings
Reading section 12 of 15 · Visualizing AdamW's Regularization Behavior on Embeddings · 3 minSection 12 of 15 · 3 min

Book contents

Section 12 of 15 · 3 min read

AdamW › Visualizing AdamW's Regularization Behavior on EmbeddingsOne section · Sections in this chapter12 / 15 ↓
Reading tools Definitions & inline links

Choose your expertise level to adjust how many terms are explained. Beginners see more tooltips, experts see fewer to maintain reading flow. Hover over underlined terms for instant definitions.

Article links

Make inline references clickable

One of the most practically important scenarios for AdamW is language model embedding training. Embeddings for common tokens receive dense updates while embeddings for rare tokens receive sparse updates. Let's simulate this embedding scenario to see the difference directly.

In[18]:
Code
# Simulate embedding training with heterogeneous update frequencies
np.random.seed(42)

# Simulate 100 "embedding" parameters with varying update frequencies
n_embeddings = 100
n_steps = 1000

# Simulate gradient frequencies: some embeddings updated every step,
# some only occasionally
update_probs = np.concatenate(
    [
        np.ones(20),  # 20 common tokens: updated every step
        np.ones(30) * 0.3,  # 30 medium tokens: updated 30% of steps
        np.ones(50) * 0.05,  # 50 rare tokens: updated 5% of steps
    ]
)

# Simulate gradient magnitudes proportional to update frequency
gradient_scale = np.sqrt(
    update_probs
)  # larger gradients for more frequent tokens

# Track v_hat (second moment estimate) for each embedding
beta2 = 0.999
v = np.zeros(n_embeddings)
v_hat_history = np.zeros((n_steps, n_embeddings))

for t in range(1, n_steps + 1):
    # Simulate which embeddings get gradients this step
    active = np.random.rand(n_embeddings) < update_probs
    g = np.where(
        active, gradient_scale + np.random.randn(n_embeddings) * 0.1, 0.0
    )
    v = beta2 * v + (1 - beta2) * g**2
    v_hat = v / (1 - beta2**t)
    v_hat_history[t - 1] = v_hat

# Final v_hat values
final_v_hat = v_hat_history[-1]
In[19]:
Code
# Compute effective regularization for each embedding
lam = 0.01
eps = 1e-8

effective_reg_l2 = lam / (np.sqrt(final_v_hat) + eps)
effective_reg_adamw = np.full(n_embeddings, lam)

# Sort by update probability for cleaner visualization
sort_idx = np.argsort(update_probs)[::-1]
Out[20]:
Visualization
Bar-style line chart showing effective regularization per embedding for Adam+L2 vs AdamW, sorted by token frequency.
Effective regularization strength for 100 simulated token embeddings sorted by update frequency (left: most frequent, right: most rare) for Adam+L2 versus AdamW. The first 20 tokens (updated every step) receive weak regularization under Adam+L2 due to their large accumulated second moments, while the 50 rarest tokens (rightmost) receive dramatically stronger regularization. AdamW applies the same lambda=0.01 to every embedding regardless of frequency, making regularization strength a deliberate hyperparameter choice rather than an artifact of the training data distribution.

This visualization captures exactly why AdamW matters for language model training. Under Adam+L2, common token embeddings receive weak regularization and rare token embeddings receive strong regularization. The regularization strength is driven by the training corpus statistics rather than by any deliberate hyperparameter choice. Under AdamW, the flat line shows that every embedding receives exactly the regularization you intended when you set weight_decay=0.01.