Cross-attention lives inside each decoder block: queries come from the text token stream, keys and values come from the audio encoder's output.
Picture a court stenographer who listens to a recording and types up what was said. Their fingers (the decoder) are deciding the next character to type, but every few keystrokes they replay a bit of the audio to remember exactly what came next. The 'replaying audio while typing' is cross-attention: the typing side asks the audio side 'what should I write now?', and the audio side hands back the relevant sound, not as raw audio, but as a structured summary the typing side knows how to read.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Concept explanation~2 min read
Everything you need to truly understand this topic: intuition, mechanics, step by step explanation, code, formulas, and worked example. Click to expand.
Whisper is OpenAI's open-source automatic speech recognition (ASR) system, released in late 2022 and widely deployed in production through 2026 as the default high-quality ASR option. It uses the classic encoder-decoder transformer architecture from the original Vaswani 2017 paper, with one twist: the encoder processes audio (mel-spectrogram frames) instead of text. Cross-attention is what bridges the two modalities, lives in every decoder block, and is the single most important architectural detail for understanding how Whisper turns audio into text.
The question of 'where does cross-attention live in Whisper' is really a question about the encoder-decoder pattern itself. Cross-attention is the second attention block inside each decoder layer (between masked self-attention and the FFN), and it pulls queries from the decoder's text stream while pulling keys and values from the encoder's audio embeddings. That asymmetric Q vs K/V sourcing is what defines cross-attention and distinguishes it from self-attention.
This deep dive walks through Whisper's architecture, the mechanics of cross-attention inside the decoder, why encoder K/V are cached and reused, the 30-second chunking design, and the comparison to newer decoder-only audio LLMs.
Whisper's encoder-decoder architecture
Whisper has two main components: an audio encoder and a text decoder. They share architectural style (transformer blocks) but operate on different input modalities.
The audio encoder
Input: 30 seconds of audio converted to a log-mel spectrogram of shape (n_mels=80, n_frames=3000) at 100 Hz. A 2-layer 1D conv stem downsamples to 1500 frames at 50 Hz, projecting from 80 mel channels to d_model. Then learned positional embeddings are added, and 6 to 32 transformer blocks (depending on model size) process the audio with full bidirectional self-attention.
Output: a (1500, d_model) tensor of audio embeddings. This is what the decoder will attend over.
The text decoder
The decoder generates transcript tokens autoregressively. Each decoder block has three sub-blocks:
- Masked self-attention over the text tokens generated so far. The mask is causal; each token attends only to past tokens.
- Cross-attention with Q from the decoder hidden states and K, V from the encoder output. This is where the decoder pulls audio information.
- Feed-forward network, identical to standard transformer FFN.
LayerNorm is applied before each sub-block (pre-norm variant). The decoder uses the same number of layers as the encoder.
The vocabulary
50k+ multilingual BPE tokens, plus special tokens for language identification (50 languages plus 'auto'), task selection (transcribe vs translate), and timestamp prediction. The special tokens are critical: they let one model handle multiple languages and both ASR and translation.
Situations where this technique stops working.
2–4 min · Everything important, quickly.
import torch
import torch.nn as nn
class WhisperDecoderBlock(nn.Module):
def __init__(self, d_model, n_heads):
super().__init__()
self.self_attn = nn.MultiheadAttention(d_model, n_heads)
self.cross_attn = nn.MultiheadAttention(d_model, n_heads)
self.ffn = nn.Sequential(
nn.Linear(d_model, 4 * d_model),
nn.GELU(),
nn.Linear(4 * d_model, d_model),
)
self.ln1 = nn.LayerNorm(d_model)
self.ln2 = nn.LayerNorm(d_model)
self.ln3 = nn.LayerNorm(d_model)
def forward(self, x, audio_enc, causal_mask):
# x: (T_text, B, d_model), decoder hidden state
# audio_enc: (T_audio, B, d_model), encoder output (fixed per audio)
# 1. Masked self-attention over text tokens
h, _ = self.self_attn(x, x, x, attn_mask=causal_mask)
x = self.ln1(x + h)
# 2. Cross-attention: Q from text, K and V from audio encoder
h, _ = self.cross_attn(query=x, key=audio_enc, value=audio_enc)
x = self.ln2(x + h)
# 3. Feed-forward
x = self.ln3(x + self.ffn(x))
return xReal products, models, and research that use this idea.
- OpenAI Whisper large-v3 (released late 2023) is the production-default for high-quality ASR in 2026, used in transcription startups, podcast indexing, and meeting recorders.
- WhisperX adds forced-alignment to Whisper's output for precise word-level timestamps, useful for subtitle generation.
What an interviewer would ask next. Try answering before peeking at the approach.
QWhy are the encoder's K and V cached and reused across decode steps in Whisper?
The encoder output is a fixed function of the audio input; it doesn't depend on the text being generated. Computing K and V from the encoder output once and reusing them for every decoder step avoids redundant work. This is the cross-attention analog of the KV cache in decoder-only models, but for the encoder side. It's why Whisper's per-token decode latency is low: the expensive part (encoding 30 seconds of audio with multiple transformer layers) is amortized across all transcript tokens.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Red flags & common mistakes
The phrases that signal junior thinking. Click to expand.
Confusing cross-attention with the encoder's self-attention. Self-attention happens within one modality (audio attending to audio); cross-attention bridges two modalities (text queries pulling from audio keys/values).
60 second bullets to scan on the way to the call.
Whisper's architecture: encoder-decoder, not decoder-only
Audio encoder pipeline: mel-spectrogram, conv stem, self-attention layers
Primary sources. Browse if you want the original framing.
Same topic, related formats. Practice these next.