Cross-attention: reading from another set
Read these first if they are new to you
- Attention: queries, keys, values Advanced
The idea in one paragraph
Cross-attention is attention between two sets of tokens. The tokens being updated, set A, make the queries. The tokens being read, set B, make the keys and values. Each A token gets a weighted sum of B's values, weighted by how well B's keys match its own query. Set B is often a condition: the words of a caption, say, or the points of the part of a shape you can see. The output has one vector per A token, however many tokens B has.
Queries come from one set; keys and values come from the other
In self-attention, one set of tokens makes all three vectors. In cross-attention, the roles split. For each token a of set A and each token b of set B, learned matrices make
q = WQa, k = WKb, v = WVb
Stack A's n queries as the rows of Q, and B's m keys and values as the rows of K and V. The formula is the same as before:
CrossAttention = softmax( QKT / √dk ) V
Only the shapes change, because n and m can differ:
| Matrix | Made from | Rows | Columns |
|---|---|---|---|
| Q, the queries | set A | n | dk |
| K, the keys | set B | m | dk |
| V, the values | set B | m | dv |
| the weights, softmax(QKT / √dk) | both | n | m |
| the output | both | n | dv |
Each row of the weights belongs to one A token and adds up to 1. The output has n rows: one new vector per A token. Set B is read, not changed. Self-attention is the special case where A and B are the same set.
Worked by hand: two tokens read from three
Set A has two tokens with queries q1 = [1, 0] and q2 = [0, 2]. Set B has three tokens with keys [2, 0], [0, 1] and [1, 1], and values [6, 0], [0, 6] and [3, 3]. The key size is dk = 2.
Predict first. Which B token will A's first token read most? Which will the second read most?
- Scores q · k: for q1, [2, 0, 1]; for q2, [0, 2, 2].
- Divide by √2: [1.414, 0, 0.707] and [0, 1.414, 1.414].
- Softmax of each row: [0.576, 0.140, 0.284] and [0.108, 0.446, 0.446].
- Weighted sums of the values. First token: 0.576 × [6, 0] + 0.140 × [0, 6] + 0.284 × [3, 3] = [4.31, 1.69]. Second token: 0.108 × [6, 0] + 0.446 × [0, 6] + 0.446 × [3, 3] = [1.99, 4.01].
The first A token reads mostly B's first token. The second splits its attention evenly between B's second and third tokens, whose keys match its query equally well.
The order of set B does not matter, and its size can change
Each A token takes a weighted sum over all of B, and a sum does not depend on the order of its terms. So reordering B's tokens leaves every output the same: cross-attention is permutation invariant in B. Reordering A's tokens reorders the outputs in the same way. Set B can also hold 3 tokens or 3,000; the output still has one vector per A token.
cross_attention.py
import numpy as np
def softmax(s):
e = np.exp(s - s.max(axis=-1, keepdims=True))
return e / e.sum(axis=-1, keepdims=True)
def cross_attention(Qa, Kb, Vb):
w = softmax(Qa @ Kb.T / np.sqrt(Qa.shape[-1])) # n rows, m columns
return w @ Vb, w
Qa = np.array([[1.0, 0.0], [0.0, 2.0]]) # queries from set A
Kb = np.array([[2.0, 0.0], [0.0, 1.0], [1.0, 1.0]]) # keys from set B
Vb = np.array([[6.0, 0.0], [0.0, 6.0], [3.0, 3.0]]) # values from set B
out, w = cross_attention(Qa, Kb, Vb)
print(np.round(w, 3))
print(np.round(out, 2))
perm = [2, 0, 1] # reorder set B
# np.allclose is True when two arrays match, up to tiny rounding errors
print(np.allclose(cross_attention(Qa, Kb[perm], Vb[perm])[0], out))
[[0.576 0.14 0.284] [0.108 0.446 0.446]] [[4.31 1.69] [1.99 4.01]] True
A model uses cross-attention to let each token choose what to read
A common block for set A runs three steps, each with a layer normalization and a residual connection: self-attention, so A's tokens can coordinate with each other; cross-attention, so each A token can read the condition B; and an MLP. The original transformer for translation worked this way: the words of the sentence being written read the words of the sentence being translated. The transformer block unit shows this pattern without the cross-attention step.
There are two other common ways to bring a condition in. A model can join A and B into one set and run self-attention over all n + m tokens. Or it can squeeze B into one summary vector and add it to every A token, which is cheap but gives every token the same information. Cross-attention lets each A token pick the parts of B it needs, at a cost of n × m scores.
Cross-attention can also shrink a large set. A model can learn a handful of query tokens that read a set of thousands of tokens, and so get a fixed-size summary of it. The Perceiver model works this way; PointNet pooling is a simpler order-free summary.
Like self-attention, cross-attention usually has several heads, and each projection usually has a bias. When the B sets in a batch have different sizes, libraries pad the short ones with dummy tokens and use a mask that sets the scores of the dummies to −∞, so they get zero weight.
Check yourself
-
Set A has 1,000 tokens and set B has 16. What shape is the table of weights, and how many output vectors are there?
Answer
The weights form a table of 1,000 rows and 16 columns: one row per A token, one column per B token. There are 1,000 output vectors, one per A token.
-
Work a similar problem. One A token has query [2, 0]. Set B has keys [1, 0] and [−1, 0], with the one-number values 5 and −5. What is the output?
Answer
Scores 2 and −2; divided by √2: 1.414 and −1.414. Softmax: e1.414 = 4.113 and e−1.414 = 0.243, so the weights are 0.944 and 0.056. Output: 0.944 × 5 + 0.056 × (−5) = 4.44.
-
You shuffle set B, then separately shuffle set A. What happens to the outputs each time?
Answer
Shuffling B changes nothing: each output is a sum over all of B. Shuffling A shuffles the outputs in the same way, since each A token still gets its own output.
-
Can one A token learn anything about another A token through a cross-attention layer?
Answer
No. Its keys and values come only from B. Information passes between A tokens in self-attention layers, which models place before or after the cross-attention.
Go further
Optional background, for readers who want more than this page.
-
Animates the original transformer's "encoder-decoder attention", which is cross-attention: the decoder's queries read the encoder's keys and values.
-
Dive into Deep Learning: "The Transformer Architecture", section "Decoder" Zhang, Lipton, Li and Smola Textbook section Advanced
Code for a decoder block with self-attention, then cross-attention to the encoder's output, then the MLP.
-
Uses a small set of learned queries that cross-attend to a large input, such as an image or a point cloud. Its Figure 1 shows the idea at a glance.
Where this shows up
No unit or explanation builds on this one yet.