CANN ops-math 算子 aclnnAffineGrid 使用指南:仿射网格生成的两段式接口详解 📅 发布时间:2026/9/20 5:11:20 👁 浏览次数: CANN ops-math 算子 aclnnAffineGrid 使用指南仿射网格生成的两段式接口详解【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-mathaclnnAffineGrid是 CANN ops-math 数学算子库math/affine_grid提供的仿射网格生成算子给定一组 3 维仿射参数矩阵 theta 与输出图像尺寸 size为仿射变换后的图像生成 2D 或 3D 采样网格grid网格中的每个坐标即变换后图像上的点在原图像上的坐标。该算子是空间变换网络STN、图像几何变换等场景的基础组件。本文将以仓库中的 aclnnAffineGrid.md 为核心结合算子源码与示例完整讲解其产品支持情况、函数原型、参数语义、异常返回码、约束限制以及可编译运行的调用示例。产品支持情况在调用算子前需先确认目标昇腾硬件是否支持该算子。根据 aclnnAffineGrid.md 的产品支持说明各产品线的支持情况如下产品系列支持情况Ascend 950PR / Ascend 950DT不支持Atlas A3 训练系列产品 / Atlas A3 推理系列产品支持Atlas A2 训练系列产品 / Atlas A2 推理系列产品支持Atlas 200I/500 A2 推理产品不支持Atlas 推理系列产品不支持Atlas 训练系列产品支持需要注意在 Atlas 训练系列产品即 910 系列上theta 与 out 的数据类型不支持 BFLOAT16仅支持 FLOAT 与 FLOAT16。这一约束在 aclnn_affine_grid.cpp 中也有对应体现源码针对 910 与 910B 分别维护了ASCEND910_DTYPE_SUPPORT_LISTFLOAT、FLOAT16和ASCEND910B_DTYPE_SUPPORT_LISTFLOAT、FLOAT16、BF16两套支持列表运行时根据GetCurrentPlatformInfo().GetSocVersion()判断当前芯片所属平台并选用相应的校验列表。功能说明给定一组 3 维的仿射参数矩阵 theta 以及输出图像的大小 size该算子生成一个 2D 或 3D 的网格该网格表示仿射后图像的点在原图像上的坐标。当 size 为 4 维N, C, H, W时theta 为 (N, 2, 3) 的 2D 仿射矩阵生成 (N, H, W, 2) 的 2D 网格当 size 为 5 维N, C, D, H, W时theta 为 (N, 3, 4) 的 3D 仿射矩阵生成 (N, D, H, W, 3) 的 3D 网格。theta 矩阵控制仿射变换过程中的旋转、缩放以及平移网格的每个元素是归一化后的采样坐标可直接用于后续的 grid_sample 类采样算子。仓库的 ST 测试用例 executor_aclnnAffineGrid.py 将该算子与 PyTorch 的torch.affine_grid_generator对齐内部先转 float32 计算再转回原 dtype用例配置 atk_aclnnAffineGrid.json 覆盖了 fp16 / bf16 / fp32 三种数据类型、2D/3D 两种分支以及多种 batchN 最大取到 257的边界场景可据此理解算子行为与数值口径。函数原型两段式接口与 CANN 算子库其他 aclnn 算子一致aclnnAffineGrid 采用两段式接口设计详见 两段式接口说明必须先调用aclnnAffineGridGetWorkspaceSize获取入参并根据计算流程算出所需的 workspace 大小再调用aclnnAffineGrid执行实际计算。第一段接口计算 workspace 大小与构建执行器aclnnStatus aclnnAffineGridGetWorkspaceSize( const aclTensor* theta, const aclIntArray* size, bool alignCorners, aclTensor* out, uint64_t* workspaceSize, aclOpExecutor** executor)第二段接口执行计算aclnnStatus aclnnAffineGrid( void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream)从头文件 aclnn_affine_grid.h 可以看到两个接口均以ACLNN_API导出第一段接口domain aclnn_ops_infer第二段接口内部通过框架的CommonOpExecutorRun完成真正的任务下发见 aclnn_affine_grid.cpp。aclnnAffineGridGetWorkspaceSize 参数说明第一段接口的参数语义与约束如下参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续Tensortheta (aclTensor*)输入仿射变换参数控制仿射变换过程中的旋转、缩放以及平移-FLOAT、FLOAT16、BFLOAT16ND(N, 2, 3) 或 (N, 3, 4)√size (aclIntArray*)输入输出图像的 size---(N, C, H, W) 或 (N, C, D, H, W)-alignCorners (bool)输入表示是否角像素点对齐为 True 时输出网格的角落像素与输入网格的角落像素对齐为 False 时输出网格的中心像素与输入网格的中心像素对齐默认为 False----out (aclTensor*)输出表示仿射后图像在原图像上的坐标-与 theta 一致ND2D: (N, H, W, 2)3D: (N, D, H, W, 3)√workspaceSize (uint64_t*)输出返回需要在 Device 侧申请的 workspace 大小-----executor (aclOpExecutor**)输出返回 op 执行器包含了算子计算流程-----补充说明theta / out 支持非连续 Tensor从源码看第一段接口在参数校验后会先调用l0op::Contiguous将 theta 转为连续 tensor 再送入计算aclnn_affine_grid.cpp计算完成后通过l0op::ViewCopy将结果写回可能非连续的 out同文件 L184因此调用方无需手动做连续化相关概念可参考 非连续Tensor说明。size 为 host 侧数据底层会通过executor-ConvertToTensor(size, DataType::DT_INT32)将其转换为 Int32 tensor 参与计算affine_grid.cpp。若 theta 的存储格式为 FRACTAL_NZ框架会打印告警日志提示不支持该格式见CheckFormat实现aclnn_affine_grid.cpp。返回值与异常场景两段接口均返回aclnnStatus状态码具体含义参见 aclnn返回码。第一段接口会完成入参校验以下场景将报错返回值错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的 theta、size 或 out 是空指针ACLNN_ERR_PARAM_INVALID161002theta 的数据类型不在支持的范围之内ACLNN_ERR_PARAM_INVALID161002out 与 theta 的数据类型不一致ACLNN_ERR_PARAM_INVALID161002theta 的维度不是 3ACLNN_ERR_PARAM_INVALID161002size 数组的大小不是 4 或者 5ACLNN_ERR_PARAM_INVALID161002size 的大小是 4 时theta 的 shape 不是 (N, 2, 3)size 的大小是 5 时theta 的 shape 不是 (N, 3, 4)ACLNN_ERR_PARAM_INVALID161002size 的大小是 4 时out 的 shape 不是 (N, H, W, 2)size 的大小是 5 时out 的 shape 不是 (N, D, H, W, 3)这些校验与源码中的CheckParams流程一一对应先做空指针检查CheckNotNull再检查数据类型与一致性CheckDtypeValid最后检查维度与 shapeCheckShape见 aclnn_affine_grid.cpp。此外CheckShape中还会对 theta 为空 tensortheta-IsEmpty()的情况直接报ACLNN_ERR_PARAM_INVALID。aclnnAffineGrid 参数说明第二段接口的参数语义如下参数名输入/输出描述workspace输入在 Device 侧申请的 workspace 内存地址workspaceSize输入在 Device 侧申请的 workspace 大小由第一段接口 aclnnAffineGridGetWorkspaceSize 获取executor输入op 执行器包含了算子计算流程stream输入指定执行任务的 Stream返回值同样为aclnnStatus状态码参见 aclnn返回码。约束说明使用 aclnnAffineGrid 时需遵守以下约束确定性计算aclnnAffineGrid 默认采用确定性实现即相同输入在多次执行中结果一致相关背景可参考 确定性计算说明。size 取值区间size 中的 N、H、W 的取值必须在 (0, 100000] 范围内。ST 用例中的 size 参数均在 1~100 区间内取值如 atk_aclnnAffineGrid.json 中 N 从 1 到 257 变化也从侧面印证了这一约束边界。调用示例下面是一个完整的可运行示例演示从 AscendCL 初始化、构造输入输出、两段式调用到结果回读与资源释放的完整流程。该示例与仓库 examples/test_aclnn_affine_grid.cpp 逻辑一致示例中额外使用了 RAII 智能指针管理资源这里为便于理解展开为显式流程具体编译和执行过程请参考 编译与运行样例。#include iostream #include vector #include acl/acl.h #include aclnnop/aclnn_affine_grid.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 shape_size 1; for (auto i : shape) { shape_size * i; } return shape_size; } 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::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根据自己的需要处理 CHECK_RET(ret 0, LOG_PRINT(Init acl failed. ERROR: %d\n, ret); return ret); // 2. 构造输入与输出需要根据API的接口自定义构造 // 本例演示2D场景theta为(N,2,3){1,2,3}size为(N,C,H,W){1,1,2,3}out为(N,H,W,2){1,2,3,2} std::vectorint64_t thetaShape {1, 2, 3}; std::vectorint64_t outShape {1, 2, 3, 2}; void* thetaDeviceAddr nullptr; void* outDeviceAddr nullptr; aclTensor* theta nullptr; aclTensor* out nullptr; std::vectorfloat thetaHostData {0, 1, 2, 3, 4, 5}; std::vectorfloat outHostData {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}; std::vectorint64_t sizeData {1, 1, 2, 3}; bool alignCorners false; // 创建theta aclTensor ret CreateAclTensor(thetaHostData, thetaShape, thetaDeviceAddr, aclDataType::ACL_FLOAT, theta); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建size aclIntArray aclIntArray *size aclCreateIntArray(sizeData.data(), sizeData.size()); // 创建out aclTensor ret CreateAclTensor(outHostData, outShape, outDeviceAddr, aclDataType::ACL_FLOAT, out); CHECK_RET(ret ACL_SUCCESS, return ret); // 3. 调用CANN算子库API需要修改为具体的API uint64_t workspaceSize 0; aclOpExecutor* executor; // 调用aclnnAffineGrid第一段接口 ret aclnnAffineGridGetWorkspaceSize(theta, size, alignCorners, out, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnAffineGridGetWorkspaceSize 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;); } // 调用aclnnAffineGrid第二段接口 ret aclnnAffineGrid(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnAffineGrid 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侧需要根据具体API的接口定义修改 auto length GetShapeSize(outShape); std::vectorfloat resultData(length, 0); ret aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, length * 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 length; i) { LOG_PRINT(result[%ld] is: %f\n, i, resultData[i]); } // 6. 释放aclTensor需要根据具体API的接口定义修改 aclDestroyTensor(theta); aclDestroyIntArray(size); aclDestroyTensor(out); // 7. 释放device资源需要根据具体API的接口定义修改 aclrtFree(thetaDeviceAddr); aclrtFree(outDeviceAddr); if (workspaceSize 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }示例要点解析构造 aclTensorCreateAclTensor中先按元素个数 × 类型大小计算字节数用aclrtMalloc申请 Device 内存aclrtMemcpy拷入数据再从后往前累乘计算连续 Tensor 的 strides最终用aclCreateTensorACL_FORMAT_ND格式创建 Tensor。创建size则使用aclCreateIntArray。两段式调用顺序第一段aclnnAffineGridGetWorkspaceSize完成参数校验并返回workspaceSize与executor随后仅在workspaceSize 0时申请 workspace第二段aclnnAffineGrid传入 workspace、executor 与 stream 执行计算。若跳过第一段直接调用第二段将无法获知 workspace 大小。结果回读与资源释放任务通过aclrtSynchronizeStream同步后用aclrtMemcpyDEVICE_TO_HOST回读结果最后依次释放 aclTensor、aclIntArray、Device 内存与 stream并aclrtResetDevice、aclFinalize收尾。若需要验证 3D 场景可将thetaShape改为 {1, 3, 4}、outShape改为 {1, D, H, W, 3}sizeData改为 {1, C, D, H, W} 五元组即可。底层实现路径速览从源码结构看aclnnAffineGrid 的计算流程可概括为参数校验空指针 → 数据类型 → shape→ theta 连续化Contiguous→ 下发 AICPU 算子任务ADD_TO_LAUNCHER_LIST_AICPU算子名 AffineGrid属性align_corners→ 结果 reshape 为目标维度(N,H,W,2) 或 (N,D,H,W,3)→ ViewCopy 写回 out关键代码位于 aclnn_affine_grid.cpp 与 affine_grid.cpp。该算子为 AICPU 实现无需开发者编写 kernel中间结果的 shape 由AffineGrid内部按 size 推导2D 时为 (N, H×W, 2)3D 时为 (N, D×H×W, 3)再经l0op::Reshape还原为带 H/W/D 的维度布局。结合 executor_aclnnAffineGrid.py 的 torch 对照实现与 atk_aclnnAffineGrid.json 的用例矩阵开发者可以清晰对齐算子行为并据此构造自己的验证用例。【免费下载链接】ops-math本项目是CANN提供的数学类基础计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-math创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考