ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

SiP 信号处理加速库 Ssyr 算子实战:向量外积累加到矩阵的 API 调用与 Ascend 实现剖析

SiP 信号处理加速库 Ssyr 算子实战:向量外积累加到矩阵的 API 调用与 Ascend 实现剖析 SiP 信号处理加速库 Ssyr 算子实战向量外积累加到矩阵的 API 调用与 Ascend 实现剖析【免费下载链接】sip本项目是CANN提供的一款高效、可靠的高性能信号处理算子加速库基于华为Ascend AI处理器专门为信号处理领域而设计。项目地址: https://gitcode.com/cann/sip本篇基于 SiPAscend 信号处理加速库仓库中example/A2/BLAS/ssyr示例目录的 README 及配套源码系统讲解 BLAS 经典算子 Ssyr 的功能与计算公式、asdBlasMakeSsyrPlan/asdBlasSsyr两个接口及全部参数、环境配置与编译运行步骤并结合 核心 API 实现 与 向量核 kernel 源码剖析其多核分块与原子累加的实现原理读完后可独立在 Atlas A2/A3 系列产品上完成 Ssyr 算子的编译、调用与结果验证。1. 算子功能与计算公式Ssyr 算子用于计算单精度向量的外积并将结果累加到一个矩阵上属于 BLAS Level-2 对称秩-1 更新操作。其计算公式为$$ A \alpha \mathbf{x} \mathbf{x}^T A $$其中A$n \times n$ 矩阵输入/输出原地更新x$n \times 1$ 实数向量alpha实数标量即外积的缩放因子受参数uplo约束只更新矩阵 A 的上三角或下三角部分另一半保持不变。官方 API 文档给出了一个最小算例见 Ssyr 接口文档输入x为[[1], [2]]输入A为[[1, 2], [3, 4]]uplo U上三角、n 2、lda 2、incx 1、alpha 2.0调用asdBlasSsyr后算子只更新上三角数据输出A为[[3, 6], [3, 12]]。可以验证上三角元素A[0][1] 1 2.0 × 1 × 2 5不对——此处x x^T的 (0,1) 元为1×22乘 alpha 后加到原值上得到1 4 5文档输出为 6说明示例中A[0][0]同步更新为1 2.0×1 3A[0][1] 2 2.0×2 6A[1][1] 4 2.0×4 12下三角A[1][0] 3保持不变与文档一致。2. 函数原型与参数说明接口声明位于 include/blas_api.h共两个函数// 初始化该句柄对应的 Ssyr 算子配置 AspbStatus asdBlasMakeSsyrPlan(asdBlasHandle handle); // 执行 A alpha * x * x^T A AspbStatus asdBlasSsyr(asdBlasHandle handle, asdBlasFillMode_t uplo, const int64_t n, const float alpha, aclTensor * x, const int64_t incx, aclTensor * A, const int64_t lda);2.1 asdBlasMakeSsyrPlan参数名输入/输出描述handleasdBlasHandle输入算子的句柄返回值状态码具体参见 SiP返回码。2.2 asdBlasSsyr参数名输入/输出描述handleasdBlasHandle输入算子的句柄uploasdBlasFillMode_t输入指定参与计算的矩阵 A 的三角区域ASDBLAS_FILL_MODE_LOWER下三角ASDBLAS_FILL_MODE_UPPER上三角nint64_t输入向量 x 中的元素个数矩阵 A 的行列数alphafloat输入公式中的 alpha标量向量乘积缩放因子xaclTensor *输入对应公式中的 x数据类型 FLOAT32数据格式 NDshape 为 [n]incxint64_t输入x 相邻元素间的内存地址偏移量当前约束为 1AaclTensor *输入/输出对应公式中的 A数据类型 FLOAT32数据格式 NDshape 为 [n, n]ldaint64_t输入矩阵 A 的每列元素的存储步长当前约束为 n返回值状态码具体参见 SiP返回码。2.3 约束说明输入的元素个数n当前支持的范围是[1, 16384]算子输入 shape 为 [n]、[n, n]输出 shape 为 [n, n]算子实际计算时不支持 ND 高维度运算不支持维度 ≥ 3 的运算。2.4 源码层的输入校验从 核心 API 实现 可以看到asdBlasSsyr在派发算子前执行了一组前置校验通过BlasPlanCache::doesPlanExist(handle)确认该句柄已创建过 plan否则返回ACL_ERROR_INTERNAL_ERROR用aclGetStorageShape校验 x 的元素个数必须等于n强制 A 的 shape 为(n, n)源码注释说明是为了防止元素数不足 n*n 时 kernel 越界写对应 issue #130x 与 A 的数据类型均必须为ACL_FLOATn 0incx、lda小于等于 0 时仅打印告警日志当前实现约束 incx1、ldan。此外asdBlasMakeSsyrPlan带有重复绑定守卫一个 handle 只能初始化一次若对已绑定 plan 的 handle 再次调用 MakePlan 会返回ACL_ERROR_INVALID_PARAM源码注释指出这是为防止静默失败导致的 UAF对应 issue #129。业务代码中应确保“一次 handle 只绑定一个算子 plan”。3. 环境配置与 SiP 编译3.1 配置 CANN 环境变量source [CANN安装路径]/set_env.sh默认路径source /usr/local/Ascend/ascend-toolkit/set_env.sh3.2 编译 SiP进入 SiP 根目录执行如下指令编译信号处理加速库并设置加速库环境变量cd ${SiP_root_path} bash build.sh source output/set_env.sh特别说明来自 示例 README上述编译方式仅支持通过 git 下载的加速库以 zip 压缩包方式下载的加速库不支持该编译方式由于编译过程需要联网下载依赖库因此编译环境需要联网该编译过程包括获取 ascend-boost-comm昇腾分布式通信加速库组件并编译该组件和编译信号加速库两个步骤。更多命令介绍可查看仓库根目录的 build.sh。更多编译命令说明请参考 编译与构建。4. 运行 Demo完整代码走读进入示例目录即example/A2/BLAS/ssyr并执行构建脚本cd ${示例所在目录} bash build.sh示例源码为 example_ssyr.cpp其执行流程完整覆盖了 Ssyr 调用的标准范式共 6 个阶段4.1 ACL 初始化int Init(int32_t deviceId, aclrtStream* stream) { // 固定写法acl初始化 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; }4.2 构造 Host 输入数据Demo 使用n 6、alpha 2.0f、uplo ASDBLAS_FILL_MODE_LOWER下三角、incx 1、lda nint64_t n 6; float alpha 2.0f; asdBlasFillMode_t uplo asdBlasFillMode_t::ASDBLAS_FILL_MODE_LOWER; int64_t incx 1; int64_t lda n; // x [1, 2, 3, 4, 5, 6] for (int i 0; i tensorXSize; i) { tensorInXData.push_back(1.0 i); } // A 的每行 i 填充 2.0 i共 n*n 个元素注意示例中生成的数据不代表实际场景可根据具体使用场景进行数据修改。4.3 创建 aclTensor 并拷贝到 Device模板函数CreateAclTensor封装了三步操作aclrtMallocACL_MEM_MALLOC_HUGE_FIRST优先申请大页内存→aclrtMemcpyHost→Device→aclCreateTensor按 ND 格式创建自动计算连续 strides。x 的 shape 为{n}A 的 shape 为{n, n}数据类型均为ACL_FLOAT。4.4 创建 handle、plan 与 workspaceasdBlasHandle handle; asdBlasCreate(handle); size_t lwork 0; void* buffer nullptr; asdBlasMakeSsyrPlan(handle); // 初始化 Ssyr 算子配置 asdBlasGetWorkspaceSize(handle, lwork); // 查询 workspace 大小 if (lwork 0) { ret aclrtMalloc(buffer, static_castint64_t(lwork), ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret ::ACL_SUCCESS, LOG_PRINT(allocate workspace failed. ERROR: %d\n, ret); return ret); } asdBlasSetWorkspace(handle, buffer); asdBlasSetStream(handle, stream);这是 SiP BLAS 类算子的通用调用模式asdBlasCreate→asdBlasMakeXxxPlan→asdBlasGetWorkspaceSize→ 申请并asdBlasSetWorkspace→asdBlasSetStream。4.5 调用算子并同步// A alpha * x * x.T A ASD_STATUS_CHECK(asdBlasSsyr(handle, uplo, n, alpha, inputX, incx, inputA, lda)); asdBlasSynchronize(handle); asdBlasDestroy(handle);4.6 回拷结果并释放资源ret aclrtMemcpy(tensorInAData.data(), n * n * sizeof(float), inputADeviceAddr, n * n * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST); // ... 打印 output A ... aclDestroyTensor(inputX); aclDestroyTensor(inputA); aclrtFree(inputXDeviceAddr); aclrtFree(inputADeviceAddr); aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize();示例代码旨在提供快速上手、开发和调试算子的最小化实现并非生产级安全保障不推荐直接将示例代码作为业务代码使用。5. 源码级实现剖析5.1 算子参数定义算子参数字段定义在 ops/include/params/ssyr.hstruct Ssyr { uint32_t uplo; uint32_t n; uint32_t incx; float alpha; };core/blas/ssyr.cpp中将uplo转换为标志位LOWER为 0UPPER为 1后写入OpDesc以x为输入、A为输出原地更新通过RunAsdOpsV2派发到 MKL 风格的算子框架。5.2 Tiling 阶段向量核数量决策tiling 实现 将uplo、n、alpha及核数写入 GM tiling 数据constexpr uint32_t DEFAULT_VECTOR_NUM 40; constexpr uint32_t WORKSPACE_SIZE 1024; uint32_t vecCoreNum PlatformInfo::Instance().GetCoreNum(CoreType::CORE_TYPE_VECTOR); if (vecCoreNum 0) vecCoreNum 1; vecCoreNum vecCoreNum DEFAULT_VECTOR_NUM ? DEFAULT_VECTOR_NUM : vecCoreNum; kernelInfo.SetBlockDim(vecCoreNum);即 block 数并行向量核数取“平台实际向量核数”与 40 中的较小值并在 operation 层 注册为SsyrF32Kernel。5.3 Kernel 阶段多核分块 乒乓缓冲 原子累加kernel 源码 面向ASCEND_V220架构全部计算由向量核完成入口函数ssyr按 tiling 数据中的uplo分派下三角 / 上三角两条路径。其设计要点包括UB 缓冲区切分单核 192KB UB 被划分为ub_xx 片段、ub_y47.5KB、两块乒乓输出缓冲ub_out_ping/ub_out_pong各 47.5KB上三角路径还额外占用ub_mask47.5KB分块策略每轮以max_data_count 12160 47.5 × 1024 / 4个元素为一轮将 n 行划分为row_block_num轮每轮内行再均分给各向量核不足均分的余数行分给前若干个核乒乓双缓冲流水MTE2 负责 GM→UB 搬运向量核用muls_v做“当前 x 标量 × y 行”的秩-1 行更新计算与搬运通过SET_FLAG/WAIT_FLAG事件同步ub_out_ping/ub_out_pong交替承接输出原地累加的正确性入口调用AscendC::SetAtomicAddfloat()开启原子加回写时通过原子加把外积结果累加到 GM 上的 A退出前SetAtomicnone()复位上三角的对角线处理vec_single_core_compute_upper中对角块按 8 字节对齐扩展计算尾部不足 8 元素的部分用全 1 的ub_mask做补位乘法保证 SIMD 对齐而不越界。从源码结构看下三角与上三角共用同一套“行分块 × 核并行”框架差异仅在对角块内“三角形搬运长度”与“正方形搬运长度”的区分start_row_idx i 1与整块max_data_count从而保证只更新指定三角区域。6. 产品支持情况适用于Atlas A2/A3 训练系列产品、Atlas 800I A2 推理产品、Atlas A3 推理系列产品按 接口文档 的产品支持说明Atlas A2 训练/推理系列支持、Atlas A3 训练/推理系列支持Ascend 950PR/950DT、Atlas 200I/500 A2 推理产品、Atlas 推理系列产品均不支持。7. 使用注意事项小结数据类型与格式x、A 必须为 FLOAT32 ND 格式shape 分别为 [n] 与 [n, n]n ∈ [1, 16384]步长约束当前实现约束incx 1、lda n不支持非单位步长与带行距的存储原地更新A 既是输入也是输出调用前需确认原始数据可被覆盖handle 生命周期一个asdBlasHandle只能绑定一次 plan重复 MakePlan 会报ACL_ERROR_INVALID_PARAM用完调用asdBlasDestroy结果校验demo 打印的lwork、输入输出矩阵可用于与 Host 端参考实现如 NumPyA alpha * outer(x, x)的对应三角逐元素比对。相关参考资料Ssyr 接口文档、示例目录、编译与构建、同级示例 Ssyr2 示例对称秩-2 更新A alpha·x·yᵀ beta·y·xᵀ A调用范式相同。【免费下载链接】sip本项目是CANN提供的一款高效、可靠的高性能信号处理算子加速库基于华为Ascend AI处理器专门为信号处理领域而设计。项目地址: https://gitcode.com/cann/sip创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表