Stable token probabilities
A language model does not pick the next word directly. It gives every possible next token a score, called a logit. Scores can be any number, positive or negative, so they are hard to read. Softmax turns them into probabilities: every value lands between 0 and 1, the values add up to 1, and a higher score always gets a larger share. The model then picks the next token from those probabilities.
Learn it
Words to know
- token
- The unit a model reads and writes: a word, a piece of a word, or a punctuation mark. Limits and prices are counted in tokens.
- logit
- A raw score a model gives to one possible next token. It can be any number; higher means more likely.
- softmax
- The function that turns a list of scores into probabilities that are all between 0 and 1 and add up to 1.
- temperature
- A setting for how a model picks the next token. Low values make the likeliest token win more often; high values make the output more varied.
How it works
- Raise
eto the power of each score.eis a fixed number, about 2.718; in code this isMath.exp(score)ormath.exp(score), not the^operator. Every value becomes positive, and a higher score much larger. - Add those values up, and divide each one by the total. Now they add up to 1.
eto the power 1000 is too large for a decimal number in either language; this is called overflow. So first subtract the largest score from every score. The largest becomes 0, the rest become 0 or negative, and the probabilities come out the same.
Worked example
Input logits = [1, 2, 3] Output [0.0900306, 0.244728, 0.665241]
| Token | Score | Score - 3 | e^(score - 3) | Share |
|---|---|---|---|---|
| first | 1 | -2 | 0.1353 | 0.1353 / 1.5032 = 0.0900 |
| second | 2 | -1 | 0.3679 | 0.3679 / 1.5032 = 0.2447 |
| third | 3 | 0 | 1 | 1 / 1.5032 = 0.6652 |
The three values add up to 1.5032, and the shares add up to 1 (0.9999 as rounded here). Each extra point of score multiplies the share by e, about 2.72.
Why it matters
Every model that writes text ends each step with this. Temperature works by dividing the scores by a number before softmax. A high probability means the model finds a token likely, not that it is true.
Your turn
Turn a list of scores into probabilities with softmax, in the form that cannot overflow.
logits- a list of at least one score; values can be as large as 1000 or as small as -1000
- Returns
- A list of probabilities in the same order as the scores. They add up to 1.
What JavaScript gives you
Math.exp(x)- e to the power x
Math.max(...list)- the largest number in a list; the three dots hand the items over one by one
list.map((x) => x * 2)- a new list with every item changed
What Python gives you
math.exp(x)- e to the power x; it needs
import math, which the starter has max(list)- the largest number in a list
[x * 2 for x in list]- a new list with every item changed
sum(list)- all the items added together
Example 1
Input logits = [1, 2, 3] Output [0.0900306, 0.244728, 0.665241]
As in the worked example: the shares are about 0.09, 0.24 and 0.67.
Example 2
Input logits = [0, 0] Output [0.5, 0.5]
Equal scores get equal shares.
Example 3
Input logits = [1000, 1000] Output [0.5, 0.5]
Still equal shares. Computed directly, e to the power 1000 overflows; after subtracting the largest score, both powers are e to the power 0, which is 1.
Example 4
Input logits = [-1000] Output [1]
With one token, its share is everything: 1. Computed directly, e to the power -1000 is stored as 0, and 0 divided by 0 has no answer; after the subtraction the power is 0.
The checks also try
- two scores one point apart
- one very large score beside a small one
- two very low scores
- scores that are not in order
- the largest score first
- the lowest and the highest score together
- two large scores 100 apart
Hints
Each hint gives away a little more. Open one only when you need it.
Hint 1: Where to start
Do it in four passes over the list: find the largest score, turn every score into a positive value, add the values up, then divide each value by the total.
Hint 2: The key step
The positive value for a score is
eto the power of the score minus the largest score. The largest score itself becomeseto the power 0, which is 1, so nothing can overflow.Hint 3: The outline
Find
largest. Build a listvaluesthat holdseto the powerscore - largestfor each score. Add the values up intototal. Return a list that holdsvalue / totalfor each value.
Solution
From here on the page gives the method away. If you are still solving, go back to the hints.
Step by step
- The largest score, to subtract from every score. After the subtraction the largest power is
eto the power 0, which is 1, and every other power is smaller. Nothing can overflow, and at least one value is not 0. - A positive value for each score. Raising
eto a power always gives a positive number, and it keeps the order: a higher score gives a larger value. - The total of the values. Dividing by the total is what makes the results add up to 1.
- Each value as a share of the total. The shift from step 1 cancels out here: it scales every value and the total by the same amount.
The same numbered steps are the comments in the solution.
JavaScript
function solve(logits) {
// 1. The largest score, to subtract from every score
const largest = Math.max(...logits);
// 2. A positive value for each score
const values = logits.map((score) => Math.exp(score - largest));
// 3. The total of the values
let total = 0;
for (const value of values) total += value;
// 4. Each value as a share of the total
return values.map((value) => value / total);
}Python
import math
def solve(logits):
# 1. The largest score, to subtract from every score
largest = max(logits)
# 2. A positive value for each score
values = [math.exp(score - largest) for score in logits]
# 3. The total of the values
total = sum(values)
# 4. Each value as a share of the total
return [value / total for value in values]
Watch out
- Without the subtraction a score of 1000 overflows, and two scores of -1000 both become 0, which leaves 0 divided by 0.
- Subtract the largest score, not the smallest. With the smallest, a list such as
[0, 1000]still raiseseto the power 1000. - In JavaScript:
Math.exp(1000)givesInfinitywithout an error, andInfinity / InfinityisNaN. A failed check that showsNaNusually means the subtraction is missing. - In Python:
math.exp(1000)raisesOverflowError: math range error. If you see that message, the subtraction is missing or uses the wrong score.
Check yourself
What two things are true of every softmax output?
Every value is between 0 and 1, and the values add up to 1.
Why does subtracting the largest score not change the answer?
It divides every value and the total by the same amount, so each share stays the same.