TensorTonic
Problems
Grouped-Query Decode Step
JAX
Medium

Compute the attention output of one new token for every query head, reading keys and values from a fixed-size cache whose heads are shared by groups of query heads.

query has shape (B, Hq, D) for B sequences, Hq query heads and head size D. key_cache and value_cache have shape (B, S, Hkv, D), where S is the number of cache slots and Hkv is the number of cache heads. With the group size G = Hq / Hkv, query head h reads cache head g=⌊h/G⌋g = \lfloor h / G \rfloorg=⌊h/G⌋, so query heads 0 to G - 1 share cache head 0, the next G query heads share cache head 1, and so on.

Only slots j<lengths[b]j < \text{lengths}[b]j<lengths[b] of sequence b hold real tokens, and the new token's own key and value are already stored among them. For query head h of sequence b, with query vector qqq and with KjK_jKj​ and VjV_jVj​ the key and value at slot j of cache head g,

sj=q⋅KjD,wj=esj∑m<lengths[b]esm,o=∑j<lengths[b]wjVj.s_j = \frac{q \cdot K_j}{\sqrt{D}}, \qquad w_j = \frac{e^{s_j}}{\sum_{m < \text{lengths}[b]} e^{s_m}}, \qquad o = \sum_{j < \text{lengths}[b]} w_j V_j .sj​=D​q⋅Kj​​,wj​=∑m<lengths[b]​esm​esj​​,o=j<lengths[b]∑​wj​Vj​.

Slots at or beyond the length hold stale numbers from earlier requests and must receive zero weight.

Your function is called under jax.jit with lengths traced, so a length cannot set the size of any array.

Return a float32 JAX array of shape (B, Hq, D) whose entry for sequence b and head h is the output ooo.

Examples

Input: query = [[[1,0],[0,1]]], key_cache = [[[[1,0]],[[0,1]],[[5,5]]]], value_cache = [[[[1,2]],[[3,4]],[[50,50]]]], lengths = [2]

Output: [[[1.660477,2.660477],[2.339523,3.339523]]]

Explanation: Both query heads read the single cache head, and only slots 0 and 1 are valid, so the stale value [50, 50] in slot 2 gets no weight. Head 0 scores the two keys as 1 / sqrt(2) = 0.707107 and 0, the softmax gives weights 0.669762 and 0.330238, and the output is 0.669762 * [1, 2] + 0.330238 * [3, 4] = [1.660477, 2.660477].

Input: query = [[[1,0],[0,1],[1,1],[-1,0]],[[0.5,0.5],[1,-1],[0,2],[2,0]]], key_cache = [[[[1,0],[0,1]],[[0,1],[1,0]],[[1,1],[-1,1]]],[[[1,0],[0,1]],[[9,9],[9,9]],[[9,9],[9,9]]]], value_cache = [[[[1,0],[0,1]],[[0,1],[1,0]],[[2,2],[-2,2]]],[[[1,2],[3,4]],[[90,90],[90,90]],[[90,90],[90,90]]]], lengths = [3,1]

Output: [[[1.203336,1.0],[1.0,1.203336],[0.00556,0.796664],[-1.011921,1.435946]],[[1.0,2.0],[1.0,2.0],[3.0,4.0],[3.0,4.0]]]

Input: query = [[[1,0,1,0],[0,2,0,-1]]], key_cache = [[[[1,1,0,0],[0,1,0,1]],[[0,0,1,1],[1,0,1,0]],[[1,0,0,1],[0,0,2,0]],[[0,1,1,0],[1,1,1,1]]]], value_cache = [[[[1,0,0,0],[0,1,0,0]],[[0,1,0,0],[0,0,1,0]],[[0,0,1,0],[0,0,0,1]],[[0,0,0,1],[1,0,0,0]]]], lengths = [4]

Output: [[[0.25,0.25,0.25,0.25],[0.31123,0.31123,0.18877,0.18877]]]

Hint 1

q.reshape(B, num_kv_heads, group, d) groups query heads by cache head.

Hint 2

jnp.einsum("bkgd,bskd->bkgs", q, keys) contracts D against a (B, S, Hkv, D) cache.

Hint 3

jnp.arange(T)[None, :] < lengths[:, None] builds a fixed-shape validity mask.

Requirements

  • Give invalid slots zero weight by masking their scores before the softmax.
  • Convert bfloat16 caches to float32 and compute the scores, softmax and weighted sum in float32.

Constraints

  • B is between 1 and 3, S is between 3 and 8, Hq is between 2 and 8, D is between 2 and 4, and Hkv is between 1 and Hq with Hq a multiple of Hkv.
  • lengths is an int32 array of shape (B,) with every value between 1 and S.
  • query is float32, and key_cache and value_cache share one dtype, float32 or bfloat16. Public cases and custom Run inputs use float32 caches.
  • All values are finite, and stale slots may hold values much larger than the valid ones.
Try Similar Problems
Top-k and Top-p SamplingMediumRotary Position EmbeddingEasyKV Cache Update at a PositionEasyPad and Mask to Bucket LengthMediumHessian-Vector ProductMediumPer-Example Gradient ClippingMediumStraight-Through Estimator with Custom VJPMediumTraced Learning Rate ScheduleMediumExponential Moving Average with ScanMediumSpectral Norm by Power IterationMediumBatched Attention with vmapMediumPairwise Distances with Nested vmapMedium

Accepts: array

Accepts: array

Accepts: array

Accepts: array

You must run your code first.
Grouped-Query Decode Step

Grouped-Query Decode Step

JAX
Medium

Compute the attention output of one new token for every query head, reading keys and values from a fixed-size cache whose heads are shared by groups of query heads.

query has shape (B, Hq, D) for B sequences, Hq query heads and head size D. key_cache and value_cache have shape (B, S, Hkv, D), where S is the number of cache slots and Hkv is the number of cache heads. With the group size G = Hq / Hkv, query head h reads cache head g=⌊h/G⌋g = \lfloor h / G \rfloorg=⌊h/G⌋, so query heads 0 to G - 1 share cache head 0, the next G query heads share cache head 1, and so on.

Only slots j<lengths[b]j < \text{lengths}[b]j<lengths[b] of sequence b hold real tokens, and the new token's own key and value are already stored among them. For query head h of sequence b, with query vector qqq and with KjK_jKj​ and VjV_jVj​ the key and value at slot j of cache head g,

sj=q⋅KjD,wj=esj∑m<lengths[b]esm,o=∑j<lengths[b]wjVj.s_j = \frac{q \cdot K_j}{\sqrt{D}}, \qquad w_j = \frac{e^{s_j}}{\sum_{m < \text{lengths}[b]} e^{s_m}}, \qquad o = \sum_{j < \text{lengths}[b]} w_j V_j .sj​=D​q⋅Kj​​,wj​=∑m<lengths[b]​esm​esj​​,o=j<lengths[b]∑​wj​Vj​.

Slots at or beyond the length hold stale numbers from earlier requests and must receive zero weight.

Your function is called under jax.jit with lengths traced, so a length cannot set the size of any array.

Return a float32 JAX array of shape (B, Hq, D) whose entry for sequence b and head h is the output ooo.

Examples

Input: query = [[[1,0],[0,1]]], key_cache = [[[[1,0]],[[0,1]],[[5,5]]]], value_cache = [[[[1,2]],[[3,4]],[[50,50]]]], lengths = [2]

Output: [[[1.660477,2.660477],[2.339523,3.339523]]]

Explanation: Both query heads read the single cache head, and only slots 0 and 1 are valid, so the stale value [50, 50] in slot 2 gets no weight. Head 0 scores the two keys as 1 / sqrt(2) = 0.707107 and 0, the softmax gives weights 0.669762 and 0.330238, and the output is 0.669762 * [1, 2] + 0.330238 * [3, 4] = [1.660477, 2.660477].

Input: query = [[[1,0],[0,1],[1,1],[-1,0]],[[0.5,0.5],[1,-1],[0,2],[2,0]]], key_cache = [[[[1,0],[0,1]],[[0,1],[1,0]],[[1,1],[-1,1]]],[[[1,0],[0,1]],[[9,9],[9,9]],[[9,9],[9,9]]]], value_cache = [[[[1,0],[0,1]],[[0,1],[1,0]],[[2,2],[-2,2]]],[[[1,2],[3,4]],[[90,90],[90,90]],[[90,90],[90,90]]]], lengths = [3,1]

Output: [[[1.203336,1.0],[1.0,1.203336],[0.00556,0.796664],[-1.011921,1.435946]],[[1.0,2.0],[1.0,2.0],[3.0,4.0],[3.0,4.0]]]

Input: query = [[[1,0,1,0],[0,2,0,-1]]], key_cache = [[[[1,1,0,0],[0,1,0,1]],[[0,0,1,1],[1,0,1,0]],[[1,0,0,1],[0,0,2,0]],[[0,1,1,0],[1,1,1,1]]]], value_cache = [[[[1,0,0,0],[0,1,0,0]],[[0,1,0,0],[0,0,1,0]],[[0,0,1,0],[0,0,0,1]],[[0,0,0,1],[1,0,0,0]]]], lengths = [4]

Output: [[[0.25,0.25,0.25,0.25],[0.31123,0.31123,0.18877,0.18877]]]

Hint 1

q.reshape(B, num_kv_heads, group, d) groups query heads by cache head.

Hint 2

jnp.einsum("bkgd,bskd->bkgs", q, keys) contracts D against a (B, S, Hkv, D) cache.

Hint 3

jnp.arange(T)[None, :] < lengths[:, None] builds a fixed-shape validity mask.

Requirements

  • Give invalid slots zero weight by masking their scores before the softmax.
  • Convert bfloat16 caches to float32 and compute the scores, softmax and weighted sum in float32.

Constraints

  • B is between 1 and 3, S is between 3 and 8, Hq is between 2 and 8, D is between 2 and 4, and Hkv is between 1 and Hq with Hq a multiple of Hkv.
  • lengths is an int32 array of shape (B,) with every value between 1 and S.
  • query is float32, and key_cache and value_cache share one dtype, float32 or bfloat16. Public cases and custom Run inputs use float32 caches.
  • All values are finite, and stale slots may hold values much larger than the valid ones.
Try Similar Problems
Top-k and Top-p SamplingMediumRotary Position EmbeddingEasyKV Cache Update at a PositionEasyPad and Mask to Bucket LengthMediumHessian-Vector ProductMediumPer-Example Gradient ClippingMediumStraight-Through Estimator with Custom VJPMediumTraced Learning Rate ScheduleMediumExponential Moving Average with ScanMediumSpectral Norm by Power IterationMediumBatched Attention with vmapMediumPairwise Distances with Nested vmapMedium

Accepts: array

Accepts: array

Accepts: array

Accepts: array

You must run your code first.
Problems
Loading...
1 / 1