Card 1 / 5
Gradient descent moves every parameter a little way against its gradient: , where is the gradient of the loss and (the learning rate) scales the step. Return the updated parameters as a new array; the input is left untouched.
params |
grads |
lr |
result |
|---|---|---|---|
[1, -2] |
[0.5, 0.5] |
0.1 |
[0.95, -2.05] |
[3] |
[6] |
0.25 |
[1.5] |
[0.5, 0.5] |
[0, 0] |
1 |
[0.5, 0.5] |
Entry by entry, : each coordinate moves against its own gradient entry, all scaled by the same . The gradient points where the loss rises fastest, so subtracting a small multiple of it lowers the loss — on with , and the step lands on , where is smaller.
Whole-array arithmetic does the loop and allocates the result: NumPy params - lr * grads builds a new array (an in-place params -= lr * grads would mutate the caller's array); Eigen params - lr * grads assigned to a fresh Eigen::VectorXd does the same.
def gradient_step(params: np.ndarray, grads: np.ndarray, lr: float) -> np.ndarray:
"""One gradient-descent update: theta <- theta - lr * g.
params: [P] current parameter values
grads: [P] gradient of the loss with respect to each parameter
lr: learning rate (step size)
Returns the updated parameters as a NEW [P] array; `params` must not be modified.
"""
return params - lr * gradsCard 2 / 5
In gradient descent the learning rate sets how far each step goes, and the loss recorded after every step is the cheapest diagnostic of whether it was chosen well. Three shapes are worth…