aclnnBatchNormReduceBackward
Applicable Products
| Applicable Products | Supported |
|---|---|
| √ | |
| √ | |
| √ | |
| × | |
| × | |
| √ |
Function
Description:
It is primarily used to compute the gradient of the BatchNorm operation during backward propagation and perform reduction operations on some intermediate results to optimize computational efficiency. The computation results are as follows:
Computes the gradient of the loss function l with respect to the scale weight γ ().
Computes the gradient of the loss function l with respect to the offset β ().
Derives the intermediate quantities sumDy and sumDyXmu required for computing from the deviation dyi of the loss function l with respect to the output (yi). Here () is the gradient of the loss function l with respect to each input (xi) of the corresponding layer.
Formula:
Function Prototype
Each operator is divided into a two-phase API. You must first call the "aclnnBatchNormReduceBackwardGetWorkspaceSize" API to obtain the input parameters and calculate the required workspace size based on the process, and then call the "aclnnBatchNormReduceBackward" API to perform the computation.
aclnnStatus aclnnBatchNormReduceBackwardGetWorkspaceSize(
const aclTensor* gradOut,
const aclTensor* input,
const aclTensor* mean,
const aclTensor* invstd,
const aclTensor* weight,
const bool inputG,
const bool weightG,
const bool biasG,
aclTensor* sumDy,
aclTensor* sumDyXmu,
aclTensor* gradWeight,
aclTensor* gradBias,
uint64_t* workspaceSize,
aclOpExecutor** executor)aclnnStatus aclnnBatchNormReduceBackward(
void *workspace,
uint64_t workspaceSize,
aclOpExecutor *executor,
const aclrtStream stream)aclnnBatchNormReduceBackwardGetWorkspaceSize
Parameters
Parameter Input/Output Description Instruction Data Type Data Format Dimension (Shape) Non-contiguous Tensor gradOut (aclTensor*) Input Represents the gradient tensor, corresponding to `` in the formula. - Supports empty tensors.
- The data type and shape must be consistent with `input`.
FLOAT32, FLOAT16, BFLOAT16 ND 2-8 √ input (aclTensor*) Input. Represents the input tensor, corresponding to `x` in the formula. - Supports null Tensor.
- Defaults to the second dimension as the channel axis, and the channel axis value cannot be 0.
FLOAT32, FLOAT16, BFLOAT16 ND 2-8 √ mean (aclTensor*) Input. Represents the mean, corresponding to `μB` in the formula. - The shape length is equal to the length of the channel axis in the input parameter `input`.
FLOAT32, FLOAT16, BFLOAT16 ND 1 √ invstd (aclTensor*) Input Represents the reciprocal of the standard deviation, corresponding to the reciprocal of the square root of `(σB)2+eps` in the formula. - The shape length equals the length of the channel axis in the input parameter `input`.
FLOAT32, FLOAT16, BFLOAT16 ND 1 √ weight (aclTensor*) Input Represents the weight tensor, corresponding to `γ` in the formula. - The shape length equals the channel axis length in the input parameter `input`.
FLOAT32, FLOAT16, BFLOAT16 ND 1 √ inputG (bool) Input Output mask that indicates whether to output `sumDy` and `sumDyXmu`. - - - - - weightG (bool) Input Indicates the output mask, marking whether to output `gradWeight`. - - - - - biasG (bool) Input Indicates the output mask, marking whether to output `gradBias`. - - - - - sumDy (aclTensor*) Output Cumulative sum of the forward output gradient `gradOut`, corresponding to `sumDy` in the formula. - Optional output. Output if `inputG` is True. The size of the shape must be equal to the channel axis length of `input`.
- The data format must be consistent with `gradOut`.
FLOAT32, FLOAT16, BFLOAT16 ND 1 √ sumDyXmu (aclTensor*) Output Represents the sum of the product of the forward output gradient `gradOut` and the centered input data `(x-μB)`, corresponding to `sumDyXmu` in the formula. - Optional output. Output if `inputG` is True. The shape size must be equal to the channel axis length of `input`.
- The data format must be consistent with `gradOut`.
FLOAT32, FLOAT16, BFLOAT16 ND 1 ✓ gradWeight (aclTensor*) Output Represents the gradient of the scale parameter, corresponding to `gradWeight` in the formula. - Optional output. Output if `weightG` is True. The size of the shape must be equal to the channel axis length of `input`.
- The data format is consistent with `gradOut`.
FLOAT32, FLOAT16, BFLOAT16 ND 1 √ gradBias (aclTensor*) Output Represents the gradient of the bias parameter, corresponding to `gradBias` in the formula. - Optional output. Output if biasG is True. The size of the shape must be equal to the length of the channel axis of input.
- The data format must be consistent with that of gradOut.
FLOAT32, FLOAT16, BFLOAT16 ND 1 √ workspaceSize (uint64_t*) Output Returns the workspace size that the user needs to apply for on the Device side. - - - - - executor (aclOpExecutor**) Output Returns the operator executor, which contains the operator computation process. - - - - - Atlas training products ,Atlas inference products : The data type of gradOut, input, mean, invstd,weight,sumDy, sumDyXmu, gradWeight, and gradBias does not support BFLOAT16.
Return Value
aclnnStatus: return code. For details, see aclnn Return Code.
The first-phase API performs input parameter validation and returns an error in the following scenarios:
Return Code Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 The data type of input, meanAll, invstdAll, mean, invstd, runningMean, runningVar, or counts is not within the supported range. When inputG is true, sumDy or sumDyXmu is a null pointer. When weightG is true, gradWeight is a null pointer. When biasG is true, gradBias is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data type or data format of gradOut, input, mean, invstd, weight, sumDy, sumDyXmu, gradWeight, or gradBias is not within the supported range. The data type of gradOut must be consistent with that of input. When inputG is true, the data type or data format of sumDy or sumDyXmu is not within the supported range. When weightG is true, the data type or data format of gradWeight is not within the supported range. When biasG is true, the data type or data format of gradBias is not within the supported range. The data formats of gradOut and input are inconsistent. The dimension of gradOut or input exceeds 8. The dimension of gradOut or input is less than 2. The size of the channel axis of input is 0. When inputG is true, the size of sumDy or sumDyXmu is inconsistent with the channel axis of input. When weightG is true, the size of gradWeight is inconsistent with the channel axis of input. When biasG is true, the size of gradBias is inconsistent with the channel axis of input.
aclnnBatchNormReduceBackward
Parameters
Parameter Input/Output Description workspace Input Memory address of the workspace applied for on the Device side. workspaceSize Input Size of the workspace applied for on the Device side, obtained through the first-phase API aclnnBatchNormReduceBackwardGetWorkspaceSize. executor Input Operator executor, which contains the operator computation process. stream Input Specifies the stream that executes the task. Return Value
aclnnStatus: return code. For details, see aclnn Return Code.
Constraints
When any input is an empty tensor, the output is an empty tensor.
Deterministic computation:
- aclnnBatchNormReduceBackward defaults to a deterministic implementation.
Example
The following provides example code for reference only. For details about compilation and running, see Compile and Run Samples.
#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_batch_norm_backward_reduce.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;
}
void PrintOutResult(std::vector<int64_t>& shape, void** deviceAddr)
{
auto size = GetShapeSize(shape);
std::vector<float> resultData(size, 0);
auto ret = aclrtMemcpy(
resultData.data(), resultData.size() * sizeof(resultData[0]), *deviceAddr, 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);
for (int64_t i = 0; i < size; i++) {
LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]);
}
}
int Init(int32_t deviceId, aclrtStream* stream)
{
// Boilerplate: resource initialization.
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::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType,
aclTensor** tensor)
{
auto size = GetShapeSize(shape) * sizeof(T);
// Call aclrtMalloc to allocate device memory.
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);
// Call aclrtMemcpy to copy data from the host to the device memory.
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);
// Calculate the strides of a contiguous tensor.
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];
}
// Call the aclCreateTensor API to create an 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. (Boilerplate) Initialize the device/stream. See the ACL API manual.
// Fill in the deviceId based on the actual device.
int32_t deviceId = 0;
aclrtStream stream;
auto ret = Init(deviceId, &stream);
// Handle the check result as needed.
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
// 2. Construct the input and output. Customize the construction based on the API interface.
std::vector<int64_t> gradOutShape = {4, 2};
std::vector<int64_t> inputShape = {4, 2};
std::vector<int64_t> meanShape = {2};
std::vector<int64_t> invstdShape = {2};
std::vector<int64_t> weightShape = {2};
std::vector<int64_t> sumDyShape = {2};
std::vector<int64_t> sumDyXmuShape = {2};
std::vector<int64_t> gradWeightShape = {2};
std::vector<int64_t> gradBiasShape = {2};
void* gradOutDeviceAddr = nullptr;
void* inputDeviceAddr = nullptr;
void* meanDeviceAddr = nullptr;
void* invstdDeviceAddr = nullptr;
void* weightDeviceAddr = nullptr;
void* sumDyDeviceAddr = nullptr;
void* sumDyXmuDeviceAddr = nullptr;
void* gradWeightDeviceAddr = nullptr;
void* gradBiasDeviceAddr = nullptr;
aclTensor* gradOut = nullptr;
aclTensor* input = nullptr;
aclTensor* mean = nullptr;
aclTensor* invstd = nullptr;
aclTensor* weight = nullptr;
aclTensor* sumDy = nullptr;
aclTensor* sumDyXmu = nullptr;
aclTensor* gradWeight = nullptr;
aclTensor* gradBias = nullptr;
std::vector<float> gradOutHostData = {1, 1, 1, 2, 2, 2, 3, 3};
std::vector<float> inputHostData = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<float> meanHostData = {1, 1};
std::vector<float> invstdHostData = {1, 1};
std::vector<float> weightHostData = {1, 1};
std::vector<float> sumDyHostData = {1, 1};
std::vector<float> sumDyXmuHostData = {1, 1};
std::vector<float> gradWeightHostData = {1, 1};
std::vector<float> gradBiasHostData = {1, 1};
ret = CreateAclTensor(gradOutHostData, gradOutShape, &gradOutDeviceAddr, aclDataType::ACL_FLOAT, &gradOut);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(inputHostData, inputShape, &inputDeviceAddr, aclDataType::ACL_FLOAT, &input);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(meanHostData, meanShape, &meanDeviceAddr, aclDataType::ACL_FLOAT, &mean);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(invstdHostData, invstdShape, &invstdDeviceAddr, aclDataType::ACL_FLOAT, &invstd);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(weightHostData, weightShape, &weightDeviceAddr, aclDataType::ACL_FLOAT, &weight);
CHECK_RET(ret == ACL_SUCCESS, return ret);
bool inputG = true;
bool weightG = true;
bool biasG = true;
ret = CreateAclTensor(sumDyHostData, sumDyShape, &sumDyDeviceAddr, aclDataType::ACL_FLOAT, &sumDy);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(sumDyXmuHostData, sumDyXmuShape, &sumDyXmuDeviceAddr, aclDataType::ACL_FLOAT, &sumDyXmu);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(
gradWeightHostData, gradWeightShape, &gradWeightDeviceAddr, aclDataType::ACL_FLOAT, &gradWeight);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(gradBiasHostData, gradBiasShape, &gradBiasDeviceAddr, aclDataType::ACL_FLOAT, &gradBias);
CHECK_RET(ret == ACL_SUCCESS, return ret);
uint64_t workspaceSize = 0;
aclOpExecutor* executor;
// Example of calling the aclnnBatchNormReduceBackward API.
// 3. Call the CANN operator library API. Replace it with the specific API name.
// Call the first-phase API of aclnnBatchNormReduceBackward.
ret = aclnnBatchNormReduceBackwardGetWorkspaceSize(
gradOut, input, mean, invstd, weight, inputG, weightG, biasG, sumDy, sumDyXmu, gradWeight, gradBias,
&workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBatchNormReduceBackwardGetWorkspaceSize failed. ERROR: %d\n", ret);
return ret);
// Apply for device memory based on the workspaceSize calculated by the first-phase API.
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);
}
// Call the second-phase API of aclnnBatchNormReduceBackward.
ret = aclnnBatchNormReduceBackward(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBatchNormReduceBackward failed. ERROR: %d\n", ret); return ret);
// 4. (Boilerplate) Synchronously wait for task execution to complete.
ret = aclrtSynchronizeStream(stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
// 5. Obtain the output values and copy the results from the device memory to the host memory. Modify based on the specific API definition.
PrintOutResult(sumDyShape, &sumDyDeviceAddr);
PrintOutResult(sumDyXmuShape, &sumDyXmuDeviceAddr);
PrintOutResult(gradWeightShape, &gradWeightDeviceAddr);
PrintOutResult(gradBiasShape, &gradBiasDeviceAddr);
// 6. Release aclTensor and aclScalar. Modify based on the specific API definition.
aclDestroyTensor(gradOut);
aclDestroyTensor(input);
aclDestroyTensor(mean);
aclDestroyTensor(invstd);
aclDestroyTensor(weight);
aclDestroyTensor(sumDy);
aclDestroyTensor(sumDyXmu);
aclDestroyTensor(gradWeight);
aclDestroyTensor(gradBias);
// 7. Release device resources. Modify based on the specific API definition.
aclrtFree(gradOutDeviceAddr);
aclrtFree(inputDeviceAddr);
aclrtFree(meanDeviceAddr);
aclrtFree(invstdDeviceAddr);
aclrtFree(weightDeviceAddr);
aclrtFree(sumDyDeviceAddr);
aclrtFree(sumDyXmuDeviceAddr);
aclrtFree(gradWeightDeviceAddr);
aclrtFree(gradBiasDeviceAddr);
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}