The learning rate decides if gradient descent converges, crawls or blows up. A rate sweep is the first experiment on any new model: train with each rate, keep the final loss, and pick the rate. In this lab you run the sweep on a small linear regression and compare the result with the bound that theory gives.
support.py gives the data, the grid of rates and the trainer. make_regression(seed) returns X of shape (64, 4) and y of shape (64,). train(X, y, lr, steps) runs full batch gradient descent on the mean squared error from w = 0. It returns the loss before each step and after the last step, an array of steps + 1 values. When the loss passes 1e10, the trainer stops and fills the rest of the curve with inf.
Task
Write five helper functions and answers().
run_sweep(X, y, lrs, steps=STEPS)returns a float array of shape(len(lrs), steps + 1). Row i istrain(X, y, lrs[i], steps).is_diverged(losses)returnsTruewhen the final loss is not finite or is larger than the first loss. Otherwise it returnsFalse.best_lr(lrs, curves)returns the rate with the lowest final loss among the runs that did not diverge. If two runs have the same final loss, return the smaller rate. If every run diverged, returnNone.smallest_diverging_lr(lrs, curves)returns the smallest rate, by value, whose run diverged. If no run diverged, returnNone.stability_bound(X)returns 2 / \lambda_{max}, where \lambda_{max} is the largest eigenvalue of the Hessian H = \frac{2}{n} X^T X of the mean squared error.
Then do the experiment in answers().
- Make the data with
make_regression(seed=0). - Change the learning rate over
LEARNING_RATES. Train each rate forSTEPSsteps. - Measure the final loss of each run. Report the best rate as
best_lrand its final loss asbest_final_loss. - Report the smallest rate that diverged as
smallest_diverging_lr. - Compute the theory bound on the same
X. Report it asstability_bound.
Input and output
| Name | Type | Shape | Meaning |
|---|---|---|---|
X |
float array | (n, d) |
the inputs, one row for each example |
y |
float array | (n,) |
the targets |
lrs |
list of floats | (k,) |
the learning rates, in any order |
steps |
int | scalar | the number of gradient steps |
losses |
float array | (steps + 1,) |
one loss curve |
curves |
float array | (k, steps + 1) |
one loss curve for each rate, in the order of lrs |
run_sweepreturns a float array of shape(k, steps + 1).is_divergedreturns a bool.best_lrandsmallest_diverging_lrreturn one element oflrsorNone.stability_boundreturns a float.answers()returns a dict with the four keys above. Each value is a Pythonfloat.
Constraints
- A curve can hold
infornan. - Do not change the input arrays.
- Do not round the answers. The checks accept a relative difference of
1e-6from the reference run. - Use numpy and the standard library only.
Examples
is_diverged(np.array([1.0, 2.0, 3.0]))Truebest_lr([0.1, 0.2, 0.3], np.array([[1.0, 0.5], [1.0, 0.2], [1.0, np.inf]]))0.2stability_bound(np.array([[1.0, 0.0], [0.0, 2.0]]))0.5X, y = make_regression(0)
train(X, y, 0.1, 3)[3.95117454 0.8025197 0.6543398 0.57749216]