Skip to content

← Attention & Transformers step 8 of 8

Hard End-to-End

Transformer Decoder Block

Implement transformer_decoder as one decoder block: causal self-attention, cross-attention to encoder outputs, then a feed-forward network. Each stage normalizes its input before computing an update and adding a residual.

This is a single-head, unbatched exercise with identity attention projections. No learned query/key/value or attention-output matrices are needed.

Inputs and output

  • X: (T, D), the decoder sequence.
  • enc_out: (S, D), the encoder sequence. S and T may differ.
  • gamma1, beta1, gamma2, beta2, gamma3, beta3: (D,), the three pairs of layer-normalization scale and bias parameters.
  • W1: (D, F) and b1: (F,), the first feed-forward layer.
  • W2: (F, D) and b2: (D,), the second feed-forward layer.

T, S, D and F are positive. All inputs share a floating-point dtype and device. Return shape (T, D), preserving dtype and device and leaving all inputs unchanged.

Layer normalization

For each row independently, compute the mean and population variance across its D features. Divide the sum of squared deviations by D, not D-1:

LN(row, gamma, beta) = gamma * (row - mean) / sqrt(variance + 1e-5) + beta

The epsilon is inside the square root. Each stage has its own gamma and beta. Do not normalize across sequence positions.

Three stages

  1. Causal self-attention. Let H1 = LN(X, gamma1, beta1). Use H1 as queries, keys and values. Compute H1 @ H1.T / sqrt(D), with shape (T, T). For query row i, mask key positions j > i with negative infinity before softmax. Position i can attend to itself and earlier positions. Normalize each score row and set X1 = X + attention_weights @ H1.
  2. Cross-attention. Let H2 = LN(X1, gamma2, beta2). Compute H2 @ enc_out.T / sqrt(D), with shape (T, S), and normalize each row over all S encoder positions. Set X2 = X1 + attention_weights @ enc_out. Use enc_out unchanged as both keys and values; do not normalize or causally mask the encoder sequence.
  3. Feed-forward update. Let H3 = LN(X2, gamma3, beta3). Compute FF = ReLU(H3 @ W1 + b1) @ W2 + b2, then return X2 + FF. ReLU replaces negative values with zero.

Use a stable softmax. Each residual adds to the stage's unnormalized input, not to H1, H2 or H3. Apply no final layer normalization, dropout, padding mask or positional encoding.

For a single decoder row, self-attention has only one available key and therefore returns H1 directly. Cross-attention can still choose among multiple encoder positions.

The visualization below illustrates attention visibility. This exercise uses causal visibility for self-attention and all encoder positions for cross-attention.

Loading visualization…