Exercise Set 29 - Adam
Concepts Practiced
- Adam as a stateful optimizer.
- First moment versus second moment estimates.
- Bias correction from zero initialization.
- Per-parameter adaptive scaling.
- Reading optimizer pseudocode.
- Knowing what Adam does and does not solve.
Notation
| Symbol | Meaning |
|---|---|
θ_t | Parameter value or parameter vector at step t. |
g_t | Gradient estimate at step t. |
m_t | First moment estimate: running average of gradients. |
v_t | Second moment estimate: running average of squared gradients. |
β_1 | First-moment decay coefficient. |
β_2 | Second-moment decay coefficient. |
η | Base learning rate. |
ε | Small numerical stability constant. |
Adam convention used in this lesson:
Problems
Problem 1
In your own words, explain why Adam keeps two memories instead of one.
Problem 2
What does m_t remember? What does v_t remember? Be specific about why v_t uses squared gradients.
Problem 3
Use toy coefficients:
β_1 = 0.8β_2 = 0.9η = 0.1εis small enough to ignorem_0 = 0v_0 = 0g_1 = 5
Compute:
m_1v_1\hat{m}_1\hat{v}_1- the approximate parameter update
Problem 4
Suppose an Adam step has:
and:
Ignore ε.
Compute:
Then explain what this says about per-parameter scaling.
Problem 5
Bias correction uses:
Explain why this correction is largest at the beginning of training and becomes less important later.
Problem 6
Write a short paragraph comparing SGD, momentum, and Adam.
Use this structure:
- SGD uses…
- Momentum adds…
- Adam adds…
Problem 7
Give one situation where Adam is likely easier to use than plain SGD.
Then give one reason Adam still does not remove the need for validation checks and learning-rate tuning.
Implementation Problems
Problem 8
Write TypeScript-style pseudocode for one Adam update over arrays:
thetagradientfirstMomentsecondMoment
Assume you are given:
steplearningRatebeta1beta2epsilon
The goal is not perfect syntax. The goal is to show the state updates in the right order.
Reflection
- Which Adam symbol was easiest to remember?
- Which symbol was most overloaded or expensive?
- Did bias correction feel like a conceptual idea or just algebra?
- What should be reinforced before learning rate schedules?
Instructor Notes / Review
Expected checkpoints:
m_tshould be described as direction memory, not as a parameter.v_tshould be described as squared-gradient scale memory, not momentum velocity.- Bias correction should be tied to
m_0 = 0andv_0 = 0. - Per-parameter scaling should be explained coordinate by coordinate.
- The implementation prompt should update optimizer state before applying the parameter update.
Reviewed Student Work - 2026-07-09
Source: uploaded Lesson 29.pdf.
Overall
Strong conceptual pass. The answers show the important Adam model: two optimizer memories, one for direction and one for scale. The scalar calculation for g_1 = 5 is correct:
Keep
- The distinction between direction memory and scale memory is clear.
- The explanation of why
sqrt(v_t)is needed is right:v_tstores squared-gradient scale, so the square root returns to gradient units. - The note that
εprevents denominator failure is right. - The Adam-easier-than-SGD example is good: parameter coordinates with very different gradient scales.
Corrections / Refinements
-
Adam’s adaptive scaling does change the final update direction.
The answer says that if we only adjusted scale independently, the direction would get distorted, so Adam also tracks direction. That is mostly right as an intuition, but there is a subtlety: Adam’s coordinatewise division by
sqrt(v_t)can itself change the direction relative to the raw gradient vector.More precise wording:
Adam separates two questions: what direction has recent gradient evidence supported, and how large are gradients usually in each coordinate? The final update is a coordinatewise normalized direction, not necessarily the same geometric direction as the raw gradient.
-
Bias correction is not mainly about preventing infinity.
εhandles the literal divide-by-zero case. Bias correction handles a different problem: becausem_0 = 0andv_0 = 0, the early running averages are artificially too small.Better wording:
Bias correction matters most early because
1 - β^tis small neart = 1, and the zero initialization strongly shrinksm_tandv_t. Astgrows,β^tapproaches zero, so1 - β^tapproaches one and the correction becomes negligible. -
The implementation sketch has the right state-shape intuition, but the bias correction needs
stepexponents.The pseudocode divides by
1 - beta1and1 - beta2. That is correct only on step 1. In general it should be:const firstHat = firstMoment[i] / (1 - beta1 ** step); const secondHat = secondMoment[i] / (1 - beta2 ** step);Also,
firstMomentandsecondMomentshould be arrays updated per parameter index, not single scalar variables shared across the whole parameter array.
Suggested Clean Pseudocode
function adamStep(
theta: number[],
gradient: number[],
firstMoment: number[],
secondMoment: number[],
step: number,
learningRate: number,
beta1: number,
beta2: number,
epsilon: number,
): void {
for (let i = 0; i < theta.length; i++) {
firstMoment[i] = beta1 * firstMoment[i] + (1 - beta1) * gradient[i];
secondMoment[i] = beta2 * secondMoment[i] + (1 - beta2) * gradient[i] ** 2;
const firstHat = firstMoment[i] / (1 - beta1 ** step);
const secondHat = secondMoment[i] / (1 - beta2 ** step);
theta[i] = theta[i] - learningRate * firstHat / (Math.sqrt(secondHat) + epsilon);
}
}
Review Result
Lesson 29 is complete. Reinforce before Lesson 30: bias correction versus ε, and the distinction between raw gradient direction and Adam’s coordinatewise normalized update direction.