lightning_indexer

Applicable Products

  • Ascend 950PR/Ascend 950DT: Not supported
  • Atlas A3 training products/Atlas A3 inference products: Supported
  • Atlas A2 training products/Atlas A2 inference products: Supported
  • Atlas 200I/500 A2 inference products: Not supported
  • Atlas inference products: Not supported
  • Atlas training products: Not supported

Function

  • Description:

    The lightning_indexer_metadata API generates a task list that contains the Batch, Head, and the block indices of Q and K at the start and end points of the Attention computation task for each AI core, for use by the subsequent lightning_indexer operator.

    The lightning_indexer API obtains the top-k positions corresponding to each token through a series of operations. The main computation process is as follows:

    1. Multiply the input parameter q (Qindex∈Rg×dQ_{index}\in\R^{g\times d}) corresponding to a token by the given context k (Kindex∈RSk×dK_{index}\in\R^{S_{k}\times d}) to obtain the correlation.
    2. After filtering out invalid negative correlation signals through the activation function ReLUReLU, obtain the correlation score vector between the current token and all preceding tokens.
    3. Multiply it by the weight coefficient w (WW), then along the direction of g, select the top Top−kTop-k indices to obtain the output sparseIndicessparseIndices, and output the corresponding sparseValuessparseValues as the input to Attention.
  • Formula:

    Top−k{[1]1× g@[(W@[1]1 × Sk) ⊙ ReLU(Qindex@KTindex)]}Top-k \left\{ \left[ 1 \left] \mathop{{}}\nolimits_{{1 \times \text{ }g}}\text{@} \left[ \left( W\text{@} \left[ 1 \left] \mathop{{}}\nolimits_{{1\text{ } \times \text{ }S\mathop{{}}\nolimits_{{k}}}} \left) \text{ } \odot \text{ }ReLU \left( Q\mathop{{}}\nolimits_{{index}}\text{@}K\mathop{{}}\nolimits_{{T}}^{{index}} \left) \left] \right\} \right. \right. \right. \right. \right. \right. \right. \right. \right. \right.

Prototype

Before calling the lightning_indexer API, call the preceding API lightning_indexer_metadata to complete the load balancing computation for lightning_indexer.

lightning_indexer_metadata(num_heads_q, num_heads_k, head_dim, topk, *, cu_seqlens_q=None, cu_seqlens_k=None, seqused_q=None, seqused_k=None, cmp_residual_k=None, batch_size=0, max_seqlen_q=-1, max_seqlen_k=-1, layout_q="BSND", layout_k="BSND", mask_mode=0, cmp_ratio=1) -> Tensor
lightning_indexer(q, k, w, topk, *, cu_seqlens_q=None, cu_seqlens_k=None, seqused_q=None, seqused_k=None, cmp_residual_k=None, block_table=None, output_idx_offset=None, metadata=None, max_seqlen_q=-1, layout_q="BSND", layout_k="BSND", mask_mode=0, cmp_ratio=1, return_value=0) -> (Tensor, Tensor)

Parameters

Note:

The dimension meanings of the q, k, and w parameters are as follows: B (Batch Size) indicates the batch size of input samples, S1 indicates the input sample sequence length of q, S2 indicates the input sample sequence length of k, N1 indicates the number of heads of q, N2 indicates the number of heads of k, D (Head Dim) indicates the dimension of the attention head, T1 indicates the cumulative sum of the input sample sequence length of q, and T2 indicates the cumulative sum of the input sample sequence length of k. The D value in parameter q is equal to the D value in parameter k, and currently only 128 is supported.

lightning_indexer_metadata

ParameterParameter TypeOptional/RequiredDescriptionData TypeDimension (Shape)
num_heads_qintRequiredNumber of heads in Query. Currently only 32/64 are supported.int32-
num_heads_kintRequiredNumber of heads in Key. Currently only 1 is supported.int32-
head_dimintRequiredDimension of the attention head. Currently only 128 is supported.int32-
topkintRequiredNumber of key sparse tokens selected from Query. Currently only [1, 2048] is supported.int32-
cu_seqlens_qTensorOptionalEffective sequence length of Query in different batches. Required only when layout_q is TND. The first value is fixed to 0. Data format is ND. Non-contiguous tensor is supported.int32B+1
cu_seqlens_kTensorOptionalEffective sequence length of Key in different batches. Required only when layout_k is TND. The first value is fixed to 0. Data format is ND. Non-contiguous tensor is supported.int32B+1
seqused_qTensorOptionalSequence length of Query that actually participates in computation in different batches. Data format is ND. Non-contiguous tensor is supported.int32B
seqused_kTensorOptionalSequence length of Key that actually participates in computation in different batches. Data format is ND. Non-contiguous tensor is supported.int32B
cmp_residual_kTensorOptionalRemainder of the compressed sequence length of cmp_kv in different batches. Used together with cmp_ratio to implement the mask and load computation of the cmp_kv part. Required when cmp_ratio is not 1 and mask_mode is 3. Data format is ND. Non-contiguous tensor is supported.int32B
batch_sizeintOptionalNumber of batches. The default value is 0.int32-
max_seqlen_qintOptionalMaximum sequence length of Query. -1 indicates any possible length. The default value is -1.int32-
max_seqlen_kintOptionalMaximum sequence length of Key. -1 indicates any possible length. The default value is -1.int32-
layout_qstrOptionalLayout format of Query. BSND and TND are supported. The default value is BSND.string-
layout_kstrOptionalLayout format of Key. BSND, TND, and PA_BBND are supported. The default value is BSND.string-
mask_modeintOptionalSparse mode. 0 indicates No mask, and 3 indicates rightDownCausal mode. The default value is 0.int32-
cmp_ratiointOptionalCompression ratio of Key. The value range is [1, 128]. The default value is 1, which indicates no compression.int32-

lightning_indexer

ParameterParameter TypeOptional/RequiredDescriptionData TypeDimension (Shape)
qTensorRequiredInput Q in the formula. Empty tensors are not supported. The data format is ND.bfloat16, float16When layout_q is BSND, the shape is (B,S1,N1,D); when layout_q is TND, the shape is (T1,N1,D).
kTensorRequiredInput K in the formula. Empty tensors are not supported. The data format is ND. Non-contiguous tensors are supported (only axis 0 supports non-contiguity in the PA_BBND use case).bfloat16, float16When layout_k is BSND, the shape is (B,S2,N2,D); when layout_k is TND, the shape is (T2,N2,D); when layout_k is PA_BBND, the shape is (block_num,block_size,N2,D).
wTensorRequiredInput W in the formula. Empty tensors are not supported. The data format is ND.floatWhen layout_q is BSND, the shape is (B,S1,N1); when layout_q is TND, the shape is (T1,N1).
topkintRequiredNumber of blocks to retain in the topK phase. The supported value range is [1, 8192].int32-
cu_seqlens_qTensorOptionalCumulative sum of the valid token counts of q in the current batch and preceding batches. Required only when layout_q is TND. The first value is fixed to 0. The data format is ND.int32(B+1,)
cu_seqlens_kTensorOptionalCumulative sum of the valid token counts of k in the current batch and preceding batches. Required only when layout_k is TND. The first value is fixed to 0. The data format is ND.int32(B+1,)
seqused_qTensorOptionalActual used length of q in different batches. The data format is ND.int32(B,)
seqused_kTensorOptionalActual used length of k in different batches. The data format is ND.int32(B,)
cmp_residual_kTensorOptionalRemainder of the token count of k before compression divided by cmp_ratio. Used when mask_mode is 3 and cmp_ratio is not 1. The data format is ND.int32(B,)
block_tableTensorOptionalBlock mapping table used for KV storage in PageAttention. Empty tensors are not supported. The data format is ND.int32(B, S2_max/block_size)
output_idx_offsetTensorOptionalOffset to add to the output index of the topK result. The value must be greater than 0. After adding the offset, the topK index must not exceed the maximum int32 value. The data format is ND.int32(B,)
metadataTensorOptionalCore-splitting information passed by the lightning_indexer_metadata operator, including the number of cores used, the block size, and the start point of the data processed by each core. Empty tensors are not supported. The data format is ND.int32(1024,)
max_seqlen_qintOptionalMaximum sequence length of q. -1 indicates any possible length. The default value is -1.int32-
layout_qstrOptionalData layout format of input q. Supports BSND and TND. The default value is BSND.string-
layout_kstrOptionalData layout format of input k. Supports BSND, TND, and PA_BBND. The default value is BSND.string-
mask_modeintOptionalMask mode. 0 indicates the defaultMask mode, and 3 indicates the rightDownCausal mode. The default value is 0.int32-
cmp_ratiointOptionalCompression ratio of k for sparse computation. Supports 1-128. The default value is 1, indicating no compression.int32-
return_valueintOptionalWhether to return the Values corresponding to Indices. 0 indicates not returning, and 1 indicates returning. The default value is 0.int32-
  • Atlas A3 training products/Atlas A3 inference products, Atlas A2 training products/Atlas A2 inference products:
    • The supported topk value range is [1, 2048], plus 3072, 4096, 5120, 6144, 7168, and 8192.
    • The sequsedQOptional, outputIdxOffsetOptional, and maxSeqlenQ features are not supported. Do not pass these parameters.
    • When layout_k is PA_BBND, sequsedKOptional must be passed. When layout_k is not PA_BBND, the sequsedKOptional feature is not supported. Do not pass this parameter.

Return Value

lightning_indexer_metadata

ParameterParameter TypeOptional/RequiredDescriptionData TypeDimension (Shape)
metadataTensorRequiredBatch, Head, and the Q and K block indices of the Attention computation task for each AI Core. The data format is ND. Non-contiguous tensors are not supported.int32shape is (1024,)

lightning_indexer

ParameterParameter TypeOptional/RequiredDescriptionData TypeDimension (Shape)
sparse_indicesTensorRequiredIndices output in the formula. Empty tensors are not supported. Invalid parts are filled with -1. The data format is ND.int32When layout_q is BSND, the shape is (B,S1,N2,topk); when layout_q is TND, the shape is (T1,N2,topk).
sparse_valuesTensorConditional outputValues output corresponding to Indices in the formula. When return_value is 1, the corresponding values are output; when return_value is 0, an empty tensor with shape [0] is output. Invalid parts are filled with -inf. The data format is ND.floatWhen layout_q is BSND, the shape is (B,S1,N2,topk); when layout_q is TND, the shape is (T1,N2,topk); when return_value is 0, the shape is (0,).

Constraints

  • This API supports use in training and inference use cases.
  • This API supports calls in single-operator mode and TorchAir graph mode (aclgraph).
  • The lightning_indexer_metadata API must be used together with the lightning_indexer operator.
  • B (Batch) indicates the batch size of the input samples.
  • The values of cu_seqlens_q and cu_seqlens_k must be the cumulative number of valid tokens of the current batch and preceding batches. The value of each subsequent element must be greater than or equal to that of the preceding element.
  • The values of seqused_q and seqused_k must indicate the number of valid tokens in each batch.
  • cmp_residual_k must satisfy cmp_residual_k[i] < cmp_ratio.
  • For details about the mask mode indicated by mask_mode, see sparse_mode parameter description.
  • The N of parameter q supports 1 to 64, the N of k supports 1, and headdim supports 128.
  • pa_kv_cache supports non-contiguity on axis 0. pa_block_size supports 1 to 1024 and meets the 32B block size alignment.
  • The data types of parameters q and k must be consistent.
  • Fill the invalid part of sparse_indices with -1 and the invalid part of sparse_values with -inf.
  • Atlas A3 training products/Atlas A3 inference products, Atlas A2 training products/Atlas A2 inference products:
    • The topk value range currently supports only [1, 2048], as well as 3072, 4096, 5120, 6144, 7168, and 8192.
    • The sequsedQOptional, outputIdxOffsetOptional, and maxSeqlenQ functions are not supported. Passing these parameters is not recommended.
    • When layout_k is PA_BBND, sequsedKOptional must be passed. When layout_k is not PA_BBND, the sequsedKOptional function is not supported, and passing this parameter is not recommended.

Deterministic Computation

  • Defaults to a deterministic computation.

Example

  • Single-operator mode call:

    import torch
    import torch_npu
    import numpy as np
    from cann_ops_transformer.ops import lightning_indexer, lightning_indexer_metadata
    
    B = 2
    S1 = 64
    S2 = 130
    N1 = 16
    N2 = 1
    D = 128
    topk = 32
    cmp_ratio = 4
    
    # Calculate the compressed S2 length and remainder.
    S2_compressed = S2 // cmp_ratio
    res_k = S2 % cmp_ratio
    
    # Construct the input.
    q = torch.randn(B, S1, N1, D, dtype=torch.float16).npu()
    k = torch.randn(B, S2_compressed, N2, D, dtype=torch.float16).npu()
    w = torch.randn(B, S1, N1, dtype=torch.float32).npu()
    cmp_residual_k = torch.tensor([res_k] * B, dtype=torch.int32).npu()
    
    # Generate metadata.
    metadata = lightning_indexer_metadata(
        num_heads_q=N1,
        num_heads_k=N2,
        head_dim=D,
        topk=topk,
        cmp_residual_k=cmp_residual_k,
        batch_size=B,
        max_seqlen_q=S1,
        max_seqlen_k=S2_compressed,
        layout_q="BSND",
        layout_k="BSND",
        mask_mode=3,
        cmp_ratio=cmp_ratio
    )
    
    # Execute lightning_indexer.
    sparse_indices, sparse_values = lightning_indexer(
        q, k, w, topk,
        cmp_residual_k=cmp_residual_k,
        metadata=metadata,
        max_seqlen_q=-1,
        layout_q="BSND",
        layout_k="BSND",
        mask_mode=3,
        cmp_ratio=cmp_ratio,
        return_value=0
    )
    print(f"sparse_indices shape: {sparse_indices.shape}")
  • aclgraph mode call:

    import torch
    import torch_npu
    import numpy as np
    import torchair
    from cann_ops_transformer.ops import lightning_indexer, lightning_indexer_metadata
    
    B = 2
    S1 = 64
    S2 = 130
    N1 = 16
    N2 = 1
    D = 128
    topk = 32
    cmp_ratio = 4
    
    S2_compressed = S2 // cmp_ratio
    res_k = S2 % cmp_ratio
    
    q = torch.randn(B, S1, N1, D, dtype=torch.float16).npu()
    k = torch.randn(B, S2_compressed, N2, D, dtype=torch.float16).npu()
    w = torch.randn(B, S1, N1, dtype=torch.float32).npu()
    cmp_residual_k = torch.tensor([res_k] * B, dtype=torch.int32).npu()
    
    class LightningIndexerNetwork(torch.nn.Module):
        def __init__(self):
            super(LightningIndexerNetwork, self).__init__()
    
        def forward(self, q, k, w, cmp_residual_k):
            metadata = torch.ops.cann_ops_transformer.lightning_indexer_metadata(
                num_heads_q=N1,
                num_heads_k=N2,
                head_dim=D,
                topk=topk,
                cmp_residual_k=cmp_residual_k,
                batch_size=B,
                max_seqlen_q=S1,
                max_seqlen_k=S2_compressed,
                layout_q="BSND",
                layout_k="BSND",
                mask_mode=3,
                cmp_ratio=cmp_ratio
            )
    
            return torch.ops.cann_ops_transformer.lightning_indexer(
                q, k, w, topk,
                cmp_residual_k=cmp_residual_k,
                metadata=metadata,
                max_seqlen_q=-1,
                layout_q="BSND",
                layout_k="BSND",
                mask_mode=3,
                cmp_ratio=cmp_ratio,
                return_value=1
            )
    
    from torchair.configs.compiler_config import CompilerConfig
    config = CompilerConfig()
    config.mode = "reduce-overhead"
    npu_backend = torchair.get_npu_backend(compiler_config=config)
    torch._dynamo.reset()
    npu_mode = torch.compile(LightningIndexerNetwork(), fullgraph=True, backend=npu_backend, dynamic=False)
    sparse_indices, sparse_values = npu_mode(q, k, w, cmp_residual_k)
    print(f"sparse_indices shape: {sparse_indices.shape}")