Inputs: two parameters θ0=[1.0,2.0] with gradients g1=[0.1,0.2]; both moment estimates start at zero and this is the first step, t=1. All maths is element-wise.
First moment:m1=0.9⋅0+0.1⋅g1=[0.01,0.02], still pulled toward its zero start.
Second moment:v1=0.999⋅0+0.001⋅g12=0.001⋅[0.01,0.04]=[0.00001,0.00004].
Bias correction undoes that pull toward zero: m^1=m1/(1−0.9)=[0.1,0.2] and v^1=v1/(1−0.999)=[0.01,0.04]. At t=1 they recover exactly g1 and g12.
Update:v^1=[0.1,0.2], so the ratio m^1/(v^1+ϵ)≈[1,1] and θ1=[1,2]−0.001⋅[1,1]=[0.999,1.999]. The ϵ only shifts the 10th decimal, lost when rounding to 6 places.
Notice: both parameters moved by exactly α even though one gradient is twice the other. The step size ignores the gradient's raw scale.
Adam is a first-order stochastic optimization algorithm that improves plain gradient descent by keeping exponentially decaying moving averages of both the gradient (a kind of momentum) and the squared gradient (a kind of adaptive per-parameter learning rate, like RMSprop). Conceptually, at each step it uses past gradients to estimate the mean and variance of the gradient for each parameter, then rescales the update so that noisy / high-variance directions get smaller effective steps and consistent directions get larger ones.
Because these moving averages start at zero, their early values are biased toward zero; Adam corrects this with bias correction factors depending on the timestep t. After correction, it updates parameters by subtracting a scaled, normalized first moment: the estimated mean gradient divided by the square root of the estimated second moment (plus a small ϵ to avoid division by zero). This yields stable, per-parameter step sizes that work well in deep learning.
1. Background Knowledge
Key concepts you should understand:
Gradient descent:
For parameters θ, learning rate α, and gradient gt=\nabla_\thetaL(\thetat−1), vanilla SGD does
θt=θt−1−αgt.
Momentum:
Keeps an exponential moving average of gradients:
mt=β1mt−1+(1−β1)gt,
then updates θ using mt instead of gt. This smooths noisy gradients and accelerates in consistent directions.
Adaptive learning rates (RMSprop-style):
Keeps an exponential moving average of squared gradients:
vt=β2vt−1+(1−β2)gt2,
and scales the step by 1/(\sqrt{v_t}+\epsilon) so each parameter gets its own effective step size.
Adam combines both: it keeps first momentmt and second momentvt, applies bias correction, then does a scaled update.
2. Algorithm / Approach Pattern
For this coding task, you are not training a network; you are asked to implement one optimizer step given all necessary inputs.
The general pattern:
Inputs:
Current parameters θt−1
Previous first moment mt−1
Previous second moment vt−1
Current gradient gt
Hyperparameters α,\beta1,\beta2,ϵ
Current timestep t (1-based)
Compute:
New first moment mt
New second moment vt
Bias-corrected moments m^t,\hat{v}t
New parameters θt
Return updated θt,mt,vt.
All operations are element-wise over the parameter tensors.
3. Step-by-Step Strategy
Assuming everything is stored as arrays/tensors of the same shape:
Update first moment (biased):
mt=β1⋅mt−1+(1−β1)⋅gt
Update second moment (biased):
Square the gradient element-wise: gt2
Then:
vt=β2⋅vt−1+(1−β2)⋅gt2
Compute bias-correction denominators:
You will be given t (or you increment it); compute: