Adam keeps two running averages for each parameter: the mean of the gradient and the mean of the squared gradient. It divides the first by the square root of the second, so every parameter gets its own step size. AdamW adds weight decay that does not pass through these averages. You write one Adam step as a pure function: it takes the state and returns a new state.
Task
Write two functions.
init_adam_state(params)returns the start state: a dict with"m"and"v"as float zero arrays of the shape ofparams, and"t"equal to the int0.adam_step(params, grads, state, lr, beta1, beta2, epsilon, weight_decay)does one update and returns(new_params, new_state).
One step computes, in this order:
The counter grows before the bias correction, so the first step uses t = 1. All operations are element by element. The decay factor multiplies the old parameters, as in the AdamW class of the lesson code. With weight_decay = 0 the step is plain Adam.
Input and output
| Name | Type | Shape | Meaning |
|---|---|---|---|
params |
float array | any shape | the parameters \theta before the step |
grads |
float array | same as params |
the gradient g |
state |
dict | "m" and "v": float arrays of the shape of params. "t": int, the number of steps done |
|
lr |
float | scalar | the learning rate \eta, default 0.001 |
beta1 |
float | scalar | default 0.9 |
beta2 |
float | scalar | default 0.999 |
epsilon |
float | scalar | default 1e-8, added after the square root |
weight_decay |
float | scalar | the decoupled decay \lambda, default 0.0 |
adam_stepreturns a tuple. The first item is a float array with the shape ofparams. The second item is a new dict with the keys"m","v"and"t".
Constraints
- Arrays have at most 100 elements.
- Do not change
params,gradsor the arrays instate. Return new arrays. - Use numpy only.
Examples
params = np.array([1.0, -2.0, 0.5])
grads = np.array([0.1, -0.3, 2.0])
state = init_adam_state(params)
params, state = adam_step(params, grads, state, lr=0.1)
params
statearray([ 0.90000001, -1.9 , 0.4 ])
{'m': array([ 0.01, -0.03, 0.2 ]), 'v': array([1.e-05, 9.e-05, 4.e-03]), 't': 1}params, state = adam_step(params, np.array([0.2, 0.1, -1.0]), state, lr=0.1)
params
statearray([ 0.80348181, -1.85997815, 0.3733663 ])
{'m': array([ 0.029, -0.017, 0.08 ]), 'v': array([4.999e-05, 9.991e-05, 4.996e-03]), 't': 2}params = np.array([1.0, -2.0, 0.5])
adam_step(params, np.array([0.1, -0.3, 2.0]), init_adam_state(params), lr=0.1, weight_decay=0.5)[0]array([ 0.85000001, -1.8 , 0.375 ])