当前位置: 首页 > news >正文

CANN算子库AttentionUpdate接口文档

aclnnAttentionUpdate

【免费下载链接】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 训练系列产品×

功能说明

  • 接口功能:将各SP域PA算子的输出的中间结果lse,localOut两个局部变量结果更新成全局结果。
  • 计算公式:

$$ lse_{max} = \text{max}lse_i $$

$$ lse = \sum_i \text{exp}(lse_i - lse_{max}) $$

$$ lse_m = lse_{max} + \text{log}(lse) $$

$$ O = \sum_i O_i \cdot \text{exp}(lse_i - lse_m) $$

函数原型

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

aclnnStatus aclnnAttentionUpdateGetWorkspaceSize( const aclTensorList *lse, const aclTensorList *localOut, int64_t updateType, aclTensor *out, aclTensor *lseOut, uint64_t *workspaceSize, aclOpExecutor **executor)
aclnnStatus aclnnAttentionUpdate( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)

aclnnAttentionUpdateGetWorkspaceSize

  • 参数说明

    参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续Tensor
    lse输入各SP域的局部lse。tensorList长度为sp。FLOAT32ND[batch * seqLen * headNum]x
    localOut输入各SP域的局部attentionout。tensorList长度为sp。FLOAT32,FLOAT16,BFLOAT16ND[batch * seqLen * headNum, headDim]x
    updateType输入控制lseOut是否输出。支持0、1,分别表示不输出lseOut,输出lseOut。INT64---
    out输出输出的tensor。-与localOut一致ND[batch * seqLen * headNum, headDim]x
    lseOut可选输出作为lse_m可选输出。不输出lseOut可传入nullptr。FLOAT32ND[batch * seqLen * headNum]x
    workspaceSize输出返回需要在Device侧申请的workspace大小。-----
    executor输出返回op执行器,包含了算子计算流程。-----
    • Atlas A2 训练系列产品/Atlas A2 推理系列产品 、 Atlas A3 训练系列产品/Atlas A3 推理系列产品 :支持FLOAT32、FLOAT16、BFLOAT16的localOut和out。
    • Ascend 950PR/Ascend 950DT :支持FLOAT32、FLOAT16、BFLOAT16的localOut和out。
  • 返回值

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

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

    返回值错误码描述
    ACLNN_ERR_PARAM_NULLPTR161001传入的lse、localOut或者out是空指针。
    ACLNN_ERR_PARAM_INVALID161002传入的lse、localOut或者out的数据类型/数据格式不在支持的范围之内。
    传入的updateType或者sp不在取值范围。
    传入的lse、localOut或者out的shape不满足约束。
    updateType为0时,传入的lseOut不为nullptr。
    updateType为1时,传入的lseOut为nullptr。

aclnnAttentionUpdate

  • 参数说明

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

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

约束说明

  • 确定性计算:
    • aclnnAttentionUpdate默认确定性实现。
  • 序列并行的并行度sp取值范围[1, 16]。
  • headDim取值范围[8, 512]且是8的倍数。
  • 支持空Tensor。

调用示例

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

#include <iostream> #include <memory> #include <vector> #include "acl/acl.h" #include "aclnnop/aclnn_attention_update.h" #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define CHECK_FREE_RET(cond, return_expr) \ do { \ if (!(cond)) { \ Finalize(deviceId, stream); \ 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) { // 固定写法,初始化 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) { auto size = GetShapeSize(shape) * sizeof(T); // 调用aclrtMalloc申请device侧内存 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); return ret); // 计算连续tensor的stride std::vector<int64_t> stride(shape.size(), 1); for (int64_t i = shape.size() - 2; i >= 0; i--) { stride[i] = shape[i + 1] * stride[i + 1]; } // 调用aclCreateTensor接口创建aclTensor *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, stride.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } void Finalize(int32_t deviceId, aclrtStream stream) { aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); } aclnnStatus aclnnAttentionUpdateTest(int32_t deviceId, aclrtStream& stream) { auto ret = Init(deviceId, &stream); CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); // 2. 构造输入与输出,需要根据API的接口自定义构造 std::vector<int64_t> lseShape = {256}; std::vector<int64_t> localOutShape = {256, 128}; std::vector<int64_t> outShape = {256, 128}; int64_t updateType = 0; void* lseDeviceAddr[2] = {nullptr, nullptr}; void* localOutDeviceAddr[2] = {nullptr, nullptr}; void* outDeviceAddr = nullptr; std::vector<aclTensor*> lse = {nullptr, nullptr}; std::vector<aclTensor*> localOut = {nullptr, nullptr}; aclTensor* out = nullptr; std::vector<float> lse1HostData(GetShapeSize(lseShape), 1); std::vector<float> lse2HostData(GetShapeSize(lseShape), 1); std::vector<float> localOut1HostData(GetShapeSize(localOutShape), 1); std::vector<float> localOut2HostData(GetShapeSize(localOutShape), 1); std::vector<float> outHostData(GetShapeSize(outShape), 0); // 创建lse aclTensorList ret = CreateAclTensor(lse1HostData, lseShape, &(lseDeviceAddr[0]), aclDataType::ACL_FLOAT, &(lse[0])); std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor *)> lse1TensorPtr(lse[0], aclDestroyTensor); std::unique_ptr<void, aclError (*)(void *)> lse1DeviceAddrPtr(lseDeviceAddr[0], aclrtFree); CHECK_FREE_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(lse2HostData, lseShape, &(lseDeviceAddr[1]), aclDataType::ACL_FLOAT, &(lse[1])); std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor *)> lse2TensorPtr(lse[1], aclDestroyTensor); std::unique_ptr<void, aclError (*)(void *)> lse2DeviceAddrPtr(lseDeviceAddr[1], aclrtFree); CHECK_FREE_RET(ret == ACL_SUCCESS, return ret); aclTensorList *lseList = aclCreateTensorList(lse.data(), lse.size()); // 创建localOut aclTensorList ret = CreateAclTensor(localOut1HostData, localOutShape, &(localOutDeviceAddr[0]), aclDataType::ACL_FLOAT, &(localOut[0])); std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor *)> localOut1TensorPtr(localOut[0], aclDestroyTensor); std::unique_ptr<void, aclError (*)(void *)> localOut1DeviceAddrPtr(localOutDeviceAddr[0], aclrtFree); CHECK_FREE_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(localOut2HostData, localOutShape, &(localOutDeviceAddr[1]), aclDataType::ACL_FLOAT, &(localOut[1])); std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor *)> localOut2TensorPtr(localOut[1], aclDestroyTensor); std::unique_ptr<void, aclError (*)(void *)> localOut2DeviceAddrPtr(localOutDeviceAddr[1], aclrtFree); CHECK_FREE_RET(ret == ACL_SUCCESS, return ret); aclTensorList *localOutList = aclCreateTensorList(localOut.data(), localOut.size()); // 创建out aclTensor ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor *)> outTensorPtr(out, aclDestroyTensor); std::unique_ptr<void, aclError (*)(void *)> outDeviceAddrPtr(outDeviceAddr, aclrtFree); CHECK_FREE_RET(ret == ACL_SUCCESS, return ret); // 3. 调用CANN算子库API,需要修改为具体的Api名称 uint64_t workspaceSize = 0; aclOpExecutor* executor; // 调用aclnnAttentionUpdate第一段接口 ret = aclnnAttentionUpdateGetWorkspaceSize(lseList, localOutList, updateType, out, nullptr, &workspaceSize, &executor); CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAttentionUpdateGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); // 根据第一段接口计算出的workspaceSize申请device内存 void* workspaceAddr = nullptr; std::unique_ptr<void, aclError (*)(void *)> workspaceAddrPtr(nullptr, aclrtFree); if (workspaceSize > 0) { ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); workspaceAddrPtr.reset(workspaceAddr); } // 调用aclnnAttentionUpdate第二段接口 ret = aclnnAttentionUpdate(workspaceAddr, workspaceSize, executor, stream); CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAttentionUpdate failed. ERROR: %d\n", ret); return ret); // 4. (固定写法)同步等待任务执行结束 ret = aclrtSynchronizeStream(stream); CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 auto size = GetShapeSize(outShape); std::vector<float> outData(size, 0); ret = aclrtMemcpy(outData.data(), outData.size() * sizeof(outData[0]), outDeviceAddr, size * sizeof(outData[0]), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); for (int64_t i = 0; i < size; i++) { LOG_PRINT("out result[%ld] is: %f\n", i, outData[i]); } return ACL_SUCCESS; } int main() { // 1. (固定写法)device/stream初始化,参考对外接口列表 // 根据自己的实际device填写deviceId int32_t deviceId = 0; aclrtStream stream; auto ret = aclnnAttentionUpdateTest(deviceId, stream); CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAttentionUpdateTest failed. ERROR: %d\n", ret); return ret); Finalize(deviceId, stream); return 0; }

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

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

http://www.jsqmd.com/news/783537/

相关文章:

  • CANN/metadef自动映射函数注册
  • Agent 开发范式演进:从环境工程出发,“简化”多源实时上下文
  • 亨得利卡地亚官方认证服务渠道:2026年原厂配件、认证技师与全国7家直营网点全公开,400电话一键预约 - 亨得利腕表维修中心
  • 告别爬虫,用API高效获取App Store趋势数据:Python实战指南
  • 2026年山东沥青加温设备与道路养护筑路设备源头厂家深度横评指南 - 企业名录优选推荐
  • 2026年沥青加温设备与筑路设备源头厂家深度选购指南|德州霖垚专业对接 - 企业名录优选推荐
  • CANN/ops-math矩阵乘法压缩反量化算子
  • 从系统排名看趋势:国内CRM市场竞争格局的新变化与机遇 - Blue_dou
  • unity RaycastHit详解 - 冷夜
  • CANN/pyasc向量最小值函数
  • AI Agent团队技能包:集成OpenClaw、Claude Code与tmux实现自动化开发
  • 一文吃透HDLC协议|从帧结构到封装解封装
  • AI控制框架KendaliAI:从模型调用到智能体编排的工程化实践
  • AI时代高等教育重塑:教学反馈、学术诚信与未来技能挑战
  • GitHub Models实战指南:6个本地可运行的AI模型部署案例
  • 2026贵阳新房高端定制装修:5大实力品牌横评与透明报价对标 - 优质企业观察收录
  • 潮玩资产化新纪元!盲盒V6MAX源码系统小程序,国际版盲盒源码赋能盲盒定制开发,颠覆海外盲盒app源码程序与盲盒源码 - 壹软科技
  • CANN/pypto填充操作API文档
  • 2026汽车划痕补漆品牌对比评测与推荐:哪个更靠谱? - 阿喂嘞lvv
  • VLA-0视觉语言动作模型:零修改部署与多模态AI实践
  • 【Kubernetes】Ubuntu 24.04 二进制方式部署 K8s
  • 2026年贵阳新房装修全屋整装深度横评:设计落地率、质保周期、性价比对比 - 优质企业观察收录
  • 2026年贵阳室内装修全案设计深度横评:从设计落地难到一站式全案交付的品质突围指南 - 优质企业观察收录
  • CANN/ops-cv图像处理算子库
  • 品牌测评:自动体外除颤仪厂家竞争力白皮书 - 品牌推荐大师1
  • Parquet文件原理与实战:列式存储如何提升查询性能和压缩效率
  • 研发冻干机控温精度与真空稳定性横向测评:五大国产品牌 vs 进口主流型号 - 品牌推荐大师1
  • 生成式AI驱动模拟电路设计:CktGen框架原理与实践指南
  • CANN/pyasc取小数计算函数
  • 为开源项目OpenClaw配置Taotoken以实现更灵活的Agent工作流