CANN/ops-nn批量归一化反向传播
aclnnFastBatchNormBackward【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nn 查看源码产品支持情况产品是否支持Ascend 950PR/Ascend 950DT×Atlas A3 训练系列产品/Atlas A3 推理系列产品×Atlas A2 训练系列产品/Atlas A2 推理系列产品√Atlas 200I/500 A2 推理产品×Atlas 推理系列产品×Atlas 训练系列产品×功能说明接口功能aclnnBatchNorm的反向传播高性能版本。用于计算输入张量的梯度以便在反向传播过程中更新模型参数。计算公式当training为true时$$ gradInput \frac{weight}{ n{\sqrt{saveVar eps}} }(n * gradOut - \sum^m_{i0}{gradOut} - \frac{x-saveMean}{ {\sqrt{saveVar eps}} }\sum^m_{i0}({gradOut} *\frac{x-saveMean}{ {\sqrt{saveVar eps}} } )) $$$$ gradWeight \sum^m_{i0}[{gradOut} * (x - saveMean)] * \frac{1}{ {\sqrt{saveVar eps}} } $$$$ gradBias \sum^m_{i0}{gradOut} $$当training为false时$$ gradInput gradOut * \frac{1}{ {\sqrt{runningVar eps}} } * weight $$$$ gradWeight \sum^m_{i0}[{gradOut} * (x - runningMean)] * \frac{1}{ {\sqrt{runningVar eps}} } $$$$ gradBias \sum^m_{i0}{gradOut} $$函数原型每个算子分为两段式接口必须先调用“aclnnFastBatchNormBackwardGetWorkspaceSize”接口获取入参并根据流程计算所需workspace大小再调用“aclnnFastBatchNormBackward”接口执行计算。aclnnStatus aclnnFastBatchNormBackwardGetWorkspaceSize( const aclTensor *gradOut, const aclTensor *input, const aclTensor *weight, const aclTensor *runningMean, const aclTensor *runningVar, const aclTensor *saveMean, const aclTensor *saveInvstd, bool training, double eps, const aclBoolArray *outputMask, int version, aclTensor *gradInput, aclTensor *gradWeight, aclTensor *gradBias, uint64_t *workspaceSize, aclOpExecutor **executor)aclnnStatus aclnnFastBatchNormBackward( void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, const aclrtStream stream)aclnnFastBatchNormBackwardGetWorkspaceSize参数说明参数名输入/输出描述使用说明数据类型数据格式维度(shape)非连续TensorgradOutaclTensor*输入表示梯度Tensor对应公式中的gradOut。支持空Tensor。支持的shape和格式有2维对应的格式为NC3维对应的格式为NCL4维对应的格式为NCHW5维对应的格式为NCDHW6-8维对应的格式为ND其中第2维固定为channel轴。FLOAT32、FLOAT16、BFLOAT16NC、NCL、NCHW、NCDHW、ND2-8√inputaclTensor*输入表示正向的输入Tensor对应公式中的x。支持空Tensor。数据类型、shape、数据格式均需要与gradOut保持一致。FLOAT32、FLOAT16、BFLOAT16NC、NCL、NCHW、NCDHW、ND2-8√weightaclTensor*输入表示权重Tensor对应公式中的weight。支持空Tensor。shape长度与入参input中channel轴的长度相等。FLOAT32、FLOAT16、BFLOAT16ND1√runningMeanaclTensor*输入表示训练期间计算的平均值对应公式中的runningMean。支持空Tensor。shape长度与入参input中channel轴的长度相等。FLOAT32、FLOAT16、BFLOAT16ND1√runningVaraclTensor*输入表示训练期间计算的方差对应公式中的runningVar。支持空Tensor。数值为非负数。shape长度与入参input中channel轴的长度相等。FLOAT32、FLOAT16、BFLOAT16ND1√saveMeanaclTensor*输入表示保存的均值对应公式中的saveMean。支持空Tensor。shape长度与入参input中channel轴的长度相等。FLOAT32、FLOAT16、BFLOAT16ND1√saveInvstdaclTensor*输入表示保存的标准差的倒数分别对应公式中的(Var(x) eps)开平方的倒数。支持空Tensor。数值为非负数。shape长度与入参input中channel轴的长度相等。FLOAT32、FLOAT16、BFLOAT16ND1√trainingbool输入表示标记是否训练场景对应公式描述中的training。true表示训练场景false表示推理场景。----epsdouble输入表示添加到方差中的值以避免出现除以零的情况。对应公式中的eps。-----outputMaskaclBoolArray*输入表示输出的掩码。size为3。分别表示是否输出gradInput、gradWeight、 gradBias若为true则输出否则输出对应位置返回空。BoolArray---versionint输入表示算子内部使用的算法版本号。目前支持可选值0、1。默认值0。----gradInputaclTensor*输出表示输入Tensor的梯度对应公式中的gradInput。支持空Tensor。可选输出若outputMask[0]为True则需要输出否则不输出。数据类型、shape、数据格式均需要与gradOut保持一致。FLOAT32、FLOAT16、BFLOAT16NC、NCL、NCHW、NCDHW、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执行器包含了算子计算流程。-----Atlas A2 训练系列产品/Atlas A2 推理系列产品 、 Atlas A3 训练系列产品/Atlas A3 推理系列产品 参数weight、runningMean、runningVar、saveMean、saveInvstd、gradWeight、gradBias的数据类型与gradOut的保持一致。返回值aclnnStatus返回状态码具体参见aclnn返回码。第一段接口完成入参校验出现以下场景时报错返回码错误码描述ACLNN_ERR_PARAM_NULLPTR161001传入的gradOut、input指针是空指针。当outputMask[0]为true传入的gradInput是空指针时。当outputMask[1]为true传入的gradWeight是空指针时。当outputMask[2]为true传入的gradBias是空指针时。ACLNN_ERR_PARAM_INVALID161002inputgradOut数据类型、数据格式和shape不在支持的范围之内。weightrunningMeanrunningVarsaveMeansaveInvstd非空时数据类型、数据格式和shape不在支持的范围之内。outputMask的长度不为3。当outputMask[0]为truegradInput数据类型、数据格式和shape不在支持的范围之内时。当outputMask[1]为truegradWeight数据类型、数据格式和shape不在支持的范围之内时。当outputMask[2]为truegradBias数据类型、数据格式和shape不在支持的范围之内时。weightrunningMeanrunningVarsaveMeansaveInvstdgradWeight非空时gradBias非空时的shape长度与input shape中channel轴的长度不相等。input、gradOut、gradInput非空时的数据格式不一致。input、gradOut、gradInput非空时的数据类型不一致。input、gradOut、gradInput非空时的shape不一致或者shape的维度大于8维或者小于2维。aclnnFastBatchNormBackward参数说明参数名输入/输出描述workspace输入在Device侧申请的workspace内存地址。workspaceSize输入在Device侧申请的workspace大小由第一段接口aclnnFastBatchNormBackwardGetWorkspaceSize获取。executor输入op执行器包含了算子计算流程。stream输入指定执行任务的Stream。返回值aclnnStatus返回状态码具体参见aclnn返回码。约束说明确定性计算aclnnFastBatchNormBackward默认确定性实现。调用示例示例代码如下仅供参考具体编译和执行过程请参考编译与运行样例。#include iostream #include vector #include acl/acl.h #include aclnnop/aclnn_fast_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); 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 ACL_SUCCESS, LOG_PRINT(Init acl failed. ERROR: %d\n, ret); return ret); // 2. 构造输入与输出需要根据API的接口自定义构造 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); // 创建self 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); // 创建sVar 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; // aclnnBatchNormBackward接口调用示例 // 3. 调用CANN算子库API需要修改为具体的API名称 // 调用aclnnFastBatchNormBackward第一段接口 ret aclnnFastBatchNormBackwardGetWorkspaceSize(gradOut, self, weight, rMean, rVar, sMean, sVar, training, eps, outMask, 0, 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); } // 调用aclnnFastBatchNormBackward第二段接口 ret aclnnFastBatchNormBackward(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侧需要根据具体API的接口定义修改 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和aclScalar需要根据具体API的接口定义修改 aclDestroyTensor(gradOut); aclDestroyTensor(self); aclDestroyTensor(weight); aclDestroyTensor(rMean); aclDestroyTensor(rVar); aclDestroyTensor(sMean); aclDestroyTensor(sVar); aclDestroyBoolArray(outMask); aclDestroyTensor(gradIn); aclDestroyTensor(gradWeight); aclDestroyTensor(gradBias); // 7. 释放device资源需要根据具体API的接口定义修改 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; }【免费下载链接】ops-nn本项目是CANN提供的神经网络类计算算子库实现网络在NPU上加速计算。项目地址: https://gitcode.com/cann/ops-nn创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考