ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

CANN ops-nn BatchNormGradV3 算子 aclnn 接口实战指南:从反向传播公式到两段式调用

CANN ops-nn BatchNormGradV3 算子 aclnn 接口实战指南:从反向传播公式到两段式调用 人工智能算子库深度学习CANNAscend【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-nn点击查看免费下载BatchNormGradV3 是 CANN 神经网络算子库 ops-nn 中 BatchNorm批归一化反向传播算子本指南围绕该模块对外暴露的aclnnBatchNormBackward与aclnnFastBatchNormBackward两个 aclnn 接口展开覆盖数学原理、产品支持矩阵、全部参数与返回码、两段式调用流程、完整可编译示例代码以及 Host/Kernel 侧的源码级实现链路。读完本文你将能够独立完成该算子梯度计算的接口调用、参数校验与排错并理解其训练/推理双路径的内部工作机制。模块定位与整体架构norm/batch_norm_grad_v3/README.md 明确指出本目录仅包含 BatchNormGradV3 算子对应的 aclnn 接口如需为该算子贡献 AscendC 实现请参考 贡献流程。也就是说本模块的对外能力是接口层其具体算子在 NPU 侧的执行与调度由本仓库的 Host 侧构图逻辑与 Kernel 侧实现共同支撑。从目录结构看模块分为四个部分op_api对外接口实现包含aclnn_batch_norm_backward.h/.cpp、aclnn_fast_batch_norm_backward.h/.cpp以及封装底层基础算子l0op的 batch_norm_backward.cppop_host算子定义def、shape 推导infershape、tiling 计算按 full load / split load / cross-core 等多种策略拆分的 tiling 文件op_kernelAscendC 内核实现入口为 batch_norm_grad_v3.cpp并按 arch35 提供 infer/train、full load/split load/recompute 等多套 regbase 实现op_host/config按产品ascend910_93、ascend910b、ascend950生成的算子二进制描述 JSON声明了算子输入输出 dtype/format 与is_training、epsilon、version属性。本模块对外提供两个接口通用接口aclnnBatchNormBackward对应 PyTorch 中torch.batch_norm_backward语义和高性能接口aclnnFastBatchNormBackward两者共享同一套数学定义差异体现在产品支持范围、version参数与内部调度策略上。BatchNorm 反向传播的数学原理两个接口的计算语义完全一致计算 aclnnBatchNorm正向批归一化的反向传播即根据输出的梯度gradOut反推输入梯度gradInput、权重梯度gradWeight与偏置梯度gradBias以便在反向传播过程中更新模型参数。training true训练场景$$gradInput \frac{weight}{n\sqrt{saveVar eps}}\left(n \cdot gradOut - \sum_{i0}^{m}{gradOut} - \frac{x - saveMean}{\sqrt{saveVar eps}} \sum_{i0}^{m}\left(gradOut \cdot \frac{x - saveMean}{\sqrt{saveVar eps}}\right)\right)$$$$gradWeight \sum_{i0}^{m}\left[gradOut \cdot (x - saveMean)\right] \cdot \frac{1}{\sqrt{saveVar eps}}$$$$gradBias \sum_{i0}^{m}gradOut$$训练场景下使用正向过程保存的saveMean与saveInvstd即saveVar eps开平方的倒数对应公式中的1/√(saveVareps)。training false推理场景$$gradInput gradOut \cdot \frac{1}{\sqrt{runningVar eps}} \cdot weight$$$$gradWeight \sum_{i0}^{m}\left[gradOut \cdot (x - runningMean)\right] \cdot \frac{1}{\sqrt{runningVar eps}}$$$$gradBias \sum_{i0}^{m}gradOut$$推理场景下使用长期累计的runningMean与runningVar作为归一化统计量。从源码实现看该路径在 aclnn_batch_norm_backward.cpp 中对应l0op::BNTrainingUpdateGrad产出 gradWeight/gradBiasl0op::BNInferGrad产出 gradInput两条 l0op 的组合训练场景则使用BNTrainingUpdateGradBNTrainingReduceGrad5 维输入NCDHW时替换为BN3DTrainingUpdateGradBN3DTrainingReduceGrad这些 l0op 的具体定义位于 batch_norm_backward.cpp。两段式 aclnn 接口调用模型CANN 的 aclnn 算子库采用两段式接口设计必须先调用第一段xxxGetWorkspaceSize接口完成入参校验、构图并计算所需 workspace 大小再调用第二段xxx接口执行计算。以aclnnBatchNormBackward为例aclnnStatus aclnnBatchNormBackwardGetWorkspaceSize( const aclTensor *gradOut, // 输出梯度 const aclTensor *input, // 正向输入 x const aclTensor *weight, // 权重可为空默认填1 const aclTensor *runningMean, // 运行均值可为空默认填0 const aclTensor *runningVar, // 运行方差可为空默认填1 const aclTensor *saveMean, // 保存均值可为空默认填0 const aclTensor *saveInvstd, // 保存的逆标准差可为空默认填1 bool training, // true训练false推理 double eps, // 方差修正值避免除零 const aclBoolArray *outputMask, // size为3的输出掩码 aclTensor *gradInput, // 输入梯度可选输出 aclTensor *gradWeight, // 权重梯度可选输出 aclTensor *gradBias, // 偏置梯度可选输出 uint64_t *workspaceSize, aclOpExecutor **executor)aclnnStatus aclnnBatchNormBackward( void *workspace, // Device侧workspace内存地址 uint64_t workspaceSize, // 第一段接口返回的大小 aclOpExecutor *executor, // 包含算子计算流程的执行器 const aclrtStream stream) // 指定执行任务的StreamaclnnFastBatchNormBackward的两段式原型与上述完全一致仅在第一段接口中额外增加一个int version参数内部算法版本号目前支持 0、1默认 0。从源码看第一段接口的核心流程见 aclnn_batch_norm_backward.cpp为创建 OpExecutor → 校验输入非空 → 空 Tensor 提前返回workspaceSize 0→CheckParams参数校验 → 将输入转为连续 TensorContiguous→ 维度大于 5 时 Reshape 到 5 维并转 NCDHW → 按平台走 regbase 或非 regbase 构图路径 → 调用GetWorkspaceSize()汇总 workspace。第二段接口则直接调用框架能力CommonOpExecutorRun(workspace, workspaceSize, executor, stream)完成计算。产品支持情况两个接口的产品支持矩阵差异较大选型时需特别注意产品系列aclnnBatchNormBackwardaclnnFastBatchNormBackwardAscend 950PR950DT 系列支持不支持Atlas A3 系列支持不支持Atlas A2 系列910b支持支持Atlas 200I/500 A2 推理产品310b不支持不支持Atlas 推理系列产品310p不支持不支持Atlas 训练系列产品910支持不支持可以看到aclnnFastBatchNormBackward目前仅面向 Atlas A2 系列产品开放是 A2 上的高性能路径。平台相关 dtype/format 约束Atlas 训练系列910、Atlas 推理系列310p仅 aclnnBatchNormBackwardgradOut、input、weight、runningMean、runningVar、saveMean、saveInvstd、gradInput、gradWeight、gradBias的数据类型不支持 BFLOAT16weight、runningMean、runningVar、saveMean、saveInvstd、gradWeight、gradBias的数据类型需与gradOut保持一致gradOut、input、gradInput的数据格式不支持 NHWC、NDHWC。Atlas A2910b、Atlas A3 系列weight、runningMean、runningVar、saveMean、saveInvstd、gradWeight、gradBias的数据类型需与gradOut保持一致gradOut、input、gradInput的数据格式不支持 NHWC、NDHWC。Ascend 950PR950DT 系列仅 aclnnBatchNormBackward支持更灵活的混合精度gradOut为 FLOAT32 时weight、runningMean、runningVar、saveMean、saveInvstd必须为 FLOAT32gradOut为 FLOAT16 时上述参数必须为 FLOAT16 或 FLOAT32gradOut为 BFLOAT16 时上述参数必须为 BFLOAT16 或 FLOAT32weight为 FLOAT32 时gradWeight必须为 FLOAT32weight为 FLOAT16 时gradWeight必须为 FLOAT16 或 FLOAT32weight为 BFLOAT16 时gradWeight必须为 BFLOAT16 或 FLOAT32gradWeight与gradBias数据类型需保持一致runningVar与runningMean、saveInvstd与saveMean数据类型需各自一致。这些约束与 Host 侧校验代码一一对应非 regbase 平台在GetDtypeSupportList()中按架构区分支持列表910 仅 FLOAT/FLOAT16910b 及以上追加 BF16regbase 平台则通过RegbaseCheckDtypeSame逐项校验类型匹配关系见 aclnn_batch_norm_backward.cpp。第一段接口参数详解下表完整列出aclnnBatchNormBackwardGetWorkspaceSize的全部参数aclnnFastBatchNormBackwardGetWorkspaceSize除version外与之相同参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续TensorgradOutaclTensor*输入梯度Tensor对应公式gradOut支持空Tensor2维对应NC3维对应NCL4维对应NCHW/NHWC5维对应NCDHW/NDHWC6-8维对应ND第2维固定为channel轴FLOAT32、FLOAT16、BFLOAT16NC、NCL、NCHW、NHWC、NCDHW、NDHWC、ND2-8√inputaclTensor*输入正向输入Tensor对应公式x支持空Tensor数据类型、shape、数据格式均需与gradOut一致FLOAT32、FLOAT16、BFLOAT16NC、NCL、NCHW、NHWC、NCDHW、NDHWC、ND2-8√weightaclTensor*输入权重Tensor对应公式weight支持空Tensorshape长度与input的channel轴长度相等FLOAT32、FLOAT16、BFLOAT16ND1√runningMeanaclTensor*输入训练期间计算的均值对应公式runningMean支持空Tensorshape长度与input的channel轴长度相等FLOAT32、FLOAT16、BFLOAT16ND1√runningVaraclTensor*输入训练期间计算的方差对应公式runningVar支持空Tensor数值为非负数shape长度与input的channel轴长度相等FLOAT32、FLOAT16、BFLOAT16ND1√saveMeanaclTensor*输入保存的均值对应公式saveMean支持空Tensorshape长度与input的channel轴长度相等或在推理场景下长度为0FLOAT32、FLOAT16、BFLOAT16ND1√saveInvstdaclTensor*输入保存的标准差的倒数即1/√(Var(x)eps)支持空Tensor数值为非负数shape长度与input的channel轴长度相等或在推理场景下长度为0FLOAT32、FLOAT16、BFLOAT16ND1√trainingbool输入训练/推理场景标记对应公式trainingtrue表示训练场景false表示推理场景----epsdouble输入添加到方差中的值避免除以零对应公式eps-----outputMaskaclBoolArray*输入输出掩码size为3依次表示是否输出gradInput、gradWeight、gradBias为true则输出否则对应位置返回空BoolArray---versionint仅Fast输入算子内部使用的算法版本号目前支持 0、1默认值 0----gradInputaclTensor*输出输入Tensor的梯度对应公式gradInput支持空Tensor可选输出outputMask[0]为true时输出数据类型、shape、数据格式均需与gradOut一致FLOAT32、FLOAT16、BFLOAT16NC、NCL、NCHW、NHWC、NCDHW、NDHWC、ND2-8√gradWeightaclTensor*输出缩放参数权重的梯度对应公式gradWeight支持空Tensor可选输出outputMask[1]为true时输出长度与input的channel轴长度相等FLOAT32、FLOAT16、BFLOAT16ND1√gradBiasaclTensor*输出偏置参数的梯度对应公式gradBias支持空Tensor可选输出outputMask[2]为true时输出shape长度与input的channel轴长度相等FLOAT32、FLOAT16、BFLOAT16ND1√workspaceSizeuint64_t*输出用户需在Device侧申请的workspace大小-----executoraclOpExecutor**输出op执行器包含算子计算流程-----两个接口在格式支持上的差别在于Fast 接口的gradOut/input/gradInput支持 NC、NCL、NCHW、NCDHW、ND不含 NHWC/NDHWC。另外注意outputMask长度必须为 3源码CheckMaskNotNull在 regbase 平台强制校验Size() ! 3见 aclnn_batch_norm_backward.cpp且当outputMask[i]为 true 时对应的输出指针不能为空。返回值与错误码第一段接口完成入参校验失败时返回aclnnStatus具体状态码参见 aclnn返回码。出现以下场景时报错ACLNN_ERR_PARAM_NULLPTR错误码 161001传入的gradOut、input指针为空指针outputMask[0]为 true 时传入的gradInput是空指针outputMask[1]为 true 时传入的gradWeight是空指针outputMask[2]为 true 时传入的gradBias是空指针。ACLNN_ERR_PARAM_INVALID错误码 161002input、gradOut的数据类型、数据格式和 shape 不在支持范围之内weight、runningMean、runningVar、saveMean、saveInvstd非空时数据类型、数据格式和 shape 不在支持范围之内outputMask的长度不为 3outputMask[0]为 true 时gradInput数据类型、数据格式和 shape 不在支持范围之内outputMask[1]为 true 时gradWeight数据类型、数据格式和 shape 不在支持范围之内outputMask[2]为 true 时gradBias数据类型、数据格式和 shape 不在支持范围之内weight、runningMean、runningVar、saveMean、saveInvstd、gradWeight非空时、gradBias非空时的 shape 长度与 input shape 中 channel 轴的长度不相等input、gradOut、gradInput非空时的数据格式不一致input、gradOut、gradInput非空时的数据类型不一致input、gradOut、gradInput非空时的 shape 不一致或 shape 维度大于 8 维、小于 2 维。这些错误场景在源码中由CheckParams串联的CheckDtypeValid、CheckFormat、CheckShape、CheckOtherShape、CheckSaveMeanSaveInvstdShape、CheckGradWeightGradBiasShape等函数逐项实现见 aclnn_batch_norm_backward.cpp可作为接口排错时的精确对照。约束说明确定性计算aclnnBatchNormBackwardAtlas A3 系列、Atlas A2 系列、Atlas 训练系列产品默认采用非确定性实现支持通过aclrtCtxSetSysParamOpt开启确定性Ascend 950PR950DT 系列默认即为确定性实现。aclnnFastBatchNormBackward默认确定性实现。确定性差异源于两个接口内部的并行拆分策略不同aclnnBatchNormBackward存在 cross-core 拆分等非确定性归约路径而 Fast 接口仅 A2 支持对应isBatchNormSupportAscendC()判断后的 AscendC 路径以确定性算法为主。调用示例可编译运行以下示例完整演示了aclnnBatchNormBackward的两段式调用全流程训练场景eps 1e-5三个输出全部开启。编译与运行的具体过程请参考编译与运行样例仓库中还提供了可参考的 examples/test_aclnn_batch_norm_backward.cpp 与 examples/arch22/test_aclnn_fast_batch_norm_backward.cpp。#include iostream #include vector #include acl/acl.h #include aclnnop/aclnn_batch_norm_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); 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手册 int32_t deviceId 0; // 根据实际device填写 aclrtStream stream; auto ret Init(deviceId, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(Init acl failed. ERROR: %d\n, ret); return ret); // 2. 构造输入与输出 std::vectorint64_t gradOutShape {1, 2, 4}; std::vectorint64_t selfShape {1, 2, 4}; std::vectorint64_t weightShape {2}; std::vectorint64_t rMeanShape {2}; std::vectorint64_t rVarShape {2}; std::vectorint64_t sMeanShape {2}; std::vectorint64_t sVarShape {2}; std::vectorint64_t gradInShape {1, 2, 4}; std::vectorint64_t gradWeightShape {2}; std::vectorint64_t gradBiasShape {2}; void* gradOutDeviceAddr nullptr; void* selfDeviceAddr nullptr; void* weightDeviceAddr nullptr; void* rMeanDeviceAddr nullptr; void* rVarDeviceAddr nullptr; void* sMeanDeviceAddr nullptr; void* sVarDeviceAddr nullptr; void* outMaskDeviceAddr nullptr; void* gradInDeviceAddr nullptr; void* gradWeightDeviceAddr nullptr; void* gradBiasDeviceAddr nullptr; aclTensor* gradOut nullptr; aclTensor* self nullptr; aclTensor* weight nullptr; aclTensor* rMean nullptr; aclTensor* rVar nullptr; aclTensor* sMean nullptr; aclTensor* sVar nullptr; aclBoolArray* outMask nullptr; aclTensor* gradIn nullptr; aclTensor* gradWeight nullptr; aclTensor* gradBias nullptr; std::vectorfloat gradOutHostData {0, 1, 2, 3, 4, 5, 6, 7}; std::vectorfloat selfHostData {0, 1, 2, 3, 4, 5, 6, 7}; std::vectorfloat weightHostData {1, 1}; std::vectorfloat rMeanHostData {0, 0}; std::vectorfloat rVarHostData {1, 1}; std::vectorfloat sMeanHostData {0, 0}; std::vectorfloat sVarHostData {1, 1}; std::vectorfloat gradInHostData(8, 0); std::vectorfloat gradWeightHostData(2, 0); std::vectorfloat gradBiasHostData(2, 0); bool training true; double eps 1e-5; // 创建gradOut aclTensor ret CreateAclTensor(gradOutHostData, gradOutShape, gradOutDeviceAddr, aclDataType::ACL_FLOAT, gradOut); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建selfinput aclTensor ret CreateAclTensor(selfHostData, selfShape, selfDeviceAddr, aclDataType::ACL_FLOAT, self); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建weight aclTensor ret CreateAclTensor(weightHostData, weightShape, weightDeviceAddr, aclDataType::ACL_FLOAT, weight); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建rMean aclTensor ret CreateAclTensor(rMeanHostData, rMeanShape, rMeanDeviceAddr, aclDataType::ACL_FLOAT, rMean); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建rVar aclTensor ret CreateAclTensor(rVarHostData, rVarShape, rVarDeviceAddr, aclDataType::ACL_FLOAT, rVar); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建sMean aclTensor ret CreateAclTensor(sMeanHostData, sMeanShape, sMeanDeviceAddr, aclDataType::ACL_FLOAT, sMean); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建sVarsaveInvstd aclTensor ret CreateAclTensor(sVarHostData, sVarShape, sVarDeviceAddr, aclDataType::ACL_FLOAT, sVar); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建outMask aclBoolArray三个输出全部开启 bool maskData[3] {true, true, true}; outMask aclCreateBoolArray((maskData[0]), 3); // 创建gradIn aclTensor ret CreateAclTensor(gradInHostData, gradInShape, gradInDeviceAddr, aclDataType::ACL_FLOAT, gradIn); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建gradWeight aclTensor ret CreateAclTensor( gradWeightHostData, gradWeightShape, gradWeightDeviceAddr, aclDataType::ACL_FLOAT, gradWeight); CHECK_RET(ret ACL_SUCCESS, return ret); // 创建gradBias aclTensor ret CreateAclTensor(gradBiasHostData, gradBiasShape, gradBiasDeviceAddr, aclDataType::ACL_FLOAT, gradBias); CHECK_RET(ret ACL_SUCCESS, return ret); uint64_t workspaceSize 0; aclOpExecutor* executor; // 3. 调用aclnnBatchNormBackward两段式接口 // 调用第一段接口校验入参 计算workspace大小 ret aclnnBatchNormBackwardGetWorkspaceSize( gradOut, self, weight, rMean, rVar, sMean, sVar, training, eps, outMask, gradIn, gradWeight, gradBias, workspaceSize, executor); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnBatchNormBackwardGetWorkspaceSize 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); } // 调用第二段接口执行计算 ret aclnnBatchNormBackward(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret ACL_SUCCESS, LOG_PRINT(aclnnBatchNormBackward 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(gradInShape); std::vectorfloat resultData(size, 0); ret aclrtMemcpy( resultData.data(), resultData.size() * sizeof(resultData[0]), gradInDeviceAddr, 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和aclBoolArray aclDestroyTensor(gradOut); aclDestroyTensor(self); aclDestroyTensor(weight); aclDestroyTensor(rMean); aclDestroyTensor(rVar); aclDestroyTensor(sMean); aclDestroyTensor(sVar); aclDestroyBoolArray(outMask); aclDestroyTensor(gradIn); aclDestroyTensor(gradWeight); aclDestroyTensor(gradBias); // 7. 释放device资源 aclrtFree(gradOutDeviceAddr); aclrtFree(selfDeviceAddr); aclrtFree(weightDeviceAddr); aclrtFree(rMeanDeviceAddr); aclrtFree(rVarDeviceAddr); aclrtFree(sMeanDeviceAddr); aclrtFree(sVarDeviceAddr); aclrtFree(gradInDeviceAddr); aclrtFree(gradWeightDeviceAddr); aclrtFree(gradBiasDeviceAddr); if (workspaceSize 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }示例要点内存管理aclrtMalloc申请 Device 内存aclrtMemcpy完成 Host↔Device 数据拷贝输出 Tensor 也是先预分配内存再通过aclCreateTensor建立视图workspace 处理仅当workspaceSize 0时才申请并释放 workspace这是两段式接口的固定模式释放顺序先销毁 Tensor/数组对象再释放 Device 内存与 Stream最后aclFinalize。调用aclnnFastBatchNormBackward时只需将头文件替换为aclnnop/aclnn_fast_batch_norm_backward.h并把第一段接口调用改为传入version参数即可例如ret aclnnFastBatchNormBackwardGetWorkspaceSize( gradOut, self, weight, rMean, rVar, sMean, sVar, training, eps, outMask, /* version */ 0, gradIn, gradWeight, gradBias, workspaceSize, executor);Fast 版本示例中gradOut/input/gradInput通常以ACL_FORMAT_NCL创建3 维输入时对应文档中 Fast 接口的格式支持范围。完整代码见 examples/arch22/test_aclnn_fast_batch_norm_backward.cpp。源码级实现剖析Host 侧构图路径aclnnBatchNormBackwardGetWorkspaceSize内部按平台选择两条构图路径见 aclnn_batch_norm_backward.cpp非 regbase 路径BatchNormBackward先通过PrepareBackwardDefaultParams为可空的runningMean/runningVar/weight/saveMean/saveInvstd填充默认值0/1/1/0/1使用FillScalar2-3 维输入先ResizeFromND升维、5 维推理输入走ResizeFrom5D随后进入BatchNormBackwardProc按 training 分支组合 l0opregbase 路径BatchNormBackwardRegbase先Contiguous归一化内存布局再对参与计算的统计量统一Cast到 FLOAT32最终以单个l0op::BatchNormGradV3原子算子完成三个梯度的计算非训练场景下gradWeight/gradBias由CalcGradWeightGradBias通过 Cast→Sub→Mul→Pow→ReduceSum 的纯 l0op 组合独立计算对应ComputeGradWeight中的invstd Pow(var eps, -0.5)实现见 aclnn_batch_norm_backward.cpp。从源码结构可以推断regbase 路径是面向 950 等新架构的高效路径而非 regbase 路径通过组合多个训练/推理梯度 l0op 兼容 910/A2 等平台。Kernel 侧调度算子内核入口 batch_norm_grad_v3.cpp 以TILING_KEY区分不同计算策略10001对应 infer 全量加载full load、20001/20002对应 infer 拆分加载split loadR0/R1 模式、20011/20012对应 infer 跨核拆分cross core、30001系列对应 train 场景各策略分别实例化BatchNormGradV3InferFullload、BatchNormGradV3InferSplitLoad、BatchNormGradV3InferSplitLoadCrossCore、BatchNormGradV3TrainFullload等模板类。tiling 侧由 batch_norm_grad_v3_tiling.cpp 及其 splitload/crosscore 变体负责计算切分参数。算子二进制配置op_host/config/ascend950/batch_norm_grad_v3_binary.json 展示了算子输入输出与属性的完整声明输入依次为dy、x、weight、running_mean、running_var、save_mean、save_rstd对应接口的gradOut/input/weight/runningMean/runningVar/saveMean/saveInvstd输出为dx、dweight、dbias属性为is_trainingbool、epsilonfloat、versionint。配置按 bf16/fp16、NCHW/NCDHW 组合生成多份二进制如BatchNormGradV3_bf16_01…BatchNormGradV3_fp16_04每个组合的统计量参数如running_mean既可以声明为与主输入同 dtype 的变体也可以声明为 float32 变体与上文 950 系列的混合精度约束吻合。测试覆盖Host 侧 op_api 单测 test_aclnn_batchnorm_backward.cpp 与 test_aclnn_fast_batchnorm_backward.cpp 通过OP_API_UT对两个接口的正常调用、空指针、非法 dtype/shape 等场景进行回归验证shape 推导单测 test_batch_norm_grad_v3_infershape.cpp 与 tiling 单测覆盖多策略 tiling 计算Kernel 侧单测 test_batch_norm_grad_v3.cpp 配合 gen_data.py、gen_tiling.py 与 compare_data.py 完成数据构造与结果比对ST 用例 atk_aclnnBatchNormBackward.json 与其 executor_aclnnBatchNormBackward.py 用于在真实 NPU 环境下的端到端验证。小结batch_norm_grad_v3模块以两个 aclnn 接口完整承载了 BatchNorm 反向传播能力aclnnBatchNormBackward覆盖 950PRDT、A2/A3、Atlas 训练系列等多平台支持训练/推理双路径与 2-8 维输入aclnnFastBatchNormBackward则面向 Atlas A2 提供默认确定性的高性能实现并引入version参数控制内部算法版本。调用时牢记三点即可快速上手第一段接口负责校验与 workspace 计算、outputMask精确控制三个可选输出的开关、统计量参数的空指针会被自动填充默认值mean0、var1、weight1从而在不传部分统计量的推理场景下依然保持接口语义完整。赞分享人工智能算子库深度学习CANNAscend【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址https://gitcode.com/cann/ops-nn点击查看免费下载相关推荐CANN ops-nn 算子实战aclnnLogitGrad 两段式接口实现 Logit 反向传播CANN ops nn 算子实战aclnnLogitGrad 两段式接口实现 Logit 反向传播 本篇文章以 CANN 开源神经网络算子库 ops nn 中人工智能算子库深度学习CANNAscendCANN ops-nn CrossEntropyLossGrad 算子完全解析反向传播公式、aclnn 两段式接口与 NPU 实现原理CANN ops nn CrossEntropyLossGrad 算子完全解析反向传播公式、aclnn 两段式接口与 NPU 实现原理 CrossEntrop人工智能算子库深度学习CANNAscendSwitch、PS4 上也能流畅看B站wiliwili 手把手实用指南Switch、PS4 上也能流畅看B站wiliwili 手把手实用指南 wiliwili 是一款为手柄用户设计的第三方 B 站客户端既能跑在 Windows音视频桌面应用上一篇如何用 N_m3u8DL-RE 快速下载 m3u8/DASH 直播与点播流下一篇SilentPatchBully 使用指南:修复《Bully 奖学金版》Windows 10 崩溃的 ASI 补丁创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表