21:38. Berlin. Tuesday evening.
I had just come home from a meetup with a question in my head.
Is an LLM probabilistic or not?
Because, well... somehow yes. But also somehow no.
What actually happens between "the model predicts a token" and "the model produces a token"?
In summary, an LLM produces a probability distribution over possible next tokens. A decoding strategy then turns that distribution into an actual token. But that explanation hides most of the interesting engineering and actually very interesting mathematics. To fully understand what happens (and to rediscover the beauty of e !), it helps to follow the process one step at a time.
When an LLM processes a prompt, it does not simply decide:
"The next token is Paris."
First of all, the model takes the input and produces a score for every possible next token, based on its learned weights.
Suppose the context is:
The capital of France is ...
Conceptually, the model might produce something like:
Paris 8.2
London 6.1
Berlin 5.4
Pizza -2.3
These scores are called logits.
A logit is a raw score produced by the model for a possible next token.
How do those scores become probabilities? That's where Softmax enters.
The problem with raw logits is that they are not probabilities. They can be positive, negative, large, or small. Within a probability distribution, all probabilities are positive, and all probabilities add up to 100%.
For example:
Paris 70 %
London 20 %
Berlin 10 %
Our logits don't do that. So we need a transformation that turns them into something that can be interpreted as probabilities. That's what Softmax does.
The Softmax function is:
At first glance, the formula might look a little bit intimidating. But it's actually pretty simple, so stay with me. Simply put, the formula does two things in order to transform the logits into probabilities:
First, it transforms every logit into a positive value. In addition, it amplifies the relative differences between the values so that the probability distribution gets clearer. That's what the exponential function e^x is for. Finally, the fraction normalizes these values by dividing each one by the sum of all exponentiated logits.
The result is a probability distribution where all values are positive and add up to 1.
Let's go down the rabbit hole step by step.
The little i simply identifies the token we're currently looking at.
pi means the probability assigned to token i .
If we're calculating the probability of Paris, we write: pi=pParis
Nothing mysterious. It's just what we're interested in - the probability.
zi is the corresponding logit for token i .
So if the logit of Paris is 2, we write: zParis=2
Still straightforward.
Look at:
The symbol ∑ simply means: Add things together. And j is the index we use to go through all the tokens we're summing over.
In this case:
Take every possible token, calculate ezj , and add all the results together.
In engineering language this would be:
Start with zero, iterate over all possible next tokens, calculate ezj for each one, and add the result to the total.
total = 0
for j in tokens:
total += exp(z[j])
Suppose we have only three tokens:
Paris z = 2
London z = 1
Berlin z = 0
Then:
That's it.
The denominator in the Softmax formula is simply the sum of all exponentiated logits.
In our example, the result would be
Now calculate the probability of Paris (z=2):
So the probability of Paris is approximately 66.5%.
Then London (z=1):
So the probability of London is approximately 24.5%.
Then Berlin (z=0):
So the probability of Berlin is approximately 9.0%.
Notice what happens: You get pretty differentiated results and at the same time, the scores turned to a probability. That is Softmax.
Exponentiate every score. Add all those values together. Then divide each individual value by the total.
And now the results form a probability distribution.
The formula only looks intimidating because mathematics is extremely good at packing an entire paragraph into one line.
Look at the following table:
| Token / probability | With exponential pi=∑jezjezi | Without exponential pi=∑jzjzi | |---|---|---| | pParis | ParseError: KaTeX parse error: Unexpected end of input in a macro argument, expected '}' at end of input: …\mathbf{66.5%} | ParseError: KaTeX parse error: Unexpected end of input in a macro argument, expected '}' at end of input: …\mathbf{66.7%} | | pLondon | ParseError: KaTeX parse error: Unexpected end of input in a macro argument, expected '}' at end of input: …\mathbf{24.5%} | ParseError: KaTeX parse error: Unexpected end of input in a macro argument, expected '}' at end of input: …\mathbf{33.3%} | | pBerlin | ParseError: KaTeX parse error: Unexpected end of input in a macro argument, expected '}' at end of input: … \mathbf{9.0%} | ParseError: KaTeX parse error: Unexpected end of input in a macro argument, expected '}' at end of input: …=\mathbf{0.0%} | Sum | 100.0% | 100.0% |
In this particular example, Paris and London still look relatively similar, but Berlin immediately drops to 0% without ex . More importantly, directly normalizing logits only works as a valid probability construction when the logits are non-negative. Real logits can also be negative.
So the exponential isn't just decoration. It gives us a transformation with the properties we need: positive values and a way of amplifying relative differences before normalization. And that brings us to e .
You might remember that e≈2.718281828...
You might also remembered that it had something to do with exponential functions and logarithms. Let's explore why it matters.
e naturally appears when we describe continuous exponential growth. And it has one remarkably convenient mathematical property:
The rate at which ex changes - f′(x) - is always and exactly its current value f(x) . Crazy.
Take this table with x , the values f(x) and their exponential growth f′(x) :
| x | f(x)=ex | f′(x)=ex |
|---|---|---|
| 0 | f(0)=1 | f′(0)=1 |
| 1 | f(1)=2.718 | f′(1)=2.718 |
| 2 | f(2)=7.389 | f′(2)=7.389 |
The larger the function becomes, the faster it grows — at a rate proportional to its current value.
Did you notice? The equation is mathematically elegant. Computers, however, have finite-precision numbers. But exponentials grow fast. Very fast. If a logit is 10000, just calculating e10000 is not a nice thing to do to your processor with floating-point arithmetic.
So real implementations use a mathematically equivalent, numerically stable form of Softmax:
Why is this allowed?
Because subtracting the same constant from every logit does not change the resulting Softmax probabilities:
for any constant (c).
Let's explain this from an engineering perspective: In practice, we want to keep the numbers inside the exponential function as small as possible. Large exponents can cause numerical overflow and make the calculation unnecessarily difficult. So we subtract the largest logit from every logit.
If the largest logit is max(z) , we calculate:
zi′=zi−max(z)
This makes the largest logit exactly zero:
max(z)−max(z)=0
And because the largest logit was subtracted from all the others, every other adjusted logit is negative:
zi−max(z)≤0
Now look at what happens when we exponentiate them.
The largest exponent is:
e0=1
And all the other exponentials are between 0 and 1:
0<ezi−max(z)<1
So instead of calculating potentially huge numbers like e1000 , we are always working with values between 0 and 1.
But why are we allowed to do this?
Because - and now we come to the already mentioned mathematical background - subtracting the same constant from every logit does not change the resulting Softmax probabilities:
softmax(z)=softmax(z−c)
for any constant c .
In our case, we simply choose:
c=max(z)
So we haven't changed the probabilities we're calculating.
We've just shifted all logits down so that the calculation stays numerically small and safe.
And since we had already come this far down the rabbit hole: ln is - simply spoken - the mathematical opposite of e : If ex is the operation that takes us from x to exponential growth, ln(x) takes us back again.
For example, if:
then:
Back to the LLM. Back to Softmax.
Let's do a quick recap. We started with:
Paris 2
London 1
Berlin 0
Softmax applies ex :
Then it normalizes:
And there it is:
Paris 66.5 %
London 24.5 %
Berlin 9.0 %
The model started with scores (logits). Softmax transformed them. The exponential function turned the relative differences into positive weights. Normalization turned those weights into proportions. And now we have a probability distribution.
The LLM hasn't randomly chosen anything yet.
We have only calculated the distribution.
Temperature doesn't itself introduce randomness. It changes the shape of the probability distribution before we sample from it.
The temperature-adjusted Softmax is:
The T stands for temperature. It modifies the logits before the exponential transformation.
Suppose we have:
Paris 2
London 1
The effect of different temperature values is:
| Temperature T | Paris: 2/T | London: 1/T | Difference |
|---|---|---|---|
| 0.5 | 4 | 2 | 2 |
| 1 | 2 | 1 | 1 |
| 2 | 1 | 0.5 | 0.5 |
- T=1 means that the logits are not changed by temperature: zi/T=zi .
Then ex acts on these values. Low temperature amplifies the differences between logits. High temperature reduces them. The resulting distribution becomes respectively sharper or flatter.
The lower the temperature, the larger the difference between the adjusted logits becomes. The exponential transformation then amplifies this difference, resulting in a sharper probability distribution. In other words, the probability becomes more concentrated on the token with the higher logit.
Vice versa, the higher the temperature, the smaller the difference between the adjusted logits becomes. After the exponential transformation, this results in a flatter probability distribution, meaning that the probability is distributed more evenly across the possible tokens.
And this is where the role of e becomes especially useful: Temperature doesn't directly manipulate the final percentages. It just changes the scores before the exponential transformation, where differences can be amplified or compressed.
The formula says: zi/T
So if (T=0), aren't we dividing by zero?
Yes. We are. But remember Limes, your friend and helper when it comes to division by zero. Because the thing is, the formula is not defined at (T=0). Mathematically, the interesting thing is the limit as (T) approaches zero from above:
Again, suppose we have
Paris 2
London 1
The effect of temperature values approaching zero is:
| Temperature T | Paris: 2/T | London: 1/T | Difference | Paris probability | London probability |
|---|---|---|---|---|---|
| 1∗ | 2 | 1 | 1 | 73.1 | 26.9 |
| 0.5 | 4 | 2 | 2 | 88.1 | 11.9 |
| 0.1 | 20 | 10 | 10 | 99.995 | 0.005 |
| 0.01 | 200 | 100 | 100 | ≈100 | ≈0 |
T=1 means that the logits are not changed by temperature: zi/T=zi .
So the table makes the effect of temperature very visible:
The values become enormous. But Softmax doesn't care about their absolute size. It cares about their relative size.
For Softmax with temperature T :
We divide the numerator and denominator by e2/T . This gives:
Now consider the limit: T→0+
Then: T1→∞ and therefore: −T1→−∞
Explanation: As T approaches zero, the value of T becomes smaller and smaller. And because there is a minus sign in front, the exponent becomes increasingly negative.
Therefore: e−1/T→0
Explanation: For a negative exponent, ex produces a value between 0 and 1 . The more negative the exponent becomes, the closer the result gets to zero.
which leaves:
For Softmax with temperature T :
We divide the numerator and denominator by e1/T . This gives:
Now consider the limit: T→0+
Then: T1→∞
Explanation: As T approaches zero, the value of T becomes smaller and smaller. The exponent therefore becomes increasingly positive.
Therefore:
Explanation: For a positive exponent, ex produces a value greater than 1 . The larger the exponent becomes, the larger the result gets. As the exponent approaches infinity, the value of ex also approaches infinity.
which leaves:
And there we have the complete result:
p1→1 and p2→0
The important trick is that we divide by the exponential term corresponding to the token we are currently calculating.
For p1 , dividing by e2/T gives us e−1/T , which approaches 0 .
For p2 , dividing by e1/T gives us e1/T , which approaches ∞ .
That makes it explicit why the probability of the larger logit approaches 1 , while the probability of the smaller logit approaches 0 .
And there it is: While the absolute numbers themselves don't matter, their ratio is becoming decisive.
Softmax doesn't care how enormous the numbers are. It cares how enormous they are relative to one another.
This is where the mathematical model and the practical API diverge slightly.
At (T=0), the Softmax equation itself isn't defined. In practice, a system may interpret temperature = 0
as a request for greedy or otherwise non-sampling decoding rather than literally dividing by zero.
Conceptually:
rather than:
Temperature zero isn't "Softmax with zero."
At T=0 , the Softmax formula itself is not defined because we would be dividing by zero.
In practice, temperature = 0
is usually used to tell the system: Just choose the token with the highest probability.
There is one small catch. What if two tokens have exactly the same highest logit?
Paris 2
London 2
Berlin 1
Now Paris and London are tied.
If we look at what happens as T gets closer and closer to zero, neither one becomes more likely than the other. They both keep the same probability.
There is no mathematical way for Softmax itself to choose between two exactly equal maximum logits. So the tie has to be resolved by the decoding algorithm, not by Softmax.
If there is no clear winner, the decoding system needs a rule for resolving the tie.
For example, a system could define a deterministic tie-breaking rule such as:
1. Find the highest logit.
2. If several tokens have the same highest logit,
choose the token with the smallest token ID.
Then:
Paris 2 ← token ID 471
London 2 ← token ID 892
Berlin 1
would always select Paris.
At this point, we have a probability distribution.
Suppose:
Paris 70 %
London 20 %
Berlin 10 %
Sampling means: Draw a token according to this distribution.
| Run | Result |
|---|---|
| One run | → Paris |
| Another | → Paris |
| Another | → London |
| Another | → Paris |
| Another | → Berlin |
The distribution itself has not changed. The concrete draw can.
A probabilistic model does not necessarily produce a probabilistic output.
So the variability comes from the sampling process itself: Temperature changes the distribution. Sampling is the random selection.
You can think about it like this:
Probability distribution
↓
Temperature
↓
"How strongly should
the options differ?"
↓
Sampling
🎲
↓
Token
Or, less formally: Temperature changes the weights. Sampling rolls the dice.
What exactly does the computer do when we sample?
As it normally doesn't have access to some magical source of true randomness, a concrete implementation can use a pseudo-random number generator, or PRNG. A pseudo-random generator produces a sequence of values from a mathematical algorithm and an initial state, commonly represented by a seed.
As a consequence, the sampling process can be probabilistic in its behavior while the concrete sequence of pseudo-random numbers is deterministic if the relevant state is fixed.
If the relevant conditions are identical — including the model parameters, input, generation settings, and random state or seed — the same pseudo-random sequence can be generated again.
So there are two different perspectives here.
From the perspective of the model or user:
Sampling behaves probabilistically.
From the perspective of a fixed implementation with a fixed pseudo-random state:
The concrete sequence can be deterministic and reproducible.
"Random" does not automatically mean "irreproducible." And "probabilistic" does not automatically mean "nondeterministic at every level of the system." The implementation matters.
Now the terminology starts to fall into place.
Top-ksays: Only consider the (k) most likely tokens.
For example, with top-k = 3
, only the three most likely tokens remain candidates for sampling: Paris, London, and Berlin.
| Token | Probability | Top-k = 3 |
|---|---|---|
| Paris | 50% | ✓ |
| London | 25% | ✓ |
| Berlin | 15% | ✓ |
| Madrid | 7% | — |
| Rome | 3% | — |
Top-pworks differently: It keeps thesmallest set of tokens whose cumulative probability mass is at least (p), after sorting candidates by probability in descending order.
For example, with top-p = 0.8
, we keep adding the most likely tokens until the cumulative probability reaches at least 80%.
| Token | Probability | Cumulative probability | Top-p = 0.8 |
|---|---|---|---|
| Paris | 50% | 50% | ✓ |
| London | 25% | 75% | ✓ |
| Berlin | 15% | 90% | ✓ |
| Madrid | 7% | 97% | — |
| Rome | 3% | 100% | — |
Here, Paris + London gives us 75%, so we need Berlin to reach 90%.
Therefore, Paris, London, and Berlin remain candidates.
Top-k fixes the number of candidates. Top-p fixes the probability mass. Both can constrain the sampling space.
The model produces the scores. Softmax turns them into a probability distribution. Temperature reshapes it. Top-k and Top-p can constrain the candidates. And sampling selects what comes next.
What initially sounded like one operation — the LLM generates the next token — is actually a chain of very different operations.
Once you follow a single token through that chain, the process becomes much less mysterious.
There is no single "generation" step. There is a sequence of mathematical transformations and a decoding decision at the end.