2025-09-09 09:40:35 +08:00
/*
* Copyright ( c ) Huawei Technologies Co . , Ltd . 2024. All rights reserved .
*
* Licensed under the Apache License , Version 2.0 ( the " License " ) ;
* you may not use this file except in compliance with the License .
* You may obtain a copy of the License at
*
* http : //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing , software
* distributed under the License is distributed on an " AS IS " BASIS ,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND , either express or implied .
* See the License for the specific language governing permissions and
* limitations under the License .
*/
# include <torch/extension.h>
# include <torch/library.h>
# include <torch/version.h>
2026-08-27 15:11:51 +08:00
# include <torch/torch.h>
# include <ATen/core/Formatting.h>
# include "acl/acl.h"
# include "acl/acl_rt.h"
2025-09-09 09:40:35 +08:00
# include <torch_npu/csrc/core/npu/NPUStream.h>
# include <torch_npu/csrc/framework/OpCommand.h>
2026-08-27 15:11:51 +08:00
# include <torch_npu/csrc/framework/utils/OpPreparation.h>
# include "torch_npu/csrc/core/npu/NPUGuard.h"
2025-09-09 09:40:35 +08:00
# include <torch_npu/csrc/npu/Module.h>
# include "ops.h"
# include "utils.h"
2026-08-27 15:11:51 +08:00
# include "aclnn_torch_adapter/op_api_common.h"
# include "moe/add_rms_norm_bias/add_rms_norm_bias_torch_adpt.h"
# ifdef VLLM_ENABLE_ATB_AND_DIRECT_KERNELS
# include "batch_matmul_transpose/batch_matmul_transpose_torch_adpt.h"
# include "mla_preprocess/mla_preprocess_torch_adpt.h"
# endif
# include "mc2/dispatch_ffn_combine/dispatch_ffn_combine_torch_adpt.h"
# include "mc2/dispatch_gmm_combine_decode/dispatch_gmm_combine_decode_torch_adpt.h"
# include "gmm/grouped_matmul_swiglu_quant_weight_nz_tensor_list/grouped_matmul_swiglu_quant_torch_adpt.h"
# include "gmm/grouped_matmul_swiglu_quant_v2/grouped_matmul_swiglu_quant_v2_torch_adpt.h"
# include "attention/lightning_indexer/lightning_indexer_torch_adpt.h"
# include "mc2/matmul_allreduce_add_rmsnorm/matmul_allreduce_add_rmsnorm_torch_adpt.h"
# include "moe/moe_gating_top_k/moe_gating_top_k_torch_adpt.h"
# include "moe/moe_init_routing_custom/moe_init_routing_custom_torch_adpt.h"
# include "attention/sparse_flash_attention/sparse_flash_attention_torch_adpt.h"
# include "attention/kv_quant_sparse_flash_attention/kv_quant_sparse_flash_attention_torch_adpt.h"
# include "attention/lightning_indexer_quant/lightning_indexer_quant_torch_adpt.h"
# include "attention/ngram_spec_decode/ngram_spec_decode_torch_adpt.h"
# include "moe/causal_conv1d_v310/causal_conv1d_310_torch_adpt.h"
# include "attention/recurrent_gated_delta_rule/recurrent_gated_delta_rule_torch_adpt.h"
# include "attention/recurrent_gated_delta_rule_v310/recurrent_gated_delta_rule_310_torch_adpt.h"
# include "attention/store_kv_block/store_kv_block_torch_adpt.h"
# include "attention/store_kv_block_metadata/store_kv_block_metadata_torch_adpt.cpp"
# include "attention/fused_gdn_gating/fused_gdn_gating_torch_adpt.h"
# include <c10/core/Device.h>
# include <c10/core/Scalar.h>
# include <c10/util/Exception.h>
# include <c10/util/Logging.h>
# include <array>
# include <cmath>
# include <iostream>
# include <memory>
# include <mutex>
# include <sstream>
# include <unordered_map>
# include <vector>
2025-09-09 09:40:35 +08:00
namespace vllm_ascend {
2026-08-27 15:11:51 +08:00
namespace {
constexpr int64_t DSA_SLOT_MAPPING_FLAT = 1 ;
constexpr int64_t DSA_SLOT_MAPPING_BLOCK_OFFSET = 2 ;
struct DevicePrintPayload {
std : : string message ;
at : : Tensor host_tensor_snapshot ;
} ;
std : : mutex & get_device_print_mutex ( )
{
static std : : mutex device_print_mutex ;
return device_print_mutex ;
}
void device_print_callback ( void * args )
{
// device_print is a debug-only helper. We intentionally do not reclaim the
// callback payload here because aclgraph replay may re-execute the same host
// callback payload multiple times. Freeing it on first execution would make
// later replays dereference a dangling pointer.
auto * payload = static_cast < DevicePrintPayload * > ( args ) ;
if ( payload = = nullptr ) {
return ;
}
std : : lock_guard < std : : mutex > guard ( get_device_print_mutex ( ) ) ;
if ( ! payload - > message . empty ( ) ) {
std : : cout < < payload - > message ;
}
if ( payload - > host_tensor_snapshot . defined ( ) ) {
if ( ! payload - > message . empty ( ) ) {
std : : cout < < std : : endl ;
}
at : : print ( std : : cout , payload - > host_tensor_snapshot . contiguous ( ) , 120 ) ;
}
std : : cout < < std : : endl ;
std : : cout . flush ( ) ;
}
void enqueue_device_print ( std : : unique_ptr < DevicePrintPayload > payload ,
aclrtStream stream )
{
auto * raw_payload = payload . release ( ) ;
const aclError ret = aclrtLaunchHostFunc ( stream , device_print_callback ,
raw_payload ) ;
if ( ret ! = ACL_SUCCESS ) {
delete raw_payload ;
}
TORCH_CHECK ( ret = = ACL_SUCCESS , " aclrtLaunchHostFunc failed, error code: " , ret ) ;
}
}
void swap_blocks_batch ( const torch : : Tensor & src_ptrs ,
const torch : : Tensor & dst_ptrs ,
const torch : : Tensor & sizes ,
int64_t direction ) {
TORCH_CHECK ( src_ptrs . device ( ) . is_cpu ( ) , " src_ptrs must be on CPU " ) ;
TORCH_CHECK ( dst_ptrs . device ( ) . is_cpu ( ) , " dst_ptrs must be on CPU " ) ;
TORCH_CHECK ( sizes . device ( ) . is_cpu ( ) , " sizes must be on CPU " ) ;
TORCH_CHECK ( src_ptrs . dtype ( ) = = torch : : kInt64 , " src_ptrs must be int64 " ) ;
TORCH_CHECK ( dst_ptrs . dtype ( ) = = torch : : kInt64 , " dst_ptrs must be int64 " ) ;
TORCH_CHECK ( sizes . dtype ( ) = = torch : : kInt64 , " sizes must be int64 " ) ;
const int64_t n = src_ptrs . size ( 0 ) ;
TORCH_CHECK ( dst_ptrs . size ( 0 ) = = n , " dst_ptrs length must match src_ptrs " ) ;
TORCH_CHECK ( sizes . size ( 0 ) = = n , " sizes length must match src_ptrs " ) ;
if ( n = = 0 ) return ;
const int64_t * src_data = src_ptrs . data_ptr < int64_t > ( ) ;
const int64_t * dst_data = dst_ptrs . data_ptr < int64_t > ( ) ;
const int64_t * size_data = sizes . data_ptr < int64_t > ( ) ;
aclrtStream stream = c10_npu : : getCurrentNPUStream ( ) . stream ( ) ;
aclrtMemcpyKind memcpy_kind ;
switch ( direction ) {
case 0 :
memcpy_kind = ACL_MEMCPY_HOST_TO_DEVICE ;
break ;
case 1 :
memcpy_kind = ACL_MEMCPY_DEVICE_TO_HOST ;
break ;
case 2 :
memcpy_kind = ACL_MEMCPY_DEVICE_TO_DEVICE ;
break ;
default :
TORCH_CHECK ( false ,
" swap_blocks_batch: invalid direction " , direction ,
" (expected 0=H2D, 1=D2H, 2=D2D) " ) ;
}
// =========================================================================
// path 1: aclrtMemcpyBatchAsync (CANN 8.5+)
// =========================================================================
# if defined(CANN_MEMCPY_BATCH_ASYNC)
if ( memcpy_kind ! = ACL_MEMCPY_DEVICE_TO_DEVICE ) {
static_assert ( sizeof ( void * ) = = sizeof ( int64_t ) ,
" void* and int64_t must be the same size " ) ;
static_assert ( sizeof ( size_t ) = = sizeof ( int64_t ) ,
" size_t and int64_t must be the same size " ) ;
void * * dst_arr = reinterpret_cast < void * * > (
const_cast < int64_t * > ( dst_data ) ) ;
void * * src_arr = reinterpret_cast < void * * > (
const_cast < int64_t * > ( src_data ) ) ;
size_t * size_arr = reinterpret_cast < size_t * > (
const_cast < int64_t * > ( size_data ) ) ;
size_t * dest_maxs = size_arr ;
// aclrtMemcpyBatchAttr uses srcLoc/dstLoc (aclrtMemLocation)
// to specify memory locations, not aclrtMemcpyKind.
int32_t device_id = 0 ;
aclrtGetDevice ( & device_id ) ;
aclrtMemLocation host_loc = { } ;
host_loc . type = ACL_MEM_LOCATION_TYPE_HOST ;
host_loc . id = 0 ;
aclrtMemLocation device_loc = { } ;
device_loc . type = ACL_MEM_LOCATION_TYPE_DEVICE ;
device_loc . id = device_id ;
aclrtMemcpyBatchAttr attr = { } ;
if ( memcpy_kind = = ACL_MEMCPY_HOST_TO_DEVICE ) {
attr . srcLoc = host_loc ;
attr . dstLoc = device_loc ;
} else { // ACL_MEMCPY_DEVICE_TO_HOST
attr . srcLoc = device_loc ;
attr . dstLoc = host_loc ;
}
size_t attrs_index = 0 ;
size_t fail_index = 0 ;
aclError result = aclrtMemcpyBatchAsync (
dst_arr , dest_maxs , src_arr , size_arr ,
static_cast < size_t > ( n ) ,
& attr , & attrs_index , 1 ,
& fail_index , stream ) ;
TORCH_CHECK ( result = = ACL_SUCCESS ,
" aclrtMemcpyBatchAsync failed at index " , fail_index ,
" with error code " , result ) ;
return ;
}
# endif
// =========================================================================
// path 2: aclrtMemcpyAsync
// =========================================================================
for ( int64_t i = 0 ; i < n ; i + + ) {
void * dst = reinterpret_cast < void * > ( dst_data [ i ] ) ;
const void * src = reinterpret_cast < const void * > ( src_data [ i ] ) ;
size_t copy_size = static_cast < size_t > ( size_data [ i ] ) ;
aclError ret = aclrtMemcpyAsync (
dst ,
copy_size ,
src ,
copy_size ,
memcpy_kind ,
stream ) ;
TORCH_CHECK ( ret = = ACL_SUCCESS ,
" aclrtMemcpyAsync failed at index " , i ,
" with error code " , ret ,
" , src= " , src_data [ i ] ,
" , dst= " , dst_data [ i ] ,
" , size= " , size_data [ i ] ) ;
}
}
# ifdef VLLM_ENABLE_ATB_AND_DIRECT_KERNELS
// Direct kernel wrappers depend on vllm_ascend_kernels, which is skipped on
// 310P and A5 builds.
void swap_blocks_impl ( torch : : Tensor & src , torch : : Tensor & dst ,
const torch : : Tensor & block_mapping , aclrtStream stream )
{
torch : : Device src_device = src . device ( ) ;
torch : : Device dst_device = dst . device ( ) ;
aclrtMemcpyKind memcpy_type ;
if ( ( ! src_device . is_cpu ( ) ) & & ( ! dst_device . is_cpu ( ) ) ) {
TORCH_CHECK ( src_device . index ( ) = = dst_device . index ( ) ,
" src and dst must be on the same npu " ) ;
memcpy_type = ACL_MEMCPY_DEVICE_TO_DEVICE ;
} else if ( ( ! src_device . is_cpu ( ) ) & & dst_device . is_cpu ( ) ) {
memcpy_type = ACL_MEMCPY_DEVICE_TO_HOST ;
} else if ( src_device . is_cpu ( ) & & ( ! dst_device . is_cpu ( ) ) ) {
memcpy_type = ACL_MEMCPY_HOST_TO_DEVICE ;
} else {
TORCH_CHECK ( false , " Invalid device combination, src tensor device: " , src_device , " , dst tensor device: " , dst_device ) ;
}
TORCH_CHECK ( block_mapping . device ( ) . is_cpu ( ) , " block_mapping must be on CPU " ) ;
char * src_ptr = static_cast < char * > ( src . data_ptr ( ) ) ;
char * dst_ptr = static_cast < char * > ( dst . data_ptr ( ) ) ;
const int64_t block_size_in_bytes = src . element_size ( ) * src . stride ( 0 ) ;
const int64_t num_blocks = block_mapping . size ( 0 ) ;
const int64_t max_src_block = src . size ( 0 ) ;
const int64_t max_dst_block = dst . size ( 0 ) ;
for ( size_t i = 0 ; i < num_blocks ; i + + ) {
int64_t src_block_number = block_mapping [ i ] [ 0 ] . item < int64_t > ( ) ;
int64_t dst_block_number = block_mapping [ i ] [ 1 ] . item < int64_t > ( ) ;
TORCH_CHECK ( src_block_number > = 0 & & src_block_number < = max_src_block ,
" src block index " , src_block_number , " out of range (max: " , max_src_block , " ) " ) ;
TORCH_CHECK ( dst_block_number > = 0 & & dst_block_number < = max_dst_block ,
" dst block index " , dst_block_number , " out of range (max: " , max_dst_block , " ) " ) ;
int64_t src_offset = src_block_number * block_size_in_bytes ;
int64_t dst_offset = dst_block_number * block_size_in_bytes ;
aclrtMemcpyAsync ( dst_ptr + dst_offset , block_size_in_bytes ,
src_ptr + src_offset , block_size_in_bytes ,
memcpy_type , stream ) ;
}
}
void swap_blocks ( torch : : Tensor & x , torch : : Tensor & y , const torch : : Tensor & z )
{
const c10_npu : : OptionalNPUGuard npuGuard (
( ! x . device ( ) . is_cpu ( ) ) ? x . device ( ) : y . device ( )
) ;
aclrtStream stream = c10_npu : : getCurrentNPUStream ( ) . stream ( ) ;
swap_blocks_impl ( x , y , z , stream ) ;
return ;
}
2025-09-09 09:40:35 +08:00
AscendType get_dtype_from_torch ( at : : ScalarType scalarType )
{
if ( scalarType = = at : : ScalarType : : Float ) {
return AscendType : : FP32 ;
} else if ( scalarType = = at : : ScalarType : : BFloat16 ) {
return AscendType : : BF16 ;
} else {
return AscendType : : FP16 ;
}
}
std : : tuple < at : : Tensor , at : : Tensor > get_masked_input_and_mask (
at : : Tensor & input ,
const int64_t org_vocab_start_index ,
const int64_t org_vocab_end_index ,
const int64_t num_org_vocab_padding ,
const int64_t added_vocab_start_index ,
const int64_t added_vocab_end_index )
/*
https : //github.com/vllm-project/vllm/blob/main/vllm/model_executor/layers/vocab_parallel_embedding.py#L161-L198
Embedding parallelized in the vocabulary dimension .
Adapted from torch . nn . Embedding , note that we pad the vocabulary size to
make sure it is divisible by the number of model parallel GPUs .
In order to support various loading methods , we ensure that LoRA - added
embeddings are always at the end of TP - sharded tensors . In other words ,
we shard base embeddings and LoRA embeddings separately ( both padded ) ,
and place them in the same tensor .
In this example , we will have the original vocab size = 1010 ,
added vocab size = 16 and padding to 64. Therefore , the total
vocab size with padding will be 1088 ( because we first pad 1010 to
1024 , add 16 , and then pad to 1088 ) .
Therefore , the tensor format looks like the following :
TP1 , rank 0 ( no sharding ) :
| < - - - - - - - - BASE - - - - - - - - > | < - BASE PADDING - - > | < - - - - - LORA - - - - - - > | < - LORA PADDING - - > |
corresponding token_id : | 0 | 1 | . . . | 1009 | - 1 | . . . | - 1 | 1010 | . . . | 1015 | - 1 | . . . | - 1 |
index : | 0 | 1 | . . . | 1009 | 1010 | . . . | 1023 | 1024 | . . . | 1039 | 1040 | . . . | 1087 |
TP2 , rank 0 :
| < - - - - - - - - - - - - - - - - - - - - BASE - - - - - - - - - - - - - - - - - - - - - > | < - - - - - LORA - - - - - - > | < - LORA PADDING - > |
corresponding token_id : | 0 | 1 | 2 | . . . | 497 | 498 | . . . | 511 | 1000 | . . . | 1015 | - 1 | . . . | - 1 |
index : | 0 | 1 | 2 | . . . | 497 | 498 | . . . | 511 | 512 | . . . | 527 | 520 | . . . | 543 |
TP2 , rank 1 :
| < - - - - - - - - - - - BASE - - - - - - - - - - - > | < - BASE PADDING - > | < - - - - - - - - - - - LORA PADDING - - - - - - - - - - - > |
corresponding token_id : | 512 | 513 | 514 | . . . | 1009 | - 1 | . . . | - 1 | - 1 | . . . | - 1 | - 1 | . . . | - 1 |
2025-10-14 10:38:28 +08:00
index : | 0 | 1 | 2 | . . . | 497 | 498 | . . . | 511 | 512 | . . . | 519 | 520 | . . . | 543 |
2025-09-09 09:40:35 +08:00
Parameters :
org_vocab_start_index //base embeddings start
org_vocab_end_index //base embeddings end
num_org_vocab_padding //base embeddings padding
added_vocab_start_index //LoRA embeddings start
added_vocab_end_index //LoRA embeddings end
*/
{
// Input validation
TORCH_CHECK ( input . dim ( ) > = 1 , " input must have at least 1 dimension " ) ;
TORCH_CHECK ( org_vocab_start_index > = 0 , " org_vocab_start_index must be non-negative " ) ;
TORCH_CHECK ( org_vocab_end_index > = org_vocab_start_index , " org_vocab_end_index must be greater than org_vocab_start_index " ) ;
TORCH_CHECK ( num_org_vocab_padding > = 0 , " num_org_vocab_padding must be non-negative " ) ;
TORCH_CHECK ( added_vocab_start_index > = org_vocab_end_index , " added_vocab_start_index must be greater than org_vocab_end_index " ) ;
TORCH_CHECK ( added_vocab_end_index > = added_vocab_start_index , " added_vocab_end_index must be greater than added_vocab_start_index " ) ;
// Get total number of elements
int64_t size = input . numel ( ) ;
// Create output tensors
at : : Tensor masked_input = at : : empty_like ( input ) ;
2026-08-27 15:11:51 +08:00
at : : Tensor mask = at : : empty_like ( input ) . to ( at : : kBool ) ;
2025-10-14 10:38:28 +08:00
2025-09-09 09:40:35 +08:00
// Get data pointers
void * input_ptr = input . data_ptr ( ) ;
void * masked_input_ptr = masked_input . data_ptr ( ) ;
void * mask_ptr = mask . data_ptr ( ) ;
2025-10-14 10:38:28 +08:00
2025-09-09 09:40:35 +08:00
// Get current stream
aclrtStream stream = c10_npu : : getCurrentNPUStream ( ) . stream ( ) ;
2025-10-14 10:38:28 +08:00
2025-09-09 09:40:35 +08:00
// Get scalar type
at : : ScalarType scalar_type = input . scalar_type ( ) ;
2025-10-14 10:38:28 +08:00
2025-09-09 09:40:35 +08:00
// Create and configure OpCommand
at_npu : : native : : OpCommand cmd ;
cmd . Name ( " get_masked_input_and_mask " ) ;
2025-10-14 10:38:28 +08:00
cmd . SetCustomHandler ( [ scalar_type , size , stream ,
2025-09-09 09:40:35 +08:00
input_ptr , masked_input_ptr , mask_ptr ,
org_vocab_start_index , org_vocab_end_index ,
num_org_vocab_padding , added_vocab_start_index ,
added_vocab_end_index ] ( ) - > int {
int device_id = 0 ;
int64_t aiv_num = 0 ;
TORCH_CHECK ( aclGetDeviceCapability ( device_id , ACL_DEVICE_INFO_VECTOR_CORE_NUM , & aiv_num ) = = ACL_SUCCESS ) ;
uint32_t loop_cnt = ( size + aiv_num - 1 ) / aiv_num ;
// Call implementation
get_masked_input_and_mask_impl (
stream ,
input_ptr ,
2025-10-14 10:38:28 +08:00
masked_input_ptr ,
2025-09-09 09:40:35 +08:00
mask_ptr ,
org_vocab_start_index ,
org_vocab_end_index ,
num_org_vocab_padding ,
added_vocab_start_index ,
added_vocab_end_index ,
size ,
loop_cnt ,
aiv_num ) ;
2025-10-14 10:38:28 +08:00
2025-09-09 09:40:35 +08:00
return 0 ;
} ) ;
cmd . Run ( ) ;
return { masked_input , mask } ;
}
void bgmv_shrink ( at : : Tensor & x , at : : Tensor & weight , at : : Tensor & indices , at : : Tensor & y , double scale )
{
at : : ScalarType scalar_type = x . scalar_type ( ) ;
TORCH_CHECK ( scalar_type = = torch : : kHalf | | scalar_type = = torch : : kBFloat16 , " only support half and bf16 " ) ;
TORCH_CHECK ( x . dim ( ) = = 2 , " x should be [batch_size, hidden_in] " ) ;
TORCH_CHECK ( weight . dim ( ) = = 3 | | weight . dim ( ) = = 4 ,
" weight should be [num_loras, hidden_out, hidden_in] or [num_loras, 1, hidden_out, hidden_in] " ) ;
TORCH_CHECK ( y . dim ( ) = = 2 , " y should be [batch_size, hidden_out] " ) ;
TORCH_CHECK ( indices . dim ( ) = = 1 , " indices should be [batch_size] " ) ;
TORCH_CHECK ( x . size ( 0 ) = = y . size ( 0 ) & & x . size ( 0 ) = = indices . size ( 0 ) ,
" the first dimension of x, y, indices should be same " ) ;
TORCH_CHECK ( x . size ( 1 ) > y . size ( 1 ) , " hidden in should be greater than hidden out " ) ;
void * x_ptr = x . data_ptr ( ) ;
void * weight_ptr = weight . data_ptr ( ) ;
void * indices_ptr = indices . data_ptr ( ) ;
int indices_size = indices . size ( 0 ) ;
void * y_ptr = y . data_ptr ( ) ;
int batch_size = x . size ( 0 ) ;
int input_hidden_token = x . size ( 1 ) ;
uint32_t lora_rank = y . size ( 1 ) ;
float scale_f = static_cast < float > ( scale ) ;
aclrtStream stream = c10_npu : : getCurrentNPUStream ( ) . stream ( ) ;
at_npu : : native : : OpCommand cmd ;
cmd . Name ( " bgmv_shrink " ) ;
cmd . SetCustomHandler ( [ scalar_type , stream , x_ptr , weight_ptr , indices_ptr , indices_size , y_ptr , batch_size , input_hidden_token ,
lora_rank , scale_f ] ( ) - > int {
auto dtype = get_dtype_from_torch ( scalar_type ) ;
int device_id = 0 ;
int64_t aiv_num = 0 ;
TORCH_CHECK ( aclGetDeviceCapability ( device_id , ACL_DEVICE_INFO_VECTOR_CORE_NUM , & aiv_num ) = = ACL_SUCCESS ) ;
int num_tokens_per_core = ( batch_size + aiv_num - 1 ) / aiv_num ;
TORCH_CHECK ( " num_tokens_per_core != 0 " , " num_tokens_per_core should not be 0 " ) ;
bgmv_shrink_impl ( dtype , stream , x_ptr , weight_ptr , indices_ptr , indices_size , y_ptr , batch_size , num_tokens_per_core ,
input_hidden_token , lora_rank , scale_f ) ;
return 0 ;
} ) ;
cmd . Run ( ) ;
return ;
}
at : : Tensor bgmv_expand ( at : : Tensor & x , at : : Tensor & weight , at : : Tensor & indices , at : : Tensor & y ,
int64_t slice_offset , int64_t slice_size )
{
at : : ScalarType scalar_type = y . scalar_type ( ) ;
TORCH_CHECK ( scalar_type = = torch : : kHalf | | scalar_type = = torch : : kBFloat16 , " only support half and bf16 " ) ;
TORCH_CHECK ( x . dim ( ) = = 2 , " x should be [batch_size, hidden_in] " ) ;
TORCH_CHECK ( weight . dim ( ) = = 3 | | weight . dim ( ) = = 4 ,
" weight should be [num_loras, hidden_out, hidden_in] or [num_loras, 1, hidden_out, hidden_in] " ) ;
TORCH_CHECK ( y . dim ( ) = = 2 , " y should be [batch_size, hidden_out] " ) ;
TORCH_CHECK ( indices . dim ( ) = = 1 , " indices should be [batch_size] " ) ;
TORCH_CHECK ( x . size ( 0 ) = = y . size ( 0 ) & & x . size ( 0 ) = = indices . size ( 0 ) ,
" the first dimension of x, y, indices should be same " ) ;
TORCH_CHECK ( x . size ( 1 ) < = slice_size , " hidden in should be smaller than hidden out " ) ;
TORCH_CHECK ( slice_offset > = 0 , " slice offset should be no smaller than 0 " ) ;
TORCH_CHECK ( ( slice_size + slice_offset ) < = y . size ( 1 ) ,
" slice_size + slice_offset should be smaller than the second dimension of y " )
at : : Tensor y_out = y ;
void * x_ptr = x . data_ptr ( ) ;
void * weight_ptr = weight . data_ptr ( ) ;
void * indices_ptr = indices . data_ptr ( ) ;
int indices_size = indices . size ( 0 ) ;
void * y_ptr = y . data_ptr ( ) ;
void * y_out_ptr = y_out . data_ptr ( ) ;
int batch_size = x . size ( 0 ) ;
int lora_rank = x . size ( 1 ) ;
int output_full_dim = y . size ( 1 ) ;
aclrtStream stream = c10_npu : : getCurrentNPUStream ( ) . stream ( ) ;
at_npu : : native : : OpCommand cmd ;
cmd . Name ( " bgmv_expand " ) ;
cmd . SetCustomHandler ( [ scalar_type , stream , x_ptr , weight_ptr , indices_ptr , indices_size , y_ptr , y_out_ptr , batch_size , lora_rank ,
slice_offset , slice_size , output_full_dim ] ( ) - > int {
auto dtype = get_dtype_from_torch ( scalar_type ) ;
int device_id = 0 ;
int64_t aiv_num = 0 ;
TORCH_CHECK ( aclGetDeviceCapability ( device_id , ACL_DEVICE_INFO_VECTOR_CORE_NUM , & aiv_num ) = = ACL_SUCCESS ) ;
int num_tokens_per_core = ( batch_size + aiv_num - 1 ) / aiv_num ;
TORCH_CHECK ( " num_tokens_per_core != 0 " , " num_tokens_per_core should not be 0 " ) ;
bgmv_expand_impl ( dtype , stream , x_ptr , weight_ptr , indices_ptr , indices_size , y_ptr , y_out_ptr , batch_size ,
num_tokens_per_core , lora_rank , slice_size , slice_offset , output_full_dim ) ;
return 0 ;
} ) ;
cmd . Run ( ) ;
return y_out ;
}
void sgmv_shrink ( at : : Tensor & x , at : : Tensor & weight , at : : Tensor & lora_indices , at : : Tensor & seq_len ,
at : : Tensor & y , double scale )
{
at : : ScalarType scalar_type = x . scalar_type ( ) ;
TORCH_CHECK ( scalar_type = = torch : : kHalf | | scalar_type = = torch : : kBFloat16 , " only support half and bf16 " ) ;
TORCH_CHECK ( x . dim ( ) = = 2 , " x should be [batch_size, hidden_in] " ) ;
TORCH_CHECK ( weight . dim ( ) = = 3 | | weight . dim ( ) = = 4 ,
" weight should be [num_loras, hidden_out, hidden_in] or [num_loras, 1, hidden_out, hidden_in] " ) ;
TORCH_CHECK ( y . dim ( ) = = 2 , " y should be [batch_size, hidden_out] " ) ;
TORCH_CHECK ( x . size ( 1 ) > y . size ( 1 ) , " hidden in should be greater than hidden out " ) ;
void * x_ptr = x . data_ptr ( ) ;
void * weight_ptr = weight . data_ptr ( ) ;
void * lora_indices_ptr = lora_indices . data_ptr ( ) ;
void * seq_len_ptr = seq_len . data_ptr ( ) ;
int lora_indices_size = lora_indices . size ( 0 ) ;
int seq_len_size = seq_len . size ( 0 ) ;
void * y_ptr = y . data_ptr ( ) ;
int batch_size = x . size ( 0 ) ;
int input_hidden_token = x . size ( 1 ) ;
uint32_t lora_rank = y . size ( 1 ) ;
float scale_f = static_cast < float > ( scale ) ;
aclrtStream stream = c10_npu : : getCurrentNPUStream ( ) . stream ( ) ;
at_npu : : native : : OpCommand cmd ;
cmd . Name ( " sgmv_shrink " ) ;
2025-10-14 10:38:28 +08:00
cmd . SetCustomHandler ( [ scalar_type , stream , x_ptr , weight_ptr , lora_indices_ptr , lora_indices_size ,
seq_len_ptr , seq_len_size , y_ptr ,
2025-09-09 09:40:35 +08:00
batch_size , input_hidden_token , lora_rank , scale_f ] ( ) - > int {
auto dtype = get_dtype_from_torch ( scalar_type ) ;
int device_id = 0 ;
int64_t aiv_num = 0 ;
TORCH_CHECK ( aclGetDeviceCapability ( device_id , ACL_DEVICE_INFO_VECTOR_CORE_NUM , & aiv_num ) = = ACL_SUCCESS ) ;
int num_tokens_per_core = ( batch_size + aiv_num - 1 ) / aiv_num ;
TORCH_CHECK ( " num_tokens_per_core != 0 " , " num_tokens_per_core should not be 0 " ) ;
sgmv_shrink_impl ( dtype , stream , x_ptr , weight_ptr , lora_indices_ptr , lora_indices_size , seq_len_ptr , seq_len_size ,
2025-10-14 10:38:28 +08:00
y_ptr , batch_size ,
2025-09-09 09:40:35 +08:00
num_tokens_per_core , input_hidden_token , lora_rank , scale_f ) ;
return 0 ;
} ) ;
cmd . Run ( ) ;
return ;
}
at : : Tensor sgmv_expand ( at : : Tensor & x , at : : Tensor & weight , at : : Tensor & lora_indices , at : : Tensor & seq_len ,
at : : Tensor & y , int64_t slice_offset , int64_t slice_size )
{
at : : ScalarType scalar_type = y . scalar_type ( ) ;
TORCH_CHECK ( scalar_type = = torch : : kHalf | | scalar_type = = torch : : kBFloat16 , " only support half and bf16 " ) ;
TORCH_CHECK ( x . dim ( ) = = 2 , " x should be [batch_size, hidden_in] " ) ;
TORCH_CHECK ( weight . dim ( ) = = 3 | | weight . dim ( ) = = 4 ,
" weight should be [num_loras, hidden_out, hidden_in] or [num_loras, 1, hidden_out, hidden_in] " ) ;
TORCH_CHECK ( y . dim ( ) = = 2 , " y should be [batch_size, hidden_out] " ) ;
TORCH_CHECK ( x . size ( 1 ) < = slice_size , " hidden in should be smaller than hidden out " ) ;
TORCH_CHECK ( slice_offset > = 0 , " slice offset should be no smaller than 0 " ) ;
TORCH_CHECK ( ( slice_size + slice_offset ) < = y . size ( 1 ) ,
" slice_size + slice_offset should be smaller than the second dimension of y " )
at : : Tensor y_out = y ;
void * x_ptr = x . data_ptr ( ) ;
void * weight_ptr = weight . data_ptr ( ) ;
void * lora_indices_ptr = lora_indices . data_ptr ( ) ;
void * seq_len_ptr = seq_len . data_ptr ( ) ;
int lora_indices_size = lora_indices . size ( 0 ) ;
int seq_len_size = seq_len . size ( 0 ) ;
void * y_ptr = y . data_ptr ( ) ;
void * y_out_ptr = y_out . data_ptr ( ) ;
int batch_size = x . size ( 0 ) ;
int lora_rank = x . size ( 1 ) ;
int output_full_dim = y . size ( 1 ) ;
aclrtStream stream = c10_npu : : getCurrentNPUStream ( ) . stream ( ) ;
at_npu : : native : : OpCommand cmd ;
cmd . Name ( " sgmv_expand " ) ;
2025-10-14 10:38:28 +08:00
cmd . SetCustomHandler ( [ scalar_type , stream , x_ptr , weight_ptr , lora_indices_ptr , lora_indices_size , seq_len_ptr , seq_len_size , y_ptr , y_out_ptr ,
2025-09-09 09:40:35 +08:00
batch_size , lora_rank , slice_offset , slice_size , output_full_dim ] ( ) - > int {
auto dtype = get_dtype_from_torch ( scalar_type ) ;
int device_id = 0 ;
int64_t aiv_num = 0 ;
TORCH_CHECK ( aclGetDeviceCapability ( device_id , ACL_DEVICE_INFO_VECTOR_CORE_NUM , & aiv_num ) = = ACL_SUCCESS ) ;
int num_tokens_per_core = ( batch_size + aiv_num - 1 ) / aiv_num ;
TORCH_CHECK ( " num_tokens_per_core != 0 " , " num_tokens_per_core should not be 0 " ) ;
2025-10-14 10:38:28 +08:00
sgmv_expand_impl ( dtype , stream , x_ptr , weight_ptr , lora_indices_ptr , lora_indices_size , seq_len_ptr , seq_len_size , y_ptr , y_out_ptr ,
2025-09-09 09:40:35 +08:00
batch_size , num_tokens_per_core , lora_rank , slice_size , slice_offset , output_full_dim ) ;
return 0 ;
} ) ;
cmd . Run ( ) ;
return y_out ;
}
2026-08-27 15:11:51 +08:00
# endif
2025-09-09 09:40:35 +08:00
2026-08-27 15:11:51 +08:00
at : : Tensor convert_hamming_dist_top_k_output ( const at : : Tensor & hashq ,
const at : : Tensor & hashkCache ,
const c10 : : optional < at : : Tensor > & indices ) {
if ( indices . has_value ( ) ) {
return indices . value ( ) ;
}
uint32_t MAX_BLOCK_PER_REQ_INHSA = 512 ;
auto n_bs = hashq . size ( 0 ) ;
auto n_kv_heads = hashkCache . size ( 1 ) ;
auto n_max_kv = MAX_BLOCK_PER_REQ_INHSA ;
at : : Tensor res = at : : empty ( { n_bs , n_kv_heads , n_max_kv } , torch : : TensorOptions ( ) . dtype ( torch : : kInt32 ) . device ( hashq . device ( ) ) ) ;
return res ;
}
at : : Tensor npu_hamming_dist_top_k ( const at : : Tensor & hashq ,
const at : : Tensor & hashkCache ,
const at : : Tensor & hashkCacheRope ,
const at : : Tensor & topN ,
const at : : Tensor & seqLen ,
const c10 : : optional < at : : Tensor > & chunkSize ,
const c10 : : optional < int64_t > maxSeqLen ,
const c10 : : optional < int64_t > sink ,
const c10 : : optional < int64_t > recent ,
const c10 : : optional < int64_t > supportOffload ,
const c10 : : optional < at : : Tensor > & blockTable ,
const c10 : : optional < at : : Tensor > & mask ,
const c10 : : optional < at : : Tensor > & indices ) {
auto & & maxSeqLen_ = maxSeqLen . value_or ( 0 ) ;
auto & & sink_ = sink . value_or ( 0 ) ;
auto & & recent_ = recent . value_or ( 0 ) ;
auto & & supportOffload_ = supportOffload . value_or ( 0 ) ;
at : : Tensor out = convert_hamming_dist_top_k_output ( hashq , hashkCache , indices ) ;
EXEC_NPU_CMD ( aclnnHammingDistTopK , hashq , hashkCache , topN , seqLen , chunkSize , blockTable , indices , hashkCacheRope , mask , maxSeqLen_ , sink_ , recent_ , supportOffload_ , out ) ;
return out ;
}
at : : Tensor npu_reshape_and_cache_bnsd ( const at : : Tensor & hashq ,
const at : : Tensor & hashkCache ,
const at : : Tensor & slotMapping ,
const at : : Tensor & seqLen ,
const at : : Tensor & hashkCacheOut ) {
EXEC_NPU_CMD ( aclnnReshapeAndCacheBnsd , hashq , hashkCache , slotMapping , seqLen , hashkCacheOut ) ;
return hashkCacheOut ;
}
at : : Tensor npu_sign_bits_pack ( const at : : Tensor & input ,
const int64_t size ) {
int64_t ySize = ( input . size ( 0 ) + 7 ) / 8 ;
int64_t outDim = 0 ;
if ( size ! = 0 ) {
outDim = ySize / size ;
}
at : : Tensor out = torch : : empty ( { size , outDim } , torch : : TensorOptions ( ) . dtype ( torch : : kUInt8 ) . device ( input . device ( ) ) ) ;
EXEC_NPU_CMD ( aclnnSignBitsPack , input , size , out ) ;
return out ;
}
std : : tuple < at : : Tensor , at : : Tensor > npu_gemma_rms_norm (
const at : : Tensor & x ,
const at : : Tensor & gamma ,
double epsilon )
2025-09-09 09:40:35 +08:00
{
2026-08-27 15:11:51 +08:00
int64_t dim_x = x . dim ( ) ;
int64_t dim_gamma = gamma . dim ( ) ;
int64_t diff = dim_x - dim_gamma ;
std : : vector < int64_t > new_shape ;
at : : Tensor rstd ;
if ( diff > 0 ) {
new_shape . reserve ( dim_x ) ;
auto x_sizes = x . sizes ( ) ;
for ( int64_t i = 0 ; i < diff ; + + i ) {
new_shape . push_back ( x_sizes [ i ] ) ;
}
for ( int64_t i = 0 ; i < dim_gamma ; + + i ) {
new_shape . push_back ( 1 ) ;
}
} else {
new_shape . assign ( dim_x , 1 ) ;
}
rstd = at : : empty ( new_shape , x . options ( ) . dtype ( at : : kFloat ) ) ;
at : : Tensor y = at : : empty ( x . sizes ( ) , x . options ( ) ) ;
EXEC_NPU_CMD ( aclnnGemmaRmsNorm , x , gamma , epsilon , y , rstd ) ;
return std : : tuple < at : : Tensor , at : : Tensor > ( y , rstd ) ;
}
2025-09-09 09:40:35 +08:00
2026-08-27 15:11:51 +08:00
void transpose_kv_cache_by_block (
const at : : TensorList & kCache ,
const at : : TensorList & vCache ,
const at : : Tensor & blockIDs ,
int64_t blockSize ,
int64_t headNum ,
int64_t headDim ,
int64_t splitNum ,
int64_t layerNum )
{
2025-09-09 09:40:35 +08:00
2026-08-27 15:11:51 +08:00
EXEC_NPU_CMD ( aclnnTransposeKvCacheByBlock , kCache , vCache , blockIDs ,
blockSize , headNum , headDim , splitNum , layerNum ) ;
2025-09-09 09:40:35 +08:00
2026-08-27 15:11:51 +08:00
}
2025-09-09 09:40:35 +08:00
2026-08-27 15:11:51 +08:00
void device_print ( c10 : : string_view msg )
{
auto payload = std : : make_unique < DevicePrintPayload > ( ) ;
payload - > message = std : : string ( msg ) ;
enqueue_device_print ( std : : move ( payload ) , c10_npu : : getCurrentNPUStream ( ) . stream ( ) ) ;
}
2025-09-09 09:40:35 +08:00
2026-08-27 15:11:51 +08:00
void device_print ( const at : : Tensor & tensor )
{
TORCH_CHECK ( tensor . defined ( ) , " tensor must be defined " ) ;
TORCH_CHECK (
tensor . device ( ) . is_cpu ( ) | |
tensor . device ( ) . type ( ) = = c10 : : DeviceType : : PrivateUse1 ,
" device_print only supports CPU and NPU tensors, but got device " ,
tensor . device ( ) ) ;
2025-09-09 09:40:35 +08:00
2026-08-27 15:11:51 +08:00
auto payload = std : : make_unique < DevicePrintPayload > ( ) ;
if ( tensor . device ( ) . is_cpu ( ) ) {
payload - > host_tensor_snapshot = tensor . contiguous ( ) . clone ( ) ;
enqueue_device_print ( std : : move ( payload ) ,
c10_npu : : getCurrentNPUStream ( ) . stream ( ) ) ;
return ;
}
const c10_npu : : OptionalNPUGuard npu_guard ( tensor . device ( ) ) ;
aclrtStream stream = c10_npu : : getCurrentNPUStream ( ) . stream ( ) ;
at : : Tensor contiguous_tensor = tensor . contiguous ( ) ;
payload - > host_tensor_snapshot = at : : empty_like (
contiguous_tensor ,
contiguous_tensor . options ( ) . device ( at : : kCPU ) . pinned_memory ( true ) ) ;
const size_t num_bytes = contiguous_tensor . numel ( ) *
contiguous_tensor . element_size ( ) ;
const aclError memcpy_ret = aclrtMemcpyAsync (
payload - > host_tensor_snapshot . data_ptr ( ) , num_bytes ,
contiguous_tensor . data_ptr ( ) , num_bytes , ACL_MEMCPY_DEVICE_TO_HOST , stream ) ;
TORCH_CHECK ( memcpy_ret = = ACL_SUCCESS ,
" aclrtMemcpyAsync failed, error code: " , memcpy_ret ) ;
// The D2H copy and host callback are queued on the same stream so the
// callback prints only after the host snapshot is ready.
enqueue_device_print ( std : : move ( payload ) , stream ) ;
}
std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor , at : : Tensor , at : : Tensor , at : : Tensor >
npu_copy_and_expand_eagle_inputs (
const at : : Tensor & target_token_ids ,
const at : : Tensor & target_positions ,
const at : : Tensor & next_token_ids ,
const at : : Tensor & query_start_loc ,
const at : : Tensor & query_end_loc ,
int64_t padding_token_id ,
int64_t parallel_drafting_token_id ,
int64_t num_padding_slots_per_request ,
bool shift_input_ids ,
int64_t total_draft_tokens )
{
int64_t total_input_tokens = target_token_ids . size ( 0 ) ;
int64_t num_reqs = query_start_loc . size ( 0 ) - 1 ;
auto device = target_token_ids . device ( ) ;
at : : Tensor out_input_ids = at : : zeros ( { total_draft_tokens } , at : : dtype ( at : : kInt ) . device ( device ) ) ;
at : : Tensor out_positions = at : : zeros ( { total_draft_tokens } , at : : dtype ( at : : kInt ) . device ( device ) ) ;
at : : Tensor out_is_rejected_token_mask = at : : zeros ( { total_draft_tokens } , at : : dtype ( at : : kChar ) . device ( device ) ) ;
at : : Tensor out_is_masked_token_mask = at : : zeros ( { total_draft_tokens } , at : : dtype ( at : : kChar ) . device ( device ) ) ;
at : : Tensor out_new_token_indices = at : : zeros ( { num_reqs * num_padding_slots_per_request } , at : : dtype ( at : : kInt ) . device ( device ) ) ;
at : : Tensor out_hidden_state_mapping = at : : zeros ( { total_input_tokens } , at : : dtype ( at : : kInt ) . device ( device ) ) ;
EXEC_NPU_CMD ( aclnnCopyAndExpandEagleInputs ,
target_token_ids , target_positions , next_token_ids , query_start_loc , query_end_loc ,
padding_token_id , parallel_drafting_token_id , num_padding_slots_per_request ,
shift_input_ids , total_input_tokens ,
out_input_ids , out_positions , out_is_rejected_token_mask , out_is_masked_token_mask ,
out_new_token_indices , out_hidden_state_mapping ) ;
return { out_input_ids , out_positions , out_is_rejected_token_mask , out_is_masked_token_mask ,
out_new_token_indices , out_hidden_state_mapping } ;
}
at : : Tensor npu_causal_conv1d_custom (
const at : : Tensor & output ,
const at : : Tensor & x ,
const at : : Tensor & weight ,
const at : : Tensor & conv_state ,
const c10 : : optional < at : : Tensor > & bias_opt ,
const c10 : : optional < at : : Tensor > & query_start_loc_opt ,
const c10 : : optional < at : : Tensor > & cache_indices_opt ,
const c10 : : optional < at : : Tensor > & initial_state_mode_opt ,
const c10 : : optional < at : : Tensor > & num_accepted_tokens_opt ,
int64_t activation_mode ,
int64_t pad_slot_id ,
int64_t run_mode )
{
EXEC_NPU_CMD ( aclnnCausalConv1d ,
x ,
weight ,
bias_opt ,
conv_state ,
query_start_loc_opt ,
cache_indices_opt ,
initial_state_mode_opt ,
num_accepted_tokens_opt ,
activation_mode ,
pad_slot_id ,
run_mode ,
output
) ;
return output ;
}
// It is expected that further improvements will be made after it is incorporated into CANN on June 30th.
std : : vector < at : : Tensor > moe_grouped_matmul (
at : : Tensor x ,
at : : Tensor weight ,
const at : : Tensor & group_list ,
int64_t split_item ,
int64_t group_type ,
int64_t group_list_type
)
{
bool transpose_weight = false ;
bool weight_nz = true ;
at : : TensorList x_list = at : : TensorList ( x ) ;
at : : TensorList weight_list = at : : TensorList ( weight ) ;
std : : vector < at : : Tensor > y ;
c10 : : TensorOptions options = x_list [ 0 ] . options ( ) . dtype ( x [ 0 ] . scalar_type ( ) ) ;
auto m = x_list [ 0 ] . sizes ( ) [ 0 ] ;
auto n = weight_list [ 0 ] . sizes ( ) [ 1 ] ;
if ( ! transpose_weight ) {
n = weight_list [ 0 ] . sizes ( ) [ 2 ] ;
}
at : : Tensor y_0 = at : : empty ( at : : IntArrayRef { m , n } , options ) ;
y . emplace_back ( y_0 ) ;
at : : TensorList result = at : : TensorList ( y ) ;
EXEC_NPU_CMD ( aclnnMoeGroupedMatmulWeightNz ,
x_list , weight_list , group_list , transpose_weight , result ) ;
return y ;
}
std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > moe_gating_top_k_hash (
const at : : Tensor & x ,
int64_t k ,
const c10 : : optional < at : : Tensor > & bias_opt ,
const c10 : : optional < at : : Tensor > & input_ids_opt ,
const c10 : : optional < at : : Tensor > & tid2eid_opt ,
int64_t k_group ,
int64_t group_count ,
double routed_scaling_factor ,
double eps ,
int64_t group_select_mode ,
int64_t renorm ,
int64_t norm_type ,
bool out_flag )
{
TORCH_CHECK ( x . dim ( ) = = 2 , " x must be 2D, but got dim= " , x . dim ( ) ) ;
TORCH_CHECK (
x . scalar_type ( ) = = at : : kHalf | | x . scalar_type ( ) = = at : : kFloat | | x . scalar_type ( ) = = at : : kBFloat16 ,
" x dtype must be float16/float32/bfloat16, but got " , x . scalar_type ( ) ) ;
TORCH_CHECK ( k > 0 , " k must be > 0, but got k= " , k ) ;
TORCH_CHECK ( k_group > = 1 , " k_group must be >= 1, but got k_group= " , k_group ) ;
TORCH_CHECK ( group_count > = 1 , " group_count must be >= 1, but got group_count= " , group_count ) ;
TORCH_CHECK ( group_select_mode = = 0 | | group_select_mode = = 1 ,
" group_select_mode must be 0 or 1, but got " , group_select_mode ) ;
TORCH_CHECK ( renorm = = 0 ,
" renorm can only be 0 currently, but got " , renorm ) ;
TORCH_CHECK ( norm_type = = 0 | | norm_type = = 1 | | norm_type = = 2 ,
" norm_type must be 0 (softmax) or 1 (sigmoid) or 2 (softplus), but got " , norm_type ) ;
TORCH_CHECK ( eps > 0.0 , " eps must be > 0, but got " , eps ) ;
TORCH_CHECK ( routed_scaling_factor > 0.0 ,
" routed_scaling_factor must be > 0, but got " , routed_scaling_factor ) ;
const auto sizes = x . sizes ( ) ;
const int64_t rows = sizes [ 0 ] ;
const int64_t expert_num = sizes [ 1 ] ;
TORCH_CHECK ( expert_num > 0 , " expert_num must be > 0 " ) ;
TORCH_CHECK ( expert_num < = 2048 ,
" expert_num (E) must be <= 2048, but got " , expert_num ) ;
if ( bias_opt . has_value ( ) & & bias_opt - > defined ( ) ) {
const auto & bias = * bias_opt ;
TORCH_CHECK ( bias . dim ( ) = = 1 , " bias must be 1D, but got dim= " , bias . dim ( ) ) ;
TORCH_CHECK ( bias . size ( 0 ) = = expert_num ,
" bias.size(0) must equal expert_num. bias.size(0)= " ,
bias . size ( 0 ) , " , expert_num= " , expert_num ) ;
TORCH_CHECK ( bias . scalar_type ( ) = = x . scalar_type ( ) ,
" bias dtype must equal x dtype. x= " , x . scalar_type ( ) ,
" , bias= " , bias . scalar_type ( ) ) ;
}
if ( input_ids_opt . has_value ( ) & & input_ids_opt - > defined ( ) ) {
const auto & input_ids = * input_ids_opt ;
TORCH_CHECK ( input_ids . scalar_type ( ) = = at : : kInt | | input_ids . scalar_type ( ) = = at : : kLong ,
" input_ids dtype must be int32 or int64, but got " , input_ids . scalar_type ( ) ) ;
TORCH_CHECK ( input_ids . numel ( ) = = rows ,
" input_ids.numel() must equal x.size(0). input_ids.numel()= " ,
input_ids . numel ( ) , " , rows= " , rows ) ;
}
if ( tid2eid_opt . has_value ( ) & & tid2eid_opt - > defined ( ) ) {
const auto & tid2eid = * tid2eid_opt ;
TORCH_CHECK ( tid2eid . scalar_type ( ) = = at : : kInt | | tid2eid . scalar_type ( ) = = at : : kLong ,
" tid2eid dtype must be int32 or int64, but got " , tid2eid . scalar_type ( ) ) ;
TORCH_CHECK ( tid2eid . dim ( ) > = 1 , " tid2eid must have dim>=1, but got dim= " , tid2eid . dim ( ) ) ;
}
const at : : Tensor & bias = c10 : : value_or_else ( bias_opt , [ ] { return at : : Tensor ( ) ; } ) ;
const at : : Tensor & input_ids = c10 : : value_or_else ( input_ids_opt , [ ] { return at : : Tensor ( ) ; } ) ;
const at : : Tensor & tid2eid = c10 : : value_or_else ( tid2eid_opt , [ ] { return at : : Tensor ( ) ; } ) ;
at : : Tensor y = at : : empty ( { rows , k } , x . options ( ) ) ;
at : : Tensor expert_idx = at : : empty ( { rows , k } , x . options ( ) . dtype ( at : : kInt ) ) ;
at : : Tensor out = at : : empty ( { rows , expert_num } , x . options ( ) . dtype ( at : : kFloat ) ) ;
EXEC_NPU_CMD ( aclnnMoeGatingTopKHash ,
x ,
bias ,
input_ids ,
tid2eid ,
k ,
k_group ,
group_count ,
routed_scaling_factor ,
eps ,
group_select_mode ,
renorm ,
norm_type ,
out_flag ,
y ,
expert_idx ,
out ) ;
return { y , expert_idx , out } ;
}
std : : vector < bool > is_contiguous_axes ( const at : : Tensor & tensor )
{
auto sizes = tensor . sizes ( ) ;
auto strides = tensor . strides ( ) ;
int64_t ndim = sizes . size ( ) ;
if ( ndim = = 0 ) {
return { } ;
}
std : : vector < bool > result ( ndim , false ) ;
std : : vector < int64_t > contiguous_stride ( ndim , 1 ) ;
for ( int64_t i = ndim - 2 ; i > = 0 ; i - - ) {
contiguous_stride [ i ] = contiguous_stride [ i + 1 ] * sizes [ i + 1 ] ;
}
for ( int64_t i = 0 ; i < ndim ; i + + ) {
result [ i ] = ( strides [ i ] = = contiguous_stride [ i ] ) ;
}
return result ;
}
std : : tuple < at : : Tensor > construct_compressor_output_tensor ( const at : : Tensor & x , const at : : Tensor & norm_weight ,
const at : : Tensor & rope_sin , int64_t cmp_ratio , int64_t coff )
{
constexpr int DIM_3 = 3 ;
auto x_dim = x . dim ( ) ;
at : : SmallVector < int64_t , 8 > cmp_kv_size ;
at : : Tensor cmp_kv ;
auto cmp_s = 0 ;
if ( x_dim = = DIM_3 ) {
cmp_s = ( x . size ( 1 ) + cmp_ratio - 1 ) / cmp_ratio ;
cmp_kv_size = { x . size ( 0 ) , cmp_s , norm_weight . size ( 0 ) } ;
} else {
cmp_s = rope_sin . size ( 0 ) ;
cmp_kv_size = { cmp_s , norm_weight . size ( 0 ) } ;
}
cmp_kv = at : : empty ( cmp_kv_size , x . options ( ) . dtype ( x . dtype ( ) ) ) ;
return std : : tuple < at : : Tensor > ( cmp_kv ) ;
}
std : : tuple < at : : Tensor > compressor ( const at : : Tensor & x , const at : : Tensor & wkv , const at : : Tensor & wgate ,
at : : Tensor & state_cache , const at : : Tensor & ape , const at : : Tensor & norm_weight ,
const at : : Tensor & rope_sin , const at : : Tensor & rope_cos ,
const c10 : : optional < at : : Tensor > & state_block_table ,
const c10 : : optional < at : : Tensor > & cu_seqlens , const c10 : : optional < at : : Tensor > & seqused ,
const c10 : : optional < at : : Tensor > & start_pos , int64_t rope_head_dim , int64_t cmp_ratio ,
int64_t coff , double norm_eps , int64_t rotary_mode , int64_t cache_mode )
{
constexpr int CONTINUOUS = 1 ;
constexpr int32_t DIM_1 = 1 ;
constexpr int32_t DIM_2 = 2 ;
constexpr int32_t DIM_3 = 3 ;
constexpr int32_t VALUE_0 = 0 ;
auto x_dim = x . dim ( ) ;
TORCH_CHECK ( x_dim = = DIM_2 | | x_dim = = DIM_3 , " x dim num[ " , x_dim , " ] should be 2 or 3 " ) ;
TORCH_CHECK ( norm_weight . defined ( ) , " Check norm_weight != nullptr failed " ) ;
auto norm_weight_dim = norm_weight . dim ( ) ;
TORCH_CHECK ( norm_weight_dim = = DIM_1 , " norm_weight dim num[ " , norm_weight_dim , " ] should be 1 " ) ;
TORCH_CHECK ( rope_sin . defined ( ) , " Check rope_sin != nullptr failed " ) ;
auto rope_sin_dim = rope_sin . dim ( ) ;
TORCH_CHECK ( rope_sin_dim = = x_dim , " rope_sin dim num[ " , rope_sin_dim , " ] should be equal to x dim num[ " , x_dim ,
" ] " ) ;
TORCH_CHECK ( cmp_ratio > VALUE_0 , " cmp_ratio should be greater than 0 " ) ;
std : : tuple < at : : Tensor > output = construct_compressor_output_tensor ( x , norm_weight , rope_sin , cmp_ratio , coff ) ;
at : : Tensor cmp_kv = std : : get < 0 > ( output ) ;
auto state_cache_dim = state_cache . dim ( ) ;
TORCH_CHECK ( state_cache_dim = = DIM_3 , " state_cache dim num[ " , state_cache_dim , " ] should be 3 " ) ;
auto contiguous_axes_result = is_contiguous_axes ( state_cache ) ;
// if (cache_mode == CONTINUOUS) {
// TORCH_CHECK(contiguous_axes_result[0] && contiguous_axes_result[1] && contiguous_axes_result[2],
// "when cache_mode == ", cache_mode, ", state_cache must be contiguous on all axes");
// }
int64_t state_cache_stride_dim0 = state_cache . stride ( 0 ) ;
EXEC_NPU_CMD ( aclnnCompressor , x , wkv , wgate , state_cache , ape , norm_weight , rope_sin , rope_cos ,
state_block_table , cu_seqlens , seqused , start_pos , rope_head_dim , cmp_ratio , coff , norm_eps ,
rotary_mode , cache_mode , state_cache_stride_dim0 , cmp_kv ) ;
return std : : tuple < at : : Tensor > ( cmp_kv ) ;
}
void check_compressor_metadata_common (
const at : : Tensor & rope_cos , const at : : Tensor & rope_sin , const at : : Tensor & cu_seqlens ,
const at : : Tensor & start_pos , const at : : Tensor & kv_block_table , int64_t kv_block_size ,
int64_t slot_mapping_format , int64_t compress_ratio , int64_t num_reqs_actual )
{
constexpr int64_t DIM_2 = 2 ;
constexpr int64_t VALUE_0 = 0 ;
TORCH_CHECK ( rope_cos . defined ( ) & & rope_sin . defined ( ) , " rope_cos and rope_sin should be defined " ) ;
TORCH_CHECK ( rope_cos . dim ( ) = = DIM_2 & & rope_sin . dim ( ) = = DIM_2 ,
" rope_cos and rope_sin should be 2D tensors " ) ;
TORCH_CHECK ( rope_cos . scalar_type ( ) = = rope_sin . scalar_type ( ) ,
" rope_cos and rope_sin should have same dtype " ) ;
TORCH_CHECK ( rope_cos . size ( 0 ) = = rope_sin . size ( 0 ) & & rope_cos . size ( 1 ) = = rope_sin . size ( 1 ) ,
" rope_cos and rope_sin should have same shape " ) ;
TORCH_CHECK ( rope_cos . size ( 0 ) > VALUE_0 & & rope_cos . size ( 1 ) > VALUE_0 ,
" rope_cos shape should be non-empty " ) ;
TORCH_CHECK ( cu_seqlens . defined ( ) & & cu_seqlens . dim ( ) = = 1 , " cu_seqlens should be a 1D tensor " ) ;
TORCH_CHECK ( start_pos . defined ( ) & & start_pos . dim ( ) = = 1 , " start_pos should be a 1D tensor " ) ;
TORCH_CHECK ( kv_block_table . defined ( ) & & kv_block_table . dim ( ) = = DIM_2 , " kv_block_table should be a 2D tensor " ) ;
TORCH_CHECK ( kv_block_size > VALUE_0 , " kv_block_size should be greater than 0 " ) ;
TORCH_CHECK ( compress_ratio > VALUE_0 , " compress_ratio should be greater than 0 " ) ;
TORCH_CHECK ( slot_mapping_format = = DSA_SLOT_MAPPING_BLOCK_OFFSET | | slot_mapping_format = = DSA_SLOT_MAPPING_FLAT ,
" slot_mapping_format should be 1(flat) or 2(block_offset), but got " , slot_mapping_format ) ;
TORCH_CHECK ( num_reqs_actual > VALUE_0 , " num_reqs_actual should be greater than 0 " ) ;
TORCH_CHECK ( cu_seqlens . size ( 0 ) > num_reqs_actual ,
" cu_seqlens dim0 should be greater than num_reqs_actual " ) ;
TORCH_CHECK ( start_pos . size ( 0 ) > = num_reqs_actual ,
" start_pos dim0 should be greater than or equal to num_reqs_actual " ) ;
TORCH_CHECK ( kv_block_table . size ( 0 ) > = num_reqs_actual ,
" kv_block_table dim0 should be greater than or equal to num_reqs_actual " ) ;
}
void check_compressor_metadata_outputs (
const at : : Tensor & rope_cos , const at : : Tensor & compress_cos , const at : : Tensor & compress_sin ,
const at : : Tensor & slot_mapping , int64_t slot_mapping_format )
{
constexpr int64_t DIM_2 = 2 ;
constexpr int64_t VALUE_0 = 0 ;
TORCH_CHECK ( compress_cos . defined ( ) & & compress_sin . defined ( ) & & slot_mapping . defined ( ) ,
" compress_cos, compress_sin, and slot_mapping should be defined " ) ;
TORCH_CHECK ( compress_cos . dim ( ) > = DIM_2 , " compress_cos dim num should be at least 2 " ) ;
TORCH_CHECK ( compress_sin . dim ( ) = = compress_cos . dim ( ) , " compress_cos and compress_sin should have same dim num " ) ;
TORCH_CHECK ( compress_cos . size ( 0 ) > VALUE_0 , " compress_cos dim0 should be greater than 0 " ) ;
TORCH_CHECK ( compress_cos . size ( compress_cos . dim ( ) - 1 ) = = rope_cos . size ( 1 ) ,
" compress_cos last dim should match rope dim " ) ;
for ( int64_t dim_idx = 0 ; dim_idx < compress_cos . dim ( ) ; + + dim_idx ) {
TORCH_CHECK ( compress_sin . size ( dim_idx ) = = compress_cos . size ( dim_idx ) ,
" compress_cos and compress_sin should have same shape " ) ;
}
TORCH_CHECK ( compress_cos . scalar_type ( ) = = rope_cos . scalar_type ( ) & &
compress_sin . scalar_type ( ) = = rope_cos . scalar_type ( ) ,
" compress outputs should have same dtype as rope_cos " ) ;
TORCH_CHECK ( slot_mapping . scalar_type ( ) = = at : : kInt , " slot_mapping dtype should be int32 " ) ;
if ( slot_mapping_format = = DSA_SLOT_MAPPING_BLOCK_OFFSET ) {
TORCH_CHECK ( slot_mapping . dim ( ) = = DIM_2 & & slot_mapping . size ( 0 ) = = compress_cos . size ( 0 ) & &
slot_mapping . size ( 1 ) = = DIM_2 ,
" block_offset slot_mapping should have shape [num_rows, 2] " ) ;
} else {
TORCH_CHECK ( slot_mapping . dim ( ) = = 1 & & slot_mapping . size ( 0 ) = = compress_cos . size ( 0 ) ,
" flat slot_mapping should have shape [num_rows] " ) ;
}
}
std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > compressor_metadata (
const at : : Tensor & rope_cos , const at : : Tensor & rope_sin , const at : : Tensor & cu_seqlens ,
const at : : Tensor & start_pos , const at : : Tensor & kv_block_table , int64_t kv_block_size ,
int64_t slot_mapping_format , int64_t compress_ratio , int64_t num_compressed_tokens , int64_t num_reqs_actual )
{
constexpr int64_t VALUE_0 = 0 ;
check_compressor_metadata_common (
rope_cos , rope_sin , cu_seqlens , start_pos , kv_block_table , kv_block_size , slot_mapping_format , compress_ratio ,
num_reqs_actual ) ;
TORCH_CHECK ( num_compressed_tokens > VALUE_0 , " num_compressed_tokens should be greater than 0 " ) ;
at : : SmallVector < int64_t , 4 > rope_output_size = { num_compressed_tokens , 1 , 1 , rope_cos . size ( 1 ) } ;
at : : Tensor compress_cos = at : : empty ( rope_output_size , rope_cos . options ( ) ) ;
at : : Tensor compress_sin = at : : empty ( rope_output_size , rope_sin . options ( ) ) ;
at : : SmallVector < int64_t , 2 > slot_mapping_size ;
if ( slot_mapping_format = = DSA_SLOT_MAPPING_BLOCK_OFFSET ) {
slot_mapping_size = { num_compressed_tokens , 2 } ;
} else {
slot_mapping_size = { num_compressed_tokens } ;
}
at : : Tensor slot_mapping = at : : empty ( slot_mapping_size , kv_block_table . options ( ) . dtype ( at : : kInt ) ) ;
EXEC_NPU_CMD ( aclnnCompressorMetadata , rope_cos , rope_sin , cu_seqlens , start_pos , kv_block_table ,
kv_block_size , slot_mapping_format , compress_ratio , num_reqs_actual , compress_cos , compress_sin ,
slot_mapping ) ;
return std : : make_tuple ( compress_cos , compress_sin , slot_mapping ) ;
}
std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > compressor_metadata_out (
const at : : Tensor & rope_cos , const at : : Tensor & rope_sin , const at : : Tensor & cu_seqlens ,
const at : : Tensor & start_pos , const at : : Tensor & kv_block_table , int64_t kv_block_size ,
int64_t slot_mapping_format , int64_t compress_ratio , int64_t num_reqs_actual , at : : Tensor & compress_cos ,
at : : Tensor & compress_sin , at : : Tensor & slot_mapping )
{
check_compressor_metadata_common (
rope_cos , rope_sin , cu_seqlens , start_pos , kv_block_table , kv_block_size , slot_mapping_format , compress_ratio ,
num_reqs_actual ) ;
check_compressor_metadata_outputs ( rope_cos , compress_cos , compress_sin , slot_mapping , slot_mapping_format ) ;
EXEC_NPU_CMD ( aclnnCompressorMetadata , rope_cos , rope_sin , cu_seqlens , start_pos , kv_block_table ,
kv_block_size , slot_mapping_format , compress_ratio , num_reqs_actual , compress_cos , compress_sin ,
slot_mapping ) ;
return std : : make_tuple ( compress_cos , compress_sin , slot_mapping ) ;
}
std : : tuple < at : : Tensor , at : : Tensor > construct_quant_lightning_indexer_output_tensor ( const at : : Tensor & query , const at : : Tensor & key ,
int64_t sparse_count , std : : string query_layout_str ,
std : : string key_layout_str , bool return_value )
{
constexpr int64_t SIZE = 8 ;
constexpr int64_t DIM_0 = 0 ;
constexpr int64_t DIM_1 = 1 ;
constexpr int64_t DIM_2 = 2 ;
constexpr int64_t DIM_3 = 3 ;
at : : SmallVector < int64_t , SIZE > output_size ;
for ( size_t i = 0 ; i < query . sizes ( ) . size ( ) ; i + + ) {
TORCH_CHECK ( query . size ( i ) > 0 , " All values within query's shape should be greater "
" than 0, but shape[ " , i , " ] is " , query . size ( i ) ) ;
}
for ( size_t i = 0 ; i < key . sizes ( ) . size ( ) ; i + + ) {
TORCH_CHECK ( key . size ( i ) > 0 , " All values within key's shape should be greater "
" than 0, but shape[ " , i , " ] is " , key . size ( i ) ) ;
}
TORCH_CHECK ( sparse_count > 0 , " sparse count should be greater than 0, but now is " , sparse_count ) ;
int64_t keyHeadNum = ( key_layout_str = = " TND " ) ? key . size ( DIM_1 ) : key . size ( DIM_2 ) ;
if ( query_layout_str = = " BSND " ) {
output_size = { query . size ( DIM_0 ) , query . size ( DIM_1 ) , keyHeadNum , sparse_count } ;
} else {
output_size = { query . size ( DIM_0 ) , keyHeadNum , sparse_count } ;
}
at : : Tensor sparse_indices_out = at : : empty ( output_size , query . options ( ) . dtype ( at : : kInt ) ) ;
at : : Tensor sparse_values_out ;
if ( return_value ) {
sparse_values_out = at : : empty ( output_size , query . options ( ) . dtype ( at : : kFloat ) ) ;
} else {
sparse_values_out = at : : empty ( { 0 } , query . options ( ) . dtype ( at : : kFloat ) ) ;
}
return std : : tuple < at : : Tensor , at : : Tensor > ( sparse_indices_out , sparse_values_out ) ;
}
std : : tuple < at : : Tensor , at : : Tensor > npu_vllm_quant_lightning_indexer_npu (
const at : : Tensor & query , const at : : Tensor & key , const at : : Tensor & weights ,
const at : : Tensor & query_dequant_scale , const at : : Tensor & key_dequant_scale ,
int64_t query_quant_mode , int64_t key_quant_mode ,
const c10 : : optional < at : : Tensor > & actual_seq_lengths_query ,
const c10 : : optional < at : : Tensor > & actual_seq_lengths_key ,
const c10 : : optional < at : : Tensor > & block_table ,
const c10 : : optional < at : : Tensor > & metadata ,
c10 : : string_view layout_query , c10 : : string_view layout_key , int64_t sparse_count ,
int64_t sparse_mode , int64_t pre_tokens , int64_t next_tokens , int64_t cmp_ratio , bool return_value )
{
std : : string query_layout_str = std : : string ( layout_query ) ;
std : : string key_layout_str = std : : string ( layout_key ) ;
std : : tuple < at : : Tensor , at : : Tensor > quant_lightning_indexer_output = construct_quant_lightning_indexer_output_tensor (
query , key , sparse_count , query_layout_str , key_layout_str , return_value ) ;
at : : Tensor sparse_indices_out = std : : get < 0 > ( quant_lightning_indexer_output ) ;
at : : Tensor sparse_values_out = std : : get < 1 > ( quant_lightning_indexer_output ) ;
char * query_layout_ptr = const_cast < char * > ( query_layout_str . c_str ( ) ) ;
char * key_layout_ptr = const_cast < char * > ( key_layout_str . c_str ( ) ) ;
int64_t stride = key . stride ( 0 ) ;
int64_t scale_stride = key_dequant_scale . stride ( 0 ) ;
if ( key_layout_str = = " PA_BSND " ) {
auto contiguous_axes_result_key = is_contiguous_axes ( key ) ;
TORCH_CHECK ( contiguous_axes_result_key [ 1 ] & & contiguous_axes_result_key [ 2 ] ,
" key must be contiguous on all axes except axis 0 " ) ;
auto contiguous_axes_result_key_scale = is_contiguous_axes ( key_dequant_scale ) ;
TORCH_CHECK ( contiguous_axes_result_key_scale [ 1 ] & & contiguous_axes_result_key_scale [ 2 ] ,
" key_dequant_scale must be contiguous on all axes except axis 0 " ) ;
}
EXEC_NPU_CMD ( aclnnVllmQuantLightningIndexer , query ,
key , weights , query_dequant_scale , key_dequant_scale , actual_seq_lengths_query , actual_seq_lengths_key ,
block_table , metadata , query_quant_mode , key_quant_mode , query_layout_ptr , key_layout_ptr , sparse_count , sparse_mode ,
pre_tokens , next_tokens , cmp_ratio , return_value , stride , scale_stride , sparse_indices_out , sparse_values_out ) ;
return std : : tuple < at : : Tensor , at : : Tensor > ( sparse_indices_out , sparse_values_out ) ;
}
std : : tuple < at : : Tensor , at : : Tensor > construct_output_tensor ( const at : : Tensor & q , std : : string layout ,
bool return_softmax_lse )
{
for ( size_t i = 0 ; i < q . sizes ( ) . size ( ) ; i + + ) {
TORCH_CHECK ( q . size ( i ) > 0 ,
" All values within query's shape should be greater "
" than 0, but shape[ " ,
i ,
" ] is " ,
q . size ( i ) ) ;
}
at : : Tensor output = at : : empty ( q . sizes ( ) , q . options ( ) . dtype ( q . dtype ( ) ) ) ;
at : : Tensor softmax_lse ;
if ( return_softmax_lse ) {
std : : vector < int64_t > lse_sizes ( q . sizes ( ) . begin ( ) , q . sizes ( ) . end ( ) ) ;
lse_sizes . back ( ) = 1 ;
softmax_lse = at : : empty ( lse_sizes , q . options ( ) . dtype ( c10 : : ScalarType : : Float ) ) ;
} else {
softmax_lse = at : : empty ( { 0 } , q . options ( ) . dtype ( c10 : : ScalarType : : Float ) ) ;
}
return std : : tuple < at : : Tensor , at : : Tensor > ( output , softmax_lse ) ;
}
std : : tuple < at : : Tensor , at : : Tensor > npu_sparse_attn_sharedkv_npu ( const at : : Tensor & q , const c10 : : optional < at : : Tensor > & ori_kv ,
const c10 : : optional < at : : Tensor > & cmp_kv , const c10 : : optional < at : : Tensor > & ori_sparse_indices ,
const c10 : : optional < at : : Tensor > & cmp_sparse_indices , const c10 : : optional < at : : Tensor > & ori_block_table ,
const c10 : : optional < at : : Tensor > & cmp_block_table , const c10 : : optional < at : : Tensor > & cu_seqlens_q ,
const c10 : : optional < at : : Tensor > & cu_seqlens_ori_kv , const c10 : : optional < at : : Tensor > & cu_seqlens_cmp_kv ,
const c10 : : optional < at : : Tensor > & seqused_q , const c10 : : optional < at : : Tensor > & seqused_kv ,
const c10 : : optional < at : : Tensor > & sinks , const c10 : : optional < at : : Tensor > & metadata ,
double softmax_scale , int64_t cmp_ratio , int64_t ori_mask_mode , int64_t cmp_mask_mode , int64_t ori_win_left ,
int64_t ori_win_right , c10 : : string_view layout_q , c10 : : string_view layout_kv , bool return_softmax_lse )
{
std : : string layout_q_str = std : : string ( layout_q ) ;
std : : string layout_kv_str = std : : string ( layout_kv ) ;
std : : tuple < at : : Tensor , at : : Tensor > output = construct_output_tensor ( q , layout_q_str , return_softmax_lse ) ;
at : : Tensor attn_out = std : : get < 0 > ( output ) ;
at : : Tensor softmax_lse = std : : get < 1 > ( output ) ;
int64_t ori_kv_stride = 0 ;
int64_t cmp_kv_stride = 0 ;
if ( ori_kv . has_value ( ) ) {
const at : : Tensor & tmp_kv = * ori_kv ;
ori_kv_stride = tmp_kv . stride ( 0 ) ;
}
if ( cmp_kv . has_value ( ) ) {
const at : : Tensor & tmp_kv = * cmp_kv ;
cmp_kv_stride = tmp_kv . stride ( 0 ) ;
}
char * layout_q_ptr = const_cast < char * > ( layout_q_str . c_str ( ) ) ;
char * layout_kv_ptr = const_cast < char * > ( layout_kv_str . c_str ( ) ) ;
EXEC_NPU_CMD ( aclnnSparseAttnSharedkv , q , ori_kv , cmp_kv , ori_sparse_indices , cmp_sparse_indices ,
ori_block_table , cmp_block_table , cu_seqlens_q , cu_seqlens_ori_kv , cu_seqlens_cmp_kv , seqused_q , seqused_kv , sinks ,
metadata , softmax_scale , cmp_ratio , ori_mask_mode , cmp_mask_mode , ori_kv_stride , cmp_kv_stride , ori_win_left , ori_win_right , layout_q_ptr ,
layout_kv_ptr , return_softmax_lse , attn_out , softmax_lse ) ;
return std : : tuple < at : : Tensor , at : : Tensor > ( attn_out , softmax_lse ) ;
}
auto get_valid_tensor = [ ] ( const c10 : : optional < at : : Tensor > & tensor_opt , at : : Device device ) {
return tensor_opt . has_value ( ) ? tensor_opt : torch : : empty ( { 0 } , torch : : dtype ( torch : : kInt32 ) . device ( device ) ) ;
} ;
at : : Tensor npu_sparse_attn_sharedkv_metadata_npu (
int64_t num_heads_q ,
int64_t num_heads_kv ,
int64_t head_dim ,
const c10 : : optional < at : : Tensor > & cu_seqlens_q ,
const c10 : : optional < at : : Tensor > & cu_seqlens_ori_kv ,
const c10 : : optional < at : : Tensor > & cu_seqlens_cmp_kv ,
const c10 : : optional < at : : Tensor > & seqused_q ,
const c10 : : optional < at : : Tensor > & seqused_kv ,
int64_t batch_size ,
int64_t max_seqlen_q ,
int64_t max_seqlen_kv ,
int64_t ori_topk ,
int64_t cmp_topk ,
int64_t cmp_ratio ,
int64_t ori_mask_mode ,
int64_t cmp_mask_mode ,
int64_t ori_win_left ,
int64_t ori_win_right ,
c10 : : string_view layout_q ,
c10 : : string_view layout_kv ,
bool has_ori_kv ,
bool has_cmp_kv ,
const c10 : : string_view device )
{
constexpr int64_t OUTPUT_SIZE = 1024 ;
at : : Device output_device = at : : Device ( std : : string ( device ) ) ;
if ( cu_seqlens_q . has_value ( ) ) {
output_device = cu_seqlens_q . value ( ) . device ( ) ;
} else if ( cu_seqlens_ori_kv . has_value ( ) ) {
output_device = cu_seqlens_ori_kv . value ( ) . device ( ) ;
} else if ( cu_seqlens_cmp_kv . has_value ( ) ) {
output_device = cu_seqlens_cmp_kv . value ( ) . device ( ) ;
} else if ( seqused_q . has_value ( ) ) {
output_device = seqused_q . value ( ) . device ( ) ;
} else if ( seqused_kv . has_value ( ) ) {
output_device = seqused_kv . value ( ) . device ( ) ;
}
at : : Tensor output = torch : : empty ( { OUTPUT_SIZE } , torch : : dtype ( torch : : kInt32 ) . device ( output_device ) ) ;
auto cu_seqlens_q_val = get_valid_tensor ( cu_seqlens_q , output_device ) ;
auto cu_seqlens_ori_kv_val = get_valid_tensor ( cu_seqlens_ori_kv , output_device ) ;
auto cu_seqlens_cmp_kv_val = get_valid_tensor ( cu_seqlens_cmp_kv , output_device ) ;
auto seqused_q_val = get_valid_tensor ( seqused_q , output_device ) ;
auto seqused_kv_val = get_valid_tensor ( seqused_kv , output_device ) ;
std : : string layout_q_str = std : : string ( layout_q ) ;
std : : string layout_kv_str = std : : string ( layout_kv ) ;
char * layout_q_ptr = const_cast < char * > ( layout_q_str . c_str ( ) ) ;
char * layout_kv_ptr = const_cast < char * > ( layout_kv_str . c_str ( ) ) ;
EXEC_NPU_CMD ( aclnnSparseAttnSharedkvMetadata , cu_seqlens_q_val , cu_seqlens_ori_kv_val , cu_seqlens_cmp_kv_val , seqused_q_val ,
seqused_kv_val , num_heads_q , num_heads_kv , head_dim , batch_size , max_seqlen_q , max_seqlen_kv , ori_topk , cmp_topk ,
cmp_ratio , ori_mask_mode , cmp_mask_mode , ori_win_left , ori_win_right , layout_q_ptr ,
layout_kv_ptr , has_ori_kv , has_cmp_kv , output ) ;
return output ;
}
at : : Tensor npu_vllm_quant_lightning_indexer_metadata_npu (
int64_t num_heads_q , int64_t num_heads_k , int64_t head_dim , int64_t query_quant_mode , int64_t key_quant_mode ,
const c10 : : optional < at : : Tensor > & actual_seq_lengths_query , const c10 : : optional < at : : Tensor > & actual_seq_lengths_key , int64_t batch_size ,
int64_t max_seqlen_q , int64_t max_seqlen_k , const c10 : : string_view layout_query , c10 : : string_view layout_key , int64_t sparse_count ,
int64_t sparse_mode , int64_t pre_tokens , int64_t next_tokens , int64_t cmp_ratio , const c10 : : string_view device )
{
constexpr int64_t OUTPUT_SIZE = 1024 ;
at : : Device output_device = at : : Device ( std : : string ( device ) ) ;
if ( actual_seq_lengths_query . has_value ( ) ) {
output_device = actual_seq_lengths_query . value ( ) . device ( ) ;
} else if ( actual_seq_lengths_key . has_value ( ) ) {
output_device = actual_seq_lengths_key . value ( ) . device ( ) ;
}
at : : Tensor output = torch : : empty ( { OUTPUT_SIZE } , torch : : dtype ( torch : : kInt32 ) . device ( output_device ) ) ;
auto actual_seq_lengths_query_val = get_valid_tensor ( actual_seq_lengths_query , output_device ) ;
auto actual_seq_lengths_key_val = get_valid_tensor ( actual_seq_lengths_key , output_device ) ;
std : : string layout_query_str = std : : string ( layout_query ) ;
char * layout_query_ptr = const_cast < char * > ( layout_query_str . c_str ( ) ) ;
std : : string layout_key_str = std : : string ( layout_key ) ;
char * layout_key_ptr = const_cast < char * > ( layout_key_str . c_str ( ) ) ;
EXEC_NPU_CMD ( aclnnVllmQuantLightningIndexerMetadata , actual_seq_lengths_query_val , actual_seq_lengths_key_val ,
num_heads_q , num_heads_k , head_dim , query_quant_mode , key_quant_mode , batch_size ,
max_seqlen_q , max_seqlen_k , layout_query_ptr , layout_key_ptr , sparse_count ,
sparse_mode , pre_tokens , next_tokens , cmp_ratio , output ) ;
return output ;
}
at : : Tensor construct_hc_post_output_tensor ( const at : : Tensor & residual )
{
constexpr int64_t SIZE = 8 ;
constexpr int64_t DIM_0 = 0 ;
constexpr int64_t DIM_1 = 1 ;
constexpr int64_t DIM_2 = 2 ;
constexpr int64_t DIM_3 = 3 ;
at : : SmallVector < int64_t , SIZE > output_size = { residual . size ( DIM_0 ) , residual . size ( DIM_1 ) , residual . size ( DIM_2 ) , residual . size ( DIM_3 ) } ;
at : : Tensor out = at : : empty ( output_size , residual . options ( ) . dtype ( residual . dtype ( ) ) ) ;
return out ;
}
// step1, 工具函数, 检查输入shape
void check_hc_post_shape_and_dtype ( const at : : Tensor & x , const at : : Tensor & residual , const at : : Tensor & post , const at : : Tensor & com ) {
// check x shape: [b, s, d]
TORCH_CHECK ( x . dim ( ) = = 3 , " Input tensor x's dim num should be 3, actual " , x . dim ( ) , " . " ) ;
for ( size_t i = 0 ; i < 3 ; i + + ) {
TORCH_CHECK ( x . size ( i ) > 0 , " Input tensor x's shape should be positive, but x.shape[ " , i , " ] is : " , x . size ( i ) , " . " ) ;
}
auto batch = x . size ( 0 ) ;
auto sequence = x . size ( 1 ) ;
auto d = x . size ( 2 ) ;
// check residual: [b, s, hc, d]
TORCH_CHECK ( residual . dim ( ) = = 4 , " Input tensor residual's dim num should be 4, actual " , residual . dim ( ) , " . " ) ;
auto hc = residual . size ( 2 ) ;
TORCH_CHECK ( hc > 0 , " The hc of residual should be positive, actual " , hc , " . " ) ;
TORCH_CHECK ( residual . size ( 0 ) = = batch , " The residual.shape[0] should be batch, actual residual.shape[0] is " , residual . size ( 0 ) , " , batch is " , batch , " . " ) ;
TORCH_CHECK ( residual . size ( 1 ) = = sequence , " The residual.shape[1] should be sequence, actual residual.shape[1] is " , residual . size ( 1 ) , " , sequence is " , sequence , " . " ) ;
TORCH_CHECK ( residual . size ( 3 ) = = d , " The residual.shape[3] should be d, actual residual.shape[3] is " , residual . size ( 3 ) , " , d is " , d , " . " ) ;
// check post [b, s, hc]
TORCH_CHECK ( post . dim ( ) = = 3 , " Input tensor post's dim num should be 3, actual " , post . dim ( ) , " . " ) ;
TORCH_CHECK ( post . size ( 0 ) = = batch , " The post.shape[0] should be batch, actual post.shape[0] is " , post . size ( 0 ) , " , batch is " , batch , " . " ) ;
TORCH_CHECK ( post . size ( 1 ) = = sequence , " The post.shape[1] should be sequence, actual post.shape[1] is " , post . size ( 1 ) , " , sequence is " , sequence , " . " ) ;
TORCH_CHECK ( post . size ( 2 ) = = hc , " The post.shape[2] should be hc, actual post.shape[2] is " , post . size ( 2 ) , " , hc is " , hc , " . " ) ;
// check com: [b, s, hc, hc]
TORCH_CHECK ( com . dim ( ) = = 4 , " Input tensor com's dim num should be 4, actual " , com . dim ( ) , " . " ) ;
TORCH_CHECK ( com . size ( 0 ) = = batch , " The com.shape[0] should be batch, actual com.shape[0] is " , com . size ( 0 ) , " , batch is " , batch , " . " ) ;
TORCH_CHECK ( com . size ( 1 ) = = sequence , " The com.shape[1] should be sequence, actual com.shape[1] is " , com . size ( 1 ) , " , sequence is " , sequence , " . " ) ;
TORCH_CHECK ( com . size ( 2 ) = = hc , " The com.shape[2] should be hc, actual com.shape[2] is " , com . size ( 2 ) , " , hc is " , hc , " . " ) ;
TORCH_CHECK ( com . size ( 3 ) = = hc , " The com.shape[3] should be hc, actual com.shape[3] is " , com . size ( 3 ) , " , hc is " , hc , " . " ) ;
// check dtype
TORCH_CHECK ( x . dtype ( ) = = at : : kFloat | | x . dtype ( ) = = at : : kHalf | | x . dtype ( ) = = at : : kBFloat16 ,
" x should be FLOAT16, BFLOAT16, or FLOAT32. " ) ;
TORCH_CHECK ( residual . dtype ( ) = = x . dtype ( ) , " x's dtype should be equal to residual's dtype. " ) ;
TORCH_CHECK ( post . dtype ( ) = = at : : kFloat | | post . dtype ( ) = = at : : kHalf | | post . dtype ( ) = = at : : kBFloat16 ,
" post should be FLOAT16, BFLOAT16, or FLOAT32. " ) ;
TORCH_CHECK ( com . dtype ( ) = = post . dtype ( ) , " com's dtype should be equal to post's dtype. " ) ;
}
at : : Tensor npu_hc_post_npu (
const at : : Tensor & x ,
const at : : Tensor & residual ,
const at : : Tensor & post ,
const at : : Tensor & comb )
{
check_hc_post_shape_and_dtype ( x , residual , post , comb ) ;
// construct the output tensor
at : : Tensor out = construct_hc_post_output_tensor ( residual ) ;
EXEC_NPU_CMD ( aclnnHcPost , x , residual , post , comb , out ) ;
return out ;
}
constexpr int64_t HC_PRE_HC_LIMIT = 4 ;
constexpr int64_t HC_PRE_D_LIMIT = 4096 ;
constexpr int64_t HC_PRE_D_LIMIT_EXTEND = 7168 ;
constexpr int64_t HC_PRE_MIX_HC_LIMIT = 24 ;
std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > construct_hc_pre_output_tensor ( const at : : Tensor & x , int64_t hc_mult )
{
auto xDims = x . dim ( ) ;
at : : SmallVector < int64_t , 8 > y_size ;
at : : SmallVector < int64_t , 8 > post_size ;
at : : SmallVector < int64_t , 8 > comb_frag_size ;
if ( xDims = = 4 ) {
auto batch = x . size ( 0 ) ;
auto size = x . size ( 1 ) ;
auto d = x . size ( 3 ) ;
y_size = { batch , size , d } ;
post_size = { batch , size , hc_mult } ;
comb_frag_size = { batch , size , hc_mult , hc_mult } ;
} else if ( xDims = = 3 ) {
auto bs = x . size ( 0 ) ;
auto d = x . size ( 2 ) ;
y_size = { bs , d } ;
post_size = { bs , hc_mult } ;
comb_frag_size = { bs , hc_mult , hc_mult } ;
}
at : : Tensor y = at : : empty ( y_size , x . options ( ) . dtype ( at : : kBFloat16 ) ) ;
at : : Tensor post = at : : empty ( post_size , x . options ( ) . dtype ( at : : kFloat ) ) ;
at : : Tensor comb_frag = at : : empty ( comb_frag_size , x . options ( ) . dtype ( at : : kFloat ) ) ;
return std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > ( y , post , comb_frag ) ;
}
at : : Tensor construct_hc_pre_rsqrt_output_tensor ( const at : : Tensor & x , float epsilon = 1e-6 )
{
constexpr int64_t SIZE = 8 ;
TORCH_CHECK ( epsilon > = 0 , " epsilon should be greater than 0. " ) ;
auto options = x . options ( ) ;
auto xDims = x . dim ( ) ;
c10 : : SmallVector < int64_t , SIZE > yOut_shape ;
for ( size_t i = 0 ; i < xDims - 2 ; i + + ) {
yOut_shape . push_back ( x . sizes ( ) [ i ] ) ;
}
yOut_shape . push_back ( 1 ) ;
at : : Tensor yOut = at : : empty ( yOut_shape , options . dtype ( at : : kFloat ) ) ;
return yOut ;
}
void check_hc_pre_shape_and_dtype (
const at : : Tensor & x ,
const at : : Tensor & hc_fn ,
const at : : Tensor & hc_scale ,
const at : : Tensor & hc_base ,
int64_t hc_mult )
{
constexpr int64_t HC_SCALE_SIZE = 3 ;
auto x_dims = x . dim ( ) ;
TORCH_CHECK ( x_dims = = 3 | | x_dims = = 4 , " Input tensor x's dim num should be 3 or 4, actual " , x_dims , " . " ) ;
for ( auto i = 0 ; i < x_dims ; i + + ) {
TORCH_CHECK ( x . size ( i ) > 0 , " Input tensor x's shape should be positive, but x.shape[ " , i , " ] is " ,
x . size ( i ) , " . " ) ;
}
auto hc = x_dims = = 4 ? x . size ( 2 ) : x . size ( 1 ) ;
auto d = x_dims = = 4 ? x . size ( 3 ) : x . size ( 2 ) ;
TORCH_CHECK ( hc_mult = = HC_PRE_HC_LIMIT , " hc_mult only supports " , HC_PRE_HC_LIMIT , " , actual " , hc_mult , " . " ) ;
TORCH_CHECK ( hc = = HC_PRE_HC_LIMIT , " The hc of x only supports " , HC_PRE_HC_LIMIT , " , actual " , hc , " . " ) ;
TORCH_CHECK ( d = = HC_PRE_D_LIMIT | | d = = HC_PRE_D_LIMIT_EXTEND , " The d of x only supports " , HC_PRE_D_LIMIT ,
" or " , HC_PRE_D_LIMIT_EXTEND , " , actual " , d , " . " ) ;
TORCH_CHECK ( hc_fn . dim ( ) = = 2 , " Input tensor hc_fn's dim num should be 2, actual " , hc_fn . dim ( ) , " . " ) ;
TORCH_CHECK ( hc_fn . size ( 0 ) = = HC_PRE_MIX_HC_LIMIT , " The hc_fn.shape[0] only supports " ,
HC_PRE_MIX_HC_LIMIT , " , actual " , hc_fn . size ( 0 ) , " . " ) ;
TORCH_CHECK ( hc_fn . size ( 1 ) = = hc * d , " The hc_fn.shape[1] should be hc * d, actual hc_fn.shape[1] is " ,
hc_fn . size ( 1 ) , " , hc is " , hc , " , d is " , d , " . " ) ;
TORCH_CHECK ( hc_scale . dim ( ) = = 1 , " Input tensor hc_scale's dim num should be 1, actual " , hc_scale . dim ( ) , " . " ) ;
TORCH_CHECK ( hc_scale . size ( 0 ) = = HC_SCALE_SIZE , " Input tensor hc_scale's shape should be [ " , HC_SCALE_SIZE ,
" ], actual [ " , hc_scale . size ( 0 ) , " ]. " ) ;
TORCH_CHECK ( hc_base . dim ( ) = = 1 , " Input tensor hc_base's dim num should be 1, actual " , hc_base . dim ( ) , " . " ) ;
TORCH_CHECK ( hc_base . size ( 0 ) = = HC_PRE_MIX_HC_LIMIT , " The hc_base.shape[0] only supports " ,
HC_PRE_MIX_HC_LIMIT , " , actual " , hc_base . size ( 0 ) , " . " ) ;
TORCH_CHECK ( x . dtype ( ) = = at : : kBFloat16 , " x's dtype should be BFLOAT16. " ) ;
TORCH_CHECK ( hc_fn . dtype ( ) = = at : : kFloat , " hc_fn's dtype should be FLOAT32. " ) ;
TORCH_CHECK ( hc_scale . dtype ( ) = = at : : kFloat , " hc_scale's dtype should be FLOAT32. " ) ;
TORCH_CHECK ( hc_base . dtype ( ) = = at : : kFloat , " hc_base's dtype should be FLOAT32. " ) ;
}
std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > run_hc_pre_composite (
const at : : Tensor & x , const at : : Tensor & hc_fn , const at : : Tensor & hc_scale , const at : : Tensor & hc_base ,
int64_t hc_mult , int64_t hc_sinkhorn_iters , double norm_eps , double hc_eps )
{
auto xDims = x . dim ( ) ;
auto rsqrt = construct_hc_pre_rsqrt_output_tensor ( x , norm_eps ) ;
EXEC_NPU_CMD ( aclnnHcPreInvRms , x , norm_eps , rsqrt ) ;
auto original_type = x . dtype ( ) ;
at : : Tensor x_float = x . to ( at : : kFloat ) ;
at : : Tensor x_flattened = x_float . flatten ( 2 , - 1 ) ;
if ( xDims = = 3 ) {
x_flattened = x_float . flatten ( 1 , - 1 ) ;
}
auto mixes = at : : linear ( x_flattened , hc_fn ) ;
auto output_tensors = construct_hc_pre_output_tensor ( x , hc_mult ) ;
at : : Tensor y = std : : get < 0 > ( output_tensors ) ;
at : : Tensor post = std : : get < 1 > ( output_tensors ) ;
at : : Tensor comb_frag = std : : get < 2 > ( output_tensors ) ;
EXEC_NPU_CMD ( aclnnHcPreSinkhorn , mixes , rsqrt , hc_scale , hc_base , x , hc_mult , hc_sinkhorn_iters , hc_eps ,
y , post , comb_frag ) ;
y = y . to ( original_type ) ;
return std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > ( y , post , comb_frag ) ;
}
std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > run_hc_pre_fusion (
const at : : Tensor & x , const at : : Tensor & hc_fn , const at : : Tensor & hc_scale , const at : : Tensor & hc_base ,
int64_t hc_mult , int64_t hc_sinkhorn_iters , double norm_eps , double hc_eps )
{
auto output_tensors = construct_hc_pre_output_tensor ( x , hc_mult ) ;
at : : Tensor y = std : : get < 0 > ( output_tensors ) ;
at : : Tensor post = std : : get < 1 > ( output_tensors ) ;
at : : Tensor comb_frag = std : : get < 2 > ( output_tensors ) ;
EXEC_NPU_CMD ( aclnnHcPre , x , hc_fn , hc_scale , hc_base , hc_mult , hc_sinkhorn_iters , hc_eps , norm_eps ,
y , post , comb_frag ) ;
return std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > ( y , post , comb_frag ) ;
}
std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > npu_hc_pre_npu (
const at : : Tensor & x , const at : : Tensor & hc_fn , const at : : Tensor & hc_scale , const at : : Tensor & hc_base ,
int64_t hc_mult , int64_t hc_sinkhorn_iters , double norm_eps , double hc_eps )
{
check_hc_pre_shape_and_dtype ( x , hc_fn , hc_scale , hc_base , hc_mult ) ;
return run_hc_pre_composite ( x , hc_fn , hc_scale , hc_base , hc_mult , hc_sinkhorn_iters , norm_eps , hc_eps ) ;
}
std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > npu_hc_pre_v2_npu (
const at : : Tensor & x , const at : : Tensor & hc_fn , const at : : Tensor & hc_scale , const at : : Tensor & hc_base ,
int64_t hc_mult , int64_t hc_sinkhorn_iters , double norm_eps , double hc_eps )
{
check_hc_pre_shape_and_dtype ( x , hc_fn , hc_scale , hc_base , hc_mult ) ;
return run_hc_pre_fusion ( x , hc_fn , hc_scale , hc_base , hc_mult , hc_sinkhorn_iters , norm_eps , hc_eps ) ;
}
at : : Tensor construct_hc_pre_inv_rms_output_tensor ( const at : : Tensor & x , float epsilon = 1e-20 )
{
constexpr int64_t SIZE = 8 ;
TORCH_CHECK ( epsilon > = 0 , " epsilon should be greater than 0. " ) ;
auto options = x . options ( ) ;
auto xDims = x . dim ( ) ;
c10 : : SmallVector < int64_t , SIZE > yOut_shape ;
for ( auto i = 0 ; i < xDims - 2 ; i + + ) {
yOut_shape . push_back ( x . sizes ( ) [ i ] ) ;
}
yOut_shape . push_back ( 1 ) ;
at : : Tensor yOut = at : : empty ( yOut_shape , options . dtype ( at : : kFloat ) ) ;
return yOut ;
}
at : : Tensor npu_hc_pre_inv_rms_npu ( const at : : Tensor & x , double epsilon = 1e-20 )
{
TORCH_CHECK ( x . numel ( ) > 0 , " Input tensor x should not be empty. " ) ;
TORCH_CHECK ( epsilon > = 0 , " epsilon should be greater than 0. " ) ;
TORCH_CHECK ( x . dtype ( ) = = at : : kFloat | | x . dtype ( ) = = at : : kHalf | | x . dtype ( ) = = at : : kBFloat16 ,
" x should be FLOAT16, BFLOAT16, or FLOAT32. " ) ;
at : : Tensor yOut ;
yOut = construct_hc_pre_inv_rms_output_tensor ( x , epsilon ) ;
EXEC_NPU_CMD ( aclnnHcPreInvRms , x , epsilon , yOut ) ;
return yOut ;
}
std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > construct_hc_pre_sinkhorn_output_tensor ( const at : : Tensor & mixes , const at : : Tensor & x , int64_t hc_mult )
{
auto xDims = x . dim ( ) ;
at : : SmallVector < int64_t , 8 > y_size ;
at : : SmallVector < int64_t , 8 > post_size ;
at : : SmallVector < int64_t , 8 > comb_frag_size ;
if ( xDims = = 4 ) {
auto batch = x . size ( 0 ) ;
auto size = x . size ( 1 ) ;
auto d = x . size ( 3 ) ;
y_size = { batch , size , d } ;
post_size = { batch , size , hc_mult } ;
comb_frag_size = { batch , size , hc_mult , hc_mult } ;
} else if ( xDims = = 3 ) {
auto bs = x . size ( 0 ) ;
auto d = x . size ( 2 ) ;
y_size = { bs , d } ;
post_size = { bs , hc_mult } ;
comb_frag_size = { bs , hc_mult , hc_mult } ;
}
at : : Tensor y = at : : empty ( y_size , x . options ( ) . dtype ( at : : kBFloat16 ) ) ;
at : : Tensor post = at : : empty ( post_size , x . options ( ) . dtype ( at : : kFloat ) ) ;
at : : Tensor comb_frag = at : : empty ( comb_frag_size , x . options ( ) . dtype ( at : : kFloat ) ) ;
return std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > ( y , post , comb_frag ) ;
}
std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > npu_hc_pre_sinkhorn_npu (
const at : : Tensor & mixes , const at : : Tensor & rsqrt , const at : : Tensor & hc_scale , const at : : Tensor & hc_base ,
const at : : Tensor & x , int64_t hc_mult , int64_t hc_sinkhorn_iters , double hc_eps )
{
auto output_tensors = construct_hc_pre_sinkhorn_output_tensor ( mixes , x , hc_mult ) ;
at : : Tensor y = std : : get < 0 > ( output_tensors ) ;
at : : Tensor post = std : : get < 1 > ( output_tensors ) ;
at : : Tensor comb_frag = std : : get < 2 > ( output_tensors ) ;
EXEC_NPU_CMD ( aclnnHcPreSinkhorn , mixes , rsqrt , hc_scale , hc_base , x , hc_mult , hc_sinkhorn_iters , hc_eps ,
y , post , comb_frag ) ;
return std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > ( y , post , comb_frag ) ;
}
void inplace_partial_rotary_mul_npu ( at : : Tensor & x , const at : : Tensor & r1 , const at : : Tensor & r2 , c10 : : string_view rotary_mode , at : : IntArrayRef partial_slice )
{
constexpr int BSND_DIM_NUM = 4 ;
static const std : : unordered_map < std : : string , int > mode_map = {
{ " half " , 0 } ,
{ " interleave " , 1 } ,
{ " quarter " , 2 } ,
{ " interleave-half " , 3 }
} ;
std : : string rotary_mode_str = std : : string ( rotary_mode ) ;
auto it = mode_map . find ( rotary_mode_str ) ;
if ( it = = mode_map . end ( ) )
{
return ;
}
auto origin_dim_num = x . dim ( ) ;
TORCH_CHECK ( origin_dim_num = = BSND_DIM_NUM , " Input tensor x's dim num should be 4, actual " , origin_dim_num , " . " ) ;
EXEC_NPU_CMD ( aclnnInplacePartialRotaryMul , x , r1 , r2 , it - > second , partial_slice ) ;
}
std : : tuple < at : : Tensor , at : : Tensor > npu_rms_norm_dynamic_quant_npu (
const at : : Tensor & x ,
const at : : Tensor & gamma ,
const c10 : : optional < at : : Tensor > & smooth_scale ,
const c10 : : optional < at : : Tensor > & beta ,
double epsilon )
{
constexpr int32_t SIZE = 8 ;
TORCH_CHECK ( x . numel ( ) > 0 , " Input tensor x should not be empty. " ) ;
TORCH_CHECK ( gamma . numel ( ) > 0 , " Input tensor gamma should not be empty. " ) ;
TORCH_CHECK ( gamma . dim ( ) = = 1 & & gamma . size ( 0 ) = = x . size ( - 1 ) , " gamma dim are not equal to last dim of x shape. " ) ;
TORCH_CHECK ( epsilon > 0 , " epsilon should be greater than 0. " ) ;
TORCH_CHECK ( x . dtype ( ) = = at : : kHalf | | x . dtype ( ) = = at : : kBFloat16 , " x should be FLOAT16, BFLOAT16. " ) ;
at : : Tensor smooth_scale2 { nullptr } ;
auto options = x . options ( ) ;
at : : Tensor y_out = at : : empty_like ( x , options . dtype ( at : : kChar ) ) ;
at : : Tensor y2_out = at : : empty ( { 1 } , options . dtype ( at : : kChar ) ) ;
c10 : : SmallVector < int64_t , SIZE > scale_out_shape ;
for ( size_t i = 0 ; i < x . sizes ( ) . size ( ) - 1 ; i + + ) {
scale_out_shape . push_back ( x . sizes ( ) [ i ] ) ;
}
at : : Tensor scale_out = at : : empty ( scale_out_shape , options . dtype ( at : : kFloat ) ) ;
at : : Tensor scale2_out = at : : empty_like ( scale_out ) ;
std : : array < bool , 2 > * output_mask = nullptr ;
int64_t * dst_type = nullptr ;
EXEC_NPU_CMD ( aclnnRmsNormDynamicQuant , x , gamma , smooth_scale , smooth_scale2 , beta , epsilon , output_mask , dst_type ,
y_out , y2_out , scale_out , scale2_out ) ;
return std : : make_tuple ( y_out , scale_out ) ;
}
void indexer_compress_epilog_npu (
at : : Tensor & indexer_compress_cache ,
at : : Tensor & indexer_compress_cache_scale ,
const at : : Tensor & x ,
const at : : Tensor & slot_mapping ,
int64_t quant_mode = 1 ,
bool round_scale = true )
{
EXEC_NPU_CMD ( aclnnIndexerCompressEpilog , indexer_compress_cache , indexer_compress_cache_scale , x ,
slot_mapping , quant_mode , round_scale ) ;
}
void validate_kv_compress_epilog_inputs (
const at : : Tensor & x ,
const at : : Tensor & slot_mapping ,
at : : Tensor & kv_compress_cache )
{
TORCH_CHECK ( x . dim ( ) = = 2 , " x must be 2D tensor, but got dimensions: " , x . dim ( ) ) ;
TORCH_CHECK ( x . size ( 0 ) > 0 & & x . size ( 1 ) > 0 ,
" x dimensions must be positive, but got: [ " , x . size ( 0 ) , " , " , x . size ( 1 ) , " ] " ) ;
TORCH_CHECK ( slot_mapping . dim ( ) = = 1 ,
" slot_mapping must be 1D tensor, but got dimensions: " , slot_mapping . dim ( ) ) ;
TORCH_CHECK ( slot_mapping . size ( 0 ) = = x . size ( 0 ) ,
" slot_mapping size must equal x's first dimension, but got slot_mapping_size= " ,
slot_mapping . size ( 0 ) , " , x.dim(0)= " , x . size ( 0 ) ) ;
if ( kv_compress_cache . dim ( ) = = 4 ) {
TORCH_CHECK ( kv_compress_cache . size ( 2 ) = = 1 ,
" kv_compress_cache 4D tensor requires headnum (dim 2) == 1, but got " ,
kv_compress_cache . size ( 2 ) ) ;
}
TORCH_CHECK ( x . dtype ( ) = = at : : kBFloat16 , " x must be BF16, but got " , x . dtype ( ) ) ;
TORCH_CHECK ( slot_mapping . dtype ( ) = = at : : kInt | | slot_mapping . dtype ( ) = = at : : kLong ,
" slot_mapping must be INT32 or INT64, but got " , slot_mapping . dtype ( ) ) ;
TORCH_CHECK ( kv_compress_cache . dtype ( ) = = at : : ScalarType : : Float8_e5m2 | |
kv_compress_cache . dtype ( ) = = at : : ScalarType : : Float8_e4m3fn ,
" kv_compress_cache must be FP8_E5M2 or FP8_E4M3, but got " , kv_compress_cache . dtype ( ) ) ;
}
void kv_compress_epilog_npu (
at : : Tensor & kv_compress_cache ,
const at : : Tensor & x ,
const at : : Tensor & slot_mapping ,
int64_t quant_group_size ,
int64_t quant_mode ,
bool round_scale_flag ,
int64_t layout )
{
validate_kv_compress_epilog_inputs ( x , slot_mapping , kv_compress_cache ) ;
at : : Tensor cache = kv_compress_cache ;
if ( cache . dim ( ) = = 4 ) {
cache = cache . squeeze ( 2 ) ;
}
int64_t round_scale = round_scale_flag ? 1 : 0 ;
int64_t cache_stride = cache . stride ( 0 ) ;
EXEC_NPU_CMD ( aclnnKvCompressEpilog , cache , x , slot_mapping , quant_group_size , quant_mode , round_scale ,
layout , cache_stride ) ;
}
std : : tuple < at : : Tensor , at : : Tensor > npu_kv_quant_sparse_attn_sharedkv_npu (
const at : : Tensor & q ,
int64_t kv_quant_mode ,
const c10 : : optional < at : : Tensor > & ori_kv ,
const c10 : : optional < at : : Tensor > & cmp_kv ,
const c10 : : optional < at : : Tensor > & ori_sparse_indices ,
const c10 : : optional < at : : Tensor > & cmp_sparse_indices ,
const c10 : : optional < at : : Tensor > & ori_block_table ,
const c10 : : optional < at : : Tensor > & cmp_block_table ,
const c10 : : optional < at : : Tensor > & cu_seqlens_q ,
const c10 : : optional < at : : Tensor > & cu_seqlens_ori_kv ,
const c10 : : optional < at : : Tensor > & cu_seqlens_cmp_kv ,
const c10 : : optional < at : : Tensor > & seqused_q ,
const c10 : : optional < at : : Tensor > & seqused_kv ,
const c10 : : optional < at : : Tensor > & sinks ,
const c10 : : optional < at : : Tensor > & metadata ,
int64_t tile_size ,
int64_t rope_head_dim ,
double softmax_scale ,
int64_t cmp_ratio ,
int64_t ori_mask_mode ,
int64_t cmp_mask_mode ,
int64_t ori_win_left ,
int64_t ori_win_right ,
c10 : : string_view layout_q ,
c10 : : string_view layout_kv ,
bool return_softmax_lse )
{
std : : string layout_q_str = std : : string ( layout_q ) ;
std : : string layout_kv_str = std : : string ( layout_kv ) ;
auto output = construct_output_tensor ( q , layout_q_str , return_softmax_lse ) ;
at : : Tensor attn_out = std : : get < 0 > ( output ) ;
at : : Tensor softmax_lse = std : : get < 1 > ( output ) ;
char * layout_q_ptr = const_cast < char * > ( layout_q_str . c_str ( ) ) ;
char * layout_kv_ptr = const_cast < char * > ( layout_kv_str . c_str ( ) ) ;
int64_t ori_kv_stride0 = 0 ;
int64_t cmp_kv_stride0 = 0 ;
if ( ori_kv . has_value ( ) & & ori_kv . value ( ) . defined ( ) ) {
ori_kv_stride0 = ori_kv . value ( ) . stride ( 0 ) ;
}
if ( cmp_kv . has_value ( ) & & cmp_kv . value ( ) . defined ( ) ) {
cmp_kv_stride0 = cmp_kv . value ( ) . stride ( 0 ) ;
}
EXEC_NPU_CMD ( aclnnKvQuantSparseAttnSharedkv , q , ori_kv , cmp_kv , ori_sparse_indices , cmp_sparse_indices ,
ori_block_table , cmp_block_table , cu_seqlens_q , cu_seqlens_ori_kv , cu_seqlens_cmp_kv ,
seqused_q , seqused_kv , sinks , metadata , kv_quant_mode , tile_size , rope_head_dim ,
softmax_scale , cmp_ratio , ori_mask_mode , cmp_mask_mode , ori_win_left , ori_win_right ,
layout_q_ptr , layout_kv_ptr , ori_kv_stride0 , cmp_kv_stride0 , return_softmax_lse ,
attn_out , softmax_lse ) ;
return std : : tuple < at : : Tensor , at : : Tensor > ( attn_out , softmax_lse ) ;
}
at : : Tensor npu_kv_quant_sparse_attn_sharedkv_metadata_npu (
int64_t num_heads_q ,
int64_t num_heads_kv ,
int64_t head_dim ,
int64_t kv_quant_mode ,
const c10 : : optional < at : : Tensor > & cu_seqlens_q ,
const c10 : : optional < at : : Tensor > & cu_seqlens_ori_kv ,
const c10 : : optional < at : : Tensor > & cu_seqlens_cmp_kv ,
const c10 : : optional < at : : Tensor > & seqused_q ,
const c10 : : optional < at : : Tensor > & seqused_kv ,
int64_t batch_size ,
int64_t max_seqlen_q ,
int64_t max_seqlen_kv ,
int64_t ori_topk ,
int64_t cmp_topk ,
int64_t tile_size ,
int64_t rope_head_dim ,
int64_t cmp_ratio ,
int64_t ori_mask_mode ,
int64_t cmp_mask_mode ,
int64_t ori_win_left ,
int64_t ori_win_right ,
c10 : : string_view layout_q ,
c10 : : string_view layout_kv ,
bool has_ori_kv ,
bool has_cmp_kv ,
const c10 : : string_view device )
{
constexpr int64_t OUTPUT_SIZE = 1024 ;
at : : Device output_device = at : : Device ( std : : string ( device ) ) ;
if ( cu_seqlens_q . has_value ( ) ) {
output_device = cu_seqlens_q . value ( ) . device ( ) ;
} else if ( cu_seqlens_ori_kv . has_value ( ) ) {
output_device = cu_seqlens_ori_kv . value ( ) . device ( ) ;
} else if ( cu_seqlens_cmp_kv . has_value ( ) ) {
output_device = cu_seqlens_cmp_kv . value ( ) . device ( ) ;
} else if ( seqused_q . has_value ( ) ) {
output_device = seqused_q . value ( ) . device ( ) ;
} else if ( seqused_kv . has_value ( ) ) {
output_device = seqused_kv . value ( ) . device ( ) ;
}
at : : Tensor output = torch : : empty ( { OUTPUT_SIZE } , torch : : dtype ( torch : : kInt32 ) . device ( output_device ) ) ;
auto cu_seqlens_q_val = get_valid_tensor ( cu_seqlens_q , output_device ) ;
auto cu_seqlens_ori_kv_val = get_valid_tensor ( cu_seqlens_ori_kv , output_device ) ;
auto cu_seqlens_cmp_kv_val = get_valid_tensor ( cu_seqlens_cmp_kv , output_device ) ;
auto seqused_q_val = get_valid_tensor ( seqused_q , output_device ) ;
auto seqused_kv_val = get_valid_tensor ( seqused_kv , output_device ) ;
std : : string layout_q_str = std : : string ( layout_q ) ;
std : : string layout_kv_str = std : : string ( layout_kv ) ;
char * layout_q_ptr = const_cast < char * > ( layout_q_str . c_str ( ) ) ;
char * layout_kv_ptr = const_cast < char * > ( layout_kv_str . c_str ( ) ) ;
EXEC_NPU_CMD ( aclnnKvQuantSparseAttnSharedkvMetadata , cu_seqlens_q_val , cu_seqlens_ori_kv_val ,
cu_seqlens_cmp_kv_val , seqused_q_val , seqused_kv_val , num_heads_q , num_heads_kv ,
head_dim , batch_size , max_seqlen_q , max_seqlen_kv , ori_topk , cmp_topk , kv_quant_mode ,
tile_size , rope_head_dim , cmp_ratio , ori_mask_mode , cmp_mask_mode , ori_win_left ,
ori_win_right , layout_q_ptr , layout_kv_ptr , has_ori_kv , has_cmp_kv , output ) ;
return output ;
}
int64_t get_type_code ( at : : ScalarType dst_type )
{
switch ( dst_type ) {
case at : : ScalarType : : Float8_e5m2 :
return 35 ;
case at : : ScalarType : : Float8_e4m3fn :
return 36 ;
case at : : ScalarType : : Half :
return 1 ;
case at : : ScalarType : : BFloat16 :
return 27 ;
default :
TORCH_CHECK ( false , " Unsupported dtype: " , dst_type ) ;
}
return 0 ;
}
std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > construct_swiglu_group_quant_output_tensor (
const at : : Tensor & x ,
int64_t dst_type ,
int64_t quant_mode ,
bool ue8m0_scale )
{
constexpr int64_t SIZE = 8 ;
constexpr int64_t SWIGLU_FACTOR = 2 ;
constexpr int64_t PER_BLOCK_FP16 = 128 ;
constexpr int64_t PER_MX_FP16 = 32 ;
constexpr int64_t MX_SCALE_ALIGN_FACTOR = 2 ;
constexpr int64_t GROUP_QUANT = 1 ;
constexpr int64_t MX_QUANT = 2 ;
constexpr int64_t FP8_QUANT = 3 ;
at : : SmallVector < int64_t , SIZE > y_size ( x . sizes ( ) . begin ( ) , x . sizes ( ) . end ( ) ) ;
for ( size_t i = 0 ; i < x . sizes ( ) . size ( ) ; i + + ) {
TORCH_CHECK ( x . size ( i ) > = 0 , " All values within x's shape should be non-negative, but shape[ " ,
i , " ] is " , x . size ( i ) ) ;
}
TORCH_CHECK ( x . dtype ( ) = = at : : kHalf | | x . dtype ( ) = = at : : kBFloat16 ,
" x should be FLOAT16 or BFLOAT16. " ) ;
int64_t x_last_dim = x . sizes ( ) . back ( ) ;
TORCH_CHECK ( quant_mode = = GROUP_QUANT | | quant_mode = = MX_QUANT | | quant_mode = = FP8_QUANT ,
" Unsupported quant mode, only support " , GROUP_QUANT , " or " , MX_QUANT , " or " , FP8_QUANT , " . " ) ;
if ( quant_mode = = GROUP_QUANT | | quant_mode = = FP8_QUANT ) {
TORCH_CHECK ( x_last_dim % 256 = = 0 ,
" In group quant, the last dim of x should be divisible by 256, actual " , x_last_dim , " . " ) ;
} else {
TORCH_CHECK ( x_last_dim % 128 = = 0 ,
" In mx quant, the last dim of x should be divisible by 128, actual " , x_last_dim , " . " ) ;
}
y_size . back ( ) = y_size . back ( ) / SWIGLU_FACTOR ;
int64_t y_last_dim = y_size . back ( ) ;
auto y_dtype = dst_type = = 35 ? at : : kFloat8_e5m2 : at : : kFloat8_e4m3fn ;
at : : Tensor y = at : : empty ( y_size , x . options ( ) . dtype ( y_dtype ) ) ;
at : : SmallVector < int64_t , SIZE > scale_size ( y_size . begin ( ) , y_size . end ( ) ) ;
if ( quant_mode = = GROUP_QUANT | | quant_mode = = FP8_QUANT ) {
scale_size . back ( ) = ( y_last_dim + PER_BLOCK_FP16 - 1 ) / PER_BLOCK_FP16 ;
} else if ( quant_mode = = MX_QUANT ) {
int64_t scale_last_dim = ( y_last_dim + PER_MX_FP16 - 1 ) / PER_MX_FP16 ;
scale_last_dim = ( scale_last_dim + MX_SCALE_ALIGN_FACTOR - 1 ) / MX_SCALE_ALIGN_FACTOR ;
scale_size . back ( ) = scale_last_dim ;
scale_size . push_back ( MX_SCALE_ALIGN_FACTOR ) ;
}
auto scale_type = at : : kFloat ;
if ( quant_mode = = MX_QUANT | | ( quant_mode = = FP8_QUANT & & ue8m0_scale ) ) {
scale_type = at : : kFloat8_e8m0fnu ;
}
at : : Tensor scale = at : : empty ( scale_size , x . options ( ) . dtype ( scale_type ) ) ;
at : : Tensor y_origin = at : : empty ( y_size , x . options ( ) . dtype ( x . dtype ( ) ) ) ;
return std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > ( y , scale , y_origin ) ;
}
std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > npu_swiglu_group_quant_npu (
const at : : Tensor & x ,
const c10 : : optional < at : : Tensor > & topk_weight ,
const c10 : : optional < at : : Tensor > & group_index ,
at : : ScalarType dst_type = at : : ScalarType : : Float8_e4m3fn ,
int64_t quant_mode = 1 ,
int64_t group_size = 128 ,
bool round_scale = false ,
bool ue8m0_scale = false ,
bool output_origin = false ,
int64_t group_list_type = 0 ,
double clamp_value = 0.0 )
{
int64_t dst_type_code = get_type_code ( dst_type ) ;
auto output_tensors = construct_swiglu_group_quant_output_tensor ( x , dst_type_code , quant_mode , ue8m0_scale ) ;
at : : Tensor y = std : : get < 0 > ( output_tensors ) ;
at : : Tensor scale = std : : get < 1 > ( output_tensors ) ;
at : : Tensor y_origin = std : : get < 2 > ( output_tensors ) ;
EXEC_NPU_CMD ( aclnnSwigluGroupQuant , x , topk_weight , group_index , dst_type_code , quant_mode , group_size ,
round_scale , ue8m0_scale , output_origin , group_list_type , clamp_value , y , scale , y_origin ) ;
return std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > ( y , scale , y_origin ) ;
}
std : : tuple < at : : Tensor , at : : Tensor > construct_load_index_kv_cache_output_tensor (
const at : : Tensor & kv_cache ,
const at : : Tensor & slot_mapping )
{
constexpr int64_t KV_LAST_DIM = 128 ;
int64_t n = slot_mapping . size ( 0 ) ;
at : : Tensor kv = at : : empty ( { n , KV_LAST_DIM } , kv_cache . options ( ) . dtype ( at : : kFloat8_e4m3fn ) ) ;
at : : Tensor kv_scale = at : : empty ( { n } , kv_cache . options ( ) . dtype ( at : : kFloat ) ) ;
return std : : tuple < at : : Tensor , at : : Tensor > ( kv , kv_scale ) ;
}
std : : tuple < at : : Tensor , at : : Tensor > npu_load_index_kv_cache_npu (
const at : : Tensor & kv_cache ,
const at : : Tensor & slot_mapping )
{
auto output_tensors = construct_load_index_kv_cache_output_tensor ( kv_cache , slot_mapping ) ;
at : : Tensor kv = std : : get < 0 > ( output_tensors ) ;
at : : Tensor kv_scale = std : : get < 1 > ( output_tensors ) ;
int64_t kv_cache_stride = kv_cache . stride ( 0 ) ;
EXEC_NPU_CMD ( aclnnLoadIndexKvCache , kv_cache , slot_mapping , kv_cache_stride , kv , kv_scale ) ;
return std : : tuple < at : : Tensor , at : : Tensor > ( kv , kv_scale ) ;
}
void indexer_compress_epilog_v2_npu (
at : : Tensor & indexer_compress_cache ,
const at : : Tensor & x ,
const at : : Tensor & slot_mapping ,
int64_t layout = 2 )
{
int64_t indexer_compress_cache_stride = indexer_compress_cache . stride ( 0 ) ;
EXEC_NPU_CMD ( aclnnIndexerCompressEpilogV2 , indexer_compress_cache , x , slot_mapping , layout ,
indexer_compress_cache_stride ) ;
}
std : : tuple < at : : Tensor , at : : Tensor > npu_dequant_swiglu_quant (
const at : : Tensor & x ,
const c10 : : optional < at : : Tensor > & weight_scale ,
const c10 : : optional < at : : Tensor > & activation_scale ,
const c10 : : optional < at : : Tensor > & bias ,
const c10 : : optional < at : : Tensor > & quant_scale ,
const c10 : : optional < at : : Tensor > & quant_offset ,
const c10 : : optional < at : : Tensor > & group_index ,
bool activate_left ,
int64_t quant_mode ,
int64_t swiglu_mode ,
double clamp_limit ,
double glu_alpha ,
double glu_bias )
{
TORCH_CHECK ( x . dim ( ) > 1 , " x dim should larger than 1 " ) ;
TORCH_CHECK ( quant_mode = = 0 | | quant_mode = = 1 , " quant_mode only support 0 or 1, but got " , quant_mode ) ;
TORCH_CHECK ( swiglu_mode = = 0 | | swiglu_mode = = 1 , " swiglu_mode only support 0 or 1, but got " , swiglu_mode ) ;
TORCH_CHECK ( std : : isfinite ( clamp_limit ) & & clamp_limit > = 0.0 , " clamp_limit should be positive finite " ) ;
TORCH_CHECK ( std : : isfinite ( glu_alpha ) , " glu_alpha should be finite " ) ;
TORCH_CHECK ( std : : isfinite ( glu_bias ) , " glu_bias should be finite " ) ;
TORCH_CHECK ( x . size ( x . dim ( ) - 1 ) % 2 = = 0 , " x last dim should be even " ) ;
c10 : : SmallVector < int64_t , 8 > y_size ;
c10 : : SmallVector < int64_t , 8 > scale_size ;
for ( int64_t i = 0 ; i < x . dim ( ) - 1 ; + + i ) {
y_size . push_back ( x . size ( i ) ) ;
scale_size . push_back ( x . size ( i ) ) ;
}
y_size . push_back ( x . size ( x . dim ( ) - 1 ) / 2 ) ;
at : : Tensor y = at : : empty ( y_size , x . options ( ) . dtype ( c10 : : ScalarType : : Char ) ) ;
at : : Tensor scale = at : : empty ( scale_size , x . options ( ) . dtype ( c10 : : ScalarType : : Float ) ) ;
std : : string quant_mode_str = quant_mode = = 1 ? " dynamic " : " static " ;
char * quant_mode_ptr = const_cast < char * > ( quant_mode_str . c_str ( ) ) ;
const at : : Tensor & weight_scale_value = c10 : : value_or_else ( weight_scale , [ ] { return at : : Tensor ( ) ; } ) ;
const at : : Tensor & activation_scale_opt = c10 : : value_or_else ( activation_scale , [ ] { return at : : Tensor ( ) ; } ) ;
const at : : Tensor & bias_opt = c10 : : value_or_else ( bias , [ ] { return at : : Tensor ( ) ; } ) ;
const at : : Tensor & quant_scale_opt = c10 : : value_or_else ( quant_scale , [ ] { return at : : Tensor ( ) ; } ) ;
const at : : Tensor & quant_offset_opt = c10 : : value_or_else ( quant_offset , [ ] { return at : : Tensor ( ) ; } ) ;
const at : : Tensor & group_index_opt = c10 : : value_or_else ( group_index , [ ] { return at : : Tensor ( ) ; } ) ;
static const bool is_v2_available =
GetOpApiFuncAddr ( " aclnnDequantSwigluQuantV2 " ) ! = nullptr & &
GetOpApiFuncAddr ( " aclnnDequantSwigluQuantV2GetWorkspaceSize " ) ! = nullptr ;
if ( swiglu_mode = = 0 & & ! is_v2_available ) {
EXEC_NPU_CMD ( aclnnDequantSwigluQuant , x , weight_scale_value , activation_scale_opt , bias_opt , quant_scale_opt ,
quant_offset_opt , group_index_opt , activate_left , quant_mode_ptr , y , scale ) ;
} else {
int64_t dst_type = 2 ;
char * round_mode = const_cast < char * > ( " rint " ) ;
int64_t activate_dim = - 1 ;
EXEC_NPU_CMD ( aclnnDequantSwigluQuantV2 , x , weight_scale_value , activation_scale_opt , bias_opt , quant_scale_opt ,
quant_offset_opt , group_index_opt , activate_left , quant_mode_ptr , dst_type , round_mode ,
activate_dim , swiglu_mode , clamp_limit , glu_alpha , glu_bias , y , scale ) ;
}
return std : : make_tuple ( y , scale ) ;
}
void npu_scatter_nd_update_v2 (
at : : Tensor & var ,
const at : : Tensor & indices ,
const at : : Tensor & update )
{
// construct the output tensor
at : : IntArrayRef var_stride = var . strides ( ) ;
EXEC_NPU_CMD ( aclnnScatterNdUpdateV2 , var , indices , update , var_stride ) ;
return ;
}
std : : tuple < at : : Tensor , at : : Tensor , at : : Tensor > chunk_gated_delta_rule_fwd_h (
const at : : Tensor & k ,
const at : : Tensor & w ,
const at : : Tensor & u ,
const c10 : : optional < at : : Tensor > & g ,
const c10 : : optional < at : : Tensor > & gk ,
const c10 : : optional < at : : Tensor > & initial_state ,
c10 : : optional < bool > output_final_state ,
c10 : : optional < int64_t > chunk_size ,
c10 : : optional < bool > save_new_value ,
c10 : : optional < at : : IntArrayRef > cu_seqlens ,
c10 : : optional < at : : IntArrayRef > chunk_indices ,
c10 : : optional < bool > use_exp2 ,
c10 : : optional < bool > transpose_state_layout )
{
bool output_final_state_ = output_final_state . has_value ( ) ? output_final_state . value ( ) : false ;
const at : : Tensor & initial_state_ = c10 : : value_or_else ( initial_state , [ ] { return at : : Tensor ( ) ; } ) ;
int64_t chunk_size_ = chunk_size . has_value ( ) ? chunk_size . value ( ) : 64 ;
const at : : Tensor & g_ = c10 : : value_or_else ( g , [ ] { return at : : Tensor ( ) ; } ) ;
const at : : Tensor & gk_ = c10 : : value_or_else ( gk , [ ] { return at : : Tensor ( ) ; } ) ;
auto k_sizes = k . sizes ( ) ;
auto u_sizes = u . sizes ( ) ;
int K = k_sizes [ 3 ] ;
int B = k_sizes [ 0 ] ;
int T = k_sizes [ 2 ] ;
int HV = u_sizes [ 1 ] ;
int V = u_sizes [ 3 ] ;
int NT = 0 ;
if ( chunk_indices . has_value ( ) ) {
auto chunk_indices_ref = chunk_indices . value ( ) ;
NT = chunk_indices_ref . size ( ) / 2 ;
} else {
NT = ( T + chunk_size_ - 1 ) / chunk_size_ ;
}
at : : Tensor h_out = at : : zeros ( { B , HV , NT , K , V } , k . options ( ) ) ;
at : : Tensor v_new_out = at : : zeros ( u . sizes ( ) , u . options ( ) ) ;
at : : Tensor final_state_out ;
if ( output_final_state_ ) {
int N = cu_seqlens . has_value ( ) ? cu_seqlens - > size ( ) - 1 : B ;
auto state_options = initial_state . has_value ( ) ? initial_state - > options ( ) : h_out . options ( ) ;
final_state_out = at : : empty ( { N , HV , K , V } , state_options ) ;
} else {
final_state_out = at : : empty ( { 1 } , k . options ( ) ) ;
}
bool save_new_value_ = save_new_value . value_or ( true ) ;
bool use_exp2_ = use_exp2 . value_or ( false ) ;
bool transpose_state_layout_ = transpose_state_layout . value_or ( false ) ;
EXEC_NPU_CMD (
aclnnChunkGatedDeltaRuleFwdH ,
k , w , u , g_ ,
gk_ , initial_state_ , output_final_state_ , chunk_size_ , save_new_value_ ,
cu_seqlens , chunk_indices , use_exp2_ , transpose_state_layout_ ,
h_out , v_new_out , final_state_out
) ;
if ( output_final_state_ ) {
return std : : make_tuple ( h_out , v_new_out , final_state_out ) ;
} else {
return std : : make_tuple ( h_out , v_new_out , at : : Tensor ( ) ) ;
}
}
at : : Tensor chunk_fwd_o (
const at : : Tensor & q ,
const at : : Tensor & k ,
const at : : Tensor & v ,
const at : : Tensor & h ,
double scale ,
const c10 : : optional < at : : Tensor > & g ,
const c10 : : optional < at : : Tensor > & g_gamma ,
c10 : : optional < at : : IntArrayRef > cu_seqlens ,
c10 : : optional < at : : IntArrayRef > chunk_indices ,
c10 : : optional < int64_t > chunk_size ,
c10 : : optional < bool > transpose_state_layout )
{
at : : Tensor o = at : : zeros ( v . sizes ( ) , v . options ( ) ) ;
int64_t chunk_size_ = chunk_size . has_value ( ) ? chunk_size . value ( ) : 64 ;
const at : : Tensor & g_ = c10 : : value_or_else ( g , [ ] { return at : : Tensor ( ) ; } ) ;
( void ) g_gamma ;
( void ) transpose_state_layout ;
EXEC_NPU_CMD (
aclnnChunkFwdO ,
q , k , v , h , g_ ,
cu_seqlens , chunk_indices , scale , chunk_size_ ,
o
) ;
return o ;
}
std : : vector < int64_t > get_npu_storage_shape ( const at : : Tensor & tensor )
{
TORCH_CHECK (
tensor . is_privateuseone ( ) ,
" get_npu_storage_shape only supports NPU tensors, but got device " ,
tensor . device ( ) ) ;
const auto & desc = NPUBridge : : GetNpuStorageImplDesc ( tensor ) ;
return std : : vector < int64_t > ( desc . storage_sizes_ . begin ( ) , desc . storage_sizes_ . end ( ) ) ;
}
} // namespace vllm_ascend
# ifdef ASCEND_PLATFORM_310P
// Pybind on Ascend 310P
TORCH_LIBRARY_EXPAND ( CONCAT ( _C , _ascend ) , ops )
{
ops . def (
" npu_causal_conv1d_310(Tensor x, "
" Tensor weight, "
" Tensor? bias, "
" Tensor conv_states, "
" Tensor? query_start_loc, "
" Tensor? cache_indices, "
" Tensor? initial_state_mode, "
" Tensor? num_accepted_tokens, "
" int activation_mode, "
" int pad_slot_id, "
" int run_mode) -> (Tensor output) " ) ;
ops . impl ( " npu_causal_conv1d_310 " , torch : : kPrivateUse1 , & vllm_ascend : : npu_causal_conv1d_310 ) ;
ops . def (
" npu_recurrent_gated_delta_rule_310(Tensor query, "
" Tensor key, "
" Tensor value, "
" Tensor beta, "
" Tensor state, "
" Tensor actual_seq_lengths, "
" Tensor ssm_state_indices, "
" Tensor? g, "
" Tensor? gk, "
" Tensor? num_accepted_tokens, "
" float scale_value=1.0) -> (Tensor output) " ) ;
ops . impl ( " npu_recurrent_gated_delta_rule_310 " , torch : : kPrivateUse1 , & vllm_ascend : : npu_recurrent_gated_delta_rule_310 ) ;
ops . def (
" chunk_gated_delta_rule_fwd_h(Tensor k, Tensor w, Tensor u, Tensor? g=None, *, Tensor? gk=None, Tensor? initial_state=None, bool? output_final_state=False, int? chunk_size=None, bool? save_new_value=True, int[]? cu_seqlens=None, int[]? chunk_indices=None, bool? use_exp2=False, bool? transpose_state_layout=False) -> (Tensor h_out, Tensor v_new_out, Tensor final_state_out) "
) ;
ops . impl ( " chunk_gated_delta_rule_fwd_h " , torch : : kPrivateUse1 , & vllm_ascend : : chunk_gated_delta_rule_fwd_h ) ;
ops . def (
" chunk_fwd_o(Tensor q, Tensor k, Tensor v, Tensor h, float scale, *, Tensor? g=None, Tensor? g_gamma=None, int[]? cu_seqlens=None, int[]? chunk_indices=None, int? chunk_size=None, bool? transpose_state_layout=False) -> Tensor "
) ;
ops . impl ( " chunk_fwd_o " , torch : : kPrivateUse1 , & vllm_ascend : : chunk_fwd_o ) ;
}
# else
// Pybind on other platform
TORCH_LIBRARY_EXPAND ( CONCAT ( _C , _ascend ) , ops )
{
// vLLM-Ascend custom ops
// Gemma RmsNorm
ops . def (
" npu_gemma_rms_norm(Tensor x, "
" Tensor gamma, "
" float epsilon=1e-6) "
" -> (Tensor y ,Tensor rstd) "
) ;
ops . impl ( " npu_gemma_rms_norm " , torch : : kPrivateUse1 , & vllm_ascend : : npu_gemma_rms_norm ) ;
ops . def (
" npu_recurrent_gated_delta_rule(Tensor query, "
" Tensor key, "
" Tensor value, "
" Tensor(a!) state, "
" *, "
" Tensor? beta=None, "
" float? scale=None, "
" Tensor? actual_seq_lengths=None, "
" Tensor? ssm_state_indices=None, "
" Tensor? num_accepted_tokens=None, "
" Tensor? g=None, "
" Tensor? gk=None) -> Tensor " ) ;
ops . impl ( " npu_recurrent_gated_delta_rule " , torch : : kPrivateUse1 , & vllm_ascend : : npu_recurrent_gated_delta_rule ) ;
# ifdef VLLM_ENABLE_ATB_AND_DIRECT_KERNELS
// Direct kernel custom ops
ops . def (
" get_masked_input_and_mask(Tensor input, "
" int org_vocab_start_index, "
" int org_vocab_end_index, "
" int num_org_vocab_padding, "
" int added_vocab_start_index, "
" int added_vocab_end_index) -> (Tensor masked_input, Tensor mask) " ) ;
ops . impl ( " get_masked_input_and_mask " , torch : : kPrivateUse1 , & vllm_ascend : : get_masked_input_and_mask ) ;
ops . def ( " bgmv_shrink(Tensor! x, Tensor! weight, Tensor! indices, Tensor! y, float scale) -> () " ) ;
ops . impl ( " bgmv_shrink " , torch : : kPrivateUse1 , & vllm_ascend : : bgmv_shrink ) ;
ops . def (
" bgmv_expand(Tensor! x, Tensor! weight, Tensor! indices, Tensor! y, "
" int slice_offset, int slice_size) -> Tensor " ) ;
ops . impl ( " bgmv_expand " , torch : : kPrivateUse1 , & vllm_ascend : : bgmv_expand ) ;
ops . def ( " sgmv_shrink(Tensor! x, Tensor! weight, Tensor! lora_indices, Tensor! seq_len, Tensor! y, float scale) -> () " ) ;
ops . impl ( " sgmv_shrink " , torch : : kPrivateUse1 , & vllm_ascend : : sgmv_shrink ) ;
ops . def (
" sgmv_expand(Tensor! x, Tensor! weight, Tensor! lora_indices, Tensor! seq_len, Tensor! y, "
" int slice_offset, int slice_size) -> Tensor " ) ;
ops . impl ( " sgmv_expand " , torch : : kPrivateUse1 , & vllm_ascend : : sgmv_expand ) ;
ops . def (
" mla_preprocess(Tensor hiddenState, Tensor wdqkv, "
" Tensor? descale0, Tensor gamma1, Tensor? beta1, Tensor wuq, Tensor? descale1, "
" Tensor gamma2, Tensor cos, Tensor sin, Tensor wuk, Tensor kv_cache, "
" Tensor kv_cache_rope, Tensor slotmapping, Tensor? quant_scale0, "
" Tensor? quant_offset0, Tensor? bias0, Tensor? quant_scale1, Tensor? quant_offset1, "
" Tensor? bias1, Tensor? ctkv_scale, Tensor? q_nope_scale, str? cache_mode, "
" str? quant_mode, bool? enable_inner_out, Tensor! q_out0, Tensor! kv_cache_out0, Tensor! q_out1, "
" Tensor! kv_cache_out1, Tensor! inner_out) -> (Tensor q_out0, Tensor kv_cache_out0, "
" Tensor q_out1, Tensor kv_cache_out1, Tensor inner_out) "
) ;
ops . impl ( " mla_preprocess " , torch : : kPrivateUse1 , & vllm_ascend : : mla_preprocess ) ;
//batch_matmul ops refer to sgl-kernel-npu
ops . def (
" batch_matmul_transpose(Tensor tensor_a, Tensor tensor_b, Tensor tensor_c, str? format_mode=None, str? quant_mode=None) -> () " ) ;
ops . impl ( " batch_matmul_transpose " , torch : : kPrivateUse1 , & vllm_ascend : : batch_matmul_transpose ) ;
ops . def ( " swap_blocks(Tensor! x, Tensor! y, Tensor z) -> () " ) ;
ops . impl ( " swap_blocks " , torch : : kPrivateUse1 , & vllm_ascend : : swap_blocks ) ;
# endif
// swap_blocks_batch takes CPU tensors (int64 pointer/size arrays), not NPU
// tensors, so dispatch must be registered on the CPU backend. The function
// internally submits async memcpy on the current NPU stream.
ops . def ( " swap_blocks_batch(Tensor x, Tensor y, Tensor z, int direction) -> () " ) ;
ops . impl ( " swap_blocks_batch " , torch : : kCPU , & vllm_ascend : : swap_blocks_batch ) ;
ops . def ( " device_print(str msg) -> () " ) ;
ops . impl ( " device_print " , c10 : : DispatchKey : : CompositeExplicitAutograd ,
static_cast < void ( * ) ( c10 : : string_view ) > ( & vllm_ascend : : device_print ) ) ;
ops . def ( " device_print_tensor(Tensor tensor) -> () " ) ;
ops . impl ( " device_print_tensor " , c10 : : DispatchKey : : CompositeExplicitAutograd ,
static_cast < void ( * ) ( const at : : Tensor & ) > ( & vllm_ascend : : device_print ) ) ;
ops . def ( " get_npu_storage_shape(Tensor tensor) -> int[] " ) ;
ops . impl ( " get_npu_storage_shape " , c10 : : DispatchKey : : CompositeExplicitAutograd ,
& vllm_ascend : : get_npu_storage_shape ) ;
ops . def (
" grouped_matmul_swiglu_quant(Tensor x, Tensor weight, Tensor weight_scale, Tensor x_scale, "
" Tensor group_list, *, Tensor? bias=None, "
" Tensor? offset=None, float swiglu_limit=0.0) -> "
" (Tensor output, Tensor output_scale, Tensor output_offset) " ) ;
ops . impl ( " grouped_matmul_swiglu_quant " , torch : : kPrivateUse1 , & vllm_ascend : : grouped_matmul_swiglu_quant ) ;
ops . def (
" grouped_matmul_swiglu_quant_weight_nz(Tensor x, Tensor weight, Tensor weight_scale, Tensor x_scale, "
" Tensor group_list, *, Tensor? bias=None, "
" Tensor? offset=None, float swiglu_limit=0.0) -> "
" (Tensor output, Tensor output_scale, Tensor output_offset) " ) ;
ops . impl ( " grouped_matmul_swiglu_quant_weight_nz " , torch : : kPrivateUse1 , & vllm_ascend : : grouped_matmul_swiglu_quant_weight_nz ) ;
ops . def (
" dispatch_gmm_combine_decode(Tensor x, Tensor expert_ids, Tensor[] gmm1_permuted_weight, "
" Tensor[] gmm1_permuted_weight_scale, "
" Tensor[] gmm2_weight, Tensor[] gmm2_weight_scale, "
" Tensor expert_scales, Tensor? expert_smooth_scales=None, "
" Tensor? x_active_mask=None, "
" str group_ep='', "
" int ep_rank_size=0, int ep_rank_id=0, int moe_expert_num=0, "
" int shared_expert_num=1, int shared_expert_rank_num=0, "
" int quant_mode=0, "
" int global_bs=0) -> (Tensor output, Tensor expert_token_nums) "
) ;
ops . impl ( " dispatch_gmm_combine_decode " , torch : : kPrivateUse1 , & vllm_ascend : : dispatch_gmm_combine_decode ) ;
ops . def (
" grouped_matmul_swiglu_quant_weight_nz_tensor_list(Tensor x, Tensor[] weight, Tensor[] weight_scale, Tensor x_scale, "
" Tensor group_list, *, "
" Tensor? bias=None, Tensor? offset=None, float swiglu_limit=0.0) -> "
" (Tensor output, Tensor output_scale, Tensor output_offset) "
) ;
ops . impl ( " grouped_matmul_swiglu_quant_weight_nz_tensor_list " , torch : : kPrivateUse1 , & vllm_ascend : : grouped_matmul_swiglu_quant_weight_nz_tensor_list ) ;
ops . def (
" grouped_matmul_swiglu_quant_v2(Tensor x, Tensor[] weight, Tensor[] weight_scale, Tensor x_scale, Tensor group_list, Tensor? smooth_scale=None, "
" Tensor[]? weight_assist_matrix=None, Tensor? bias=None, int? dequant_mode=0, int? dequant_dtype=0, int? quant_mode=0, "
" int? quant_dtype=0, bool transpose_weight=False, int group_list_type=0, int[2] tuning_config=[],float swiglu_limit=0.0) -> "
" (Tensor output, Tensor output_scale) "
) ;
ops . impl ( " grouped_matmul_swiglu_quant_v2 " , torch : : kPrivateUse1 , & vllm_ascend : : grouped_matmul_swiglu_quant_v2 ) ;
ops . def (
" npu_lightning_indexer( "
" Tensor query, Tensor key, Tensor weights, "
" *, "
" Tensor? actual_seq_lengths_query=None, "
" Tensor? actual_seq_lengths_key=None, "
" Tensor? block_table=None, "
" str layout_query= \" BSND \" , str layout_key= \" BSND \" , "
" int sparse_count=2048, int sparse_mode=3, "
" int pre_tokens=9223372036854775807, "
" int next_tokens=9223372036854775807, "
" bool return_value=False "
" ) -> (Tensor sparse_indices, Tensor sparse_values) "
) ;
ops . impl ( " npu_lightning_indexer " , torch : : kPrivateUse1 , & vllm_ascend : : npu_lightning_indexer ) ;
ops . def (
" npu_sparse_flash_attention(Tensor query, Tensor key, Tensor value, "
" Tensor sparse_indices, float scale_value, *, "
" Tensor? block_table=None, Tensor? actual_seq_lengths_query=None, "
" Tensor? actual_seq_lengths_kv=None, Tensor? query_rope=None, "
" Tensor? key_rope=None, int sparse_block_size=1, "
" str layout_query='BSND', str layout_kv='BSND', "
" int sparse_mode=3, int pre_tokens=9223372036854775807, "
" int next_tokens=9223372036854775807, int attention_mode=2, "
" bool return_softmax_lse=False) -> (Tensor attention_out, Tensor softmax_max, Tensor softmax_sum) "
) ;
ops . impl ( " npu_sparse_flash_attention " , torch : : kPrivateUse1 , & vllm_ascend : : npu_sparse_flash_attention ) ;
ops . def (
" npu_kv_quant_sparse_flash_attention(Tensor query, Tensor key, Tensor value, "
" Tensor sparse_indices, float scale_value, *, "
" int key_quant_mode=1, int value_quant_mode=1, "
" Tensor? key_dequant_scale=None, "
" Tensor? value_dequant_scale=None, "
" Tensor? block_table=None, "
" Tensor? actual_seq_lengths_query=None, "
" Tensor? actual_seq_lengths_kv=None, "
" int sparse_block_size=1, "
" str layout_query='BSND', str layout_kv='BSND', "
" int sparse_mode=3, "
" int pre_tokens=9223372036854775807, "
" int next_tokens=9223372036854775807, "
" int attention_mode=2, "
" int quant_scale_repo_mode=1, "
" int tile_size=128, "
" int rope_head_dim=64, "
" bool return_softmax_lse=False) "
" -> (Tensor attention_out, Tensor softmax_max, Tensor softmax_sum) "
) ;
ops . impl ( " npu_kv_quant_sparse_flash_attention " , torch : : kPrivateUse1 ,
& vllm_ascend : : npu_kv_quant_sparse_flash_attention ) ;
ops . def (
" dispatch_ffn_combine(Tensor x, Tensor[] weight1, Tensor[] weight2, Tensor expert_idx, "
" Tensor[] scale1, Tensor[] scale2, Tensor[] bias1, Tensor[] bias2, Tensor probs, str group, "
" int max_output_size, Tensor! out, Tensor! expert_token_nums, Tensor? x_active_mask=None, float swiglu_limit=1000000.0) -> (Tensor out, Tensor expert_token_nums) "
) ;
ops . impl ( " dispatch_ffn_combine " , torch : : kPrivateUse1 , & vllm_ascend : : dispatch_ffn_combine ) ;
ops . def ( " matmul_allreduce_add_rmsnorm(Tensor x1, Tensor x2, Tensor residual, Tensor gamma, \
str groupTp , int tpRankSize , int tpRankId , float epsilon , bool isTransB , bool isGatherAddOut ) - > ( Tensor output , Tensor add_out ) " );
ops . impl ( " matmul_allreduce_add_rmsnorm " , torch : : kPrivateUse1 , & vllm_ascend : : matmul_allreduce_add_rmsnorm ) ;
ops . def (
" npu_moe_init_routing_custom(Tensor x, Tensor expert_idx, *, Tensor? scale=None, Tensor? offset=None, int active_num=-1, "
" int expert_capacity=-1, int expert_num=-1, int drop_pad_mode=0, int expert_tokens_num_type=0, "
" bool expert_tokens_num_flag=False, int quant_mode=0, int[2] active_expert_range=[], "
" int row_idx_type=0) -> (Tensor, Tensor, Tensor, Tensor) "
) ;
ops . impl ( " npu_moe_init_routing_custom " , torch : : kPrivateUse1 , & vllm_ascend : : npu_moe_init_routing_custom ) ;
// vLLM-Ascend custom ops
ops . def (
" moe_gating_top_k(Tensor x, "
" int k, "
" int k_group, "
" int group_count, "
" int group_select_mode, "
" int renorm, "
" int norm_type, "
" bool out_flag, "
" float routed_scaling_factor, "
" float eps, "
" Tensor? bias_opt=None) "
" -> (Tensor y ,Tensor expert_idx, Tensor out) "
) ;
ops . impl ( " moe_gating_top_k " , torch : : kPrivateUse1 , & vllm_ascend : : moe_gating_top_k ) ;
ops . def (
" npu_add_rms_norm_bias(Tensor x1, "
" Tensor x2, "
" Tensor gamma, "
" Tensor? beta=None, "
" float epsilon=1e-6) "
" -> (Tensor y ,Tensor rstd, Tensor x) "
) ;
ops . impl ( " npu_add_rms_norm_bias " , torch : : kPrivateUse1 , & vllm_ascend : : npu_add_rms_norm_bias ) ;
ops . def (
" npu_hamming_dist_top_k(Tensor q, Tensor k_comp, Tensor k_comp_rope, Tensor k, "
" Tensor seq_len, Tensor? chunk_size=None, "
" int? max_seq_len=None, int? sink=None, int? recent=None, int? support_offload=None, "
" Tensor? key_block_table=None, Tensor? mask=None, Tensor? indices=None) -> Tensor "
) ;
ops . impl ( " npu_hamming_dist_top_k " , torch : : kPrivateUse1 , & vllm_ascend : : npu_hamming_dist_top_k ) ;
ops . def (
" npu_reshape_and_cache_bnsd(Tensor q, Tensor k_comp, Tensor slot_mapping, Tensor seq_len, Tensor k_out) -> Tensor "
) ;
ops . impl ( " npu_reshape_and_cache_bnsd " , torch : : kPrivateUse1 , & vllm_ascend : : npu_reshape_and_cache_bnsd ) ;
ops . def ( " npu_sign_bits_pack(Tensor input, int size) -> Tensor " ) ;
ops . impl ( " npu_sign_bits_pack " , torch : : kPrivateUse1 , & vllm_ascend : : npu_sign_bits_pack ) ;
ops . def (
" transpose_kv_cache_by_block(Tensor[] kCache, Tensor[] vCache, Tensor blockIDs, int blockSize, int headNum, int headDim, int splitNum, int layerNum) -> () "
) ;
ops . impl ( " transpose_kv_cache_by_block " , torch : : kPrivateUse1 , & vllm_ascend : : transpose_kv_cache_by_block ) ;
ops . def (
" npu_copy_and_expand_eagle_inputs(Tensor target_token_ids, Tensor target_positions, "
" Tensor next_token_ids, Tensor query_start_loc, Tensor query_end_loc, "
" int padding_token_id, int parallel_drafting_token_id, int num_padding_slots_per_request, "
" bool shift_input_ids, int total_draft_tokens) -> "
" (Tensor out_input_ids, Tensor out_positions, Tensor out_is_rejected_token_mask, "
" Tensor out_is_masked_token_mask, Tensor out_new_token_indices, Tensor out_hidden_state_mapping) "
) ;
ops . impl ( " npu_copy_and_expand_eagle_inputs " , torch : : kPrivateUse1 , & vllm_ascend : : npu_copy_and_expand_eagle_inputs ) ;
ops . def (
" npu_causal_conv1d_custom(Tensor output, Tensor x, "
" Tensor weight, "
" Tensor conv_state, "
" Tensor? bias_opt, "
" Tensor? query_start_loc_opt, "
" Tensor? cache_indices_opt, "
" Tensor? initial_state_mode_opt, "
" Tensor? num_accepted_tokens_opt, "
" int activation_mode, "
" int pad_slot_id, "
" int run_mode "
" ) -> (Tensor output) " ) ;
ops . impl ( " npu_causal_conv1d_custom " , torch : : kPrivateUse1 , & vllm_ascend : : npu_causal_conv1d_custom ) ;
ops . def (
" moe_grouped_matmul( "
" Tensor x, "
" Tensor weight, "
" Tensor group_list, "
" int split_item, "
" int group_type, "
" int group_list_type) "
" -> Tensor[] "
) ;
ops . impl ( " moe_grouped_matmul " , torch : : kPrivateUse1 , & vllm_ascend : : moe_grouped_matmul ) ;
ops . def (
" moe_gating_top_k_hash( "
" Tensor x, "
" int k, "
" Tensor? bias=None, "
" Tensor? input_ids=None, "
" Tensor? tid2eid=None, "
" int k_group=1, "
" int group_count=1, "
" float routed_scaling_factor=1.0, "
" float eps=1e-20, "
" int group_select_mode=0, "
" int renorm=0, "
" int norm_type=0, "
" bool out_flag=False "
" ) -> (Tensor y, Tensor expert_idx, Tensor out) "
) ;
ops . impl ( " moe_gating_top_k_hash " , torch : : kPrivateUse1 , & vllm_ascend : : moe_gating_top_k_hash ) ;
ops . def (
" compressor( "
" Tensor x, Tensor wkv, Tensor wgate, "
" Tensor(a!) state_cache, Tensor ape, Tensor norm_weight, "
" Tensor rope_sin, Tensor rope_cos, "
" Tensor? state_block_table, Tensor? cu_seqlens, "
" Tensor? seqused, Tensor? start_pos, "
" int rope_head_dim, int cmp_ratio, int coff, "
" float norm_eps, int rotary_mode, int cache_mode "
" ) -> Tensor "
) ;
ops . impl ( " compressor " , torch : : kPrivateUse1 , & vllm_ascend : : compressor ) ;
ops . def (
" compressor_metadata( "
" Tensor rope_cos, Tensor rope_sin, "
" Tensor cu_seqlens, Tensor start_pos, Tensor kv_block_table, "
" int kv_block_size, int slot_mapping_format, int compress_ratio, int num_compressed_tokens, "
" int num_reqs_actual "
" ) -> (Tensor, Tensor, Tensor) "
) ;
ops . impl ( " compressor_metadata " , torch : : kPrivateUse1 , & vllm_ascend : : compressor_metadata ) ;
ops . def (
" compressor_metadata_out( "
" Tensor rope_cos, Tensor rope_sin, "
" Tensor cu_seqlens, Tensor start_pos, Tensor kv_block_table, "
" int kv_block_size, int slot_mapping_format, int compress_ratio, int num_reqs_actual, "
" Tensor(a!) compress_cos, Tensor(b!) compress_sin, Tensor(c!) slot_mapping "
" ) -> (Tensor(a!), Tensor(b!), Tensor(c!)) "
) ;
ops . impl ( " compressor_metadata_out " , torch : : kPrivateUse1 , & vllm_ascend : : compressor_metadata_out ) ;
ops . def (
" npu_vllm_quant_lightning_indexer( "
" Tensor query, Tensor key, Tensor weights, "
" Tensor query_dequant_scale, Tensor key_dequant_scale, "
" int query_quant_mode=0, int key_quant_mode=0, "
" Tensor? actual_seq_lengths_query=None, "
" Tensor? actual_seq_lengths_key=None, "
" Tensor? block_table=None, "
" Tensor? metadata=None, "
" str layout_query= \" BSND \" , str layout_key= \" BSND \" , "
" int sparse_count=2048, int sparse_mode=3, "
" int pre_tokens=9223372036854775807, "
" int next_tokens=9223372036854775807, "
" int cmp_ratio=1, bool return_value=False "
" ) -> (Tensor sparse_indices, Tensor sparse_values) "
) ;
ops . impl ( " npu_vllm_quant_lightning_indexer " , torch : : kPrivateUse1 , & vllm_ascend : : npu_vllm_quant_lightning_indexer_npu ) ;
ops . def (
" npu_sparse_attn_sharedkv( "
" Tensor q, *, "
" Tensor? ori_kv=None, "
" Tensor? cmp_kv=None, "
" Tensor? ori_sparse_indices=None, "
" Tensor? cmp_sparse_indices=None, "
" Tensor? ori_block_table=None, "
" Tensor? cmp_block_table=None, "
" Tensor? cu_seqlens_q=None, "
" Tensor? cu_seqlens_ori_kv=None, "
" Tensor? cu_seqlens_cmp_kv=None, "
" Tensor? seqused_q=None, "
" Tensor? seqused_kv=None, "
" Tensor? sinks=None, "
" Tensor? metadata=None, "
" float softmax_scale=0, "
" int cmp_ratio=0, "
" int ori_mask_mode=4, "
" int cmp_mask_mode=3, "
" int ori_win_left=128, "
" int ori_win_right=0, "
" str layout_q= \" BSND \" , "
" str layout_kv= \" PA_ND \" , "
" bool return_softmax_lse=False "
" ) -> (Tensor out, Tensor softmax_lse) "
) ;
ops . impl ( " npu_sparse_attn_sharedkv " , torch : : kPrivateUse1 , & vllm_ascend : : npu_sparse_attn_sharedkv_npu ) ;
ops . def (
" npu_sparse_attn_sharedkv_metadata( "
" int num_heads_q, "
" int num_heads_kv, "
" int head_dim, "
" Tensor? cu_seqlens_q=None, "
" Tensor? cu_seqlens_ori_kv=None, "
" Tensor? cu_seqlens_cmp_kv=None, "
" Tensor? seqused_q=None, "
" Tensor? seqused_kv=None, "
" int batch_size=0, "
" int max_seqlen_q=0, "
" int max_seqlen_kv=0, "
" int ori_topk=0, "
" int cmp_topk=0, "
" int cmp_ratio=4, "
" int ori_mask_mode=4, "
" int cmp_mask_mode=3, "
" int ori_win_left=128, "
" int ori_win_right=0, "
" str layout_q= \" BSND \" , "
" str layout_kv= \" PA_ND \" , "
" bool has_ori_kv=True, "
" bool has_cmp_kv=True, "
" str device= \" npu \" "
" ) -> (Tensor metadata) "
) ;
ops . impl ( " npu_sparse_attn_sharedkv_metadata " , torch : : kPrivateUse1 , & vllm_ascend : : npu_sparse_attn_sharedkv_metadata_npu ) ;
ops . def (
" npu_vllm_quant_lightning_indexer_metadata( "
" int num_heads_q, "
" int num_heads_k, "
" int head_dim, "
" int query_quant_mode, "
" int key_quant_mode, "
" Tensor? actual_seq_lengths_query=None, "
" Tensor? actual_seq_lengths_key=None, "
" int batch_size=0, "
" int max_seqlen_q=0, "
" int max_seqlen_k=0, "
" str layout_query= \" BSND \" , "
" str layout_key= \" BSND \" , "
" int sparse_count=2048, "
" int sparse_mode=3, "
" int pre_tokens=9223372036854775807, "
" int next_tokens=9223372036854775807, "
" int cmp_ratio=1, "
" str device= \" npu \" "
" ) -> (Tensor metadata) "
) ;
ops . impl ( " npu_vllm_quant_lightning_indexer_metadata " , torch : : kPrivateUse1 , & vllm_ascend : : npu_vllm_quant_lightning_indexer_metadata_npu ) ;
ops . def (
" npu_hc_post( "
" Tensor x, "
" Tensor residual, "
" Tensor post, "
" Tensor comb "
" ) -> (Tensor out) "
) ;
ops . impl ( " npu_hc_post " , torch : : kPrivateUse1 , & vllm_ascend : : npu_hc_post_npu ) ;
ops . def (
" npu_hc_pre( "
" Tensor x, Tensor hc_fn, Tensor hc_scale, Tensor hc_base, "
" int hc_mult, int hc_sinkhorn_iters, "
" float norm_eps, float hc_eps "
" ) -> (Tensor out0, Tensor out1, Tensor out2) "
) ;
ops . impl ( " npu_hc_pre " , torch : : kPrivateUse1 , & vllm_ascend : : npu_hc_pre_npu ) ;
ops . def (
" npu_hc_pre_v2( "
" Tensor x, Tensor hc_fn, Tensor hc_scale, Tensor hc_base, "
" int hc_mult, int hc_sinkhorn_iters, "
" float norm_eps, float hc_eps "
" ) -> (Tensor out0, Tensor out1, Tensor out2) "
) ;
ops . impl ( " npu_hc_pre_v2 " , torch : : kPrivateUse1 , & vllm_ascend : : npu_hc_pre_v2_npu ) ;
ops . def (
" npu_hc_pre_inv_rms( "
" Tensor x, float epsilon=1e-20 "
" ) -> (Tensor out) "
) ;
ops . impl ( " npu_hc_pre_inv_rms " , torch : : kPrivateUse1 , & vllm_ascend : : npu_hc_pre_inv_rms_npu ) ;
ops . def (
" npu_hc_pre_sinkhorn( "
" Tensor mixes, Tensor rsqrt, Tensor hc_scale, Tensor hc_base, Tensor x, "
" int hc_mult, int hc_sinkhorn_iters, float hc_eps "
" ) -> (Tensor out0, Tensor out1, Tensor out2) "
) ;
ops . impl ( " npu_hc_pre_sinkhorn " , torch : : kPrivateUse1 , & vllm_ascend : : npu_hc_pre_sinkhorn_npu ) ;
ops . def (
" inplace_partial_rotary_mul( "
" Tensor(a!) x, Tensor r1, Tensor r2, str rotary_mode, int[] partial_slice "
" ) -> () "
) ;
ops . impl ( " inplace_partial_rotary_mul " , torch : : kPrivateUse1 , & vllm_ascend : : inplace_partial_rotary_mul_npu ) ;
ops . def (
" npu_rms_norm_dynamic_quant( "
" Tensor x, "
" Tensor gamma, "
" Tensor? smooth_scale=None, "
" Tensor? beta=None, "
" float epsilon=1e-6 "
" ) -> (Tensor y_out, Tensor scale_out) "
) ;
ops . impl ( " npu_rms_norm_dynamic_quant " , torch : : kPrivateUse1 , & vllm_ascend : : npu_rms_norm_dynamic_quant_npu ) ;
ops . def (
" indexer_compress_epilog( "
" Tensor(a!) indexer_compress_cache, "
" Tensor(b!) indexer_compress_cache_scale, "
" Tensor x, "
" Tensor slot_mapping, "
" int quant_mode=1, "
" bool round_scale=True "
" ) -> () "
) ;
ops . impl ( " indexer_compress_epilog " , torch : : kPrivateUse1 , & vllm_ascend : : indexer_compress_epilog_npu ) ;
ops . def (
" kv_compress_epilog( "
" Tensor(a!) kv_compress_cache, "
" Tensor x, "
" Tensor slot_mapping, "
" int quant_group_size, "
" int quant_mode, "
" bool round_scale_flag, "
" int layout "
" ) -> () "
) ;
ops . impl ( " kv_compress_epilog " , torch : : kPrivateUse1 , & vllm_ascend : : kv_compress_epilog_npu ) ;
ops . def (
" npu_kv_quant_sparse_attn_sharedkv( "
" Tensor q, "
" int kv_quant_mode, "
" Tensor? ori_kv=None, "
" Tensor? cmp_kv=None, "
" Tensor? ori_sparse_indices=None, "
" Tensor? cmp_sparse_indices=None, "
" Tensor? ori_block_table=None, "
" Tensor? cmp_block_table=None, "
" Tensor? cu_seqlens_q=None, "
" Tensor? cu_seqlens_ori_kv=None, "
" Tensor? cu_seqlens_cmp_kv=None, "
" Tensor? seqused_q=None, "
" Tensor? seqused_kv=None, "
" Tensor? sinks=None, "
" Tensor? metadata=None, "
" int tile_size=0, "
" int rope_head_dim=0, "
" float softmax_scale=0.0, "
" int cmp_ratio=0, "
" int ori_mask_mode=4, "
" int cmp_mask_mode=3, "
" int ori_win_left=127, "
" int ori_win_right=0, "
" str layout_q='BSND', "
" str layout_kv='PA_ND', "
" bool return_softmax_lse=False "
" ) -> (Tensor out, Tensor softmax_lse) "
) ;
ops . impl ( " npu_kv_quant_sparse_attn_sharedkv " , torch : : kPrivateUse1 ,
& vllm_ascend : : npu_kv_quant_sparse_attn_sharedkv_npu ) ;
ops . def (
" npu_kv_quant_sparse_attn_sharedkv_metadata( "
" int num_heads_q, "
" int num_heads_kv, "
" int head_dim, "
" int kv_quant_mode, "
" Tensor? cu_seqlens_q=None, "
" Tensor? cu_seqlens_ori_kv=None, "
" Tensor? cu_seqlens_cmp_kv=None, "
" Tensor? seqused_q=None, "
" Tensor? seqused_kv=None, "
" int batch_size=0, "
" int max_seqlen_q=0, "
" int max_seqlen_kv=0, "
" int ori_topk=0, "
" int cmp_topk=0, "
" int tile_size=0, "
" int rope_head_dim=0, "
" int cmp_ratio=-1, "
" int ori_mask_mode=4, "
" int cmp_mask_mode=3, "
" int ori_win_left=127, "
" int ori_win_right=0, "
" str layout_q='BSND', "
" str layout_kv='PA_ND', "
" bool has_ori_kv=True, "
" bool has_cmp_kv=True, "
" str device='npu' "
" ) -> Tensor "
) ;
ops . impl ( " npu_kv_quant_sparse_attn_sharedkv_metadata " , torch : : kPrivateUse1 ,
& vllm_ascend : : npu_kv_quant_sparse_attn_sharedkv_metadata_npu ) ;
ops . def (
" npu_swiglu_group_quant(Tensor x, Tensor? topk_weight, Tensor? group_index, "
" ScalarType dst_type=39, "
" int quant_mode=1, int group_size=128, "
" bool round_scale=False, bool ue8m0_scale=False, "
" bool output_origin=False, int group_list_type=0, "
" float clamp_value=0.0) "
" -> (Tensor y, Tensor scale, Tensor y_origin) " ) ;
ops . impl ( " npu_swiglu_group_quant " , torch : : kPrivateUse1 , & vllm_ascend : : npu_swiglu_group_quant_npu ) ;
ops . def (
" npu_load_index_kv_cache( "
" Tensor kv_cache, Tensor slot_mapping "
" ) -> (Tensor out, Tensor out_scale) "
) ;
ops . impl ( " npu_load_index_kv_cache " , torch : : kPrivateUse1 , & vllm_ascend : : npu_load_index_kv_cache_npu ) ;
ops . def (
" indexer_compress_epilog_v2( "
" Tensor(a!) indexer_compress_cache, "
" Tensor x, "
" Tensor slot_mapping, "
" int layout=2 "
" ) -> () "
) ;
ops . impl ( " indexer_compress_epilog_v2 " , torch : : kPrivateUse1 ,
& vllm_ascend : : indexer_compress_epilog_v2_npu ) ;
ops . def (
" npu_dequant_swiglu_quant( "
" Tensor x, *, "
" Tensor? weight_scale=None, "
" Tensor? activation_scale=None, "
" Tensor? bias=None, "
" Tensor? quant_scale=None, "
" Tensor? quant_offset=None, "
" Tensor? group_index=None, "
" bool activate_left=True, "
" int quant_mode=0, "
" int swiglu_mode=0, "
" float clamp_limit=0.0, "
" float glu_alpha=1.0, "
" float glu_bias=0.0 "
" ) -> (Tensor y, Tensor scale) "
) ;
ops . impl ( " npu_dequant_swiglu_quant " , torch : : kPrivateUse1 , & vllm_ascend : : npu_dequant_swiglu_quant ) ;
ops . def (
" npu_scatter_nd_update_v2( "
" Tensor(a!) var, Tensor indices, Tensor update "
" ) -> () "
) ;
ops . impl ( " npu_scatter_nd_update_v2 " , torch : : kPrivateUse1 , & vllm_ascend : : npu_scatter_nd_update_v2 ) ;
// This operator is planned to be integrated into PTA in the near future.
// Once that happens, the implementation in csrc will be removed.
ops . def (
" npu_lightning_indexer_quant(Tensor query, Tensor key, Tensor weights, Tensor query_dequant_scale, "
" Tensor key_dequant_scale, *, Tensor? actual_seq_lengths_query=None, "
" Tensor? actual_seq_lengths_key=None, Tensor? block_table=None, "
" int query_quant_mode=0, int key_quant_mode=0, "
" str layout_query='BSND', str layout_key='BSND', "
" int sparse_count=2048, int sparse_mode=3) -> Tensor "
) ;
ops . impl ( " npu_lightning_indexer_quant " , torch : : kPrivateUse1 , & vllm_ascend : : npu_lightning_indexer_quant ) ;
// N-gram spec decode
ops . def (
" npu_ngram_spec_decode(Tensor(a!) token_ids, Tensor num_tokens_no_spec, "
" Tensor sampled_token_ids, Tensor discard_request_mask, "
" int vocab_size, int min_n, int max_n, int k) -> "
" (Tensor token_ids, Tensor next_token_ids, Tensor draft_token_ids, Tensor num_valid_draft_tokens) "
) ;
ops . impl ( " npu_ngram_spec_decode " , torch : : kPrivateUse1 ,
& vllm_ascend : : npu_ngram_spec_decode ) ;
ops . def (
" chunk_gated_delta_rule_fwd_h(Tensor k, Tensor w, Tensor u, Tensor? g=None, *, Tensor? gk=None, Tensor? initial_state=None, bool? output_final_state=False, int? chunk_size=None, bool? save_new_value=True, int[]? cu_seqlens=None, int[]? chunk_indices=None, bool? use_exp2=False, bool? transpose_state_layout=False) -> (Tensor h_out, Tensor v_new_out, Tensor final_state_out) "
) ;
ops . impl ( " chunk_gated_delta_rule_fwd_h " , torch : : kPrivateUse1 , & vllm_ascend : : chunk_gated_delta_rule_fwd_h ) ;
ops . def (
" chunk_fwd_o(Tensor q, Tensor k, Tensor v, Tensor h, float scale, *, Tensor? g=None, Tensor? g_gamma=None, int[]? cu_seqlens=None, int[]? chunk_indices=None, int? chunk_size=None, bool? transpose_state_layout=False) -> Tensor "
) ;
ops . impl ( " chunk_fwd_o " , torch : : kPrivateUse1 , & vllm_ascend : : chunk_fwd_o ) ;
//store_kv_block
ops . def (
" store_kv_block_metadata(Tensor slot_mapping_npu, Tensor group_len, Tensor group_key_idx, Tensor group_key_cache_idx, int block_size=0) "
" -> () "
) ;
ops . impl ( " store_kv_block_metadata " , torch : : kPrivateUse1 , & vllm_ascend : : store_kv_block_metadata ) ;
ops . def (
" store_kv_block(Tensor key_in, Tensor key_cache_in, Tensor group_len, Tensor group_key_idx,Tensor group_key_cache_idx, int block_size=0) -> () "
) ;
ops . impl ( " store_kv_block " , torch : : kPrivateUse1 , & vllm_ascend : : store_kv_block ) ;
// Fused GDN gating.
ops . def (
" npu_fused_gdn_gating(Tensor A_log, "
" Tensor a, "
" Tensor b, "
" Tensor dt_bias, "
" float beta=1.0, "
" float threshold=20.0) -> (Tensor g, Tensor beta_output) " ) ;
ops . impl ( " npu_fused_gdn_gating " , torch : : kPrivateUse1 , & vllm_ascend : : npu_fused_gdn_gating ) ;
2025-09-09 09:40:35 +08:00
}
2026-08-27 15:11:51 +08:00
# endif