news 2026/9/18 14:05:30

CANN ops-cv 算子深度解析:UpsampleBicubic2dAAGrad 双三次抗锯齿上采样反向传播算子使用指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
CANN ops-cv 算子深度解析:UpsampleBicubic2dAAGrad 双三次抗锯齿上采样反向传播算子使用指南

CANN ops-cv 算子深度解析:UpsampleBicubic2dAAGrad 双三次抗锯齿上采样反向传播算子使用指南

【免费下载链接】ops-cv本项目是CANN提供的图像处理、目标检测相关的算子库,实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-cv

导读

UpsampleBicubic2dAAGrad是 CANN ops-cv 图像算子库中双三次抗锯齿(Bicubic with Anti-Aliasing)上采样算子UpsampleBicubic2dAA的反向传播(Gradient)算子,用于在 NPU 上完成上采样梯度回传,是训练场景下图像缩放链路的关键一环。本文以 image/upsample_bicubic2d_aa_grad/README.md 为主体,结合仓库内 aclnn 接口文档、调用示例与算子源码,完整讲解其计算公式、参数语义、约束条件、两段式 aclnn 调用流程以及 Host 侧 Tiling 与 Kernel 侧的底层实现。读完本文,你将能够正确理解该算子的梯度传播原理,并通过aclnnUpsampleBicubic2dAAGrad接口在 Ascend 平台上完成反向计算的调用与验证。

一、产品支持情况

根据 image/upsample_bicubic2d_aa_grad/README.md 与 aclnnUpsampleBicubic2dAAGrad 接口文档,该算子在不同硬件平台上的支持情况如下:

产品是否支持
Ascend 950PR / Ascend 950DT
Atlas A3 训练系列产品 / Atlas A3 推理系列产品
Atlas A2 训练系列产品 / Atlas A2 推理系列产品
Atlas 200I/500 A2 推理产品×
Atlas 推理系列产品×
Atlas 训练系列产品×

从源码的算子注册配置也可以印证这一点。在 upsample_bicubic2d_aa_grad_def.cpp 中,通过AICore().AddConfig("ascend910b")AddConfig("ascend910_93")(对应 Atlas A2/A3 系列)以及带DynamicCompileStaticFlagDynamicRankSupportFlagDynamicShapeSupportFlagascend950配置注册了 AICore 算子实现,而 op_host/config 下也仅存在ascend910_93ascend910bascend950三套编译配置目录,与文档中"三种产品支持、三种产品不支持"的结论完全对应。需要特别说明的是,与正向算子 UpsampleBicubic2dAA 相比,该反向算子不支持 Kirin X90 / Kirin 9030 处理器系列

二、功能说明与计算原理

2.1 算子定位:双三次抗锯齿上采样的反向传播

UpsampleBicubic2dAAGrad是 UpsampleBicubic2dAA(仓库内路径为 image/upsample_bicubic2d_aa/README.md)的反向传播算子。若输入张量gradOutput的 shape 为(N, C, H, W),则输出张量gradInput的 shape 为(N, C, inputSize[2], inputSize[3]),即反向把 H、W 维度恢复为前向输入的空间尺寸。

2.2 计算公式

对于一个二维插值点(N, C, h, w),其反向梯度gradInput(N, C, h, w)的计算公式为:

$$ {gradInput(N, C, h, w)}=\sum_{i=0}^{3}\sum_{j=0}^{3}{W(i, j)}*{f(h_i, w_j)} $$

其中:

  • ij是权重W(i, j)的索引变量;
  • f(h_i, w_j)gradOutput(h_i, w_j)处的像素值;
  • W(i, j)是双三次抗锯齿插值的权重函数。

2.3 缩放比例 scaleH / scaleW

正向与反向计算共享同一套缩放比例定义,scaleHscaleWalignCornersscalesH/scalesW联合决定:

$$ scaleH =\begin{cases} (inputSize[2]-1) / (outputSize[0]-1) & alignCorners=true \ 1 / scalesH & alignCorners=false\ &\ scalesH>0\ inputSize[2] / outputSize[0] & otherwise \end{cases} $$

$$ scaleW =\begin{cases} (inputSize[3]-1) / (outputSize[1]-1) & alignCorners=true \ 1 / scalesW & alignCorners=false\ &\ scalesW>0\ inputSize[3] / outputSize[1] & otherwise \end{cases} $$

这里需要注意两点:

  1. alignCorners 的语义alignCornerstrue表示输入和输出张量的角像素点对齐(缩放比例基于"尺寸减一"计算);为false表示输入和输出张量的边像素点对齐(缩放比例基于原始尺寸计算)。这一语义与 PyTorch 中F.interpolatealign_corners参数一致。
  2. 反向算子的缩放比例是倒数关系:在 aclnn_upsample_bicubic2d_aa_grad.cpp 中,ComputeBicubic2dAABackwardScales函数实现了1.0 / scale(当scale > 0时)的换算逻辑;若scale未指定(≤ 0),则退化为input_size / output_size的尺寸比值。反向缩放比例越小,意味着前向上采样倍数越大。

2.4 权重函数 W(d)

双三次抗锯齿插值的权重函数使用经典的a = -0.5三次样条核:

$$ W(d) =\begin{cases} (a+2)|d|^3-(a+3)|d|^2+1 & |d|\leq1 \ a|d|^3-5a|d|^2+8a|d|-4a & 1<|d|<2 \ 0 & otherwise \end{cases} $$

其中:

  • $a=-0.5$(抗锯齿场景下的标准取值,对应三次样条核的 Catmull-Rom 变体);
  • $d = |(h, w) - (h_i, w_j)|$,即插值点与采样点之间的距离。

a = -0.5与正向算子 UpsampleBicubic2dAA README 中的权重定义完全一致,确保了前反向计算的一致性。从权重公式可以看出,每个输出像素的反向梯度由周围至多 4×4 邻域内的梯度像素加权累加得到,这与正向计算中每个输出点对 4×4 邻域采样点加权求和是对偶的。

三、参数说明

以下参数表格来自 image/upsample_bicubic2d_aa_grad/README.md 的"参数说明"章节,并结合 aclnnUpsampleBicubic2dAAGrad 接口文档 中的接口语义做了补充:

参数名输入/输出/属性描述数据类型数据格式
grad_output输入表示反向计算的梯度 Tensor,对应公式中的gradOutput。数据类型与输出grad_input一致FLOAT32、FLOAT16、BFLOAT16ND
output_size属性表示输入grad_output在 H 和 W 维度上的空间大小,对应公式中的outputSize。size 为 2,且各元素均大于零INT64-
input_size属性表示输出grad_input分别在 N、C、H 和 W 维度上的空间大小,对应公式中的inputSize。size 为 4,且各元素均大于零INT64-
align_corners可选属性决定是否对齐角像素点,对应公式中的alignCorners。为true时输入和输出张量的角像素点被对齐,否则不对齐。默认值为falseBOOL-
scales_h可选属性表示输出grad_input的 height 维度乘数,对应公式中的scalesH。默认值为空FLOAT32-
scales_w可选属性表示输出grad_input的 width 维度乘数,对应公式中的scalesW。默认值为空FLOAT32-
grad_input输出表示反向计算的输出张量,对应公式中的gradInput。数据类型与输入grad_output一致FLOAT32、FLOAT16、BFLOAT16ND

在 aclnn 接口层面,上述属性会以入参形式出现在函数签名中:outputSizeinputSize封装为aclIntArrayalignCornersboolscalesH/scalesWdouble(详见 aclnn_upsample_bicubic2d_aa_grad.h)。算子定义文件 upsample_bicubic2d_aa_grad_def.cpp 中的注册信息与文档一致:grad_output/grad_input支持DT_FLOAT16DT_FLOATDT_BF16三种数据类型,格式为 ND;output_sizeinput_size为必选ListInt属性;align_corners为可选 BOOL 属性(默认false);scales_hscales_w为可选 Float 属性。

数据格式说明:当数据格式为 ND 时,默认按照 NCHW 格式处理;接口层面也接受显式的 NCHW 格式(ACL_FORMAT_NCHW)。

四、约束说明

4.1 算子级约束

image/upsample_bicubic2d_aa_grad/README.md 中标注算子本身"无"额外约束,但接口文档在更细的粒度上给出了如下限制,这些约束在调用时同样必须满足:

shape 与内存约束(适用于全部支持产品):

  • gradOutputout每个维度的取值小于等于2^20
  • 参数out的 N 轴和 C 轴与gradOutput保持一致;
  • 内存占用需满足:

$$ (gradOutput_H \times gradOutput_W + out_H \times out_W + gradOutput_H \times out_W) \times N \times C \times sizeof(dtype) < 60 \times 1024 \times 1024 \times 1024 $$

其中NC为输入输出张量的 N、C 轴大小,dtype为输入张量的数据类型;

  • 额外要求 $N \times C \times gradOutput_H < 2^{31}$。

缩放比例一致性约束:参数inputSizeoutputSizescalesHscalesW需要满足:

$$ outputSize_H = floor(inputSize_H \times scalesH) $$

$$ outputSize_W = floor(inputSize_W \times scalesW) $$

Atlas A2/A3 系列缩小倍数约束:反向接口的输入数据缩小倍数必须小于等于 50:

$$ outputSize_H / 输出shape的高度H \le 50 $$

$$ outputSize_W / 输出shape的宽度W \le 50 $$

这一约束与 Host 侧参数校验代码中MIN_SUPPORT_SCALE = 0.02(即最小支持缩放比例,aclnn_upsample_bicubic2d_aa_grad.cpp)的检查相互呼应:反向缩放比例不能过小,否则会触发ACLNN_ERR_PARAM_INVALID错误。

4.2 确定性计算

  • Atlas A3 / Atlas A2 系列:aclnnUpsampleBicubic2dAAGrad默认使用确定性实现
  • Ascend 950PR / Ascend 950DT:默认使用非确定性实现,支持通过aclrtCtxSetSysParamOpt开启确定性计算。

关于确定性计算的更多背景可参考 docs/zh/context/determinism_compute.md。

五、调用方式:两段式 aclnn 接口

5.1 两段式接口总览

该算子遵循 CANN 算子库统一的两段式接口调用规范:必须先调用aclnnUpsampleBicubic2dAAGradGetWorkspaceSize接口获取计算所需 workspace 大小以及包含算子计算流程的执行器,再调用aclnnUpsampleBicubic2dAAGrad接口执行计算

第一段接口的函数原型:

aclnnStatus aclnnUpsampleBicubic2dAAGradGetWorkspaceSize( const aclTensor *gradOutput, const aclIntArray *outputSize, const aclIntArray *inputSize, bool alignCorners, double scalesH, double scalesW, aclTensor *out, uint64_t *workspaceSize, aclOpExecutor **executor)

第二段接口的函数原型:

aclnnStatus aclnnUpsampleBicubic2dAAGrad( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)

两个接口均返回aclnnStatus状态码,具体取值参见 aclnn 返回码。

5.2 第一段接口参数详解

参数名输入/输出描述使用说明数据类型数据格式shape非连续 Tensor
gradOutput(aclTensor*)输入反向计算的梯度 Tensor,对应gradOutput不支持空 Tensor;ND 格式下默认按 NCHW 处理FLOAT32、FLOAT16、BFLOAT16NCHW、ND4
outputSize(aclIntArray*)输入gradOutput在 H、W 维的空间大小size 为 2,各元素大于零INT64---
inputSize(aclIntArray*)输入输出out在 N、C、H、W 维的空间大小size 为 4,各元素大于零INT64---
alignCorners(bool)输入是否对齐角像素点true对齐,否则不对齐----
scalesH(double)输入输出out的 height 维度乘数不能传入负值----
scalesW(double)输入输出out的 width 维度乘数不能传入负值----
out(aclTensor*)输出反向计算的输出张量,对应gradInput不支持空 Tensor;数据类型与格式与gradOutput保持一致FLOAT32、FLOAT16、BFLOAT16NCHW、ND4
workspaceSize(uint64_t*)输出返回需要在 Device 侧申请的 workspace 大小-----
executor(aclOpExecutor**)输出返回 op 执行器,包含算子计算流程-----

第一段接口的常见报错场景(返回码与错误码参见 aclnn 返回码):

返回码错误码描述
ACLNN_ERR_PARAM_NULLPTR161001传入的 gradOutput、inputSize 或 out 是空指针
ACLNN_ERR_PARAM_INVALID161002gradOutput 或 out 的数据类型不在支持范围内;gradOutput 与 out 数据类型不一致;gradOutput 的 shape 不是 4 维;inputSize 的 H 维或 W 维取值小于 1;inputSize 的 size 不为 4;outputSize 的 size 不为 2;scalesH 或 scalesW 为负值

这些校验逻辑都可以在源码 aclnn_upsample_bicubic2d_aa_grad.cpp 中逐一对号入座:CheckNotNull负责空指针检查、CheckDtypeValid负责数据类型与一致性检查、CheckShape负责维度与 size 检查、CheckScalesValid负责负数检查、CheckInputElement负责元素非零与格式检查。

5.3 第二段接口参数详解

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

六、完整调用示例

仓库在 examples/test_aclnn_upsample_bicubic2d_aa_grad.cpp 提供了完整的可直接参考的调用样例。完整代码框架如下(编译与执行步骤请参考 编译与运行样例):

#include <iostream> #include <vector> #include "acl/acl.h" #include "aclnnop/aclnn_upsample_bicubic2d_aa_grad.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::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 CreateAclNchTensor(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的strides std::vector<int64_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_NCHW, shape.data(), shape.size(), *deviceAddr); return 0; } int main() { // 1. (固定写法)device/stream初始化,参考acl API手册 int32_t deviceId = 0; // 根据自己的实际device填写 aclrtStream stream; auto ret = Init(deviceId, &stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); // 2. 构造输入与输出,需要根据API的接口自定义构造 std::vector<int64_t> inputShape = {1, 1, 4, 2}; // gradOutput shape: NCHW std::vector<int64_t> outShape = {1, 1, 8, 4}; // gradInput shape: NCHW void* inputDeviceAddr = nullptr; void* outDeviceAddr = nullptr; aclTensor* input = nullptr; aclTensor* out = nullptr; std::vector<float> inputHostData = {0, 1, 2, 3, 4, 5, 6, 7}; const size_t kSize32 = 32U; std::vector<float> outHostData(kSize32, 0); const size_t kSize4 = 4U; std::vector<int64_t> outputSize = {kSize4, 2}; // gradOutput的H、W std::vector<int64_t> inputSize = {1, 1, 8, 4}; // gradInput的N、C、H、W bool alignCorners = true; double scalesH = 0.5; double scalesW = 0.5; // 创建input aclTensor ret = CreateAclNchTensor(inputHostData, inputShape, &inputDeviceAddr, aclDataType::ACL_FLOAT, &input); CHECK_RET(ret == ACL_SUCCESS, return ret); // 创建input aclIntArray auto outputSizeArray = aclCreateIntArray(outputSize.data(), 2); auto inputSizeArray = aclCreateIntArray(inputSize.data(), 4); // 创建out aclTensor ret = CreateAclNchTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); CHECK_RET(ret == ACL_SUCCESS, return ret); // 3. 调用CANN算子库API uint64_t workspaceSize = 0; aclOpExecutor* executor; // 调用aclnnUpsampleBicubic2dAAGrad第一段接口 ret = aclnnUpsampleBicubic2dAAGradGetWorkspaceSize(input, outputSizeArray, inputSizeArray, alignCorners, scalesH, scalesW, out, &workspaceSize, &executor); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnUpsampleBicubic2dAAGradGetWorkspaceSize 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); } // 调用aclnnUpsampleBicubic2dAAGrad第二段接口 ret = aclnnUpsampleBicubic2dAAGrad(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnUpsampleBicubic2dAAGrad 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::vector<float> 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: %f\n", i, resultData[i]); } // 6. 释放aclTensor和aclIntArray aclDestroyTensor(input); aclDestroyTensor(out); // 7. 释放device资源 aclrtFree(inputDeviceAddr); aclrtFree(outDeviceAddr); if (workspaceSize > 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }

该示例的关键调用步骤可以归纳为 7 步,与 CANN aclnn 接口的标准调用范式一致:

  1. 初始化aclInitaclrtSetDeviceaclrtCreateStream
  2. 构造张量:通过aclrtMalloc申请 Device 内存、aclrtMemcpy拷贝 Host 数据,再以aclCreateTensor创建aclTensor(注意按连续 NCHW 布局计算 strides);outputSize/inputSizeaclCreateIntArray封装;
  3. 第一段接口aclnnUpsampleBicubic2dAAGradGetWorkspaceSize完成参数校验并返回workspaceSizeexecutor
  4. 申请 workspace:当workspaceSize > 0时用aclrtMalloc申请 Device 侧 workspace;
  5. 第二段接口aclnnUpsampleBicubic2dAAGrad在指定 stream 上执行计算;
  6. 同步与取数aclrtSynchronizeStream等待计算完成,aclrtMemcpy将结果从 Device 拷贝回 Host 并打印;
  7. 资源释放aclDestroyTensoraclrtFreeaclrtDestroyStreamaclrtResetDeviceaclFinalize

示例中的具体参数为:gradOutputshape(1,1,4,2)(FLOAT32),outputSize = [4, 2]inputSize = [1,1,8,4]alignCorners = truescalesH = scalesW = 0.5,输出gradInputshape(1,1,8,4),即把4×2的梯度张量反向传播回8×4的输入空间。

七、源码级实现剖析

为了让读者对该算子有更深层的理解,下面结合仓库源码,从算子注册、Host 侧 Tiling 到 Kernel 执行梳理其完整实现链路。

7.1 算子定义与注册

upsample_bicubic2d_aa_grad_def.cpp 通过OP_ADD(UpsampleBicubic2dAAGrad)注册算子,核心声明为:

  • Input("grad_output"):必选,支持 FLOAT16/FLOAT/BF16,格式 ND;
  • Output("grad_input"):必选,数据类型与输入一致;
  • Attr("output_size")(必选 ListInt)、Attr("input_size")(必选 ListInt)、Attr("align_corners")(可选 BOOL,默认 false)、Attr("scales_h")/Attr("scales_w")(可选 Float);
  • AICore 配置:ascend910bascend910_93使用基础配置;ascend950使用开启动态编译、动态 Rank、动态 Shape 的regbaseConfig,并指定 op 文件为upsample_bicubic2d_aa_grad_apt

7.2 Host 侧 Tiling:数据切分与 workspace 规划

Tiling 逻辑位于 upsample_bicubic2d_aa_grad_tiling.cpp 与 upsample_bicubic2d_aa_grad_tiling.h。从 Tiling 数据结构UpsampleBicubicAAGradTilingData可以看出该算子的实现策略:

  • 记录scale_w/scale_h及其倒数invscale_w/invscale_h、支撑半径support_w/support_h、最大插值尺寸max_interp_size_w/h,供 Kernel 重建插值权重;
  • 维护slideStartList/slideEndList/tailSlideStartList/tailSlideEndList/tailRowStartList/tailRowEndList等 H/W 两个方向上的滑窗区间列表(MAX_CORE_CONT = 50,对应文档中缩小倍数上限 50 的实现约束),用于多核并行切分;
  • 内嵌两个TCubeTilingmatmulTiling_wmatmulTiling_h),从源码结构可以推断该算子在 Kernel 侧通过 Cube 矩阵乘单元(Matmul)分别对 W 与 H 方向的权重矩阵与梯度数据做矩阵乘累加,把"4×4 邻域加权求和"转化为矩阵乘形式以提升计算效率。

此外,WORK_SPACE_SIZE = 32 * 1024 * 1024(32MB)等常量定义了 workspace 的规划基准,Tiling 阶段按核数将中间矩阵大小写入 tilingData,供 Kernel 侧通过GetUserWorkspace获取。

7.3 Kernel 侧执行入口

upsample_bicubic2d_aa_grad.cpp 是 Kernel 入口函数,通过TILING_KEY_IS(1/2/3)分别派发到UpSampleBicubic2dAAGradND<half>UpSampleBicubic2dAAGradND<float>UpSampleBicubic2dAAGradND<bfloat16_t>三个模板实例(对应 FLOAT16、FLOAT32、BFLOAT16),并通过REGIST_MATMUL_OBJ注册 W/H 两个方向的 Matmul 对象后执行InitProcess。arch35 目录下(arch35)存放了 Ascend 950 架构(ascend950配置)的 SIMT 与 DataCopy 相关实现,体现了不同架构下的 Kernel 差异化适配。

7.4 测试验证

仓库为该算子提供了完整的测试覆盖:

  • Host 侧单测:test_aclnn_upsample_bicubic2d_aa_grad.cpp(aclnn 接口层)与 test_upsample_bicubic2d_aa_grad_tiling.cpp(Tiling 层);
  • Kernel 侧单测:test_upsample_bicubic2d_aa_grad.cpp,配套 gen_data.py 与 compare_data.py 进行数据生成与结果比对;
  • ST 测试:atk_aclnnUpsampleBicubic2dAAGrad.json 与 executor_aclnnUpsampleBicubic2dAAGrad.py 提供了基于 ATK 框架的端到端验证入口。

八、使用建议与总结

  • 前反向配套使用UpsampleBicubic2dAAGrad与 UpsampleBicubic2dAA 共享同一套align_cornersscales_h/scales_w语义与a = -0.5的权重定义,训练场景中反向传播时应保持与前向一致的属性配置,避免梯度数值偏差;
  • 注意反向缩小倍数限制:Atlas A2/A3 系列上反向输入缩小倍数须 ≤ 50(等价于反向缩放比例 ≥ 0.02),超出会触发参数校验错误;
  • 充分利用非连续 Tensor 支持gradOutputout均支持非连续 Tensor(如切片、转置视图),可直接接入更复杂的自动求导图,无需手动contiguous(相关背景可参考 docs/zh/context/non_contiguous_tensor.md);
  • 确定性要求:若训练过程需要严格的逐次可复现结果,在 Atlas A2/A3 上默认即为确定性实现;在 Ascend 950 上需通过aclrtCtxSetSysParamOpt显式开启。

总之,UpsampleBicubic2dAAGrad 是 CANN ops-cv 中实现"抗锯齿双三次上采样"梯度回传的标准算子:理解其 4×4 邻域加权求和的计算本质、掌握align_cornersscales的参数语义,再配合两段式 aclnn 接口的标准调用范式,即可在 Atlas A2/A3 与 Ascend 950 系列平台上正确、高效地完成图像上采样训练链路的反向计算。

【免费下载链接】ops-cv本项目是CANN提供的图像处理、目标检测相关的算子库,实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-cv

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

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/9/18 14:02:58

案例研究的数据收集:会先没了的那几样,得排在前面收

案例研究的数据收集想分步做到多源&#xff0c;卡点常不在找得广不广&#xff0c;而在先收了不会消失的那些。写论文时&#xff0c;骨架可先搭一版&#xff0c;用的是免费智能大纲。论文里要放的时间线与统计图&#xff0c;交给免费科研元素生成。另几处讲法各答一问&#xff1…

作者头像 李华
网站建设 2026/9/18 14:02:34

2026医院病人防走失定位软件:急诊绿通患者定位系统选型推荐

随着2026年智慧医院建设迈向精细化与人性化&#xff0c;医疗机构对特殊人群的安全管理标准显著提升。针对急诊绿色通道患者及易走失人群的定位与全流程监护&#xff0c;已成为保障医疗安全的核心环节。本文将从选型要点出发&#xff0c;重点解析大希科技在医院病人防走失及急诊…

作者头像 李华
网站建设 2026/9/18 14:02:09

Charles Rewrite:HTTP调试链路的底层控制中枢

1. 为什么“Charles 重写”不是功能开关&#xff0c;而是调试链路的底层控制权“Charles 重写”这四个字&#xff0c;在绝大多数新手眼里&#xff0c;就是菜单栏里一个灰扑扑的 Rewrite 功能入口&#xff0c;点开后填几行规则&#xff0c;再点启用——完事。我第一次这么干时&a…

作者头像 李华