A machine with no ears
We can generate, and we cannot yet steer, because the model has never been told what we want. Chapter 5's machine runs happily without us: pour in a field of random numbers, walk it down the noise schedule, decode, and an apple appears. Possibly red, possibly golden, possibly on a marble counter we never asked for. The noise predictor $\boldsymbol{\epsilon}_\theta(\mathbf{z}_t, t)$ has two inputs, a noisy latent and a noise level, and neither is a place to put a sentence.
This chapter adds one. The standing request throughout is "a green apple on a wooden table." Those seven words become numbers, the numbers enter the U-Net, and one patch of latent decides to listen to "green" rather than "table".
A prompt becomes numbers
The trip from text to numbers happens in two stages, and you have met both in the sister book.
Stage one: tokens. The sentence is cut into tokens, the chunks a model reads. Ours becomes seven, one per word, which is convenient but not guaranteed, since rarer words split into pieces. The LLM book's Chapter 7 does this properly.
Stage two: the text encoder. Those tokens go into a separate trained network whose only job is to turn them into vectors, the ordered lists of numbers Chapter 1 also called points, which carry meaning in the direction they point, the idea from meaning as direction. It is a relative of the transformer that runs a chatbot rather than the same thing, and this chapter treats it as a sealed box: text in one end, numbers out the other.
What comes out is the conditioning, written $\mathbf{c}$: a set of vectors, one per token. It is a stack rather than one vector for the whole sentence, kept separate so "green" and "wooden" stay individually addressable further down. That separateness is what the next section's arithmetic is about.
The denoiser grows a third input
The structural change is one symbol:
$$\boldsymbol{\epsilon}_\theta(\mathbf{z}_t,\, t,\, \mathbf{c})$$In words: the noise predictor now takes three things, the noisy latent $\mathbf{z}_t$, the noise level $t$ and the conditioning $\mathbf{c}$, and still hands back one thing.
Be precise about that one thing. The output is still a noise estimate, the same shape as $\mathbf{z}_t$, as in Chapter 3. The prompt does not make the network output an apple. It makes the network output a different guess about the noise. Since Chapter 5's update rule subtracts a fraction of that guess at every sampler step, a different guess walks the latent down a different path, and a different apple comes out of Chapter 4's decoder $\mathrm{Dec}$.
Training is unchanged too. We still manufacture the answer key the way Chapter 3 did, with a real image, a random noise level, a drawn noise blob and a built $\mathbf{z}_t$. The difference is that the training image arrives with a caption, that caption is encoded into $\mathbf{c}$, and the network is handed $\mathbf{c}$ while it guesses. The loss does not change one character. Over millions of examples the network finds that the vectors in $\mathbf{c}$ are worth using, because using them makes its noise guesses better.
Patches that ask the prompt
Inside those mint diamonds is attention: a way for one thing to gather information from several candidates, taking more from the relevant ones. Everything inside it plays one of three roles, the same three the LLM book's attention chapter uses. A query ("what am I looking for?"), a key ("here's the kind of thing I am"), and a value (the payload it hands over if picked). Dot products made scores, softmax made shares, and the shares mixed the values. That recipe is unchanged here. What differs is where the roles come from.
Cross-attention takes its queries from the image and its keys and values from the text. Each patch of the latent asks, and every token of the prompt answers. Roles drawn from one sequence are self-attention. Roles split across two different things, a picture asking a sentence, make it cross-attention. Nothing about the arithmetic changes.
Run one. Take a single patch of the latent, one small square in the middle of the fruit, with the two-number query $\mathbf{q} = [1,\, 1]$, and two tokens of our prompt, "green" and "apple". Real vectors are hundreds of numbers long, and two keeps every digit checkable by hand. Every number below is rounded to three decimals.
Who decided green's key is $[1, 1]$? Inside the block, each token's vector is turned into its key by a small learned matrix and into its value by a second one, and the patch's numbers become its query through a third. Those matrices are part of $\theta$, tuned during training like everything else. The numbers below are made up, and small enough to check by hand.
The cast
| from | token | key k | value v |
|---|---|---|---|
| the prompt | green | [1, 1] | [2, 0] |
| the prompt | apple | [1, −1] | [0, 3] |
And from the latent, one patch, supplying only a query: $\mathbf{q} = [1,\, 1]$.
Step one, the scores. Each is a dot product: multiply matching slots, add them up.
$$\mathbf{q} \cdot \mathbf{k}_{\text{green}} = 1 \times 1 + 1 \times 1 = 1 + 1 = 2$$In words: this patch's question lines up with what "green" advertises, giving a score of 2.
$$\mathbf{q} \cdot \mathbf{k}_{\text{apple}} = 1 \times 1 + 1 \times (-1) = 1 - 1 = 0$$In words: the same question against "apple"'s label cancels out, giving a score of 0. This patch is asking a color question, and "apple" is not answering it.
Step two, turn the scores into shares totaling 1. That is softmax: raise $e$ to each score, then divide each result by the total of all of them.
Two things there need unpacking. The symbol $e$ is a fixed number, about $2.718$, a mathematical constant like $\pi$ and nothing more than a number we raise to powers. And there are two reasons to raise anything to a power here. Every share has to come out positive, and raising $e$ to a power guarantees that even when the score is negative. It also exaggerates the gaps, so a slightly higher score takes a much larger slice of the patch's attention than plain division by the total would give it.
With $e^{2} = 7.389$ and $e^{0} = 1$, since anything raised to the power 0 is 1, the total is $7.389 + 1 = 8.389$.
$$\mathrm{softmax}(2,\, 0) = \left(\frac{7.389}{8.389},\; \frac{1}{8.389}\right) = (0.881,\; 0.119)$$In words: this patch spends 88.1% of its listening on the token "green" and 11.9% on "apple". The two shares add to 1.000, which softmax guarantees.
Step three, mix the values using those shares.
$$0.881\begin{bmatrix} 2 \\ 0 \end{bmatrix} + 0.119\begin{bmatrix} 0 \\ 3 \end{bmatrix} = \begin{bmatrix} 1.762 \\ 0 \end{bmatrix} + \begin{bmatrix} 0 \\ 0.357 \end{bmatrix} = \begin{bmatrix} 1.762 \\ 0.357 \end{bmatrix}$$In words: take 88.1% of green's payload and 11.9% of apple's, and add them. First slot: $0.881 \times 2 + 0.119 \times 0 = 1.762 + 0 = 1.762$. Second slot: $0.881 \times 0 + 0.119 \times 3 = 0 + 0.357 = 0.357$.
That vector $[1.762,\, 0.357]$ folds back into the patch's own numbers before the U-Net carries on. The patch arrived carrying "I am somewhere in a noisy blob" and leaves carrying "and the prompt says my neighborhood is mostly green, with a little apple." Every patch does this, at every scale of the U-Net, at every sampler step.
Green apple, red apple
Change one word and watch the arithmetic move. Swap "green" for "red". A color word still advertises itself as a color word, so its key stays $\mathbf{k}_{\text{red}} = [1,\, 1]$. What it hands over is the opposite end of the color axis: $\mathbf{v}_{\text{red}} = [-2,\, 0]$.
The scores are identical, because the keys are: $1 \times 1 + 1 \times 1 = 2$ against "red" and $0$ against "apple" as before. So the shares are identical too, $0.881$ and $0.119$, and the patch listens in the same proportions. What changes is what it hears:
$$0.881\begin{bmatrix} -2 \\ 0 \end{bmatrix} + 0.119\begin{bmatrix} 0 \\ 3 \end{bmatrix} = \begin{bmatrix} -1.762 \\ 0 \end{bmatrix} + \begin{bmatrix} 0 \\ 0.357 \end{bmatrix} = \begin{bmatrix} -1.762 \\ 0.357 \end{bmatrix}$$In words: first slot, $0.881 \times (-2) + 0.119 \times 0 = -1.762 + 0 = -1.762$. Second slot, unchanged at $0.881 \times 0 + 0.119 \times 3 = 0.357$.
Read the two results side by side: $[1.762,\, 0.357]$ against $[-1.762,\, 0.357]$. The second number, the appleness, did not move. The first flipped sign. One word swung this patch to the far end of one axis and left everything else alone, which is what "the prompt changed the color but not the subject" means mechanically. Multiply it by thousands of patches and a couple of dozen sampler steps and you get a red apple from the same starting static.
Worked example: adding a style word
A style phrase is another token in the stack, competing for the same shares. Add "watercolor" to the green-apple prompt, with key $\mathbf{k}_{\text{watercolor}} = [0,\, 1]$ and value $\mathbf{v}_{\text{watercolor}} = [1,\, -2]$.
New score: $\mathbf{q} \cdot \mathbf{k}_{\text{watercolor}} = 1 \times 0 + 1 \times 1 = 0 + 1 = 1$. So the three scores are $(2,\, 0,\, 1)$.
Softmax over three: $e^{2} = 7.389$, $e^{0} = 1$, $e^{1} = 2.718$, total $7.389 + 1 + 2.718 = 11.107$. Shares: $7.389 / 11.107 = 0.665$, $1 / 11.107 = 0.090$, $2.718 / 11.107 = 0.245$. They add to $0.665 + 0.090 + 0.245 = 1.000$.
Blend, first slot: $0.665 \times 2 + 0.090 \times 0 + 0.245 \times 1 = 1.330 + 0 + 0.245 = 1.575$.
Blend, second slot: $0.665 \times 0 + 0.090 \times 3 + 0.245 \times (-2) = 0 + 0.270 - 0.490 = -0.220$.
Result: $[1.575,\, -0.220]$, against the two-token $[1.762,\, 0.357]$. The style word did not replace green. It took a share, dropping green's 0.881 to 0.665, and dragged the second slot negative. Every word you add takes a share from every other word, which is the arithmetic behind "long prompts get mushy."
Two runs from the same static
To see what conditioning buys us, run Chapter 5's sampler twice from the same starting latent $\mathbf{z}_T$, with the same seed, the same noise schedule and the same number of sampler steps, changing nothing but the third input.
Run one is unconditioned. We pass the empty prompt $\varnothing$, a real prompt containing no words, run through the same text encoder into a real stack of vectors. The predictor still works, but with nothing to lean on it aims at the average of everything that could look like this, which is a generic, uncommitted image. Run two is conditioned: same $\mathbf{z}_T$, but $\mathbf{c}$ carries "a green apple on a wooden table". At the first sampler step the two predictions already disagree slightly, and since the update rule subtracts a fraction of the prediction, from step two onward the runs stand on different latents and drift apart.
The rest of the chapter is built on one observation: we have both predictions, and the difference between them is a direction. Subtract the unconditioned guess from the conditioned one and what remains is the part of the answer the prompt is responsible for, the greenness and woodenness the empty prompt did not contribute. That difference is a vector we can lean on harder than the model did on its own.
The guidance scale
The technique is called classifier-free guidance. Run the noise predictor twice at every sampler step, once with the prompt and once with the empty prompt, then push away from the unconditioned answer in the direction of the conditioned one, and keep pushing past it. The amount of push is the guidance scale $s$.
$$\hat{\boldsymbol{\epsilon}} = \boldsymbol{\epsilon}_\theta(\mathbf{z}_t, t, \varnothing) + s\left(\boldsymbol{\epsilon}_\theta(\mathbf{z}_t, t, \mathbf{c}) - \boldsymbol{\epsilon}_\theta(\mathbf{z}_t, t, \varnothing)\right)$$In words: start at the unconditioned noise guess, measure the step from there to the conditioned noise guess, multiply that step by $s$, and take it. The result $\hat{\boldsymbol{\epsilon}}$, read "epsilon-hat", is what we hand to Chapter 5's update rule in place of a plain prediction.
Three values of $s$ are worth the algebra, because the middle one is the most misread number in the field.
At $s = 0$, write $\boldsymbol{\epsilon}_\varnothing$ for the unconditioned guess and $\boldsymbol{\epsilon}_{\mathbf{c}}$ for the conditioned one:
$$\hat{\boldsymbol{\epsilon}} = \boldsymbol{\epsilon}_\varnothing + 0\left(\boldsymbol{\epsilon}_{\mathbf{c}} - \boldsymbol{\epsilon}_\varnothing\right) = \boldsymbol{\epsilon}_\varnothing + 0 = \boldsymbol{\epsilon}_\varnothing$$In words: multiply the step by zero and you never leave the starting point. The prompt is thrown away entirely and you get the unconditioned image.
At $s = 1$, the term in brackets is taken once:
$$\hat{\boldsymbol{\epsilon}} = \boldsymbol{\epsilon}_\varnothing + 1\left(\boldsymbol{\epsilon}_{\mathbf{c}} - \boldsymbol{\epsilon}_\varnothing\right) = \boldsymbol{\epsilon}_\varnothing + \boldsymbol{\epsilon}_{\mathbf{c}} - \boldsymbol{\epsilon}_\varnothing = \boldsymbol{\epsilon}_{\mathbf{c}}$$In words: the two copies of $\boldsymbol{\epsilon}_\varnothing$ cancel, one added and one subtracted, and what is left is the conditioned prediction on its own.
Sit with that line, because it is where most explanations go wrong. $s = 1$ is the model's unamplified answer to your prompt, the prediction it would make if you had passed $\mathbf{c}$ and never run the second pass. Guidance switched off is $s = 0$, which gives an image with no prompt in it. Between the two you fade the prompt in. Above 1 you exaggerate it.
At $s > 1$ we extrapolate past the conditioned answer. Work it on one number, one coordinate of one latent at one sampler step. Say the unconditioned prediction there is $0.60$ and the conditioned prediction is $0.50$. The difference is
$$0.50 - 0.60 = -0.10$$In words: knowing the prompt moved this coordinate's noise guess down by one-tenth. That tenth is the prompt's entire contribution here.
At a guidance scale of $s = 7.5$, a common default:
$$\hat{\epsilon} = 0.60 + 7.5 \times (-0.10) = 0.60 + (-0.75) = 0.60 - 0.75 = -0.15$$In words: multiply the prompt's one-tenth of influence by seven and a half to get $-0.75$, add that to the unconditioned $0.60$, and land on $-0.15$.
The two predictions the model made were $0.60$ and $0.50$, and the guided value $-0.15$ is nowhere near either. We took a small, trustworthy direction and stretched it seven and a half times. At $s = 3$ we would have landed on $0.60 + 3 \times (-0.10) = 0.60 - 0.30 = 0.30$, a shorter stretch of the same move.
So what breaks at high $s$? The noise predictor was trained on latents from real images at real noise levels, and its guesses are reliable in that neighborhood. Extrapolating seven or twenty times past that answer marches the estimate out of the region where it was ever checked against reality, and the sampler follows it there. In pictures that shows up as blown-out color, scorched contrast, hard edges where things should be soft, and rigid, literal obedience to the prompt. Low $s$ gives weak adherence, where the prompt is a suggestion the image half-takes. The useful band for most models runs roughly 5 to 9, with $s = 7.5$ a common default. Those are typical configuration choices rather than laws.
Nothing requires the second pass to use the empty prompt. Swap $\varnothing$ for a real encoded prompt like "blurry, extra stems" and the formula pushes away from that instead. That is all a negative prompt is.
See it move
Where you'll meet this
Open any Stable-Diffusion-style workflow graph and this chapter is drawn on the screen.
There are two CLIP Text Encode nodes, not one. Each is the sealed text-encoder box
from earlier: a prompt goes in, and out comes a wire labeled CONDITIONING that
carries $\mathbf{c}$. Both wires run into the sampler node, into sockets marked
positive and negative. The positive socket is $\mathbf{c}$. The negative
socket is what stands in for $\varnothing$ in the guidance formula, which is why leaving it
blank is a normal thing to do: blank is the empty prompt.
On the sampler node sits a field labeled cfg, usually defaulting near 7 or 8.
That is $s$, the multiplier on the gap between the two predictions the sampler is already
computing. It is neither a quality dial nor a prompt-strength dial. When someone's images look
"burned", that is the first number to check, and you now know why. They are reading a
calibration curve far outside the range it was built on.
Two everyday experiences come out of this arithmetic. Prompt crowding, where a twelve-word prompt honors each word less than a four-word one, is the softmax shares splitting further, the way our style word dropped green's 0.881 to 0.665. And phrasing mattering more than it "should" is the text encoder producing a different $\mathbf{c}$ for a different sentence. There is no keyword matching in the pipeline to be robust for you.
There is a hard edge to all of it. Every one of these knobs steers the model within what it already knows. If you want the heirloom apple variety in your garden, or one illustrator's line quality, no prompt reaches it. The text encoder will encode your words, the cross-attention will blend them, and the model will produce its best generic guess, because nothing in $\theta$ ever saw your apple. So how do you teach a fixed, finished model one new specific thing without retraining all of it?
What you now know
- A prompt becomes numbers in two stages, tokens then a text encoder, and what comes out is the conditioning $\mathbf{c}$, one vector per token, with no image and no caption database anywhere in the process.
- The noise predictor gains a third input and becomes $\boldsymbol{\epsilon}_\theta(\mathbf{z}_t, t, \mathbf{c})$, and its output is still a noise estimate. The prompt changes the guess, not the kind of thing being guessed.
- Cross-attention is the LLM book's attention with the roles split across two sources: the query comes from a latent patch, the keys and values from the prompt tokens. Our patch scored 2 against "green" and 0 against "apple", giving shares of 0.881 and 0.119 and a blended output of $[1.762,\, 0.357]$.
- Swapping "green" for "red" left the shares untouched at 0.881 and 0.119 and flipped the blend to $[-1.762,\, 0.357]$. One axis moved and the appleness did not.
- Classifier-free guidance runs the predictor twice and extrapolates: $\hat{\boldsymbol{\epsilon}} = \boldsymbol{\epsilon}_\varnothing + s(\boldsymbol{\epsilon}_{\mathbf{c}} - \boldsymbol{\epsilon}_\varnothing)$. At $s = 0$ it collapses to the unconditioned prediction and at $s = 1$ to the plain conditioned one, so $s = 1$ is not "off", while a typical $s = 7.5$ turned $0.60$ and $0.50$ into a guided $-0.15$.
- Guidance costs a second U-Net pass at every sampler step, roughly doubling the work.
Where we're headed. You can now aim the machine. The same starting static and the same seed will give you a green apple or a red one on demand, and you know which number to turn when the color goes scorched. What you cannot do is ask for something the model has never encountered, like your particular apple variety or your friend's illustration style, because conditioning only selects among directions that $\theta$ already contains, and no value of $s$ can amplify a direction that isn't there. The fix is a small trained add-on called a LoRA, which leaves the base model frozen and learns a small correction to a few of its weight matrices.