Logistic regression from scratch
Problem
Logistic regression is a linear model with a sigmoid on the output. The output is the probability of class 1. Gradient descent on the binary cross-entropy loss trains it. The same loss and gradient return in every neural network classifier with two classes.
Task
Write four functions.
sigmoid(z)returns \sigma(z) = 1 / (1 + e^{-z}) for each element ofz.compute_loss(X, y, w, b)returns the mean binary cross-entropy of the model p = \sigma(X w + b).compute_gradients(X, y, w, b)returns(dw, db), the gradient of that mean loss with respect towandb.fit(X, y, learning_rate, epochs)trains the model with full batch gradient descent and returns(w, b, loss_history).
The loss of one example is -[y \log p + (1 - y) \log(1 - p)]. With z = x \cdot w + b, the same value is \log(1 + e^z) - y z. The loss is the mean over the n examples.
The gradients are dw = X^T (p - y) / n and db = \frac{1}{n} \sum_i (p_i - y_i).
fit starts with w as a zero vector and b = 0.0. Each epoch does these steps:
- Compute
(dw, db)at the currentwandb. - Move
wandbone step against their gradients. The step islearning_ratetimes the gradient. - Append the loss at the new
wandbtoloss_history.
Large values of |z| overflow np.exp. The sigmoid and the loss must be correct for any finite z. Do not clip the probabilities.
Input and output
| Name | Type | Shape | Meaning |
|---|---|---|---|
z | float array | any shape | the input of sigmoid |
X | float array | (n, d) | one example in each row |
y | float array | (n,) | the label of each example, 0.0 or 1.0 |
w | float array | (d,) | the weights |
b | float | scalar | the bias |
learning_rate | float | scalar | the step size |
epochs | int | scalar | the number of gradient steps, 0 or more |
sigmoidreturns a float array with the shape ofz.compute_lossreturns a Pythonfloat.compute_gradientsreturns a float array of shape(d,)and a Pythonfloat.fitreturns a float array of shape(d,), a Pythonfloatand a list ofepochsfloats.
Constraints
1 <= n <= 1000and1 <= d <= 50.zcan be any finite float, also values such as1000.0and-1000.0.- Do not change the input arrays.
- Use numpy only.
Examples
pythonsigmoid(np.array([-2.0, 0.0, 2.0, 1000.0, -1000.0]))text[0.11920292 0.5 0.88079708 1. 0. ]pythonX = np.array([[1.0, 2.0], [2.0, 1.0], [3.0, 4.0], [4.0, 3.0]])
y = np.array([0.0, 0.0, 1.0, 1.0])
w = np.array([0.5, -0.25])
compute_loss(X, y, w, 0.1)
compute_gradients(X, y, w, 0.1)text0.6545645625913818
(array([ 0.00990023, -0.07111509]), 0.1663330660944403)pythonfit(X, y, 0.1, 3)text(array([0.10335357, 0.10335357]), -0.016102386795294854, [0.6521696016041545, 0.6346023820290841, 0.6258174296603579])Hints
4 hintsSolution and notes
LockedPass every check with Submit to open the reference solution and the notes.
Run it on your computer
Clone the repository, install numpy and run the same checks in a terminal:
python3 scripts/practice/run.py logistic-regression my_answer.py
python3 scripts/practice/run.py logistic-regression my_answer.py --examplesStart my_answer.py from starter.py.
Your code is saved in this browser as you type. On a phone you can read and edit the code, but the checks are easier to use on a desktop.
Keyboard shortcuts
- Ctrl Enter
- Run the examples
- Ctrl Shift Enter
- Submit
- Tab / Shift Tab
- Indent or outdent the lines
- Esc then Tab
- Move the focus out of the editor
- Alt H
- Show the next hint
On a Mac, use Cmd in place of Ctrl.
Select Run to check the examples, or Submit to run every check.