aclnnMaxPool
Supported Products
| Product | Supported |
|---|---|
| √ | |
| √ | |
| × | |
| × | |
| √ |
Function
- Description: Performs max pooling on the three-dimensional or four-dimensional input tensor.
- Formula:
When ceilMode is set to False, the H and W dimensions in the shape of the out tensor are deduced as follows:
When ceilMode is set to True, the H and W dimensions in the shape of the out tensor are deduced as follows:
- If the upper left corner of the sliding window starts from the lower or right padding or goes off-bounds (no valid value can be obtained), the sliding window result is discarded. The shape of the corresponding spatial axis needs to be subtracted by 1 based on the preceding deduction formula.
Prototype
Each operator has two-phase API calls. First, aclnnMaxPoolGetWorkspaceSize is called to obtain the workspace size required for computation and the executor that contains the operator computation process. Then, aclnnMaxPool is called to perform computation.
aclnnStatus aclnnMaxPoolGetWorkspaceSize(const aclTensor *self, const aclIntArray *kernelShape, const aclIntArray *strides, const int64_t autoPad, const aclIntArray *pads, const aclIntArray *dilations, const int64_t ceilMode, aclTensor *out, uint64_t *workspaceSize, aclOpExecutor **executor)aclnnStatus aclnnMaxPool(void *workspace, uint64_t workspaceSize, aclOpExecutor *executor, aclrtStream stream)
aclnnMaxPoolGetWorkspaceSize
Parameters:
- self (aclTensor*, compute input): aclTensor on the device, corresponding to H_in and W_in in the formula. The shape must be three-dimensional (C, H, W) or four-dimensional (N, C, H, W). N indicates the batch size, C indicates the tensor channel size, H indicates the tensor height, and W indicates the tensor width. Other dimensions are not supported. Non-contiguous tensors are supported. The data format can be ND.
Atlas training series products : The data type can be FLOAT16.Atlas A2 training products/Atlas A2 inference products andAtlas A3 training series products/Atlas A3 inference series products : The data type can be FLOAT16 or FLOAT32.
- kernelShape (aclIntArray*, compute input): size of the max pooling window, corresponding to k_h and k_w in the formula. The length is 1 or 2, and the array elements must be greater than 0.
- strides (aclIntArray*, compute input): strides of the window, corresponding to s_h and s_w in the formula. The array length is 0, 1, or 2, and the array elements must be greater than 0. If the array length is 0, the default value 1 is used for strides.
- autoPad (int64_t, compute input): padding mode. The value can only be set to 0, which indicates NOTSET.
- pads (aclIntArray*, compute input): padding at the start and end positions along the spatial axis, corresponding to padding_size in the formula. The length can be 0, 1, 2, or 4. If the array length is 0, no padding is performed. If the array length is 1, the same value is padded to H_top, H_bottom, W_left, and W_right. If the array length is 2, H_top and H_bottom are padded with the first value in the array, and W_left and W_right are padded with the second value in the array. If the array length is 4, padding is performed based on the [H_top, W_left, H_bottom, W_right] position. The sum of paddings in single spatial axis directions must be less than or equal to the kernelShape in the corresponding direction.
- dilations (aclIntArray*, compute input): dilation value along the kernel spatial axis, corresponding to dilation_size in the formula. Only the input scenario where the value is 1 is supported. The length can be 0, 1, 2, or 4.
- ceilMode (int64_t, compute input): rounding mode of the output shape. The value 0 indicates False (round down), and a non-zero value indicates True (round up).
- out (aclTensor*, compute output): The data type is the same as that of self. The shape is deduced from the preceding formula. The data format and dimensions are the same as those of the input self.
Atlas training series products : The data type can be FLOAT16.Atlas A2 training products/Atlas A2 inference products andAtlas A3 training series products/Atlas A3 inference series products : The data type can be FLOAT16 or FLOAT32.
- workspaceSize (uint64_t*, output): size of the workspace to be allocated on the device.
- executor (aclOpExecutor**, output): operator executor, containing the operator computation process.
- self (aclTensor*, compute input): aclTensor on the device, corresponding to H_in and W_in in the formula. The shape must be three-dimensional (C, H, W) or four-dimensional (N, C, H, W). N indicates the batch size, C indicates the tensor channel size, H indicates the tensor height, and W indicates the tensor width. Other dimensions are not supported. Non-contiguous tensors are supported. The data format can be ND.
Returns:
aclnnStatus: status code. For details, see aclnn Return Codes.
The first-phase API implements input parameter verification. The following errors may be thrown: 161001 (ACLNN_ERR_PARAM_NULLPTR): 1. The passed self or out is a null pointer. 161002 (ACLNN_ERR_PARAM_INVALID): 1. The data type or format of self is not supported. 2. self is not three-dimensional or four-dimensional. 3. The output shape computed by max pooling is inconsistent with the specified shape. 4. The length of kernelShape is not 1 or 2. 5. kernelShape has values less than or equal to 0. 6. The length of strides is not 0, 1, or 2. 7. strides has values less than or equal to 0. 8. The length of pads is not 0, 1, 2, or 4. 9. The sum of paddings in single spatial axis directions must be less than or equal to the kernelShape in the corresponding direction. 10. The length of dilation is not 0, 1, 2, or 4. 11. The value of dilation is not 1.
aclnnMaxPool
Parameters:
- workspace (void*, input): address of the workspace to be allocated on the device.
- workspaceSize (uint64_t, input): size of the workspace to be allocated on the device, which is obtained by the first-phase API aclnnMaxPoolGetWorkspaceSize.
- executor (aclOpExecutor*, input): operator executor, containing the operator computation process.
- stream (aclrtStream, input): stream for executing the task.
Returns:
aclnnStatus: status code. For details, see aclnn Return Codes.
Constraints
- Deterministic compute:
- aclnnMaxPool defaults to a deterministic implementation.
Example
The following example is for reference only. For details, see Compilation and Running Sample.
#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_max_pool.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) {
// (Fixed writing) Initialize resources.
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 memory on the 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);
// Call aclrtMemcpy to copy the data on the host to the memory on the 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);
// Compute the strides of the 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. (Fixed writing) Initialize the device and stream. For details, see the ACL API manual.
// Set the device ID in use.
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. Construct the input and output based on the API.
std::vector<int64_t> selfShape = {2, 2, 3, 3};
std::vector<int64_t> outShape = {2, 2, 2, 2};
std::vector<int64_t> kernel_size = {2, 2};
std::vector<int64_t> strides_size = {2, 2};
std::int64_t autoPads = 0;
std::vector<int64_t> padding_size = {0, 0, 0, 0};
std::vector<int64_t> dilation_size = {1, 1};
std::int64_t ceilMode = 1;
void* selfDeviceAddr = nullptr;
void* outDeviceAddr = nullptr;
aclTensor* self = nullptr;
aclTensor* out = nullptr;
aclIntArray* kernel_shape = aclCreateIntArray(kernel_size.data(), 2);
aclIntArray* strides = aclCreateIntArray(strides_size.data(), 2);
aclIntArray* padding = aclCreateIntArray(padding_size.data(), 4);
aclIntArray* dilations = aclCreateIntArray(dilation_size.data(), 2);
std::vector<float> selfHostData = {1, 2, 3, 4, 5, 6, 7, 8, 9,
10, 11, 12, 13, 14, 15, 16, 17, 18,
19, 20, 21, 22, 23, 24, 25, 26, 27,
28, 29, 30, 31, 32, 33, 34, 35, 36};
std::vector<float> outHostData = {0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0};
// Create a self aclTensor.
ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create an out aclTensor.
ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// 3. Call the CANN operator library API, which needs to be replaced with the actual API.
uint64_t workspaceSize = 0;
aclOpExecutor* executor;
// Call the first-phase API of aclnnMaxPool.
ret = aclnnMaxPoolGetWorkspaceSize(self, kernel_shape, strides, autoPads, padding, dilations, ceilMode, out, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnMaxPoolGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
// Allocate device memory based on workspaceSize computed 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 aclnnMaxPool.
ret = aclnnMaxPool(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnMaxPool failed. ERROR: %d\n", ret); return ret);
// 4. (Fixed writing) Wait until the task execution is 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. Modify the configuration based on the API definition.
auto size = GetShapeSize(outShape);
std::vector<float> outData(size, 0);
ret = aclrtMemcpy(outData.data(), outData.size() * sizeof(outData[0]), outDeviceAddr,
size * sizeof(outData[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, outData[i]);
}
// 6. Release aclTensor and aclScalar. Modify the configuration based on the API definition.
aclDestroyTensor(self);
aclDestroyTensor(out);
// 7. Release device resources.
aclrtFree(selfDeviceAddr);
aclrtFree(outDeviceAddr);
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}