CANN ops-math FloorMod 算子全解析:数学语义、aclnn 调用与 NPU 源码实现

发布时间:2026/9/20 1:29:28
CANN ops-math FloorMod 算子全解析:数学语义、aclnn 调用与 NPU 源码实现 算子库人工智能CANN【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-math点击查看免费下载本篇文章基于 CANN ops-math 开源仓库中math/floor_mod目录的官方算子文档系统讲解数学基础算子 FloorMod向下取整求余即 remainder/floor mod的功能语义、产品支持情况、x1/x2/y 参数规格、aclnn 两段式接口的完整调用方式并结合算子原型floor_mod_proto.h、Host 侧定义与 Tilingfloor_mod_def.cpp、floor_mod_tiling_arch35.cpp以及 Kernel 侧 DAGfloor_mod_dag.h等源码证据深入剖析其在 NPU 上的实现原理。读完本文你将掌握 FloorMod 的数学语义与 C 语言%的区别、如何在业务代码中通过 aclnnRemainder 系列接口完成标量/张量间的求余运算以及该算子在 Atlas 系列产品上“Broadcast 符号校正”的底层计算路径。一、算子功能与数学语义FloorMod 算子实现的是逐元素向下取整求余floor remainder。其行为与 PyTorch 的torch.remainder、TensorFlow 的FloorMod保持一致先将标量self或张量selfbroadcast 成与张量other一致的 shape再对每个元素计算self除以other对应元素后的余数。结果的符号与除数other相同且结果的绝对值严格小于other的绝对值。实际计算remainder(self, other)等效于以下公式$$ out_i self - floor(self / other_i) * other_i $$其中floor表示向下取整向负无穷方向舍入这正是该算子与 C 语言%向零截断的 truncated remainder的本质区别所在。以官方文档中的示例为例self 5.0 # float other tensor([[-1, -2], [-3, -4]]).type(int32) result remainder(self, other) # result的值 # tensor([[ 0., -1.], # [-1., -3.]]) float # 对于元素other中的-4来说计算结果为5 - floor(5 / -4) * -4 -3 # 可以看到最终结果-3的绝对值小于原来的-4的绝对值。推导该示例中的一个元素5 / -4 -1.25floor(-1.25) -2代入公式得到5 - (-2) * (-4) 5 - 8 -3。若使用向零截断的 C 语言语义5 % -4只会得到1两者符号规则完全不同。这一语义在源码注释中同样被明确为“Consistent with: floor(x1/x2) * x2 mod(x1, x2) x1”见 floor_mod_proto.h并注明兼容 TensorFlow 的 FloorMod 算子。对于 Tensor 对 Tensor 的场景两个输入先广播为一致 shape 再计算例如接口文档 aclnnRemainderTensorTensoraclnnInplaceRemainderTensorTensor.md 中的示例self tensor([[-1, -2], [-3, -4]]).type(int64) other tensor([-3, -3]).type(float16) result remainder(self, other) # result的值 # tensor([[-1., -2.], # [-0., -1.]], dtypefloat16) # 首先是将other broadcast成和self一致的shape成为 [[-3, -3], [-3, -3]]然后再进行计算。 # 对于元素self中的-3来说计算结果为(-3) % (-3) 0二、产品支持情况根据 math/floor_mod/README.md 的产品支持矩阵FloorMod 算子在不同产品上的支持情况如下产品是否支持Ascend 950PR/Ascend 950DT√Atlas A3 训练系列产品/Atlas A3 推理系列产品√Atlas A2 训练系列产品/Atlas A2 推理系列产品√Atlas 200I/500 A2 推理产品×Atlas 推理系列产品×Atlas 训练系列产品√需要注意的是产品支持矩阵在不同接口变体上存在细微差异例如在 aclnnRemainderTensorTensor 接口文档 中Atlas 推理系列产品标注为支持且在该文档中明确了“Atlas 训练系列产品不支持 BFLOAT16 数据类型”等细节而 aclnnRemainderScalarTensor 接口文档 则补充说明Atlas 训练系列产品不支持 BFLOAT16。实际使用时应以目标产品的具体接口文档为准。从 Host 侧注册代码 floor_mod_def.cpp 可以确认AICore 计算配置仅注册了ascend950与ascend350两个平台分别对应 Ascend 950 与 Atlas A3 系列而 Atlas 训练系列产品910通过框架/AICPU 路径支持。三、参数说明FloorMod 算子的输入输出参数在 math/floor_mod/README.md 的参数说明中定义如下参数名输入/输出/属性描述数据类型数据格式x1输入公式中的输入张量self_iFLOAT16, BFLOAT16, FLOAT, INT32, INT64NDx2输入公式中的输入张量other_iFLOAT16, BFLOAT16, FLOAT, INT32, INT64NDy输出公式中的输出张量out_iFLOAT16, BFLOAT16, FLOAT, INT32, INT64ND从算子原型 floor_mod_proto.h 可见REG_OP(FloorMod)声明的类型集合为{DT_INT32, DT_INT64, DT_FLOAT, DT_FLOAT16, DT_DOUBLE, DT_BF16}比 README 表格多出DOUBLE——该类型在接口层面aclnn 文档中self/other支持 DOUBLE和 AICPU 路径中有效。而 floor_mod_def.cpp 中 OpDef 注册的 AICore 数据类型为{DT_BF16, DT_FLOAT16, DT_FLOAT, DT_INT32, DT_INT64}与 README 表格一致格式统一为FORMAT_ND且动态 shape、动态 rankDynamicRankSupportFlag(true)、DynamicShapeSupportFlag(true)均被开启。关于 shape 与 broadcast 关系原型注释floor_mod_proto.h给出了以下约束可在开发中直接参考x2的输入数据不支持 0除零保护见下文“约束与注意事项”当张量元素值超过 2048 时算子在 mini 平台上的精度无法保证达到双千分位要求由于架构差异该算子在 NPU 与 CPU 上的计算结果可能不一致若 shape 表示为(D1, D2, …, Dn)则需要满足D1*D2*…*DN ≤ 1000000且n ≤ 8。四、调用方式与接口变体4.1 aclnn 两段式调用模型FloorMod 在 aclnn 层提供remainder语义的多组接口全部遵循 CANN 的两段式接口调用模型先调用xxxGetWorkspaceSize第一段接口完成入参校验并获取计算所需 workspace 大小与包含算子计算流程的执行器executor再调用第二段执行接口传入 workspace 与 stream 真正下发计算。aclnn 返回码的定义可参见 aclnn_return_code.md。math/floor_mod/README.md 的调用说明给出了基本用法通过 aclnnRemainderScalarTensor 接口调用 FloorMod 算子对应示例代码见 test_aclnn_remainder_scalar_tensor.cpp。4.2 接口变体与选择根据math/floor_mod/docs与math/floor_mod/examples目录FloorMod 共提供六种 aclnn 接口每个接口又包含 GetWorkspaceSize 与执行两段接口输入形式说明aclnnRemainderScalarTensorscalarself tensorother标量与张量求余输出新建张量aclnnRemainderTensorScalartensorself scalarother张量与标量求余输出新建张量aclnnInplaceRemainderTensorScalartensorself scalarother张量与标量求余结果直接写回self内存inplaceaclnnRemainderTensorTensortensorself tensorother两个张量 broadcast 后求余输出新建张量aclnnInplaceRemainderTensorTensortensorself tensorother两个张量 broadcast 后求余结果写回self内存inplaceRemainderTensorTensor与InplaceRemainderTensorTensor实现相同的功能区别仅在于前者需新建一个输出张量对象存储计算结果后者无需新建输出张量对象直接在输入张量self的内存中存储计算结果参见 aclnnRemainderTensorTensor 接口文档。实际业务中若希望避免额外显存开销可优先考虑 inplace 版本。4.3 函数原型以 aclnnRemainderScalarTensor 为例两段式接口原型为aclnnStatus aclnnRemainderScalarTensorGetWorkspaceSize( const aclScalar* self, const aclTensor* other, aclTensor* out, uint64_t* workspaceSize, aclOpExecutor** executor)aclnnStatus aclnnRemainderScalarTensor( void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream)TensorTensor 与 inplace 变体的原型接口文档为aclnnStatus aclnnRemainderTensorTensorGetWorkspaceSize(const aclTensor *self, const aclTensor *other, aclTensor *out, uint64_t *workspaceSize, aclOpExecutor **executor) aclnnStatus aclnnRemainderTensorTensor(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream) aclnnStatus aclnnInplaceRemainderTensorTensorGetWorkspaceSize(aclTensor* selfRef, const aclTensor *other, uint64_t *workspaceSize, aclOpExecutor **executor) aclnnStatus aclnnInplaceRemainderTensorTensor(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)4.4 GetWorkspaceSize 参数详解第一段接口aclnnRemainderScalarTensorGetWorkspaceSize的入参与出参如下接口文档参数名输入/输出描述数据类型数据格式维度(shape)非连续TensorselfaclScalar*输入公式中的输入selfINT32、INT64、FLOAT16、FLOAT、DOUBLE、BFLOAT16---otheraclTensor*输入公式中的输入otherINT32、INT64、FLOAT16、FLOAT、DOUBLE、BFLOAT16ND0-8√outaclTensor*输出公式中的输出outINT32、INT64、FLOAT16、FLOAT、DOUBLE、BFLOAT16ND0-8√workspaceSizeuint64_t*输出返回需要在 Device 侧申请的 workspace 大小----executoraclOpExecutor**输出返回 op 执行器包含了算子计算流程----关键使用说明self的数据类型与other需满足 TensorScalar 互推导关系且推导出的数据类型必须能转换为out的数据类型other、out均支持空 Tensorout的 shape 需要与other一致若为 TensorTensor 变体则self、other的 shape 需满足 broadcast 关系out的 shape 为两者 broadcast 之后的 shape支持非连续 Tensor数据格式仅支持 ND维度数不支持 8 维以上在Atlas 训练系列产品910上不支持 BFLOAT16 数据类型接口文档。4.5 第一段接口的返回值与错误码第一段接口完成入参校验出现以下场景时报错错误码体系见 aclnn_return_code.md返回值错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的 self、other、out 是空指针ACLNN_ERR_PARAM_INVALID161002other、out 的 shape 不一样ACLNN_ERR_PARAM_INVALID161002self 和 other 无法做数据类型推导ACLNN_ERR_PARAM_INVALID161002self 和 other 推导出的数据类型不属于支持的数据类型ACLNN_ERR_PARAM_INVALID161002self 和 other 推导出的数据类型无法转换为指定输出 out 的类型ACLNN_ERR_PARAM_INVALID161002other、out 的维度数大于 8 维第二段执行接口aclnnRemainderScalarTensor的入参为workspaceDevice 侧申请的 workspace 内存地址、workspaceSize由第一段接口获取、executorop 执行器、stream指定执行任务的 Stream返回aclnnStatus状态码。五、完整调用示例aclnnRemainderScalarTensor以下示例代码取自 aclnnRemainderScalarTensor 接口文档演示了“标量 self 对张量 other 求余”的完整调用流程设备初始化 → 构造输入输出 → 两段式接口调用 → 同步等待 → 取回结果 → 资源释放。编译与运行的具体工程步骤请参考编译与运行样例。#include iostream #include vector #include acl/acl.h #include aclnnop/aclnn_remainder.h #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::vectorint64_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); aclFinalize(); return ret); ret aclrtCreateStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtCreateStream failed. ERROR: %d\n, ret); aclrtResetDevice(deviceId); aclFinalize(); return ret); return 0; } template typename T int CreateAclTensor(const std::vectorT hostData, const std::vectorint64_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的strides std::vectorint64_t strides(shape.size(), 1); for (int64_t i shape.size() - 2; i 0; i--) { strides[i] shape[i 1] * strides[i 1]; } // 调用aclCreateTensor接口创建aclTensor *tensor aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } int main() { // 1.固定写法device/stream初始化参考acl API手册 // 根据自己的实际device填写deviceId 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. 构造输入与输出需要根据API的接口自定义构造 std::vectorint64_t otherShape {3, 3}; std::vectorint64_t outShape {3, 3}; void* otherDeviceAddr nullptr; void* outDeviceAddr nullptr; aclScalar* self nullptr; aclTensor* other nullptr; aclTensor* out nullptr; std::vectorint64_t otherHostData {0, 1, 2, 3, 4, 5, 6, 7, 8}; std::vectorint64_t outHostData {0, 0, 0, 0, 0, 0, 0, 0, 0}; int64_t Self 3; // 创建self aclScalar self aclCreateScalar(Self, aclDataType::ACL_INT64); CHECK_RET(self ! nullptr, return ret); // 创建other aclTensor ret CreateAclTensor(otherHostData, otherShape, otherDeviceAddr, aclDataType::ACL_INT64, other); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建out aclTensor ret CreateAclTensor(outHostData, outShape, outDeviceAddr, aclDataType::ACL_INT64, out); CHECK_RET(ret ACL_SUCCESS, return ret); // 3. 调用CANN算子库API需要修改为具体的API名称 uint64_t workspaceSize 0; aclOpExecutor* executor; // 调用aclnnRemainderScalarTensor第一段接口 ret aclnnRemainderScalarTensorGetWorkspaceSize(self, other, out, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnRemainderScalarTensorGetWorkspaceSize failed. ERROR: %d\n, ret); return ret); // 根据第一段接口计算出的workspaceSize申请device内存 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); } // 调用aclnnRemainderScalarTensor第二段接口 ret aclnnRemainderScalarTensor(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnRemainderScalarTensor failed. ERROR: %d\n, ret); return ret); // 4.固定写法同步等待任务执行结束 ret aclrtSynchronizeStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSynchronizeStream failed. ERROR: %d\n, ret); return ret); // 5. 获取输出的值将device侧内存上的结果拷贝至host侧 auto size GetShapeSize(outShape); std::vectorint64_t resultData(size, 0); ret aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_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(result[%ld] is: %ld\n, i, resultData[i]); } // 6. 释放aclTensor和aclScalar aclDestroyScalar(self); aclDestroyTensor(other); aclDestroyTensor(out); // 7. 释放device资源 aclrtFree(otherDeviceAddr); aclrtFree(outDeviceAddr); if (workspaceSize 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }示例中other [[0..8]]、self 3输出结果将逐元素等于3 % other[i]按 floor 语义。若业务需要“张量对张量”或“原地写回”语义仅需将 API 替换为aclnnRemainderTensorTensor/aclnnInplaceRemainderTensorTensor等对应变体调用骨架完全一致。六、约束与注意事项综合 aclnnRemainderScalarTensor 接口文档 与算子原型注释使用 FloorMod 时需注意确定性计算aclnnRemainderScalarTensor默认是确定性实现关于确定性计算的通用约定可参考 determinism_compute.mdINT32 精度范围当self的数据类型为 INT32 时优先保障范围[-2^24, 2^24]内的功能与精度整型除零行为当other为 0 且self的数据类型为整型时out的结果为self原型注释中则表述为“x2 不支持 0”两者结合看即整型除零时返回被除数以规避未定义行为元素数量限制shape 各维度乘积D1*D2*…*DN ≤ 1000000且n ≤ 8数值范围当张量元素值超过 2048 时算子在 mini 平台上的精度无法保证达到双千分位要求跨架构差异由于架构不同该算子在 NPU 与 CPU 上的计算结果可能不一致。七、源码级实现原理7.1 算子原型注册op_graphfloor_mod_proto.h 通过REG_OP(FloorMod)完成算子原型的静态注册声明输入x1、x2与输出y三者均支持DT_INT32, DT_INT64, DT_FLOAT, DT_FLOAT16, DT_DOUBLE, DT_BF16六种类型语义注释中明确了“Integer division by zero on NPU returns x1”以及“Support broadcasting operations”。7.2 Host 侧算子定义与推导op_hostfloor_mod_def.cpp 通过OpDef注册了算子描述AICore 配置同时注册ascend950与ascend350两个平台并开启DynamicCompileStaticFlag、DynamicRankSupportFlag、DynamicShapeSupportFlag关闭DynamicFormatFlag同时设置PrecisionReduceFlag(true)允许精度降低以换取性能并指定 kernel 实现文件floor_mod_apt。floor_mod_infershape.cpp 通过IMPL_OP_INFERSHAPE(FloorMod).InferShape(Ops::Base::InferShape4Broadcast)直接复用公共的 broadcast 形状推导逻辑从实现层面印证了该算子对输入 shape 的广播语义。7.3 Tiling 实现arch35floor_mod_tiling_arch35.cpp 完成了算子的任务切分TilingCheckDtype校验x1、x2、y三者数据类型必须一致针对不同输入类型选择不同的广播算子 DAGFLOAT16/BF16 使用FloorModFloatWithCastOphalf、FLOAT 使用FloorModFloatOpfloat、INT32 使用FloorModInt32Opint32_t、INT64 使用FloorModInt64Opint64_t统一通过BroadcastBaseTilingKERNEL_TYPE_NDDMA模式完成切分并将调度模式写入tilingKey关键的资源规划细节由于 Kernel 中所有输入类型都会先 cast 到 float32 再进入高阶 API 计算临时 buffer 按 float 大小估算GetFmodTmpBufferFactorSize(sizeof(float), ...)INT32/INT64 路径额外追加DCACHE_SIZE32KB的 workspacePostTiling中还会将 UB 大小扣减 32KB 后再写入上下文。7.4 Kernel 计算逻辑op_kernelfloor_mod_apt.cpp 是 kernel 入口按模板参数DTYPE_X1在编译期分派半精度/BF16 走FloorModFloatWithCastOp、FLOAT 走FloorModFloatOp、INT32 走FloorModInt32Op、INT64 走FloorModInt64Op统一用BroadcastSch调度器调用sch.Process(x1, x2, y)。floor_mod_dag.h 给出了核心计算 DAG浮点路径先调用向量高阶 APIVec::FmodHighPrecision得到截断余数truncated remainder随后由FmodPostCompute/FmodCastFloatPostCompute做符号校正后处理——当fmodRes与除数inputX2的符号不同且fmodRes ! 0时将结果加上除数inputX2这正是把“向零截断余数”转换为“向下取整余数”的关键一步与本文第一节的数学公式self - floor(self/other)*other完全等价半精度/BF16 路径FloorModFloatWithCastOp先经Vec::Castfloat, T将输入提升到 float 精度计算避免低精度中间结果损失输出前再 cast 回原类型整型路径FloorModInt通过 SIMT 向量函数FloorModInt_1asc_vf_call启动 1024 线程逐元素执行src1 % src2并做同样的“符号不同且余数非零则加除数”校正FmodIntPostCompute还处理了-1除数的边界情况。7.5 API 分派逻辑op_apifloor_mod.cpp 展示了 l0op 层的分派策略AICPU_DTYPE_SUPPORT_LIST {op::DataType::DT_DOUBLE}即 DOUBLE 类型走 AICPU 实现FloorModAiCpu对应 TF-AICPU 路径其余类型INT32、INT64、FLOAT16、FLOAT、BFLOAT16走 AICore 实现FloorModAiCoreFloorMod顶层函数先通过BroadcastInferShape计算广播后的输出 shape再用executor-AllocTensor分配输出张量最后按数据类型分派到 AICore 或 AICPU。八、测试与验证仓库为该算子配备了完整的测试资产可用于验证实现正确性Kernel 基准goldengolden.py 以 PyTorch 的torch.remainder作为参考实现对 INT32/INT64/FLOAT/FLOAT16/BFLOAT16 全类型生成期望输出并实现了除零保护整型除零位置置-1、浮点除零位置置NaN同时通过 numpy 与 torch 之间的 bfloat16 视图转换处理 BF16 数据UT 用例API 层单测见 tests/ut/op_api如test_aclnn_remainder_scalar_tensor.cpp、test_remainder_tensor_tensor.cpp、inplace 系列Host 层单测包括 shape 推导 test_floor_mod_infershape.cpp 与 arch35 Tiling 单测 test_floor_mod_tiling.cppST 用例aclnn 系列接口的系统测试配置见 tests/st/aclnnRemainderScalarTensor/atk_aclnnRemainderScalarTensor.json 等arch35 平台 kernel 级 ST 用例见 ttk_kernel_floor_mod_st.csv。九、总结FloorMod 是 CANN ops-math 中语义明确、实现精巧的数学基础算子它在数学上等价于self - floor(self/other)*other结果与被除数同符号在接口上通过 aclnnRemainder 系列六种变体覆盖标量/张量、新建输出/原地写回等全部常见调用形态在实现上采用“fmod/%截断求余 符号校正”的两步法配合 Broadcast 调度框架在 NPU 上完成高效并行计算。开发者在使用时只需按两段式接口模型完成 workspace 申请与 executor 下发即可将向下取整求余能力无缝接入 Atlas 系列产品上的模型计算图。赞分享算子库人工智能CANN【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-math点击查看免费下载相关推荐CANN ops-math FloorMod 算子全解析向下取整取模的数学语义、aclnn 调用与 AscendC 内核实现CANN ops math FloorMod 算子全解析向下取整取模的数学语义、aclnn 调用与 AscendC 内核实现 FloorMod 是 CANN算子库人工智能CANNCANN ops-math 数学算子库 AsStrided 算子详解PyTorch as_strided 语义的 NPU 实现与 aclnn 调用指南CANN ops math 数学算子库 AsStrided 算子详解PyTorch as_strided 语义的 NPU 实现与 aclnn 调用指南 导读算子库人工智能CANNCANN ops-math 余弦算子 Cos 深度解析算子定义、NPU 核函数实现与 aclnn API 调用实战CANN ops math 余弦算子 Cos 深度解析算子定义、NPU 核函数实现与 aclnn API 调用实战 CANN ops math 是 CANN算子库人工智能CANN上一篇MinerU PDF 解析使用指南从一条命令到 3 种部署模式下一篇如何用Python实现Windows微信自动群发3倍效率提升的实用方案创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询