Math · Week 1 · Note 1 of 14

Functions, exponents and logarithms

Three ideas from school algebra carry most of the math in machine learning: a function is a machine, an exponent is repeated growth, and a logarithm asks “which power?”. This note rebuilds them with small numbers, then shows the one place they matter most: how a model’s score for being wrong is written.

Why this note matters

The previous note ended with a model, three houses, and a loss: one number that says how wrong the model’s guesses are. For guessing a price, the loss was the average of the squared errors. But a great deal of machine learning is not about guessing a number. It is about guessing how likely something is: that this email is spam, that the next word is “the”, that this picture shows a cat. How wrong is a guess of “70% likely” when the thing then happens? Or does not happen?

The answer that the whole field settled on is built from a logarithm, and the step that turns a model’s raw scores into percentages is built from the number ee. Those two facts are the reason this note exists. Small things that look like notation also live here: a step size written as 3×10−43 \times 10^{-4}, a chart with a “log scale” axis. If these are comfortable, the rest of the math track is a series of short steps.

Interviewers do not ask “what is a logarithm?”. They ask questions whose answers are built from it:

  • “Why is the loss for a probability guess the negative log of the probability, not just one minus the probability?”
  • “Why do we add up logs of probabilities instead of multiplying the probabilities?”
  • “Your code that turns scores into percentages returns NaN on large inputs. Why, and how do you fix it?”
  • “Why search step sizes on a log scale?”

By the end of this note you can answer all four, in plain words. Each is worked out below and then collected in the interview section. Words that belong to later notes are marked like this : hover for a one-line meaning, or ignore them on a first read.

In plain words

Each everyday idea has a precise name and symbol. You need both: the first to think, the second to speak.

Everyday ideaTechnical termSymbol
A machine from input to outputfunctionf(x)f(x)
The knobs on the machineparametersf(x; θ)f(x;\,\theta) or fθ(x)f_\theta(x)
Feeding one machine’s output into anothercompositionf(g(x))f(g(x))
Repeated multiplicationexponent (power)ana^n
Growth that compounds continuouslythe exponential functionexe^x or exp⁡(x)\exp(x)
“Which power gives this number?”logarithmlog⁡bx\log_b x
The logarithm with base eenatural logln⁡x\ln x (in code, np.log)
A function that undoes anotherinverseln⁡(ex)=x\ln(e^x) = x

Functions: machines with knobs

x input the rule for example: 2x + 1 f(x) output knobs = parameters f
Fig. 1. A function turns an input into an output. A model is a function with parameters: knobs that training adjusts.

A function is a rule that gives exactly one output for each input. We write the rule with a name and the input in brackets: f(x)=2x+1f(x) = 2x + 1 means “the function called ff takes a number xx, doubles it and adds one”. The brackets do not mean multiplication; they mean “apply the rule to”. So f(3)=7f(3) = 7 and f(0)=1f(0) = 1.

Three things about functions matter later, so meet them now with small numbers.

1. Parameters are the knobs. f(x)=2x+1f(x) = 2x + 1 has two numbers baked in, the 2 and the 1. Make them adjustable and write f(x)=wx+bf(x) = wx + b. Now ww and bb are parameters: they are part of the machine, not inputs. With w=2,b=1w = 2, b = 1 you get the function above; with w=−1,b=5w = -1, b = 5 you get a different one. When the parameters matter, we write f(x; w,b)f(x;\, w, b) or fθ(x)f_\theta(x), where θ\theta (“theta”) is the standard name for “all the parameters together”. Training a model means: the inputs are fixed by the data, so search over θ\theta for the knobs that give the best outputs.

2. Functions can be chained. Feed one machine’s output into another. If g(x)=x2g(x) = x^2 and f(x)=2x+1f(x) = 2x + 1, then f(g(3))f(g(3)) means “first gg, then ff”: g(3)=9g(3) = 9, then f(9)=19f(9) = 19. The other order gives something else: f(3)=7f(3) = 7, then g(7)=49g(7) = 49. This is composition. It matters because the big models of later weeks are nothing but long compositions: a neural network is “do this simple step, then this one, then this one”, dozens of times. Week 2 adds the tool for finding the slope of a composition, the chain rule.

3. A function has a picture. Plot inputs along the bottom and outputs up the side and you get its graph. f(x)=2x+1f(x) = 2x + 1 is a straight line, which is why it is called linear. g(x)=x2g(x) = x^2 is a U-shaped curve. Most of what follows is about recognising a handful of these shapes on sight; the zoo at the end collects them.

Read Khan Academy: Functions (Algebra 1) If function notation feels rusty, do the first two exercise sets, “Evaluating functions” and “Inputs and outputs of a function”. Twenty minutes.

Exponents and their rules

An exponent counts repeated multiplication: 23=2⋅2⋅2=82^3 = 2 \cdot 2 \cdot 2 = 8. The 2 is the base, the 3 is the exponent or power. The rumour after hh hours is 2h2^h people, and 224=16,777,2162^{24} = 16{,}777{,}216.

Six rules cover everything you will meet. Check each with the small numbers next to it rather than memorising it.

RuleCheck with numbersWhy it is true
am⋅an=am+na^m \cdot a^n = a^{m+n} 23⋅22=8⋅4=32=252^3 \cdot 2^2 = 8 \cdot 4 = 32 = 2^5 Three 2s multiplied, then two more: five 2s in all.
am/an=am−na^m / a^n = a^{m-n} 25/22=32/4=8=232^5 / 2^2 = 32 / 4 = 8 = 2^3 Two of the five 2s cancel.
(am)n=amn(a^m)^n = a^{mn} (23)2=82=64=26(2^3)^2 = 8^2 = 64 = 2^6 Three 2s, taken twice over: six 2s.
a0=1a^0 = 1 23/23=12^3 / 2^3 = 1 and also =20= 2^{0} Follows from the division rule with m=nm = n.
a−n=1/ana^{-n} = 1 / a^n 2−3=1/8=0.1252^{-3} = 1/8 = 0.125 Keep dividing by 2 past 202^0: 4, 2, 1, ½, ¼, ⅛.
a1/n=ana^{1/n} = \sqrt[n]{a} 161/2=416^{1/2} = 4 because 4⋅4=164 \cdot 4 = 16 Two copies of 161/216^{1/2} must multiply to 16116^1.

The negative-exponent rule is the one that shows up most. The size of each training step (the learning rate , week 2) is written like 3×10−43 \times 10^{-4}, which is 3/104=3/10,000=0.00033 / 10^4 = 3 / 10{,}000 = 0.0003. In code that is 3e-4. Reading these without pausing is a small skill worth having before you tune your first model.

(0, 1) eˣ 2ˣ e⁻ˣ x y 3 −3
Fig. 2. Growth curves. All pass through (0, 1) because anything to the power 0 is 1. e^x grows faster than 2^x; e^(−x) is the same curve mirrored, and it is how probabilities shrink.

Two facts about Fig. 2 are used constantly. First, axa^x is always positive: no matter how negative xx gets, e−xe^{-x} only creeps towards zero and never touches or crosses it. Second, it is always increasing: a bigger xx always gives a bigger exe^x, so the order of inputs is preserved in the outputs. Keep both in mind. They are exactly the two properties you need to turn a list of scores, which can be negative, into a list of percentages, which cannot, without changing which score was biggest. That recipe is below.

Read Khan Academy: Exponential models (Algebra 2) Only the exercise sets on exponent properties and on graphing exponentials. Skip the word problems about bank interest.

The number e

e≈2.71828e \approx 2.71828 is a constant like π\pi. It is the natural base for exponents because of one property, which the calculus notes will use on every page: the curve y=exy = e^x has, at every point, a slope equal to its own height. At the point where ex=5e^x = 5, the curve is rising at a rate of 5. No other base does this; 2x2^x rises at about 0.69 times its height, 10x10^x at about 2.3 times. Using ee makes every derivative involving exponentials come out without stray constants, which is the only reason mathematicians, and therefore machine learning, prefer it.

You will see exe^x written as exp⁡(x)\exp(x) when the exponent is long, for example exp⁡(−(x−μ)2/2σ2)\exp(-(x-\mu)^2 / 2\sigma^2), the formula for the bell curve you will meet in week 3. In code it is np.exp(x). A few values to have in your head:

xx−3−10123510
exe^x0.050.3712.727.3920.114822,026

Notice how quickly the right side explodes. e10e^{10} is already twenty-two thousand, and e710e^{710} is larger than the biggest number a 64-bit float can hold. A model’s raw scores can easily be in the hundreds, so “exe^x overflows” is a real bug you will meet, and the scores section shows the standard fix.

Watch 3Blue1Brown: What’s so special about Euler’s number e? About 14 minutes. The clearest explanation of the slope-equals-height property. You do not need the calculus it mentions yet; watch it for the pictures and rewatch it in week 2. Read Better Explained: An intuitive guide to exponential functions and e The bank-interest story in full, with pictures. Ten minutes, no calculus.

Logarithms: “which power?”

Formally, log⁡bx\log_b x is the number yy such that by=xb^y = x. The two statements say the same thing in two directions:

by=x⟺log⁡bx=yb^y = x \quad\Longleftrightarrow\quad \log_b x = y

So log⁡28=3\log_2 8 = 3 because 23=82^3 = 8, and log⁡101000=3\log_{10} 1000 = 3 because 103=100010^3 = 1000. The base bb is which number is being raised to the power. Three bases appear in practice:

BaseWrittenWhere it appearsIn NumPy / PyTorch
eeln⁡x\ln x or just log⁡x\log x in ML papersEvery loss built from probabilities; the log-probabilities that model APIs returnnp.log
2log⁡2x\log_2 xMeasuring information in bits (entropy , week 4)np.log2
10log⁡10x\log_{10} xStep-size scales, plots, “orders of magnitude”np.log10
ln 0.01 = −4.6 ln 0.5 = −0.69 ln 1 = 0 ln e = 1 ln 7.39 = 2 x no log of 0 or negatives
Fig. 3. The natural logarithm. It climbs steeply near zero and flattens out, crosses zero at x = 1, is negative for inputs below 1, and does not exist for zero or negative inputs.

Read the shape of Fig. 3 carefully, because it is the shape of the loss for probability guesses, which the next section builds:

  • log⁡1=0\log 1 = 0, because e0=1e^0 = 1. A probability of 1 will mean zero loss.
  • For inputs between 0 and 1 the log is negative, because you need a negative power of ee to get below 1. Probabilities live here, so log-probabilities are always negative numbers.
  • Near zero the curve plunges: log⁡0.1=−2.3\log 0.1 = -2.3, log⁡0.01=−4.6\log 0.01 = -4.6, log⁡0.001=−6.9\log 0.001 = -6.9. Each extra zero costs another 2.3. Nothing stops the fall; the log of a number heads to minus infinity as the number heads to zero.
  • Above 1 it keeps rising but ever more slowly. Going from 1 to 7.39 raises the log by 2; going from 7.39 to 54.6 raises it by 2 again. Multiplying the input by the same factor adds the same amount to the output.
  • log⁡0\log 0 and the log of any negative number do not exist. In code they come out as -inf and nan, and they are the most common source of a NaN loss.
Read Better Explained: Demystifying the natural logarithm Reads ln x as “how long to grow to x”. Short, and it makes the negative values and the shape obvious.

The log rules you will use

RuleCheck with numbersComes from
log⁡(ab)=log⁡a+log⁡b\log(ab) = \log a + \log b log⁡2(8⋅4)=log⁡232=5=3+2\log_2(8 \cdot 4) = \log_2 32 = 5 = 3 + 2 aman=am+na^m a^n = a^{m+n}
log⁡(a/b)=log⁡a−log⁡b\log(a/b) = \log a - \log b log⁡2(8/4)=1=3−2\log_2(8/4) = 1 = 3 - 2 am/an=am−na^m / a^n = a^{m-n}
log⁡(an)=nlog⁡a\log(a^n) = n \log a log⁡2(82)=log⁡264=6=2⋅3\log_2(8^2) = \log_2 64 = 6 = 2 \cdot 3 (am)n=amn(a^m)^n = a^{mn}
log⁡1=0\log 1 = 0 any base a0=1a^0 = 1
log⁡bb=1\log_b b = 1 ln⁡e=1, log⁡22=1\ln e = 1,\ \log_2 2 = 1 b1=bb^1 = b
log⁡b(bx)=x\log_b(b^x) = x and blog⁡bx=xb^{\log_b x} = x ln⁡(e5)=5, eln⁡7=7\ln(e^5) = 5,\ e^{\ln 7} = 7 log and power undo each other
log⁡bx=ln⁡xln⁡b\log_b x = \dfrac{\ln x}{\ln b} log⁡21000=6.908/0.693=9.97\log_2 1000 = 6.908 / 0.693 = 9.97 change of base; any base is a constant multiple of any other

The change-of-base rule has a practical consequence: which base you use changes nothing except a constant factor. The place where a function is smallest is the same whether you measure in ln⁡\ln, log⁡2\log_2 or log⁡10\log_{10}. This is why a paper can say “log” without caring, and why the same quantity can be reported “in bits” (base 2) or “in nats” (base ee) and mean the same thing.

Two things that look like rules but are not:

Read Khan Academy: Logarithms (Algebra 2) Do the exercise sets “Evaluate logarithms”, “Use the properties of logarithms” and “Change of base”. Thirty minutes, and it covers every rule above with instant feedback.

Why machine learning loves logs

Reason 1: products become sums. A model that assigns probabilities to several independent events gives the whole sequence a probability equal to the product of the individual ones. Say a model gives probabilities 0.9, 0.8 and 0.95 to three correct answers. The probability of getting all three right is

0.9×0.8×0.95=0.6840.9 \times 0.8 \times 0.95 = 0.684

Take the log of each and add instead:

log⁡0.9+log⁡0.8+log⁡0.95=(−0.105)+(−0.223)+(−0.051)=−0.380\log 0.9 + \log 0.8 + \log 0.95 = (-0.105) + (-0.223) + (-0.051) = -0.380

and e−0.380=0.684e^{-0.380} = 0.684, the same answer. For three numbers this is no easier. For a million training examples, or for a 500-token sentence where each token has its own probability, a sum is something you can compute, average and take slopes of, and a product is not. Almost every model is trained by making this sum of logs as large as possible, which is the same as making the product as large as possible. In week 3 the product gets a name, the likelihood , and the maximum likelihood note builds on exactly this calculation.

Reason 2: tiny numbers stay representable. Multiply a thousand probabilities of 0.001 and the true answer is 10−300010^{-3000}. A 64-bit float cannot hold anything smaller than about 10−30810^{-308}, so the computer returns exactly 0, and every model you compare returns 0 too. This is called underflow. In log space the same quantity is 1000×log⁡0.001=−69081000 \times \log 0.001 = -6908, an ordinary number. The code section shows this happening.

Reason 3: confident mistakes are punished without limit. A loss should be a number that is small when the model is right and large when it is wrong, and logs of probabilities are negative, so flip the sign. The loss used for probability guesses is −log⁡p-\log p, where pp is the probability the model gave to the answer that turned out to be correct. It is called the log loss. Fig. 4 is its graph.

p = 0.99 → 0.01 p = 0.9 → 0.11 p = 0.5 → 0.69 p = 0.1 → 2.3 p = 0.01 → 4.6 p 0 1 −log p
Fig. 4. The log loss −log p for one example, where p is the probability given to the correct answer. Nearly free when p is near 1; climbs without limit as p nears 0.

Compare this with the obvious alternative, a loss of 1−p1 - p. Being 90% sure and right costs 0.1 either way. But being 99% sure of the wrong answer, so p=0.01p = 0.01 for the right one, costs 0.99 under 1−p1 - p and 4.6 under −log⁡p-\log p. Push to p=0.0001p = 0.0001 and the first loss barely moves to 0.9999 while the second jumps to 9.2. The log loss keeps caring, more and more, exactly when the model is most confidently wrong, and that pressure is what teaches a model to say “70%” only when it really is right about 70% of the time. It is the forecaster’s score from the plain-words box: cheap when right, unbounded when arrogantly wrong.

A fourth, smaller reason: log scales. When you try step sizes for training, the useful candidates are 0.1, 0.01, 0.001, 0.0001: each a factor of 10 apart, not a fixed amount apart. On a log scale those are evenly spaced. The same holds for plotting a loss that falls from 1000 to 0.1: on a plain axis the interesting part is squashed into an invisible sliver at the bottom; on a log axis every factor of 10 gets equal room. Whenever a quantity varies by multiplication, think in logs.

Turning scores into percentages

For the scores z=(2,1,0)z = (2, 1, 0):

(e2, e1, e0)e2+e1+e0=(7.39, 2.72, 1)11.11=(0.665, 0.245, 0.090)\frac{(e^2,\ e^1,\ e^0)}{e^2 + e^1 + e^0} = \frac{(7.39,\ 2.72,\ 1)}{11.11} = (0.665,\ 0.245,\ 0.090)

Check the properties: every entry is positive, they add to 1, and the biggest score got the biggest share. Written as a formula, the share for score number ii is

pi=ezi∑jezjp_i = \frac{e^{z_i}}{\sum_j e^{z_j}}

where ∑j\sum_j just means “add up over all the scores”. This recipe is so common that it has a name, softmax, and the raw scores are called logits. You do not need either word yet; the softmax note in week 5 tells the full story. Here the point is only to see exe^x doing the job Fig. 2 promised.

Now the bug. Scores of (1000,1001,1002)(1000, 1001, 1002) are perfectly ordinary for a model that has not been trained yet, but e1000e^{1000} is far beyond the largest float, so every term becomes inf and the division gives nan. The fix: subtract the largest score from all of them first. The exponent rule says ezi−c=ezi/ece^{z_i - c} = e^{z_i} / e^c, and the ece^c appears in both the top and the bottom of the fraction, so it cancels. The percentages are identical; only the intermediate numbers change:

(1000,1001,1002)−1002=(−2,−1,0)(1000, 1001, 1002) - 1002 = (-2, -1, 0)
(e−2, e−1, e0)e−2+e−1+e0=(0.135, 0.368, 1)1.503=(0.090, 0.245, 0.665)\frac{(e^{-2},\ e^{-1},\ e^{0})}{e^{-2} + e^{-1} + e^{0}} = \frac{(0.135,\ 0.368,\ 1)}{1.503} = (0.090,\ 0.245,\ 0.665)

After the shift the biggest exponent is 0, so the biggest term is e0=1e^0 = 1 and nothing can overflow. Every machine-learning library does this inside its scores-to-percentages function, which is why hand-written versions that forget it are a classic interview question. The code section shows both versions.

The functions to recognise on sight

Most formulas in the rest of these notes are made from six shapes. If you can sketch each from memory and name where it appears, you can read the formulas as pictures instead of symbols.

y = 2x + 1 a line: the simplest model y = x² squared error y = eˣ scores → percentages y = ln x the log loss y = 1 / (1 + e⁻ˣ) the S curve (sigmoid), week 3 y = max(0, x) keep positives only (ReLU), week 5
Fig. 5. Six functions that make up most of machine learning. Each panel shows x from −3 to 3.
FunctionShapeKey factsWhere you will meet it
wx+bwx + bstraight lineslope ww, crosses the y-axis at bbthe house-price model; linear regression; every layer of a neural network before its bend
x2x^2U shapenever negative, minimum at 0, grows fastmean squared error; penalties on big parameters (regularization , week 3)
exe^xhockey stick upalways positive, increasing, slope equals valuescores to percentages (above); the bell curve (week 3)
log⁡x\log xsteep then flatonly for x>0x > 0, zero at 1, negative below 1the log loss; measuring information (week 4)
σ(x)=11+e−x\sigma(x) = \dfrac{1}{1 + e^{-x}}S curvesquashes any number into (0, 1), σ(0)=0.5\sigma(0) = 0.5turning one score into a yes/no probability (sigmoid , week 3)
max⁡(0,x)\max(0, x)flat then diagonalzero for negatives, identity for positivesthe bend between layers of a network (ReLU , week 5)

Look at the sigmoid formula with fresh eyes now. It is built from Fig. 2: e−xe^{-x} is huge for very negative xx, so 1/(1+huge)1/(1 + \text{huge}) is nearly 0; it is nearly 0 for very positive xx, so 1/(1+0)1/(1 + 0) is nearly 1; and at x=0x = 0 it is 1/(1+1)=0.51/(1 + 1) = 0.5. The whole S-shape falls out of the exponential’s behaviour at the two ends.

Try it Desmos graphing calculator Type each of the six functions, then change the numbers in them and watch the shape move. Ten minutes of this beats an hour of staring at formulas. Try y = 1/(1+e^(−k x)) and slide k.

Code

Type these out; do not paste. Each one demonstrates a sentence from above.

The rules, checked numerically

import numpy as np

a = 6.0
b = 1.5
n = 3.0

# np.log is the NATURAL log (base e). np.log2 is base 2, np.log10 is base
# 10.
# product -> sum:        2.1972... 2.1972...
print(np.log(a * b), np.log(a) + np.log(b))
# quotient -> difference: 1.3863... 1.3863...
print(np.log(a / b), np.log(a) - np.log(b))
# power -> multiple:     5.3753... 5.3753...
print(np.log(a ** n), n * np.log(a))
print(np.log(np.exp(2.5)))                     # log undoes exp:        2.5
print(np.exp(np.log(a)))                       # exp undoes log:        6.0
# change of base:        2.5850... 2.5850...
print(np.log2(a), np.log(a) / np.log(2))

# The same check written as a test: assert stops the program if the
# condition is false.
# np.isclose allows for the tiny rounding differences that decimals always
# have.
assert np.isclose(np.log(a * b), np.log(a) + np.log(b))

print(np.log(1), np.log(np.e), np.log(0.5), np.log(0.01))
# 0.0 1.0 -0.6931471805599453 -4.605170185988091

Underflow, and why log space fixes it

import numpy as np

# One thousand examples, each given probability 0.001 by a model.
p = np.full(1000, 0.001)       # an array of 1000 copies of 0.001

product = np.prod(p)           # multiply all 1000 together
log_sum = np.sum(np.log(p))    # add up their logs instead
# underflow: the true value 10^-3000 is below the smallest float
print(product)
# prints 0.0
# the same quantity in log space: an ordinary number
print(log_sum)
# prints -6907.755278982137

# A second model gives each example 0.002, so it is clearly better. Can we
# tell?
q = np.full(1000, 0.002)
# both products are 0.0
print(np.prod(q) > np.prod(p))
# prints False
# log space sees the difference
print(np.sum(np.log(q)) > np.sum(np.log(p)))
# prints True

Scores to percentages, naive and safe

import numpy as np

def scores_to_percentages_naive(z):
    # step 1: make every score positive, keep the order
    e = np.exp(z)
    # step 2: divide by the total so they add up to 1
    return e / np.sum(e)

def scores_to_percentages(z):
    # shift every score down by the biggest one (same answer, safe numbers)
    z = z - np.max(z)
    e = np.exp(z)
    return e / np.sum(e)

small = np.array([2.0, 1.0, 0.0])
big = np.array([1000.0, 1001.0, 1002.0])

print(scores_to_percentages(small).round(3))    # [0.665 0.245 0.09 ]
# exp(1000) overflows to inf; inf / inf is nan
print(scores_to_percentages_naive(big))
# prints [nan nan nan]
print(scores_to_percentages(big).round(3))      # [0.09  0.245 0.665]
# NumPy also prints "RuntimeWarning: overflow encountered in exp" for the
# naive line.
# This recipe is called softmax; the week 5 note builds on it.

The log loss

import numpy as np

def log_loss(p_correct):
    # minus the log of the probability the model gave to the right answer
    return -np.log(p_correct)

for p in [0.99, 0.9, 0.5, 0.1, 0.01]:
    loss = log_loss(p)
    # :<5 pads p to 5 characters, :.3f prints 3 decimals
    print(f"p = {p:<5}  loss = {loss:.3f}")
# p = 0.99   loss = 0.010
# p = 0.9    loss = 0.105
# p = 0.5    loss = 0.693
# p = 0.1    loss = 2.303
# p = 0.01   loss = 4.605

# Compare with the obvious alternative, 1 - p. At p = 0.01 it is only 0.99:
# it has stopped caring.
print(1 - 0.01)          # 0.99
print(log_loss(0.01))    # 4.605170185988091

Where you will meet this again

  • Week 2, loss functions. The log loss, −log⁡p-\log p, becomes the standard loss for yes/no questions, with the probability pp coming out of the S-curve from the zoo.
  • Week 3, maximum likelihood. “Add up the logs of the probabilities the model gave to what really happened, and make that as big as possible” turns out to be where almost every loss comes from. The product gets the name likelihood .
  • Week 4, entropy. −log⁡p-\log p averaged over outcomes measures how unpredictable something is; that is entropy , and the log loss gets its grown-up name, cross-entropy .
  • Week 5, softmax. The scores-to-percentages recipe becomes softmax , the last step of every model that chooses between categories, and the subtract-the-max trick returns with a second trick for taking its log safely.
  • Weeks 7 to 9, language models. A language model gives a score to every token it could write next, about 50,000 of them, and softmax turns those into percentages. Its training loss is −log⁡p-\log p of the token that actually came next, averaged over every position: Fig. 4 applied billions of times. People report ee raised to that average loss and call it perplexity ; a value of 10 means “as unsure as choosing among 10 equally likely tokens”. And model APIs return log-probabilities rather than probabilities, for Reasons 1 and 2 above.

The full interview answer

The most common form this note takes in an interview is “why is the loss for a probability a log?” or “why not just use one minus the probability?”. (After week 4 you will hear it asked as “why is cross-entropy a log?”; same question.) Here is a complete answer in about sixty seconds, built from the short lines above.

If they push further, be ready for:

  • “Why base ee rather than 2?” Any base differs by a constant factor, so the minimizer is the same; ee makes derivatives clean. Base 2 gives the loss in bits.
  • “What loss means the model was perfect?” 0: it gave probability 1 to every correct answer. In practice that is a sign of a bug or of test answers leaking into training.
  • “Why does my loss show NaN?” Usually log⁡0\log 0 somewhere: a probability that reached exactly zero, or an overflow in a hand-written scores-to-percentages step. Clip probabilities away from zero, or use the library’s loss function, which does the safe version.
  • “Why are logprobs negative?” Probabilities are at most 1 and log⁡1=0\log 1 = 0, so every log-probability is zero or below.

Practice questions

Answer each one out loud before opening it.

What does f(x; θ) mean, and what changes during training?

It is a function of the input xx whose behaviour depends on parameters θ\theta. The input comes from the data and is fixed; training changes θ\theta to minimize a loss. In a big network θ\theta is every weight and bias.

Why is e^x used to turn scores into percentages instead of, say, x² or |x|, which also make numbers positive?

exe^x is strictly increasing, so a larger score always gets a larger percentage; x2x^2 and ∣x∣|x| would give the scores −5 and 5 the same percentage. It is also smooth, with a slope equal to its own value, which makes the calculus in week 5 come out clean.

Without a calculator: log₂ 32, log₁₀ 0.001, ln(e⁵), e^(ln 7), ln 1.

5 (since 25=322^5 = 32); −3 (since 10−3=0.00110^{-3} = 0.001); 5; 7; 0.

A model gives the correct answer probability 0.01. What is its loss? And at 0.99?

−log⁡0.01=4.6-\log 0.01 = 4.6 and −log⁡0.99=0.01-\log 0.99 = 0.01. The confidently wrong case costs about 460 times more than the confidently right case.

Why do we add log-probabilities instead of multiplying probabilities?

Because log⁡(ab)=log⁡a+log⁡b\log(ab) = \log a + \log b: the sum of logs is the log of the product, so nothing is lost. The sum is numerically safe (no underflow), it is easy to average and differentiate, and maximizing it finds the same parameters as maximizing the product.

Each extra zero in a probability (0.1, 0.01, 0.001) adds how much to the log loss? Why?

About 2.3 each time, because log⁡10=2.303\log 10 = 2.303 and log⁡(p/10)=log⁡p−log⁡10\log(p/10) = \log p - \log 10. Dividing the input by a fixed factor subtracts a fixed amount from the log: that is the power rule in action.

Your hand-written scores-to-percentages function returns NaN for scores around 1000. What happened and what is the fix?

e1000e^{1000} overflows to infinity, and infinity divided by infinity is NaN. Subtract the maximum score from all scores before exponentiating. The factor emax⁡e^{\max} cancels between numerator and denominator, so the output is unchanged and all intermediate values are at most 1.

Is log(a + b) = log a + log b?

No. There is no simple rule for the log of a sum. log⁡(ab)=log⁡a+log⁡b\log(ab) = \log a + \log b is the product rule. Check: log⁡2(4+4)=3\log_2(4 + 4) = 3 but log⁡24+log⁡24=4\log_2 4 + \log_2 4 = 4.

Why does changing the base of the log not change which parameters minimize a loss?

Change of base: log⁡bx=ln⁡x/ln⁡b\log_b x = \ln x / \ln b, so every base is a positive constant times the natural log. Multiplying a loss by a positive constant leaves its minimizer where it was; only the reported value changes.

Why are training step sizes (learning rates) searched on a log scale?

Because the effect of a step size is multiplicative: 0.01 and 0.001 behave very differently, while 0.011 and 0.010 behave the same. Spacing candidates by a constant factor (evenly spaced in log space) spends the budget where behaviour actually changes.

If g(x) = x² and f(x) = 2x + 1, what are f(g(2)) and g(f(2))?

f(g(2))=f(4)=9f(g(2)) = f(4) = 9 and g(f(2))=g(5)=25g(f(2)) = g(5) = 25. Order matters in composition; a big model is a specific order of compositions.

What is 3e-4 as a decimal, and what does the notation mean?

0.0003. It means 3×10−4=3/1043 \times 10^{-4} = 3 / 10^4. Negative exponents are reciprocals.

Practice problems

Do these on paper first, then check. The hand problems are the kind interviewers ask you to do on a whiteboard; the coding ones build the habits you will use every day. Solutions are hidden under each problem.

By hand

1. Simplify: 2³ · 2⁴, (3²)³, 5⁰, 2⁻³, 16^(1/2), (e²)(e⁻²).

27=1282^7 = 128; 36=7293^6 = 729; 11; 1/8=0.1251/8 = 0.125; 44; e0=1e^0 = 1.

2. Expand ln(a b² / c) into separate logs.

ln⁡a+2ln⁡b−ln⁡c\ln a + 2\ln b - \ln c. Product rule for the numerator, power rule for b2b^2, quotient rule for the division.

3. Write log₂ x using only natural logs, then evaluate log₂ 1000 given ln 1000 = 6.908 and ln 2 = 0.693.

log⁡2x=ln⁡x/ln⁡2\log_2 x = \ln x / \ln 2. So log⁡21000=6.908/0.693=9.97\log_2 1000 = 6.908 / 0.693 = 9.97, consistent with 210=10242^{10} = 1024.

4. Three probabilities: 0.5, 0.25, 0.125. Compute their product directly, then as a sum of base-2 logs.

Product: 0.015625=2−60.015625 = 2^{-6}. Logs: log⁡20.5+log⁡20.25+log⁡20.125=−1−2−3=−6\log_2 0.5 + \log_2 0.25 + \log_2 0.125 = -1 - 2 - 3 = -6, and 2−6=0.0156252^{-6} = 0.015625. Same answer, and the sum is easier.

5. How many times larger is the loss −ln 0.1 than −ln 0.9?

−ln⁡0.1=2.303-\ln 0.1 = 2.303 and −ln⁡0.9=0.105-\ln 0.9 = 0.105. Ratio about 22. Being 10% confident in the right answer costs 22 times more than being 90% confident.

6. Solve 2ˣ = 1000 approximately, and 10ˣ = 0.0003.

x=log⁡21000≈9.97x = \log_2 1000 \approx 9.97. For the second, 0.0003=3×10−40.0003 = 3 \times 10^{-4}, so x=log⁡103+(−4)=0.477−4=−3.52x = \log_{10} 3 + (-4) = 0.477 - 4 = -3.52.

7. A loss falls from 1000 to 0.1 over training. On a plain axis, what fraction of the chart’s height does the part from 1 to 0.1 occupy? On a log₁₀ axis?

Plain axis: the range is 1000, and the interesting final stretch spans 0.9 of it, so 0.09% of the height, invisible. Log axis: the range is log⁡101000−log⁡100.1=3−(−1)=4\log_{10} 1000 - \log_{10} 0.1 = 3 - (-1) = 4 units, and the stretch from 1 to 0.1 is 1 unit, a quarter of the chart. That is why loss curves are plotted on log axes.

8. Turn the scores (2, 1, 0) into percentages by hand. (e² = 7.389, e = 2.718.)

Sum 7.389+2.718+1=11.1077.389 + 2.718 + 1 = 11.107. Percentages (0.665,0.245,0.090)(0.665, 0.245, 0.090). They add to 1 and keep the order of the scores.

9. Turn the scores (1000, 1001, 1002) into percentages by hand without overflowing anything.

Subtract 1002: (−2,−1,0)(-2, -1, 0). Exponentials (0.135,0.368,1)(0.135, 0.368, 1), sum 1.503, so (0.090,0.245,0.665)(0.090, 0.245, 0.665). Note it is the mirror image of problem 8, because the gaps between the scores are the same but reversed.

10. Scores (3, 3, 3). What percentages come out, and why? What about scores (3, 3, 3) + 100?

Equal scores give equal shares: (e3,e3,e3)/3e3=(1/3,1/3,1/3)(e^3, e^3, e^3) / 3e^3 = (1/3, 1/3, 1/3). Adding the same number to every score multiplies every eze^{z} by the same e100e^{100}, which cancels in the division, so the shares are unchanged. Only the gaps between scores matter. That is also why subtracting the maximum is harmless.

11. Sketch, from memory, y = ln x, y = −ln x for 0 < x ≤ 1, and y = eˣ on the same axes. Mark where each crosses an axis.

ln⁡x\ln x crosses the x-axis at 1 and plunges towards the y-axis. −ln⁡x-\ln x is its mirror: 0 at x=1x = 1, rising steeply towards the y-axis. exe^x crosses the y-axis at 1 and never touches the x-axis. Compare with Figs. 2, 3 and 4.

12. The sigmoid is σ(x) = 1 / (1 + e⁻ˣ). Evaluate σ(0), σ(4), σ(−4), and show σ(−x) = 1 − σ(x).

σ(0)=0.5\sigma(0) = 0.5; σ(4)=1/(1+0.018)=0.982\sigma(4) = 1/(1 + 0.018) = 0.982; σ(−4)=1/(1+54.6)=0.018\sigma(-4) = 1/(1 + 54.6) = 0.018. For the identity: 1−σ(x)=e−x/(1+e−x)1 - \sigma(x) = e^{-x}/(1 + e^{-x}); multiply top and bottom by exe^{x} to get 1/(ex+1)=σ(−x)1/(e^{x} + 1) = \sigma(-x).

Code

13. Write a function that checks all seven log rules from the table numerically for random positive a, b and random n, using np.isclose. Run it a thousand times.
import numpy as np

def check_log_rules(trials):
    # random-number generator; seed 0 repeats the same numbers
    rng = np.random.default_rng(0)
    for trial in range(trials):
        # a random number between 0.01 and 100
        a = rng.uniform(0.01, 100)
        b = rng.uniform(0.01, 100)
        n = rng.uniform(-3, 3)
        assert np.isclose(np.log(a * b), np.log(a) + np.log(b))
        assert np.isclose(np.log(a / b), np.log(a) - np.log(b))
        assert np.isclose(np.log(a ** n), n * np.log(a))
        assert np.isclose(np.log(1.0), 0.0)
        assert np.isclose(np.log(np.e), 1.0)
        assert np.isclose(np.log(np.exp(n)), n)
        assert np.isclose(np.exp(np.log(a)), a)
        assert np.isclose(np.log2(a), np.log(a) / np.log(2))
    print("all rules hold in", trials, "random trials")

check_log_rules(1000)     # all rules hold in 1000 random trials
14. Show underflow: multiply 400 probabilities of 0.1 directly and in log space. At what count does the direct product first become exactly 0.0?
import numpy as np

p = 0.1
direct = 1.0          # the running product
logspace = 0.0        # the running sum of logs
# the first count at which the product hits exactly 0.0
first_zero = None
for k in range(1, 401):
    direct = direct * p
    logspace = logspace + np.log(p)
    if first_zero is None and direct == 0.0:
        first_zero = k
print(first_zero)
# prints 324: 0.1 to the 324 is below the smallest positive float (about 4.9e-324)
print(logspace)
# prints -921.0340371976151: still a perfectly ordinary number
print(np.exp(logspace))    # 0.0 again, as soon as you leave log space
15. Write scores_to_percentages(z) with the subtract-the-max trick. On 1,000 random lists of 50 scores between −1000 and 1000, check that no share is negative and that the shares add to 1. On small scores (between −5 and 5), check it agrees with the naive version.
import numpy as np

def scores_to_percentages(z):
    z = z - np.max(z)          # subtract the biggest score
    e = np.exp(z)
    return e / np.sum(e)

def naive(z):
    e = np.exp(z)
    return e / np.sum(e)

rng = np.random.default_rng(0)
for trial in range(1000):
    # 50 random scores, some huge
    big = rng.uniform(-1000, 1000, size=50)
    p = scores_to_percentages(big)
    # nothing negative (very small shares round to 0.0)
    assert np.min(p) >= 0
    assert np.isclose(np.sum(p), 1.0)              # shares add up to 1

    # scores the naive version can handle
    small = rng.uniform(-5, 5, size=50)
    # every share agrees
    assert np.allclose(scores_to_percentages(small), naive(small))

print("safe version: never breaks, always adds to 1, matches the naive one on small scores")
print(np.sum(naive(big)))
# prints nan: the naive version on the last big scores does not even add to 1
16. Plot −log p for p from 0.001 to 1, and on the same axes plot 1 − p. Mark p = 0.01 on both. Write one sentence about what you see.
import numpy as np
import matplotlib.pyplot as plt

# 500 evenly spaced values from 0.001 to 1
p = np.linspace(0.001, 1, 500)
plt.plot(p, -np.log(p), label="-log p")
plt.plot(p, 1 - p, label="1 - p")
# the two losses at p = 0.01
plt.scatter([0.01, 0.01], [-np.log(0.01), 0.99], color="red")
plt.xlabel("probability given to the correct answer")
plt.ylabel("loss")
plt.legend()
plt.show()
# At p = 0.01 the two losses are 4.6 and 0.99: the log loss keeps punishing
# confident mistakes
# while 1 - p has already stopped caring.

Common mistakes

All sources

Everything linked above, in the order to use it, plus one reference for later. Every np. function used on this page is explained on the NumPy reference.

  1. Khan Academy, Functions (exercises). Only if function notation is rusty.
  2. Khan Academy, Exponential models and Logarithms (exercises). The graded problem sets for this note.
  3. 3Blue1Brown, “What’s so special about Euler’s number e?” (video, 14 min).
  4. Better Explained, “An intuitive guide to exponential functions and e” and “Demystifying the natural logarithm” (articles).
  5. Desmos (interactive), for the function zoo.
  6. Deisenroth, Faisal and Ong, Mathematics for Machine Learning (free PDF). Not needed for this note; it is the reference for the rest of the math track, and its chapter 2 starts where the next note starts.

One-minute revision