Grouped-query attention

ResearchMedium30 min12 checks

attentiongqatransformerskv-cache

Problem

Grouped-query attention (GQA) lets several query heads share one key head and one value head. The model then stores fewer keys and values in its cache. With one group, GQA is multi-query attention. With one group for each query head, GQA is standard multi-head attention. Large open models such as Llama 3 use GQA.

Task

Write three functions.

  1. repeat_kv(kv, n_heads) repeats each key or value head so that every query head has a matching head.
  2. grouped_query_attention(x, w_q, w_k, w_v, w_o, n_heads, n_kv_heads) returns the output and the attention weights of GQA self-attention.
  3. mean_pool_kv_heads(w, n_heads, n_kv_heads) turns the key or value projection of a multi-head checkpoint into a GQA projection.

Let H be n_heads, G be n_kv_heads, r = H / G and d_{head} = D / H. Head h of a projected array holds the columns h \cdot d_{head} to (h + 1) \cdot d_{head} - 1, in the same order. Query head h uses key and value group \lfloor h / r \rfloor. So the first r query heads use group 0, the next r use group 1, and so on.

The steps of grouped_query_attention are:

  1. Q = x W_q, K = x W_k, V = x W_v. There are no bias terms.
  2. Split Q into H heads and split K and V into G heads each. Repeat K and V to H heads.
  3. In each head, compute \mathrm{softmax}(Q_h K_h^T / \sqrt{d_{head}})\, V_h. The softmax is over the key axis. There is no mask.
  4. Join the H head outputs in head order, so that the result has shape (B, T, D), and multiply by W_o.

mean_pool_kv_heads takes a projection with H heads. Group g of the result is the mean of the heads g r to g r + r - 1.

All three functions raise ValueError when H is not a multiple of G.

Input and output

NameTypeShapeMeaning
kvfloat array(B, G, T, d_head)keys or values split into G heads
xfloat array(B, T, D)a batch of B sequences of T tokens with D features
w_qfloat array(D, D)the query projection
w_k, w_vfloat array(D, G * d_head)the key and value projections
w_ofloat array(D, D)the output projection
n_headsintthe number of query heads H
n_kv_headsintthe number of key and value groups G
wfloat array(D, H * d_head)a key or value projection with H heads
  • repeat_kv returns a float array of shape (B, H, T, d_head).
  • grouped_query_attention returns a tuple (output, weights). output has shape (B, T, D). weights has shape (B, H, T, T), and weights[b, h, i, j] is the weight that query i gives to key j in head h.
  • mean_pool_kv_heads returns a float array of shape (D, G * d_head).

Constraints

  • 1 <= B <= 4, 1 <= T <= 32, 1 <= G <= H <= 16 and D is a multiple of H.
  • Divide the scores by \sqrt{d_{head}}, not by \sqrt{D}.
  • Do not change the input arrays.
  • Use numpy only.

Examples

pythonkv = np.arange(8.0).reshape(1, 2, 2, 2)
repeat_kv(kv, 4)[0]
text[[[0. 1.]
  [2. 3.]]

 [[0. 1.]
  [2. 3.]]

 [[4. 5.]
  [6. 7.]]

 [[4. 5.]
  [6. 7.]]]
pythonx = np.array([[[1.0, 0.0, 0.0, 1.0], [0.0, 1.0, 1.0, 0.0], [1.0, 1.0, 0.0, 0.0]]])
w_k = np.array([[1.0, 0.0], [0.0, 1.0], [0.0, 0.0], [0.0, 0.0]])
w_v = np.array([[1.0, 0.0], [0.0, 2.0], [0.0, 0.0], [1.0, 0.0]])
output, weights = grouped_query_attention(x, np.eye(4), w_k, w_v, np.eye(4), 2, 1)
textoutput
[[[1.20333628 1.19777581 0.79666372 1.60444837]
  [0.79666372 1.60444837 1.20333628 1.19777581]
  [1.         1.50348984 1.         1.33333333]]]
weights
[[[[0.40111209 0.19777581 0.40111209]
   [0.19777581 0.40111209 0.40111209]
   [0.24825508 0.24825508 0.50348984]]

  [[0.19777581 0.40111209 0.40111209]
   [0.40111209 0.19777581 0.40111209]
   [0.33333333 0.33333333 0.33333333]]]]
pythonmean_pool_kv_heads(np.arange(16.0).reshape(2, 8), 4, 2)
text[[ 1.  2.  5.  6.]
 [ 9. 10. 13. 14.]]

Source paper GQA: Training Generalized Multi-Query Transformer Models from Multi-Head Checkpoints, Ainslie et al., 2023.

Hints

4 hints

    Solution and notes

    Locked

    Pass every check with Submit to open the reference solution and the notes.

    Run it on your computer

    Clone the repository, install numpy and run the same checks in a terminal:

    python3 scripts/practice/run.py grouped-query-attention my_answer.py
    python3 scripts/practice/run.py grouped-query-attention my_answer.py --examples

    Start my_answer.py from starter.py.

    Your code

    Python loads on the first run

    Your code is saved in this browser as you type. On a phone you can read and edit the code, but the checks are easier to use on a desktop.

    Keyboard shortcuts
    Ctrl Enter
    Run the examples
    Ctrl Shift Enter
    Submit
    Tab / Shift Tab
    Indent or outdent the lines
    Esc then Tab
    Move the focus out of the editor
    Alt H
    Show the next hint

    On a Mac, use Cmd in place of Ctrl.

    Select Run to check the examples, or Submit to run every check.