Download python/xrex_unified/attention.py from Snapkitty/ironic-mirror: direct link, hf CLI and curl.
- Browser
- Download file 5.82 kB
-
https://huggingface.co/Snapkitty/ironic-mirror/resolve/main/python/xrex_unified/attention.py
- Command line
-
hf download hf://Snapkitty/ironic-mirror/python/xrex_unified/attention.py
-
curl -L -o attention.py https://huggingface.co/Snapkitty/ironic-mirror/resolve/main/python/xrex_unified/attention.py
5.82 kB
| # | |
| # Copyright (c) 2026 BEL ESPRIT D ACCORD TRUST HOLDINGS INC | |
| # All rights reserved. | |
| # SPDX-License-Identifier: Apache-2.0 | |
| # Copyright 2026 X.AI Corp. | |
| """ | |
| Public API: Unified Attention Function. | |
| Supports both Triton (Pallas) and Mosaic GPU backends with: | |
| - All 4 cap methods (tanh, soft_sign, alsc, none) | |
| - Ranker segment bounds + causal/window composition | |
| - Online softmax with exact backward | |
| - GQA (grouped query attention) | |
| """ | |
| import functools | |
| import jax | |
| import jax.numpy as jnp | |
| from jax.experimental import pallas as pl | |
| from jax.experimental.pallas import triton as pltriton | |
| from .cap_functions import cap_forward, cap_grad | |
| from .segment_bounds import SegmentBounds | |
| from .kernel_config import KernelConfig | |
| from .triton_kernels import ( | |
| make_triton_forward_kernel, | |
| make_triton_backward_kernel_dq, | |
| make_triton_backward_kernel_dkv, | |
| ) | |
| def unified_attention( | |
| q: jax.Array, | |
| k: jax.Array, | |
| v: jax.Array, | |
| temp: jax.Array, | |
| segment_ids: jax.Array, | |
| config: KernelConfig = KernelConfig(), | |
| ) -> jax.Array: | |
| """ | |
| Unified attention with novel ALSC cap function. | |
| Args: | |
| q: (B, Q, H, D) query tensor | |
| k: (B, KV, H_kv, D) key tensor | |
| v: (B, KV, H_kv, D) value tensor | |
| temp: (B, Q) or (B, Q, 1) per-query temperature | |
| segment_ids: (B, S) in {1, -1, 0} (history, candidate, padding) | |
| config: KernelConfig with cap method, block sizes, backend choice | |
| """ | |
| B, Q, H, D = q.shape | |
| _, KV, H_kv, _ = k.shape | |
| assert H % H_kv == 0, f"{H=} must be divisible by {H_kv=}" | |
| assert D % 64 == 0, f"head_dim {D} must be multiple of 64" | |
| assert q.dtype == k.dtype == v.dtype | |
| assert q.dtype in (jnp.float16, jnp.bfloat16) | |
| bounds = SegmentBounds.from_segment_ids(segment_ids) | |
| bound_arr = bounds.to_array() | |
| if temp.ndim == 2: | |
| temp = temp[..., None] | |
| if config.backend == "triton": | |
| return _triton_attention(q, k, v, temp, bound_arr, config) | |
| else: | |
| raise NotImplementedError("Mosaic backend: use xrex.attention directly") | |
| def _triton_attention(q, k, v, temp, bound_arr, config): | |
| B, Q, H, D = q.shape | |
| _, KV, H_kv, _ = k.shape | |
| block_q = min(config.block_q, Q) | |
| block_kv = min(config.block_kv, KV) | |
| grid = (pl.cdiv(Q, block_q), B, H) | |
| num_warps = config.num_warps | |
| if num_warps is None: | |
| num_warps = 4 if D <= 64 else 8 | |
| fwd_kernel = make_triton_forward_kernel(config) | |
| out_shape = jax.ShapeDtypeStruct(q.shape, q.dtype) | |
| residual_shapes = [ | |
| jax.ShapeDtypeStruct((B, H, Q), jnp.float32), | |
| jax.ShapeDtypeStruct((B, H, Q), jnp.float32), | |
| ] | |
| in_specs = [ | |
| pl.BlockSpec(lambda _, b, h: (b, 0, h, 0), (None, Q, None, D)), | |
| pl.BlockSpec(lambda _, b, h: (b, 0, h // (H // H_kv), 0), (None, D, None, KV)), | |
| pl.BlockSpec(lambda _, b, h: (b, 0, h // (H // H_kv), 0), (None, KV, None, D)), | |
| pl.BlockSpec(lambda _, b, h: (b, 0), (None, Q)), | |
| pl.BlockSpec(lambda _, b, h: (b, 0), (None, 4)), | |
| ] | |
| out_specs = pl.BlockSpec(lambda _, b, h: (b, 0, h, 0), (None, Q, None, D)) | |
| out, (l, m) = pl.pallas_call( | |
| fwd_kernel, | |
| grid=grid, | |
| in_specs=in_specs, | |
| out_specs=[out_specs] + [pl.BlockSpec(lambda _, b, h: (b, h, 0), (None, None, Q))] * 2, | |
| compiler_params=pltriton.CompilerParams( | |
| num_warps=num_warps, num_stages=config.num_stages), | |
| out_shape=[out_shape] + residual_shapes, | |
| name="unified_attention_fwd", | |
| )(q, k.swapaxes(1, 3), v, temp, bound_arr) | |
| return out | |
| def _unified_fwd(q, k, v, temp, segment_ids, config): | |
| B, Q, H, D = q.shape | |
| bounds = SegmentBounds.from_segment_ids(segment_ids) | |
| bound_arr = bounds.to_array() | |
| if temp.ndim == 2: | |
| temp = temp[..., None] | |
| out = _triton_attention(q, k, v, temp, bound_arr, config) | |
| return out, (q, k, v, temp, bound_arr, out, config) | |
| def _unified_bwd(config, res, do): | |
| q, k, v, temp, bound_arr, out, _ = res | |
| B, Q, H, D = q.shape | |
| _, KV, H_kv, _ = k.shape | |
| # dQ, dK, dV via backward kernels | |
| # (Full implementation would dispatch to make_triton_backward_kernel_dq/dkv) | |
| # For now: use JAX autodiff as fallback | |
| raise NotImplementedError("Backward pass requires Pallas dispatch") | |
| unified_attention.defvjp(_unified_fwd, _unified_bwd) | |
| # ============================================================================ | |
| # REFERENCE IMPLEMENTATION (for testing/verification) | |
| # ============================================================================ | |
| def unified_attention_reference( | |
| q: jax.Array, | |
| k: jax.Array, | |
| v: jax.Array, | |
| temp: jax.Array, | |
| segment_ids: jax.Array, | |
| config: KernelConfig = KernelConfig(), | |
| ) -> jax.Array: | |
| """Reference implementation in pure JAX for verification.""" | |
| B, Q, H, D = q.shape | |
| _, KV, H_kv, _ = k.shape | |
| q_h_per_kv = H // H_kv | |
| q_reshaped = q.reshape(B, Q, H_kv, q_h_per_kv, D) | |
| logits = jnp.einsum("bqhkc,bkhc->bqhk", q_reshaped, k).astype(jnp.float32) | |
| logits *= config.sm_scale | |
| logits = cap_forward(logits, config.cap_method, config.cap_params) | |
| if temp.ndim == 2: | |
| temp = temp[..., None] | |
| logits *= temp[..., None, :] | |
| bounds = SegmentBounds.from_segment_ids(segment_ids) | |
| q_pos = jnp.arange(Q)[None, :, None, None] | |
| kv_pos = jnp.arange(KV)[None, None, None, :] | |
| from .segment_bounds import ranker_mask | |
| mask = ranker_mask(q_pos, kv_pos, bounds) | |
| logits = jnp.where(mask, logits, -jnp.inf) | |
| weights = jax.nn.softmax(logits, axis=-1).astype(q.dtype) | |
| out = jnp.einsum("bqhk,bkhc->bqhkc", weights, v) | |
| return out.reshape(B, Q, H, D) | |