
ATVOSS Power 幂运算表达式接口全解析从 Compute 声明到昇腾 AI Core 指令的下沉实现【免费下载链接】atvossATVOSSAscend C Templates for Vector Operator Subroutines是一套基于Ascend C开发的Vector算子库致力于为昇腾硬件上的Vector类融合算子提供极简、高效、高性能、高拓展的编程方式。项目地址: https://gitcode.com/cann/atvossPower 是 CANN/atvossAscend C Templates for Vector Operator Subroutines提供的幂运算接口用于在 Vector 类融合算子中表达逐元素求幂的运算逻辑。本文以 docs/api/Power.md 为骨架结合 math_expression.h、math_evaluator.h 与 test_op_power.cpp 的源码与测试证据完整讲解 Power 的函数原型、参数语义、表达式构建机制、求值链路与端到端验证方法。读完本文你将能在自己的 Compute 配置中正确使用PowerN(...)对张量或标量做编译期常幂运算并理解它最终如何被翻译为昇腾硬件上的AscendC::Power指令。功能说明Power 执行幂运算对操作数lhs中的每个元素求lhs[i] ^ scalarValue其中幂次scalarValue是一个编译期常量以模板非类型参数auto scalarValue形式传入操作数既可以是张量ExpressionT也可以是标量T。在 docs/api/README.md 的 Operator 接口列表中Power 与、-、*、/、Exp、Sqrt、Cast、Abs等并列属于 Compute 层用户可直接调用的运算接口之一。与Sqrt、Exp、Abs这类无参一元算子不同Power 属于带编译期标量参数的一元算子与Divs同构这也是它在接口形态上的核心特点运算行为由模板参数scalarValue在编译期固定运行时不再携带任何额外属性。所属头文件与函数原型Power 的声明位于 include/operators/math_expression.h头文件内的版权与 License 声明见仓库根目录 LICENSE完整原型如下// include/operators/math_expression.h 中的声明对应源码 L125-L143 templateauto scalarValue, typename T struct OpPower : UnaryOpT { OpPower() default; constexpr OpPower(T t) : UnaryOpT(t) {} }; templateauto scalarValue, typename T __host_aicore__ constexpr auto Power(ExpressionT lhs) { return ExpressionOpPowerscalarValue, T{{lhs.data}}; } templateauto scalarValue, typename T __host_aicore__ constexpr auto Power(T lhs) { return ExpressionOpPowerscalarValue, T{{std::forwardT(lhs)}}; }原型共分三层算子结构体OpPower继承自UnaryOpT是承载幂运算的表达式节点通过UnaryOpT保存操作数并带有IsUnaryOp、DataType、TensorType、RetType等类型元信息张量重载Power(ExpressionT lhs)当操作数是张量表达式时将其数据成员lhs.data包进ExpressionOpPowerscalarValue, T标量重载Power(T lhs)当操作数是普通标量时以std::forwardT(lhs)转发构造同一个表达式类型覆盖ExpressionT之外的一切操作数形态。两个重载都标记了__host_aicore__ constexpr意味着该函数既可在 Host 侧编译执行也可在 AI CoreDevice侧编译执行并且返回值在编译期即可确定——这正是 atvoss 表达式模板Expression Template体系编译期构建、运行期零开销设计的关键一环。参数说明原文档 Power.md 的参数表完整整理如下参数名称参数类型输入/输出数据类型参数说明默认值scalarValue模板参数输入NAPower 操作的幂次NAT模板参数输入NAPower 操作数的数据类型NAlhs函数形参输入NAPower 操作数当类型是 ExpressionT 时是张量当类型是 T 时是标量NA结合源码可以进一步明确三点语义scalarValue是模板非类型参数templateauto ...语法因此幂次必须在编译期确定为常量例如Power2(in)、Power3(in)它不能被运行时变量替代这也是 Power 与以函数实参传幂次的常规 API 之间的本质区别T由调用处自动推导PowerscalarValue(lhs)中T从lhs的类型推导无需显式指定当lhs是ExpressionT时T为张量元素类型当lhs是普通标量时T即为该标量类型lhs的双形态语义重载一处理ExpressionT张量操作数重载二处理T标量操作数。在求值阶段标量形态的幂次同样以scalarValue为准即标量自身的值被忽略、只取编译期幂次这一语义需注意使用场景——文档示例中的标量用法实际是把幂次固定、操作数作为占位输入参与表达式构建。返回值说明返回值数据类型返回值说明ExpressionOpPowerscalarValue, T返回一个 OpPower 的表达式返回值并非计算结果本身而是一个惰性求值的表达式对象它记录了对操作数lhs求scalarValue次幂这一运算意图真正的计算发生在该表达式被赋值给输出占位符out PowerN(in)之后由求值器Evaluator在设备端执行。这一先建表达式、后统一求值的机制是 atvoss Compute 层所有算子接口的共同约定。Power 在表达式模板框架中的定位要正确理解 Power需要先看清它赖以生存的表达式基座定义见 include/expression/expr_template.hExpressionT基本表达式容器内部持有T const data{}重载了operator以产生OpAssignT, U赋值表达式UnaryOpT一元运算基类提供IsUnaryOp类型标记、DataType、TensorType、RetType元信息与GetData()访问器。OpPower正是它的直接子类因此天然满足框架对一元算子的静态检测IsUnaryOp_vPlaceHolderN, T, ParamUsage声明计算图的参数占位符N为参数编号、T为参数类型、ParamUsage决定数据流向IN/OUT/IN_OUT。Power的输入lhs与输出目标通常都来自PlaceHolder。由于Power返回的是纯编译期构造的表达式类型它可以直接嵌套进out Power2(in)这样的赋值表达式中与、-、*、/等二元运算、以及Sqrt、Exp、Abs等一元运算自由组合构成更复杂的融合算子计算图。从表达式到硬件指令的求值链路Power 表达式并不直接执行计算它的落地路径在 include/operators/math_evaluator.h 中完成分为两层第一层PowerAssign设备端函数源码 L211-L216template typename OperationShape, auto scalarValue, typename T __aicore__ inline void PowerAssign( AscendC::LocalTensorT dst, const AscendC::LocalTensorT src, OperationShape operationShape) { AscendC::Power(dst, src, T{scalarValue}, operationShape.axis0); }这里完成了两个关键动作将编译期幂次scalarValue显式转换为操作数类型T{scalarValue}从而适配AscendC::Power对标量实参的类型要求调用昇腾向量指令AscendC::Power(dst, src, scalar, axis0)按operationShape.axis0指定的计算长度对整段src逐元素求幂并写入dst。第二层EvaluatorOpAssignT, OpPowerscalarValue, U特化源码 L524-L537template typename T, typename U, int scalarValue struct EvaluatorOpAssignT, OpPowerscalarValue, U { using Type void; template typename Context __aicore__ inline auto operator()(const OpAssignT, OpPowerscalarValue, U op, Context context) const { using Dtype Dtype_tT; OperationShape operationShape GetShapeOperation::Unary(context.argsTensors); return Atvoss::Tile::PowerAssignOperationShape, scalarValue, Dtype( EvaluatorT{}(op.GetLhs(), context).GetUbTensor(), EvaluatorU{}(op.GetRhs().GetData(), context).GetUbTensor(), operationShape); } };该特化通过模式匹配捕获赋值表达式 OpPower 右操作数这一结构随后用GetShapeOperation::Unary(context.argsTensors)从运行时参数张量推导出本算子的计算形状长度信息递归求值左操作数输出张量与右操作数输入数据取各自的GetUbTensor()得到设备端LocalTensor把形状、幂次scalarValue、数据类型Dtype一并交给PowerAssign完成指令下发。这条链路清晰展示了 atvoss 的编译期模板分发思想表达式类型在编译期被精确匹配到对应的求值器特化运行时只保留必需的形状与地址信息不存在虚函数或运行时反射开销。使用示例原文档 Power.md 给出了两种典型用法张量操作数与标量操作数。下面结合 Compute 配置结构完整展开。示例一张量逐元素求幂template typename InputDtype, typename OutputDtype struct Config { struct Compute { template template typename class Tensor __host_aicore__ constexpr auto Compute() const { auto in Atvoss::PlaceHolder1, TensorInputDtype, Atvoss::ParamUsage::IN(); auto out Atvoss::PlaceHolder2, TensorOutputDtype, Atvoss::ParamUsage::OUT(); // 张量每个元素求 2 次幂out[i] in[i]^2 return (out Power2(in)); }; }; };示例二标量操作数template typename InputDtype, typename OutputDtype struct Config { struct Compute { template template typename class Tensor __host_aicore__ constexpr auto Compute() const { auto scalar Atvoss::PlaceHolder1, InputDtype, Atvoss::ParamUsage::IN(); auto out Atvoss::PlaceHolder2, TensorOutputDtype, Atvoss::ParamUsage::OUT(); // 标量参与幂运算out scalar^2 return (out Power2(scalar)); }; }; };注意示例二中占位符的声明差异张量占位符用TensorInputDtype包装标量占位符则直接用InputDtype裸类型这正是 PlaceHolder.md 中张量参数与标量参数两种形态的体现。Compute()采用__host_aicore__ constexpr固化写法其结构规范可参考 Compute.md。示例三完整可编译的算子配置将 Power 接入完整的 atvoss 三层构建链Block 层 / Kernel 层 / Device 层配置方式与 examples/abs/abs.cpp 中 Abs 算子的模式一致template typename T1, typename T2 struct PowerConfig { struct PowerCompute { template template typename class Tensor __host_aicore__ constexpr auto Compute() const { auto in Atvoss::PlaceHolder1, TensorT1, Atvoss::ParamUsage::IN(); auto out Atvoss::PlaceHolder2, TensorT2, Atvoss::ParamUsage::OUT(); return (out Power3(in)); }; }; using ArchTag Atvoss::Arch::DAV_3510; using BlockOp Atvoss::Ele::BlockBuilderPowerCompute, ArchTag; using KernelOp Atvoss::Ele::KernelBuilderBlockOp; using DeviceOp Atvoss::DeviceAdapterKernelOp; };其中ArchTag Atvoss::Arch::DAV_3510指定目标昇腾芯片架构BlockBuilder/KernelBuilder/DeviceAdapter分别承担 Block 层、Kernel 层与 Device 层的装配对应接口见 BlockBuilder.md、KernelBuilder.md、DeviceAdapter.mdDeviceOp::Run(arguments, stream)负责实际下发执行。端到端验证test_op_power仓库在 tests/st/test_op_power.cpp 中提供了 Power 算子的端到端系统测试覆盖从 Host 到 Device 的完整运行链路可直接作为实战模板ACL 初始化aclInit/aclrtSetDevice/aclrtCreateContext/aclrtCreateStream建立运行环境内存分配与数据拷贝aclrtMalloc分配输入输出设备内存aclrtMemcpy以ACL_MEMCPY_HOST_TO_DEVICE拷入初始数据测试用例全部初始化为 3参数构造用Atvoss::TensorT包装设备指针与形状一维 8 元素通过Atvoss::ArgumentsBuilder{}.inputOutput(t1, t2).build()生成算子入参执行实例化PowerConfigint32_t, int32_t::DeviceOp并调用deviceOp.Run(arguments, stream)结果回拷与校验aclrtSynchronizeStream同步后拷回结果与 golden 数据比对。关键的验证逻辑是输入全为 3、幂次为 3因此 golden 值为27std::vectorT2 golden(8, 27); // 3^3 27 if (!VerifyResults(golden, hostOutput)) { std::cout Accuracy verification failed. std::endl; } else { std::cout Accuracy verification passed. std::endl; }主函数以Runint32_t, int32_t()运行 int32 输入/输出用例。从 tests/st/CMakeLists.txt 可以看到tests/st目录下所有test_*.cpp会被自动 glob 收集使用昇腾 bisheng 编译器--npu-archdav-3510 -xascSOC 限定ascend950构建并链接ascendcl、platform、register、tiling_api、runtime等运行时库。这意味着任何PowerN的新用法都可以仿照该测试文件通过向tests/st添加test_*.cpp或修改PowerConfig的输入类型、幂次与 golden 值来快速验证。约束与注意事项原文档将 Power 的约束说明标为 NA即接口本身没有额外使用限制。但从源码实现可以归纳出以下几点工程实践层面的注意事项幂次必须编译期确定scalarValue是模板非类型参数只能传入编译期常量如2、3需要运行时幂次的场景应改用其他接口或自行扩展表达式幂次会被转换为操作数类型求值阶段执行T{scalarValue}若scalarValue无法无损转换为T如浮点幂次作用于整型张量需要注意类型转换语义与潜在截断表达式必须赋值给输出才生效单独调用PowerN(in)只构建惰性表达式必须出现于out PowerN(in)这类赋值表达式中才会被求值器匹配并下发到设备参与赋值的左值类型依据 expr_template.h 中operator的静态断言赋值号左侧只能是Param、LocalVar或左值引用Power 表达式的目标输出应声明为PlaceHolder..., ParamUsage::OUT架构前提测试与示例均基于DAV_3510ascend950架构编译运行跨架构使用请以当前 CMakeASCEND.cmake 及工程说明为准。与其他一元算子的关系在 math_expression.h 中Power 与两类一元算子并存无参一元算子Sqrt、Exp、Abs通过DeclareUnaryOp宏批量声明仅携带操作数不带额外模板参数带编译期标量参数的一元算子Power与Divs结构完全同构后者将scalarValue作为除数求值时换算为T{1}/scalarValue并改用AscendC::Muls二者是 atvoss 中模板常量参数化算子的代表。这种设计使 Power 既能作为独立算子使用也能嵌入out Power2(in1) in2这类混合表达式与其他一元/二元算子共同构成融合计算图最终统一由各自Evaluator特化分发到对应AscendC向量指令上执行。参考资料接口文档docs/api/Power.md、docs/api/README.md接口声明include/operators/math_expression.h求值实现include/operators/math_evaluator.h表达式基座include/expression/expr_template.h端到端测试tests/st/test_op_power.cpp、tests/st/CMakeLists.txt相关接口文档UnaryOp.md、Compute.md、PlaceHolder.md、BlockBuilder.md、KernelBuilder.md、DeviceAdapter.md【免费下载链接】atvossATVOSSAscend C Templates for Vector Operator Subroutines是一套基于Ascend C开发的Vector算子库致力于为昇腾硬件上的Vector类融合算子提供极简、高效、高性能、高拓展的编程方式。项目地址: https://gitcode.com/cann/atvoss创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考