指南:aclnnUpsampleBicubic2dBackward 雙三次上采樣反向傳播接口深度解析)
CANN ops-cv 算子開發(fā)指南aclnnUpsampleBicubic2dBackward 雙三次上采樣反向傳播接口深度解析【免費(fèi)下載鏈接】ops-cv本項(xiàng)目是CANN提供的圖像處理、目標(biāo)檢測(cè)相關(guān)的算子庫(kù)實(shí)現(xiàn)網(wǎng)絡(luò)在NPU上加速計(jì)算。項(xiàng)目地址: https://gitcode.com/cann/ops-cv本文基于 CANN 開源算子倉(cāng)庫(kù) ops-cv 中的 image/upsample_bicubic2d_grad 算子模塊系統(tǒng)講解aclnnUpsampleBicubic2dBackward兩段式接口的功能原理、數(shù)學(xué)公式、參數(shù)約束、返回碼與確定性計(jì)算規(guī)則并結(jié)合 op_api、tiling、kernel 源碼剖析其底層實(shí)現(xiàn)路徑。讀完本文你將能夠理解該梯度算子的完整調(diào)用契約掌握在 Atlas 訓(xùn)練/推理產(chǎn)品上編寫正確、高效調(diào)用代碼的方法。一、算子功能與產(chǎn)品支持情況aclnnUpsampleBicubic2dBackward是 aclnnUpsampleBicubic2d2D 雙三次上采樣的反向傳播接口。在前向過(guò)程中輸入張量self的 shape 為 (N, C, H, W)輸出out的 shape 為 (N, C, outputSize[0], outputSize[1])反向時(shí)接口接收上采樣結(jié)果處的梯度gradOut將其散射回原始輸入尺寸輸出gradInput的 shape 為 (N, C, inputSize[2], inputSize[3])。該算子在倉(cāng)庫(kù) image/upsample_bicubic2d_grad/README.md 中注冊(cè)的產(chǎn)品支持情況如下產(chǎn)品是否支持Ascend 950PR/Ascend 950DT不支持Atlas A3 訓(xùn)練系列產(chǎn)品/Atlas A3 推理系列產(chǎn)品支持Atlas A2 訓(xùn)練系列產(chǎn)品/Atlas A2 推理系列產(chǎn)品支持Atlas 200I/500 A2 推理產(chǎn)品支持Atlas 推理系列產(chǎn)品支持Atlas 訓(xùn)練系列產(chǎn)品不支持說(shuō)明README 中的支持矩陣與接口文檔aclnnUpsampleBicubic2dBackward.md的產(chǎn)品列表存在差異接口文檔標(biāo)注 Ascend 950PR/950DT 與 Atlas 訓(xùn)練系列產(chǎn)品“支持”。兩者口徑不同README 反映算子靜態(tài)注冊(cè)的 AICore 配置接口文檔反映 aclnn 層接口能力實(shí)際使用請(qǐng)以所安裝 CANN 版本的產(chǎn)品兼容性說(shuō)明為準(zhǔn)。從算子定義文件 upsample_bicubic2d_grad_def.cpp 可以看到算子UpsampleBicubic2dGrad的 AICore 配置僅注冊(cè)了ascend910b與ascend910_93兩類 SoC這與 README 中“Atlas 訓(xùn)練系列產(chǎn)品不支持”的結(jié)論一致。二、反向傳播數(shù)學(xué)原理2.1 梯度散射公式對(duì)于一個(gè)二維插值點(diǎn) (N, C, h, w)反向傳播的梯度gradInput(N, C, h, w)表示為$$ {gradInput(N, C, h, w)}\sum_{i0}^{3}\sum_{j0}^{3}{W(i, j)}*{f(h_i, w_j)} $$其中f(h_i, w_j)是gradOut在 (h_i, w_j) 處的像素值W(i, j)是雙三次抗鋸齒插值權(quán)重i、j 是權(quán)重矩陣的索引變量。2.2 尺度因子計(jì)算scaleH 與 scaleW 決定插值時(shí)的采樣映射關(guān)系按alignCorners與scalesH/scalesW的取值分三種情況$$ scaleH \begin{cases} (inputSize[2]-1) / (outputSize[0]-1) alignCornerstrue \ 1 / scalesH alignCornersfalsescalesH0\ inputSize[2] / outputSize[0] otherwise \end{cases} $$$$ scaleW \begin{cases} (inputSize[3]-1) / (outputSize[1]-1) alignCornerstrue \ 1 / scalesW alignCornersfalsescalesW0\ inputSize[3] / outputSize[1] otherwise \end{cases} $$alignCorners 為 true輸入與輸出張量的角像素點(diǎn)對(duì)齊尺度由 (尺寸-1) 的比值決定alignCorners 為 false 且 scales 0使用調(diào)用者傳入的縮放因子的倒數(shù)其他情況使用尺寸直接比值。這一分支邏輯在 op_api 源碼 aclnn_upsample_bicubic_2d_backward.cpp 的computeScalelambda 中逐行對(duì)應(yīng)實(shí)現(xiàn)alignCorner為真時(shí)返回(inputSizes-1)/(outputSizes-1)outputSizes 為 1 時(shí)返回 0scale 0時(shí)返回1/scale否則返回inputSizes/outputSizes。2.3 雙三次插值核權(quán)重權(quán)重函數(shù)W(d)即 Catmull-Rom 樣條核a -0.75$$ W(d) \begin{cases} (a2)|d|^3-(a3)|d|^21 |d|\leq1 \ a|d|^3-5a|d|^28a|d|-4a 1|d|2 \ 0 otherwise \end{cases} $$其中 a -0.75d |(h, w) - (h_i, w_j)| 為目標(biāo)采樣點(diǎn)與鄰近像素的距離。反向傳播正是把輸出梯度按這套權(quán)重散射回輸入空間。三、兩段式接口與函數(shù)原型每個(gè) aclnn 算子都遵循兩段式接口設(shè)計(jì)必須先調(diào)用 GetWorkspaceSize 段接口完成入?yún)⑿r?yàn)、推導(dǎo)計(jì)算流程并返回所需 workspace 大小與執(zhí)行器再調(diào)用執(zhí)行段接口傳入 workspace 與執(zhí)行器完成計(jì)算。aclnnStatus aclnnUpsampleBicubic2dBackwardGetWorkspaceSize( const aclTensor* gradOut, const aclIntArray* outputSize, const aclIntArray* inputSize, const bool alignCorners, double scalesH, double scalesW, aclTensor* gradInput, uint64_t* workspaceSize, aclOpExecutor** executor)aclnnStatus aclnnUpsampleBicubic2dBackward( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)四、aclnnUpsampleBicubic2dBackwardGetWorkspaceSize 參數(shù)詳解4.1 參數(shù)說(shuō)明參數(shù)名輸入/輸出描述使用說(shuō)明數(shù)據(jù)類型數(shù)據(jù)格式維度(shape)非連續(xù)TensorgradOutaclTensor*輸入反向計(jì)算的梯度 Tensor對(duì)應(yīng)公式中的gradOut不支持空 Tensor數(shù)據(jù)類型與gradInput一致數(shù)據(jù)格式為 ND 時(shí)默認(rèn)按 NCHW 處理FLOAT32、FLOAT16、BFLOAT16NCHW、ND、NHWC4√outputSizeaclIntArray*輸入gradOut在 H 和 W 維上的空間大小對(duì)應(yīng)公式outputSizesize 為 2且各元素均大于零INT64---inputSizeaclIntArray*輸入gradInput在 N、C、H、W 或 N、H、W、C 維上的空間大小對(duì)應(yīng)公式inputSizesize 為 4且各元素均大于零INT64---alignCornersbool輸入是否對(duì)齊角像素點(diǎn)對(duì)應(yīng)公式alignCornersTrue 時(shí)輸入輸出張量角像素點(diǎn)對(duì)齊否則不對(duì)齊----scalesHdouble輸入gradInput的 height 維度乘數(shù)對(duì)應(yīng)公式scalesH-----scalesWdouble輸入gradInput的 width 維度乘數(shù)對(duì)應(yīng)公式scalesW-----gradInputaclTensor*輸出反向計(jì)算的輸出張量對(duì)應(yīng)公式gradInput不支持空 Tensor數(shù)據(jù)類型、數(shù)據(jù)格式與gradOut一致N、C 軸與gradOut保持一致FLOAT32、FLOAT16、BFLOAT16NCHW、ND、NHWC4√workspaceSizeuint64_t*輸出需在 Device 側(cè)申請(qǐng)的 workspace 大小-----executoraclOpExecutor**輸出op 執(zhí)行器包含算子計(jì)算流程-----平臺(tái)差異化限制Atlas 訓(xùn)練系列產(chǎn)品gradOut、gradInput的數(shù)據(jù)類型不支持 BFLOAT16數(shù)據(jù)格式不支持 NHWC。Atlas A2 訓(xùn)練/推理系列產(chǎn)品、Atlas A3 訓(xùn)練/推理系列產(chǎn)品gradOut、gradInput的數(shù)據(jù)格式不支持 NHWC。從源碼 aclnn_upsample_bicubic_2d_backward.cpp 可以看到數(shù)據(jù)類型支持列表按平臺(tái)區(qū)分非 910B 平臺(tái)如 Atlas 訓(xùn)練系列僅支持DT_FLOAT16與DT_FLOAT910B 及更新平臺(tái)額外支持DT_BF16。格式校驗(yàn)邏輯CheckShape同樣按平臺(tái)區(qū)分非 910B 平臺(tái)僅接受 ND 與 NCHW。4.2 返回值與第一段接口報(bào)錯(cuò)場(chǎng)景返回值類型為aclnnStatus具體參見 aclnn返回碼。第一段接口完成入?yún)⑿r?yàn)以下場(chǎng)景報(bào)錯(cuò)返回碼錯(cuò)誤碼描述ACLNN_ERR_PARAM_NULLPTR161001gradOut、outputSize、inputSize 或 gradInput 為空指針ACLNN_ERR_PARAM_INVALID161002gradOut 的數(shù)據(jù)類型和數(shù)據(jù)格式不在支持范圍內(nèi)gradOut 和 gradInput 的數(shù)據(jù)類型不一致gradOut 的維度不為 4 維outputSize 的 size 不等于 2outputSize 的某個(gè)元素值小于 1inputSize 的 size 不等于 4inputSize 的某個(gè)元素值小于 1gradOut 與 inputSize 在 N、C 維度上的 size 不同gradOut 在 H、W 維上的 size 與 outputSize[0]、outputSize[1] 不一致gradOut 和 gradInput 的 N/C 軸維度大小不相等gradOut 和 gradInput 的數(shù)據(jù)格式不在支持范圍之內(nèi)這些校驗(yàn)在源碼中被拆分為CheckNotNull、CheckInputElement、CheckShape、CheckDtypeValid、CheckUplimit等靜態(tài)函數(shù)見 aclnn_upsample_bicubic_2d_backward.cpp并在第一段接口入口依次執(zhí)行。五、aclnnUpsampleBicubic2dBackward 執(zhí)行段接口參數(shù)名輸入/輸出描述workspace輸入Device 側(cè)申請(qǐng)的 workspace 內(nèi)存地址workspaceSize輸入Device 側(cè) workspace 大小由第一段接口獲取executor輸入op 執(zhí)行器包含算子計(jì)算流程stream輸入指定執(zhí)行任務(wù)的 Stream執(zhí)行段接口內(nèi)部?jī)H調(diào)用CommonOpExecutorRun完成異步下發(fā)見 aclnn_upsample_bicubic_2d_backward.cpp真正的計(jì)算由第一段接口構(gòu)建的算子圖在 NPU 上執(zhí)行。六、約束說(shuō)明6.1 維度上限Atlas A2/A3 系列Atlas A3 與 Atlas A2 訓(xùn)練/推理系列產(chǎn)品需滿足gradOut、gradInput 的所有維度取值均小于等于 (2^31 - 1)N * C * outputSize_H 2^31 - 1N、C 為輸入/輸出的 N、C 軸。該約束在 CheckUplimit 中實(shí)現(xiàn)針對(duì) 910BDAV_2201架構(gòu)逐維檢查是否超過(guò)INT32_MAX并檢查N * C * outputH的上限。6.2 scale 與 shape 的一致性約束參數(shù) inputSize、outputSize、scalesH、scalesW 需滿足$$ outputSize_H floor(inputSize_H * scalesH) $$$$ outputSize_W floor(inputSize_W * scalesW) $$6.3 確定性計(jì)算約束aclnnUpsampleBicubic2dBackward默認(rèn)是非確定性實(shí)現(xiàn)支持通過(guò)aclrtCtxSetSysParamOpt開啟確定性計(jì)算。開啟后當(dāng)滿足以下任一條件時(shí)不支持確定性計(jì)算inputSize_W 130000inputSize_H / outputSize_H 50inputSize_W / outputSize_W 50 且 inputSize_N * inputSize_C * inputSize_H inputSize_W * 0.5inputSize_H / outputSize_H 0.02 且 inputSize_W / outputSize_W 0.02 且 inputSize_N * inputSize_C * inputSize_H inputSize_W * 10000。這些閾值的常量MAX_W 130000、MAX_SCALE 50、HALF_ONE 0.5、MAX_W_RADIO 10000定義在源碼 aclnn_upsample_bicubic_2d_backward.cpp由CheckCanCalc函數(shù)第 248-273 行逐條判斷。確定性開關(guān)通過(guò)aclrtCtxGetSysParamOpt(ACL_OPT_DETERMINISTIC, ...)讀取第 417 行讀取失敗時(shí)降級(jí)為非確定性。七、源碼實(shí)現(xiàn)路徑剖析7.1 op_api 層的多分支執(zhí)行策略第一段接口按平臺(tái)與條件選擇三條計(jì)算路徑aclnn_upsample_bicubic_2d_backward.cppRegBase910_93 等新平臺(tái)路徑將 gradOut、gradInput 轉(zhuǎn)為連續(xù) Tensor 后直接調(diào)用l0op::ResizeBicubicV2Grad內(nèi)核算子再經(jīng)ViewCopy寫回 gradInput910B 快速路徑當(dāng)滿足CheckCanCalcscale 與 shape 在安全區(qū)間內(nèi)時(shí)若輸入輸出 H/W 完全相同則直接ViewCopy拷貝否則將 FP16/BF16 先 Cast 為 FP32 計(jì)算以保證精度調(diào)用l0op::UpsampleBicubic2dGrad后 Cast 回原類型通用路徑將 gradOut 轉(zhuǎn)置為 (H, W, N, C) 布局permuteHWNCList {2, 3, 0, 1}調(diào)用l0op::ResizeGradDCUBIC_MODE完成梯度散射最后經(jīng) Reshape、Transpose、ViewCopy 恢復(fù)輸出布局該路徑下若開啟確定性且輸入為 FP16會(huì)先 Cast 到 FP32 再計(jì)算FP16_DETERMINSTIC_CAST。7.2 tiling 層的雙模式調(diào)度tiling 實(shí)現(xiàn) upsample_bicubic2d_grad_tiling.cpp 依據(jù)IsDeterministicCalc選擇兩種調(diào)度模式BASE_MODETilingKey 10000001將 H、W 維度按 fractalNUM_FRACTAL切塊通過(guò)matmul_tiling::MatmulApiTiling為 H、W 兩個(gè)方向的矩陣乘分別生成 tiling 參數(shù)MMParamH / MMParamW并計(jì)算 workspace含 ratio 矩陣與中間結(jié)果緩沖見 SetLaunchInfoDETERMINISTIC_MODETilingKey 10000002采用滑動(dòng)窗口slideSize切分計(jì)算單核 K 維singleCoreKH/KW、中間矩陣尺寸intermediateMatrixSize與 ratio 矩陣尺寸workspace 相應(yīng)放大見 SetLaunchInfoDC。內(nèi)核入口 upsample_bicubic2d_grad.cpp 按數(shù)據(jù)類型FLOAT/FLOAT16/BF16與 TilingKey 分別實(shí)例化UpsampleBicubic2dGradBase基礎(chǔ)模式和UpsampleBicubic2dGradDCND確定性模式兩個(gè)算子類。7.3 算子靜態(tài)配置ascend910b 下的 binary.json 為每種 dtypefloat16/float32/bfloat16注冊(cè)了獨(dú)立 kernel 二進(jìn)制屬性默認(rèn)值分別為align_cornersfalse、scales_h0.0、scales_w0.0與 op_def 中的可選屬性聲明一致scales_h/scales_w 默認(rèn) 0.0align_corners 默認(rèn) false。八、完整調(diào)用示例以下示例代碼同時(shí)存在于接口文檔與 examples/test_aclnn_upsample_bicubic2d_grad.cpp展示了完整的“初始化 → 建 Tensor → 兩段式調(diào)用 → 同步 → 取結(jié)果 → 釋放資源”流程。具體編譯與執(zhí)行過(guò)程請(qǐng)參考編譯與運(yùn)行樣例。#include iostream #include vector #include acl/acl.h #include aclnnop/aclnn_upsample_bicubic_2d_backward.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); 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); // 調(diào)用aclrtMalloc申請(qǐng)device側(cè)內(nèi)存 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); // 調(diào)用aclrtMemcpy將host側(cè)數(shù)據(jù)拷貝到device側(cè)內(nèi)存上 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); // 計(jì)算連續(xù)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]; } // 調(diào)用aclCreateTensor接口創(chuàng)建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手冊(cè) // 根據(jù)自己的實(shí)際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. 構(gòu)造輸入與輸出需要根據(jù)API的接口自定義構(gòu)造 std::vectorint64_t selfShape {1, 1, 2, 2}; std::vectorint64_t outShape {1, 1, 3, 3}; void* selfDeviceAddr nullptr; void* outDeviceAddr nullptr; aclTensor* self nullptr; aclTensor* out nullptr; std::vectorfloat selfHostData {1, 2, 3, 4.1}; std::vectorfloat outHostData {0, 0, 0, 0, 0, 0, 0, 0, 0}; // 創(chuàng)建self aclTensor ret CreateAclTensor(selfHostData, selfShape, selfDeviceAddr, aclDataType::ACL_FLOAT, self); CHECK_RET(ret ACL_SUCCESS, return ret); // 創(chuàng)建out aclTensor ret CreateAclTensor(outHostData, outShape, outDeviceAddr, aclDataType::ACL_FLOAT, out); CHECK_RET(ret ACL_SUCCESS, return ret); std::vectorint64_t outArraySize {2, 2}; const aclIntArray* outputSize aclCreateIntArray(outArraySize.data(), outArraySize.size()); CHECK_RET(outputSize ! nullptr, return ACL_ERROR_INTERNAL_ERROR); std::vectorint64_t inputArraySize {1, 1, 3, 3}; const aclIntArray* inputSize aclCreateIntArray(inputArraySize.data(), inputArraySize.size()); CHECK_RET(inputSize ! nullptr, return ACL_ERROR_INTERNAL_ERROR); // 3. 調(diào)用CANN算子庫(kù)API需要修改為具體的Api名稱 uint64_t workspaceSize 0; aclOpExecutor* executor; const double scalesH 1.1; const double scalesW 1.1; // 調(diào)用aclnnUpsampleBicubic2dBackward第一段接口 ret aclnnUpsampleBicubic2dBackwardGetWorkspaceSize(self, outputSize, inputSize, 1, scalesH, scalesW, out, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnUpsampleBicubic2dBackwardGetWorkspaceSize failed. ERROR: %d\n, ret); return ret); // 根據(jù)第一段接口計(jì)算出的workspaceSize申請(qǐng)device內(nèi)存 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); } // 調(diào)用aclnnUpsampleBicubic2dBackward第二段接口 ret aclnnUpsampleBicubic2dBackward(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnUpsampleBicubic2dBackward failed. ERROR: %d\n, ret); return ret); // 4. 固定寫法同步等待任務(wù)執(zhí)行結(jié)束 ret aclrtSynchronizeStream(stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclrtSynchronizeStream failed. ERROR: %d\n, ret); return ret); // 5. 獲取輸出的值將device側(cè)內(nèi)存上的結(jié)果拷貝至host側(cè)需要根據(jù)具體API的接口定義修改 auto size GetShapeSize(outShape); std::vectorfloat 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需要根據(jù)具體API的接口定義修改 aclDestroyTensor(self); aclDestroyTensor(out); aclDestroyIntArray(outputSize); aclDestroyIntArray(inputSize); // 7. 釋放device資源需要根據(jù)具體API的接口定義修改 aclrtFree(selfDeviceAddr); aclrtFree(outDeviceAddr); if (workspaceSize 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }示例要點(diǎn)解讀示例中輸入self即 gradOutshape 為 (1, 1, 2, 2)inputSize {1, 1, 3, 3}指定輸出 gradInput 的 shape 為 (1, 1, 3, 3)outputSize {2, 2}與 gradOut 的 H/W 維一致alignCorners傳 1truescalesH/scalesW 傳 1.1此時(shí)因 alignCorners 為 true實(shí)際 scale 由(inputSize-1)/(outputSize-1)決定scales 僅作占位由于 gradInputout的 shape 與 inputSize 在 N、C 軸一致滿足 4.1 節(jié)的校驗(yàn)要求。九、測(cè)試用例與驗(yàn)證倉(cāng)庫(kù)為算子提供了兩層測(cè)試支撐op_api 單測(cè)test_aclnn_upsample_bicubic_2d_backward.cpp覆蓋 float32/float16 正常路徑期望ACLNN_SUCCESS以及 double、int8、uint8 等不支持類型期望ACLNN_ERR_PARAM_INVALID可用于驗(yàn)證第一段接口的入?yún)⑿r?yàn)行為Python 單測(cè)aclnnUpsampleBicubic2dBackward.py 與 ST 級(jí)測(cè)試tests/st 目錄下的 atk JSON 與 executor 腳本用于端到端數(shù)值驗(yàn)證tiling 單測(cè)test_upsample_bicubic2d_grad_tiling.cpp 與kernel 單測(cè)test_upsample_bicubic2d_grad.cpp 分別校驗(yàn) tiling 數(shù)據(jù)與內(nèi)核計(jì)算邏輯。十、總結(jié)aclnnUpsampleBicubic2dBackward是 ops-cv 中實(shí)現(xiàn)雙三次上采樣梯度回傳的標(biāo)準(zhǔn) aclnn 接口其核心價(jià)值在于以2^31-1維度上限和確定性開關(guān)為邊界通過(guò) op_api 層的多平臺(tái)路徑選擇與 tiling 層的雙模式調(diào)度在 Atlas A2/A3 等產(chǎn)品上高效完成梯度散射。開發(fā)者只需嚴(yán)格遵循兩段式調(diào)用流程、保證inputSize/outputSize/scales之間的一致性約束即可獲得正確、可復(fù)現(xiàn)的反向梯度結(jié)果。如需深入算子圖融合或確定性實(shí)現(xiàn)的細(xì)節(jié)可繼續(xù)閱讀倉(cāng)庫(kù) image/upsample_bicubic2d_grad 目錄下的 op_host、op_kernel 與 tests 源碼?!久赓M(fèi)下載鏈接】ops-cv本項(xiàng)目是CANN提供的圖像處理、目標(biāo)檢測(cè)相關(guān)的算子庫(kù)實(shí)現(xiàn)網(wǎng)絡(luò)在NPU上加速計(jì)算。項(xiàng)目地址: https://gitcode.com/cann/ops-cv創(chuàng)作聲明:本文部分內(nèi)容由AI輔助生成(AIGC),僅供參考