Neuron and softmax — fill in two holes
In the last step you saw the neuron and softmax at work. Now you write them as Python — and a piece is missing from each.
Pseudocode
neuron(x, w, b):
return x @ w + b
softmax(z): # z is [n, 10], one row = one picture's scores
for every row:
e ← exp(score − the largest score in that row)
return e / (the sum of e in that row)
Nothing complicated, but there is one line that looks unnecessary — and is not.
"Subtract the largest." Mathematically softmax does not change: subtracting the same number from all scores leaves the ratios of the probabilities as they were. But on a computer exp(1000) is infinity, and infinity / infinity is nan. After subtracting the largest, the biggest score becomes 0, and exp(0) = 1 — it never overflows.
Your job
Create neuron.py and test_neuron.py (see the right-hand panel) in the same folder as tensors_demo.py.
neuron.py is complete and runs, but is wrong: two places are marked HOLE 1 and HOLE 2.
- HOLE 1 —
neuron. In place of the weighted sum there are "zeros of the right shape": the code runs, but every score is 0. Write the real formula. - HOLE 2 —
softmax. The division by the sum is already there. What is missing is one line of stability: subtract each row's largest value beforetorch.exp.
Three hints for HOLE 2:
z.max(dim=1)returns a pair (values and indices); the values are.values;- "for every row" means
dim=1; - the result must be
[n, 1], not[n]— otherwise it subtracts along the wrong axis. Whichmaxparameter keeps that, you remember from the lesson 2 drills (task 4).
sigmoid is already written — it is only there so you can see what one activation looks like.
Run the test before filling anything
$ python -m unittest
FFF.FF..
FAIL: test_bias_is_added (...)
AssertionError: 0.0 != 0.7 within 5 places (0.7 difference)
FAIL: test_many_neurons_many_images (...)
AssertionError: Lists differ: [[0.0, 0.0], [0.0, 0.0]] != [[1.5, 9.5], [5.5, 49.5]]
FAIL: test_one_neuron_one_image (...)
AssertionError: 0.0 != 4.75 within 5 places (4.75 difference)
FAIL: test_big_scores_do_not_overflow (...)
AssertionError: True is not false : got [[nan, 0.0, 0.0]] - overflow?
FAIL: test_every_row_is_stabilised_on_its_own (...)
AssertionError: True is not false : got [[nan, 0.0, 0.0], [nan, nan, nan]]
----------------------------------------------------------------------
Ran 8 tests in 0.003s
FAILED (failures=5)
(Only the important lines are kept.)
Notice what passes: three dots — sigmoid, "rows add up to 1" and "known softmax values". The unstable softmax works correctly on ordinary numbers and breaks only on big ones. A person would not notice this on their own — the test does: got [[nan, 0.0, 0.0]].
Fill both holes and run again — you should see OK.
When it does not pass
Each of these was tried here:
0.0 != 0.7(the bias test), while the other two neuron tests are off by exactly the bias — you wrotex @ wand forgot+ b. The formula is almost right:4.5 != 4.75and[[1.0, 10.0], [5.0, 50.0]]instead of[[1.5, 9.5], [5.5, 49.5]].a Tensor with 3 elements cannot be converted to Scalar— you wrotex * w + b.*is element by element: you got three numbers, not one sum.got [[1.0, 0.0, 0.0], [nan, nan, nan]]withz - z.max()— you subtracted one largest value for the whole table, not one per row. The first row survived; in the secondexp(−2000)is0, and0 / 0isnan.The size of tensor a (3) must match the size of tensor b (2) at non-singleton dimension 1—z.max(dim=1).valueswithoutkeepdim=True: you got[n]where[n, 1]is needed, and PyTorch tries to match the wrong axis.