aclnnMaxPool2dWithIndicesBackward
Applicable Products
| Product | Supported |
|---|---|
| √ | |
| √ | |
| √ | |
| × | |
| × | |
| × |
Function
Backward propagation of the forward max pooling operation aclnnMaxPool2dWithIndices.
Derivation formula for input tensor:
When ceilMode is set to False, the derivation formula for the H and W dimensions in the shape of the indices tensor is as follows:
When ceilMode is set to True, the derivation formula for the H and W dimensions in the shape of the out tensor is as follows:
If the top-left starting position of a sliding window falls within the bottom or right padding area, or lies outside the image (where no valid value can be obtained), the result of that sliding window is discarded. In this case, the shape of the corresponding spatial axis is reduced by 1 based on the derivation formula above:
Function Prototype
Each operator consists of a two-phase API. You must first call the "aclnnMaxPool2dWithIndicesBackwardGetWorkspaceSize" API to obtain the workspace size required for computation and the executor that encapsulates the operator computation process, and then call the "aclnnMaxPool2dWithIndicesBackward" API to perform the computation.
aclnnStatus aclnnMaxPool2dWithIndicesBackwardGetWorkspaceSize(
const aclTensor *gradOutput,
const aclTensor *self,
const aclTensor *indices,
const aclIntArray *kernelSize,
const aclIntArray *stride,
const aclIntArray *padding,
const aclIntArray *dilation,
bool ceilMode,
aclTensor *gradInput,
uint64_t *workspaceSize,
aclOpExecutor **executor)aclnnStatus aclnnMaxPool2dWithIndicesBackward(
void *workspace,
uint64_t workspaceSize,
aclOpExecutor *executor,
aclrtStream stream)aclnnMaxPool2dWithIndicesBackwardGetWorkspaceSize
Parameters:
Parameter Input/Output Description Instruction Data Type Data Format Dimension (Shape) Non-contiguous Tensor gradOutput Input Gradient output from the previous step during backward propagation. Has the same shape as the forward output and the same data format as self. FLOAT, FLOAT16, BFLOAT16 ND, NCHW, NHWC. 3-4 √ self Input Forward input data. - FLOAT, FLOAT16, BFLOAT16 ND, NCHW, NHWC 3-4 √ indices Input Indices of the forward output. Has the same shape as the input gradOutput Specifies the index positions of the maximum elements in the forward output. The data format must be consistent with self. INT32, INT64 ND, NCHW, NHWC 3-4 √ kernelSize Input. Size of the sliding window used in the pooling operation. Only supports a length of 1 or 2. INT64 - - - stride Input Step size of the sliding window. Only lengths of 0, 1, and 2 are supported. When the length of stride is 0, the value of stride equals the value of kernelSize. INT64 - - - padding Input Padding of the input data, indicating the amount of padding on each dimension of the input, which affects how the pooling window covers the entire input tensor. Only lengths of 1 and 2 are supported. INT64 - - - dilation Input Specifies the dilation factor for the pooling operation, which increases the spacing between elements within the pooling window. - INT64 - - - ceilMode Input Specifies the rounding method used when computing the output shape. If set to True, uses ceiling rounding when computing the output shape; if set to False, uses floor rounding. BOOL - - - gradInput Output Gradient output by backward propagation. Has the same shape and data format as self. BFLOAT16, FLOAT16, FLOAT32 ND, NCHW, NHWC. 3-4 √ workspaceSize Output Returns the workspace size to be requested on the Device side. - - - - - executor Output Returns the operator executor, which contains the operator computation process. - - - - - Ascend 950PR/Ascend 950DT : The gradOutput and self support FLOAT, FLOAT16, and BFLOAT16 data types, and ND, NCHW, and NHWC data formats. The indices support INT32 and INT64 data types. Supports dilation element values greater than 0, and 1D or 2D input.Atlas A2 training products/Atlas A2 inference products ,Atlas A3 training products/Atlas A3 inference products : The gradOutput and self support the FLOAT data type. The ND and NCHW data formats are supported. When the input is 3D, it represents CHW values. The indices support the INT32 data type. Only dilation of (1, 1) is supported.Return value
aclnnStatus: Return Status. See aclnn Return Code. The first-phase API performs input parameter validation and reports an error in the following scenarios:
Return Code Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 The passed self and indices are null pointers. ACLNN_ERR_PARAM_INVALID 161002 The data types of gradOutput, self, indices, and gradInput are not within the supported range. The data formats of gradOutput, self, indices, and gradInput are not within the supported range. The shapes of gradOutput and indices are inconsistent, or the shapes of self and gradInput are inconsistent. The length of kernelSize is not 1 or 2. kernelSize contains a value less than or equal to 0. The length of stride is not 0, 1, or 2. stride contains a value less than or equal to 0. The number of elements in padding is not equal to 1 or 2. The padding values contain a value less than 0 or greater than kernelSize. The dilation element values do not meet the input parameter requirements.
aclnnMaxPool2dWithIndicesBackward
Parameters:
Parameter Input/Output Description workspace Input Workspace memory address applied for on the device side. workspaceSize Input Workspace size applied for on the device side, obtained through the first-phase API aclnnMaxPool2dWithIndicesBackwardGetWorkspaceSize. executor Input Operator executor that contains the operator computation process. stream Input Specifies the stream for task execution. Return value
aclnnStatus: return code. For details, see aclnn Return Code.
Constraints
Deterministic computation:
- aclnnMaxPool2dWithIndicesBackward defaults to a non-deterministic implementation. You can enable deterministic computation by calling aclrtCtxSetSysParamOpt.
The input data does not support NaN or -Inf. The indices value must not exceed in the formula and must be greater than or equal to 0.
Example
The following provides example code for reference only. For details about compilation and running, see Compile and Run Samples.
#include <cstdio>
#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_max_pool2d_with_indices_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::vector<int64_t>& shape) {
int64_t shapeSize = 1;
for (auto i : shape) {
shapeSize *= i;
}
return shapeSize;
}
int Init(int32_t deviceId, aclrtStream* stream) {
// Boilerplate for 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 apply for 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 host data to 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 aclCreateTensor to create an 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. (Boilerplate) Initialize the device/stream. See the acl API manual.
// Fill in the deviceId based on your actual device.
int32_t deviceId = 0;
aclrtStream stream;
auto ret = Init(deviceId, &stream);
// Handle the check based on your requirements.
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 = {1, 1, 2, 1};
std::vector<int64_t> selfShape = {1, 1, 4, 3};
std::vector<int64_t> indicesShape = {1, 1, 2, 1};
std::vector<int64_t> gradInShape = {1, 1, 4, 3};
std::vector<int64_t> kernelSizeData = {2, 2};
std::vector<int64_t> strideData = {2, 2};
std::vector<int64_t> paddingData = {0, 0};
std::vector<int64_t> dilationData = {1, 1};
void* gradOutDeviceAddr = nullptr;
void* selfDeviceAddr = nullptr;
void* indicesDeviceAddr = nullptr;
void* gradInDeviceAddr = nullptr;
aclTensor* gradOut = nullptr;
aclTensor* self = nullptr;
aclTensor* indices = nullptr;
aclTensor* gradIn = nullptr;
std::vector<float> gradOutHostData = {0.4757, 0.1726};
std::vector<float> selfHostData = {0.0850, -0.5147, -0.0212, -0.5654, -0.3222, 0.5847, 1.7510, 0.9954, 0.1842, 0.8392, 0.4835, 0.9213};
std::vector<int32_t> indicesHostData = {0, 6};
std::vector<float> gradInHostData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// Create the gradOut aclTensor.
ret = CreateAclTensor(gradOutHostData, gradOutShape, &gradOutDeviceAddr, aclDataType::ACL_FLOAT, &gradOut);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the self aclTensor.
ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create indices aclTensor.
ret = CreateAclTensor(indicesHostData, indicesShape, &indicesDeviceAddr, aclDataType::ACL_INT32, &indices);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create gradIn aclTensor.
ret = CreateAclTensor(gradInHostData, gradInShape, &gradInDeviceAddr, aclDataType::ACL_FLOAT, &gradIn);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create input array.
aclIntArray* kernelSize = aclCreateIntArray(kernelSizeData.data(), 2);
aclIntArray* stride = aclCreateIntArray(strideData.data(), 2);
aclIntArray* padding = aclCreateIntArray(paddingData.data(), 2);
aclIntArray* dilation = aclCreateIntArray(dilationData.data(), 2);
const bool ceilMode = false;
uint64_t workspaceSize = 0;
aclOpExecutor* executor;
// Example of aclnnMaxPool2dWithIndicesBackward API call
// 3. Call the CANN operator library API. Replace with the specific API name.
// Call the first-phase API of aclnnMaxPool2dWithIndicesBackward.
ret = aclnnMaxPool2dWithIndicesBackwardGetWorkspaceSize(gradOut, self, indices, kernelSize, stride, padding, dilation, ceilMode, gradIn, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnMaxPool2dWithIndicesBackwardGetWorkspaceSize 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 aclnnMaxPool2dWithIndicesBackward.
ret = aclnnMaxPool2dWithIndicesBackward(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnMaxPool2dWithIndicesBackward failed. ERROR: %d\n", ret); return ret);
// 4. (Boilerplate) Synchronize and 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 value and copy the result from the device memory to the host memory. Modify this based on the specific API definition.
auto size = GetShapeSize(gradInShape);
std::vector<float> 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 gradIn 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. Release aclTensor and aclScalar. Modify based on the specific API definition.
aclDestroyTensor(gradOut);
aclDestroyTensor(self);
aclDestroyTensor(indices);
aclDestroyTensor(gradIn);
// 7. Release device resources. Modify based on the specific API definition.
aclrtFree(gradOutDeviceAddr);
aclrtFree(selfDeviceAddr);
aclrtFree(indicesDeviceAddr);
aclrtFree(gradInDeviceAddr);
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}