Full Linear Regression Training Loop finds the best-fit line iteratively: guess, measure the error, nudge the weights, repeat, for as many epochs as it takes to converge. For plain linear regression specifically, that iteration turns out to be unnecessary: the loss surface (02-mse-loss's mean squared error, as a function of the weights) is a smooth, convex bowl with exactly one minimum, and calculus can solve for that minimum's exact location directly, in one shot, with no learning rate, no epochs, no convergence to wait for at all.
This is the Normal Equation, and understanding it matters for more than just efficiency: it's the moment where "why does gradient descent need a learning rate at all" gets a genuine answer, for THIS specific, simple problem, it doesn't, gradient descent is solving something calculus can solve exactly. Most of the models this curriculum builds (anything with a nonlinearity) don't have this luxury, which is precisely why gradient descent is the general-purpose tool used everywhere else.
Theory derives the exact solution by setting the loss's gradient to zero and solving algebraically, folding the bias into the weight vector by augmenting the input with a constant column of ones.
Implement closed_form_linear_regression(input, target) against that reasoning. The signature and docstring are already in the editor.
(weight, bias) in the exact same (1, in_features)/(1,) shapes Full Linear Regression Training Loop returns.np.linalg.pinv (the pseudoinverse), not np.linalg.inv, for the reason Theory explains.input), rather than solving for it separately.Open one at a time. Each gives away a little more than the last.
np.hstack([input, np.ones((n, 1))]) appends a column of ones, turning "weight AND bias" into one single combined vector to solve for.
np.linalg.pinv(X_augmented) @ target solves the whole system in one call; the last row of the result is the bias, everything before it is the weight.
Click "Run Tests" to test your implementation