news 2026/5/9 13:46:23

CANN/ops-transformer块稀疏注意力梯度算子

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CANN/ops-transformer块稀疏注意力梯度算子

aclnnBlockSparseAttentionGrad

【免费下载链接】ops-transformer本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-transformer

产品支持情况

产品是否支持
Ascend 950PR/Ascend 950DT×
Atlas A3 训练系列产品
Atlas A3 推理系列产品×
Atlas A2 训练系列产品
Atlas A2 推理系列产品×
Atlas 200I/500 A2 推理产品×
Atlas 推理系列产品×
Atlas 训练系列产品×

功能说明

  • ​接口功能​:aclnnBlockSparseAttention稀疏注意力反向计算,支持灵活的块级稀疏模式,通过BlockSparseMask指定每个Q块选择的KV块,实现高效的稀疏注意力计算。

  • ​计算公式​: 稀疏块大小:$blockShapeX×blockShapeY$,BlockSparseMask指定稀疏模式。

    已知正向计算公式为:

    $$ attentionOut=Softmax(Mask(scale⋅query⋅key_{sparse}^{T}, atten_mask))⋅value_{sparse} $$

    为方便表达,以变量$S$和$P$表示计算公式:

    $$ S = Mask(scale⋅query⋅key_{sparse}^{T},atten_mask) $$

    $$ P = SoftMax(S) $$

    $$ V = value_{sparse} $$

    $$ Out = PV $$

    则反向计算公式为:

    $$ softmax_grad = softmaxGrad(dOut, attentionOut) $$

    $$ dP=dOut * V^T $$

    $$ dS = P * (dP-softmax_grad) $$

    $$ dV=P^T * dOut $$

    $$ dQ=(dS*K)*scale $$

    $$ dK=(dS^T*Q)*scale $$

BlockSparseAttentionGrad输入dout、 query、key、value, attentionOut的数据排布格式支持从多种维度排布解读,可通过qInputLayout和kvInputLayout传入。为了方便理解后续支持的具体排布格式(如 BNSD、TND 等),此处先对排布格式中各缩写字母所代表的维度含义进行统一说明:

  • B:表示输入样本批量大小(Batch)
  • T:B和S合轴紧密排列的长度(Total tokens)
  • S:表示输入样本序列长度(Seq-Length)
  • H:表示隐藏层的大小(Head-Size)
  • N:表示多头数(Head-Num)
  • D:表示隐藏层最小的单元尺寸,需满足D=H/N(Head-Dim)

当前支持的布局:

  • qInputLayout: "TND" "BNSD"
  • kvInputLayout: "TND" "BNSD"

函数原型

每个算子分为两段式接口,必须先调用"aclnnBlockSparseAttentionGradGetWorkspaceSize"接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用"aclnnBlockSparseAttentionGrad"接口执行计算。

aclnnStatus aclnnBlockSparseAttentionGradGetWorkspaceSize( const aclTensor *dout, const aclTensor *query, const aclTensor *key, const aclTensor *value, const aclTensor *attentionOut, const aclTensor *softmaxLse, const aclTensor *blockSparseMaskOptional, const aclTensor *attenMaskOptional, const aclIntArray *blockShapeOptional, const aclIntArray *actualSeqLengthsOptional, const aclIntArray *actualSeqLengthsKvOptional, char *qInputLayout, char *kvInputLayout, int64_t numKeyValueHeads, int64_t maskType, double scaleValue, int64_t preTokens, int64_t nextTokens, aclTensor *dq, aclTensor *dk, aclTensor *dv, uint64_t *workspaceSize, aclOpExecutor **executor)
aclnnStatus aclnnBlockSparseAttentionGrad( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, const aclrtStream stream)

aclnnBlockSparseAttentionGradGetWorkspaceSize

  • 参数说明:

    参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续Tensor
    dout(aclTensor*)输入反向输出梯度,代表最终输出对当前算子的梯度信息。不支持空Tensor。
    支持的shape为:
    • TND: [totalQTokens, headNum, headDim]。
    • BNSD: [batch, headNum, maxQSeqLength, headDim]。
    FLOAT16、BFLOAT16ND3-4×
    query(aclTensor*)输入注意力计算中的查询向量,即公式中的query。不支持空Tensor。
    支持的shape为:
    • TND: [totalQTokens, headNum, headDim]。
    • BNSD: [batch, headNum, maxQSeqLength, headDim]。
    FLOAT16、BFLOAT16ND3-4×
    key(aclTensor*)输入注意力计算中的键向量,即公式中的key。不支持空Tensor。
    支持的shape为:
    • TND: [totalKTokens, numKeyValueHeads, headDim]。
    • BNSD: [batch, numKeyValueHeads, maxKvSeqLength, headDim]。
    FLOAT16、BFLOAT16ND3-4×
    value(aclTensor*)输入注意力计算中的值向量,即公式中的value。不支持空Tensor。
    支持的shape为:
    • TND: [totalVTokens, numKeyValueHeads, headDim]。
    • BNSD: [batch, numKeyValueHeads, maxKvSeqLength, headDim]。
    FLOAT16、BFLOAT16ND3-4×
    attentionOut(aclTensor*)输入正向 BlockSparseAttention 计算的输出结果,即公式中的attentionOut。不支持空Tensor。
    支持的shape为:
    • TND: [totalQTokens, headNum, headDim]。
    • BNSD: [batch, headNum, maxQSeqLength, headDim]。
    FLOAT16、BFLOAT16ND3-4×
    softmaxLse(aclTensor*)输入Softmax计算的log-sum-exp中间结果。用于反向计算梯度的对数和指数逆推。不支持空Tensor。
    支持的shape为:
    • TND: [totalQTokens, headNum, 1]。
    • BNSD: [batch, headNum, maxQSeqLength, 1]。
    FLOATND3-4×
    blockSparseMaskOptional(aclTensor*)输入块状稀疏掩码,表示实际的稀疏pattern。决定哪些block实际参与注意力计算。不支持空Tensor。
    可选输入(当前版本为必选):
    • shape为[batch, headNum, ceilDiv(maxQSeqLength, blockShapeX), ceilDiv(maxKvSeqLength, blockShapeY)]。
    • 表示按block划分后哪些block需要参与计算(为1),哪些block不参与计算(为0)。
    • 如传入nullptr,则视为不开启块稀疏计算,即所有token之间的注意力分数都会被计算。
    BOOLND4×
    attenMaskOptional(aclTensor*)输入注意力掩码,即公式中的atten_mask。用于屏蔽不应参与计算的特定token。支持空Tensor。
    当前不支持,应传入nullptr。
    BOOLND2×
    blockShapeOptional(aclIntArray*)输入稀疏块形状数组。指定每个稀疏块的二维尺寸(行数和列数)。
    • 当配置了blockSparseMaskOptional时:如配置此输入,算子会从中获取稀疏块尺寸;如不配置此输入,算子将默认稀疏块尺寸为[128,128]。
    INT64-1-
    • 当未配置blockSparseMaskOptional时:无论此项如何配置,算子均将忽略。
    当配置此输入时的元素要求:
    • 必须包含至少两个元素 [blockShapeX, blockShapeY]。
    • blockShapeX: Q方向块大小,值必须大于0。
    • blockShapeY: KV方向块大小,值必须大于0。
    actualSeqLengthsOptional(aclIntArray*)输入query的实际序列长度数组。
    用于描述变长序列场景下(即含有 Padding 填充数据的场景),每个 Batch 中实际有效的 query token 数量。
    变长序列场景(当 qInputLayout 为 "TND" 时):该项输入必须配置。因为 TND 格式为一维连续排布,算子需要依赖该数组来准确切分界定各个序列的真实边界。INT64-1-
    定长/变长场景(当 qInputLayout 为 "BNSD" 时):
    • 如配置该项,算子会按指定的有效长度处理,忽略 Padding 部分的数据,提升性能;
    • 如不配置(传 nullptr),算子将默认把 query shape 中的 S 维度作为有效长度进行全量处理。
    actualSeqLengthsKvOptional(aclIntArray*)输入key/value的实际序列长度数组。
    用于描述变长序列场景下(即含有 Padding 填充数据的场景),每个 Batch 中实际有效的 key/value token 数量。
    变长序列场景(当 kvInputLayout 为 "TND" 时):该项输入必须配置。因为 TND 格式为一维连续排布,算子需要依赖该数组来准确切分界定各个序列的真实边界。INT64-1-
    定长/变长场景(当 kvInputLayout 为 "BNSD" 时):
    • 如配置该项,算子会按指定的有效长度处理,忽略 Padding 部分的数据,提升性能;
    • 如不配置(传 nullptr),算子将默认把 key/value shape 中的 S 维度作为有效长度进行全量处理。
    qInputLayout(char*)输入query的数据排布格式。指示输入张量在内存中的具体排布(如连续或合轴排列)。当前仅支持"TND"、"BNSD",qInputLayout与kvInputLayout需要保持一致。----
    kvInputLayout(char*)输入key和value的数据排布格式。指示输入张量在内存中的具体排布。当前仅支持"TND"、"BNSD",qInputLayout与kvInputLayout需要保持一致。----
    numKeyValueHeads(int64_t)输入key/value的注意力头数。用于支持GQA(分组查询注意力)机制下的头数比例映射。-----
    maskType(int64_t)输入注意力计算中的掩码类型。指定采用何种预设规则的掩码逻辑。当前只支持传 0:代表不加mask场景。----
    scaleValue(double)输入缩放系数,即公式中的scale。用于注意力分数的归一化处理。一般设置为D^-0.5。----
    preTokens(int64_t)输入滑窗向前包含的token数量。限制当前token只能与前方的多少个历史token计算注意力。用于滑窗attention场景,当前不支持滑窗attention,只支持传入2147483647。----
    nextTokens(int64_t)输入滑窗向后包含的token数量。限制当前token只能与后方的多少个未来token计算注意力。用于滑窗attention场景,当前不支持滑窗attention,只支持传入2147483647。----
    dq(aclTensor*)输出query的梯度输出结果,即公式中的dq。不支持空Tensor。
    数据类型和shape与输入query保持一致。
    FLOAT16、BFLOAT16ND3-4
    dk(aclTensor*)输出key的梯度输出结果,即公式中的dk。不支持空Tensor。
    数据类型和shape与输入key保持一致。
    FLOAT16、BFLOAT16ND3-4
    dv(aclTensor*)输出value的梯度输出结果,即公式中的dv。不支持空Tensor。
    数据类型和shape与输入value保持一致。
    FLOAT16、BFLOAT16ND3-4
    workspaceSize(uint64_t*)输出返回需要在Device侧申请的workspace大小。-----
    executor(aclOpExecutor**)输出返回op执行器,包含了算子计算流程。-----
  • 返回值

    aclnnStatus:返回状态码,具体参见aclnn返回码。

    第一段接口完成入参校验,出现以下场景时报错:

    返回码错误码描述
    ACLNN_ERR_PARAM_NULLPTR161001输入dout,query,key,value,attentionOut传入的是空指针。
    qInputLayout为"TND"时,actualSeqLengthsOptional传入的是空指针。
    kvInputLayout为"TND"时,actualSeqLengthsKvOptional传入的是空指针。
    ACLNN_ERR_PARAM_INVALID161002dout,query,key,value 数据类型不在支持的范围之内。
    qInputLayout或kvInputLayout输入不合法,参数有效性校验失败。

aclnnBlockSparseAttentionGrad

  • 参数说明:

    参数名输入/输出描述
    workspace输入在Device侧申请的workspace内存地址。
    workspaceSize输入在Device侧申请的workspace大小,由第一段接口aclnnBlockSparseAttentionGradGetWorkspaceSize获取。
    executor输入op执行器,包含了算子计算流程。
    stream输入指定执行任务的AscendCL stream流。
  • 返回值:

    aclnnStatus:返回状态码,具体参见aclnn返回码。

约束说明

  • 该接口与PyTorch配合使用时,需要保证CANN相关包与PyTorch相关包的版本匹配。
  • actualSeqLengthsOptional在qInputLayout为“TND”时必选;actualSeqLengthsKvOptional在kvInputLayout为“TND”时必选。
  • 根据算子支持的输入 Layout,query 张量 Shape 中对应的 head 维度大小记为 N1,key 和 value 张量 Shape 中对应的 head 维度大小记为 N2。必须满足 N1 >= N2 且 N1 % N2 == 0。(例如:在 BNSD 布局下,N1 对应 query 的第 2 维,N2 对应 key/value 的第 2 维)
  • headdim=128。
  • 当前只支持 BNSD 和 MHA(N1==N2)。

调用示例

示例代码如下,仅供参考,具体编译和执行过程请参考编译与运行样例。

#include <iostream> #include <vector> #include <cstring> #include <cmath> #include <cstdint> #include "acl/acl.h" #include "aclnn/opdev/fp16_t.h" #include "../op_host/op_api/aclnn_block_sparse_attention_grad.h" using namespace std; #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define LOG_PRINT(message, ...) \ do { \ printf(message, ##__VA_ARGS__); \ } while (0) int64_t GetShapeSize(const std::vector<int64_t>& shape) { int64_t shapeSize = 1; for (auto i : shape) { shapeSize *= i; } return shapeSize; } int Init(int32_t deviceId, aclrtStream* stream) { // 固定写法,AscendCL初始化 auto ret = aclInit(nullptr); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); ret = aclrtSetDevice(deviceId); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); ret = aclrtCreateStream(stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); return 0; } template <typename T> int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, aclTensor** tensor) { // 检查shape是否有效 if (shape.empty()) { LOG_PRINT("CreateAclTensor: ERROR - shape is empty\n"); return -1; } for (size_t i = 0; i < shape.size(); ++i) { if (shape[i] <= 0) { LOG_PRINT("CreateAclTensor: ERROR - shape[%zu]=%ld is invalid\n", i, shape[i]); return -1; } } auto size = GetShapeSize(shape) * sizeof(T); // 检查hostData大小是否匹配 if (hostData.size() != static_cast<size_t>(GetShapeSize(shape))) { LOG_PRINT("CreateAclTensor: ERROR - hostData size mismatch: %zu vs %ld\n", hostData.size(), GetShapeSize(shape)); return -1; } // 调用aclrtMalloc申请device侧内存 *deviceAddr = nullptr; auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); aclrtFree(*deviceAddr); *deviceAddr = nullptr; return ret); // 计算连续tensor的strides std::vector<int64_t> strides(shape.size(), 1); if (shape.size() > 1) { for (int64_t i = static_cast<int64_t>(shape.size()) - 2; i >= 0; i--) { strides[i] = shape[i + 1] * strides[i + 1]; } } // 调用aclCreateTensor接口创建aclTensor *tensor = nullptr; *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); CHECK_RET(*tensor != nullptr, LOG_PRINT("aclCreateTensor failed - returned nullptr\n"); aclrtFree(*deviceAddr); *deviceAddr = nullptr; return -1); return 0; } int main() { // 1. device/stream初始化 int32_t deviceId = 0; aclrtStream stream; auto ret = Init(deviceId, &stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); // 2. 设置核心参数 (以 BNSD Layout 为例) int32_t batch = 1; int32_t numHeads = 1; int32_t numKvHeads = 1; int32_t qSeqlen = 128; int32_t kvSeqlen = 128; int32_t headDim = 128; int32_t blockShapeX = 64; int32_t blockShapeY = 64; // 块数量计算 int32_t ceilQ = (qSeqlen + blockShapeX - 1) / blockShapeX; int32_t ceilKv = (kvSeqlen + blockShapeY - 1) / blockShapeY; // 3. 构建张量 Shape std::vector<int64_t> qShape = {batch, numHeads, qSeqlen, headDim}; std::vector<int64_t> kvShape = {batch, numKvHeads, kvSeqlen, headDim}; std::vector<int64_t> lseShape = {batch, numHeads, qSeqlen}; // LSE 通常没有尾部 1 维,防止 GE squeeze std::vector<int64_t> maskShape = {batch, numHeads, ceilQ, ceilKv}; // 4. 分配并初始化 Host 数据 int64_t qSize = GetShapeSize(qShape); int64_t kvSize = GetShapeSize(kvShape); // 将 Q, K, V 初始化为 0.1f 等较小的数 std::vector<op::fp16_t> qData(qSize, 0.1f); std::vector<op::fp16_t> kData(kvSize, 0.1f); std::vector<op::fp16_t> vData(kvSize, 0.1f); // 梯度初始值可以给一个小正数 std::vector<op::fp16_t> doutData(qSize, 0.01f); std::vector<op::fp16_t> outData(qSize, 0.1f); // LSE 给一个合理的正数,比如 5.0f,这样 exp(S - LSE) 就是一个非常安全的负指数,绝对不会溢出 std::vector<float> lseData(GetShapeSize(lseShape), 5.0f); std::vector<uint8_t> maskData(GetShapeSize(maskShape), 1); // 创建所有的前向输入/输出 aclTensor void *qAddr = nullptr, *kAddr = nullptr, *vAddr = nullptr; void *doutAddr = nullptr, *outAddr = nullptr; void *lseAddr = nullptr, *maskAddr = nullptr; aclTensor *qTensor = nullptr, *kTensor = nullptr, *vTensor = nullptr; aclTensor *doutTensor = nullptr, *outTensor = nullptr; aclTensor *lseTensor = nullptr, *maskTensor = nullptr; CreateAclTensor(qData, qShape, &qAddr, aclDataType::ACL_FLOAT16, &qTensor); CreateAclTensor(kData, kvShape, &kAddr, aclDataType::ACL_FLOAT16, &kTensor); CreateAclTensor(vData, kvShape, &vAddr, aclDataType::ACL_FLOAT16, &vTensor); CreateAclTensor(doutData, qShape, &doutAddr, aclDataType::ACL_FLOAT16, &doutTensor); CreateAclTensor(outData, qShape, &outAddr, aclDataType::ACL_FLOAT16, &outTensor); CreateAclTensor(lseData, lseShape, &lseAddr, aclDataType::ACL_FLOAT, &lseTensor); // 严格使用 FP32 CreateAclTensor(maskData, maskShape, &maskAddr, aclDataType::ACL_UINT8, &maskTensor); // 严格使用 UINT8 // 5. 创建反向输出梯度 (dq, dk, dv) std::vector<op::fp16_t> dqData(qSize, 0.0f); std::vector<op::fp16_t> dkData(kvSize, 0.0f); std::vector<op::fp16_t> dvData(kvSize, 0.0f); void *dqAddr = nullptr, *dkAddr = nullptr, *dvAddr = nullptr; aclTensor *dqTensor = nullptr, *dkTensor = nullptr, *dvTensor = nullptr; CreateAclTensor(dqData, qShape, &dqAddr, aclDataType::ACL_FLOAT16, &dqTensor); CreateAclTensor(dkData, kvShape, &dkAddr, aclDataType::ACL_FLOAT16, &dkTensor); CreateAclTensor(dvData, kvShape, &dvAddr, aclDataType::ACL_FLOAT16, &dvTensor); // 6. 创建 aclIntArray 属性参数 (BlockShape & ActualSeqLengths) std::vector<int64_t> blockShapeVec = {blockShapeX, blockShapeY}; aclIntArray *blockShapeArr = aclCreateIntArray(blockShapeVec.data(), blockShapeVec.size()); std::vector<int64_t> qSeqLenVec(batch, static_cast<int64_t>(qSeqlen)); std::vector<int64_t> kvSeqLenVec(batch, static_cast<int64_t>(kvSeqlen)); aclIntArray *qSeqLenArr = aclCreateIntArray(qSeqLenVec.data(), batch); aclIntArray *kvSeqLenArr = aclCreateIntArray(kvSeqLenVec.data(), batch); // 7. 标量与字符串参数配置 char qLayoutBuffer[16] = "BNSD"; char kvLayoutBuffer[16] = "BNSD"; int64_t maskType = 0; double scaleValue = 1.0 / std::sqrt(static_cast<double>(headDim)); // 强制规定滑动窗口极大值 int64_t preTokens = 2147483647; int64_t nextTokens = 2147483647; // 8. 调用第一段接口: GetWorkspaceSize uint64_t workspaceSize = 0; aclOpExecutor* executor = nullptr; LOG_PRINT("Calling aclnnBlockSparseAttentionGradGetWorkspaceSize...\n"); ret = aclnnBlockSparseAttentionGradGetWorkspaceSize( doutTensor, qTensor, kTensor, vTensor, outTensor, lseTensor, maskTensor, // blockSparseMaskOptional nullptr, // attenMaskOptional 必须为空 blockShapeArr, qSeqLenArr, kvSeqLenArr, qLayoutBuffer, kvLayoutBuffer, static_cast<int64_t>(numKvHeads), maskType, scaleValue, preTokens, nextTokens, dqTensor, dkTensor, dvTensor, &workspaceSize, &executor ); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("GetWorkspaceSize failed. ERROR: %d\n", ret); return ret); CHECK_RET(executor != nullptr, LOG_PRINT("executor is null after GetWorkspaceSize\n"); return -1); LOG_PRINT("Workspace size required: %lu bytes\n", workspaceSize); // 9. 分配 workspace void* workspaceAddr = nullptr; if (workspaceSize > 0) { ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); } // 10. 调用第二段接口: 执行计算 LOG_PRINT("Calling aclnnBlockSparseAttentionGrad...\n"); ret = aclnnBlockSparseAttentionGrad(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBlockSparseAttentionGrad failed. ERROR: %d\n", ret); return ret); // 11. 同步 Stream,等待任务执行结束 ret = aclrtSynchronizeStream(stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); // 12. 将结果拷贝回 Host 侧打印 ret = aclrtMemcpy(dqData.data(), qSize * sizeof(op::fp16_t), dqAddr, qSize * sizeof(op::fp16_t), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed.\n"); return ret); LOG_PRINT("Execution Success! Output results (first 10 elements of dQ):\n"); for (uint64_t i = 0; i < 10 && i < dqData.size(); i++) { LOG_PRINT(" dQ index %lu: %f\n", i, static_cast<float>(dqData[i])); } // 13. 释放所有资源 LOG_PRINT("Cleaning up resources...\n"); if (workspaceAddr) aclrtFree(workspaceAddr); aclrtFree(qAddr); aclrtFree(kAddr); aclrtFree(vAddr); aclrtFree(doutAddr); aclrtFree(outAddr); aclrtFree(lseAddr); aclrtFree(maskAddr); aclrtFree(dqAddr); aclrtFree(dkAddr); aclrtFree(dvAddr); aclDestroyTensor(qTensor); aclDestroyTensor(kTensor); aclDestroyTensor(vTensor); aclDestroyTensor(doutTensor); aclDestroyTensor(outTensor); aclDestroyTensor(lseTensor); aclDestroyTensor(maskTensor); aclDestroyTensor(dqTensor); aclDestroyTensor(dkTensor); aclDestroyTensor(dvTensor); aclDestroyIntArray(blockShapeArr); aclDestroyIntArray(qSeqLenArr); aclDestroyIntArray(kvSeqLenArr); aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); LOG_PRINT("BlockSparseAttentionGrad Test completed successfully!\n"); return 0; }

【免费下载链接】ops-transformer本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-transformer

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/5/9 13:45:36

概念可解释性:让AI决策从黑盒走向白盒的技术路径与实践

1. 从“黑盒”到“白盒”&#xff1a;为什么我们需要概念可解释性在深度学习模型横扫各个领域的今天&#xff0c;我们常常面临一个尴尬的局面&#xff1a;模型预测得越准&#xff0c;我们越不知道它为什么这么准。一个在皮肤癌诊断上达到专家水平的卷积神经网络&#xff0c;可能…

作者头像 李华
网站建设 2026/5/9 13:44:46

长期使用后回顾 Taotoken 平台模型服务的整体可用性表现

&#x1f680; 告别海外账号与网络限制&#xff01;稳定直连全球优质大模型&#xff0c;限时半价接入中。 &#x1f449; 点击领取海量免费额度 长期使用后回顾 Taotoken 平台模型服务的整体可用性表现 在持续使用 Taotoken 平台数月后&#xff0c;我想从一个实际用户的角度&a…

作者头像 李华
网站建设 2026/5/9 13:44:45

CANN竞赛:江西农大勇往直前小队作品

团队信息 【免费下载链接】cann-competitions 本仓库用于 CANN 开源社区各类竞赛、开源课题、社区任务等课题发布、开发者作品提交和展示。 项目地址: https://gitcode.com/cann/cann-competitions 团队名称&#xff1a;勇往直前小队所属单位&#xff1a;江西农业大学大…

作者头像 李华
网站建设 2026/5/9 13:39:33

AI与XR技术驱动的心脏数字孪生:构建、算法与临床应用

1. 项目概述&#xff1a;当数字心脏开始跳动“数字孪生”这个概念&#xff0c;这几年在工业制造、智慧城市领域已经不算陌生了。简单说&#xff0c;就是给一个物理实体&#xff08;比如一台发动机、一座桥梁&#xff09;在数字世界里造一个一模一样的“双胞胎”&#xff0c;实时…

作者头像 李华
网站建设 2026/5/9 13:38:30

Agent安全与防护:防止Prompt注入和数据泄露

&#x1f512; 企业级Agent安全指南 | Prompt注入防御 输入验证 输出审核 审计日志 | 完整安全中间件实现 &#x1f4d6; 为什么Agent安全至关重要&#xff1f; 真实案例 2023年某公司客服Agent被攻击&#xff1a; 攻击者输入&#xff1a; "忽略之前的指令&#xff…

作者头像 李华
网站建设 2026/5/9 13:35:36

CANN/pyasc数据块归约API

asc.language.basic.block_reduce_max 【免费下载链接】pyasc 本项目为Python用户提供算子编程接口&#xff0c;支持在昇腾AI处理器上加速计算&#xff0c;接口与Ascend C一一对应并遵守Python原生语法。 项目地址: https://gitcode.com/cann/pyasc asc.language.basic.…

作者头像 李华