One Perceiver Resampler Block
Problem Statement
Implement one full Perceiver-Resampler cross-attention block: learned queries attend to the concatenation of the image features and the queries themselves (the resampler's key/value trick), followed by an add-and-project residual.
Background
The Flamingo/BLIP-2 resampler updates Q learned latents by cross-attending to visual features X. A single block does:
- Keys/values come from KV = concat(X, latents) along the token axis — the latents attend to the image and to themselves.
- Single-head scaled dot-product attention with the latents as queries: A = softmax(latents @ KV^T / sqrt(d)) @ KV.
- Residual add: out = latents + A.
All matrices share dimension d (no separate projections in this simplified block). Softmax is row-wise and numerically stable.
Your Task
Implement:
def perceiver_block(latents, X):
- latents: Q x d learned queries.
- X: N x d image features.
Return the Q x d output as a nested list rounded to 4 decimals.
Input Format
- latents: Q x d nested list.
- X: N x d nested list.
Output Format
- A Q x d nested list rounded to 4 decimals.
Sample
latents = [[1.0, 0.0]]
X = [[0.0, 2.0]]
print(perceiver_block(latents, X))
Output:
[[1.6698, 0.6605]]
Example
latents = [[1.0, 0.0]] X = [[0.0, 2.0]] print(perceiver_block(latents, X))
[[1.6698, 0.6605]]
KV = [[0,2],[1,0]]. Scores = latents·KV^T / sqrt(2) = [0, 1]/sqrt(2) = [0, 0.7071]; softmax = [0.3302, 0.6698]; A = 0.3302*[0,2]+0.6698*[1,0] = [0.6698, 0.6605]; out = latents + A = [1.6698, 0.6605].
Constraints
1 <= Q, N <= 256,1 <= d <= 512.- Keys/values are
concat(X, latents)along the token axis. - Scale by
1/sqrt(d); softmax over the KV axis, stably; then residual-add the latents. - Round to 4 decimals; avoid
-0.0.