aclnnUpsampleBilinear2dBackwardV2
Applicable Products
| Product | Supported |
|---|---|
| √ | |
| √ | |
| √ | |
| × | |
| √ | |
| √ |
Function
Description: Backpropagation of aclnnUpsampleBilinear2d.
Atlas A2 training products/Atlas A2 inference products ,Atlas A3 training products/Atlas A3 inference products ,Ascend 950PR/Ascend 950DT : Compared with aclnnUpsampleBilinear2dBackward, this API supports scale-based computation and adds constraints on outputSize and scale. Select the appropriate API based on actual requirements.Atlas training products ,Atlas inference products : Compared with aclnnUpsampleBilinear2dBackward, this API has no changes.
Formula:
- Core forward algorithm logic:
- Map each point of the target image back to the source image, obtaining a coordinate with fractional parts.
- Based on this floating-point coordinate, compute the adjacent points in the source image.
- Calculate the weights from each adjacent point to the corresponding target point, then multiply and accumulate by weight to obtain the target point value.
- Specific computation logic:
The scaling method is divided into corner alignment and edge alignment. Corner alignment means aligning with the pixel center of the top-left corner of the original image, while edge alignment means aligning with the top-left vertex and two edges of the original image. Differences exist in the calculation of the scaling factor and coordinate positions. For a 2D interpolation point , the following formulas apply:
Therefore, for a point p(x,y) in a certain direction of the output, the point mapped back to the original image is denoted as q(x',y'), and the relationship is as follows:
Where:
Then the following formula applies:
Assume that the output image out of the forward interpolation is influenced by the original image input , then:
- Core forward algorithm logic:
Function Prototype
Each operator is divided into a two-phase API. You must first call the "aclnnUpsampleBilinear2dBackwardV2GetWorkspaceSize" API to obtain the workspace size required for computation and the executor that contains the operator computation process, and then call the "aclnnUpsampleBilinear2dBackwardV2" API to execute the computation.
aclnnStatus aclnnUpsampleBilinear2dBackwardV2GetWorkspaceSize(
const aclTensor *gradOut,
const aclIntArray *outputSize,
const aclIntArray *inputSize,
bool alignCorners,
double scalesH,
double scalesW,
aclTensor *out,
uint64_t *workspaceSize,
aclOpExecutor **executor)aclnnStatus aclnnUpsampleBilinear2dBackwardV2(
void* workspace,
uint64_t workspace_size,
aclOpExecutor* executor,
aclrtStream stream)aclnnUpsampleBilinear2dBackwardV2GetWorkspaceSize
Parameters
Parameter Name Input/Output Description Usage Description Data Type Data Format Dimension (shape) Non-contiguous Tensor gradOut (aclTensor*) Input Represents the gradient tensor for backward computation, corresponding to `gradOutput` in the corresponding formula. Empty tensors are not supported. FLOAT32, FLOAT16, BFLOAT16 NCHW, NHWC 4 √ outputSize (aclIntArray*) input Represents the spatial size of the input `gradOut` in the H and W dimensions. Corresponds to `outputSize` in the corresponding formula. size is 2, and each element is greater than zero. INT64 - - - inputSize (aclIntArray*) Input Represents the spatial size of the output `out` in the N, C, H, and W dimensions, respectively. Corresponds to `inputSize` in the corresponding formula. The size is 4, and each element is greater than zero. INT64 - - - alignCorners (bool) Input Determines whether to align corner pixels, corresponding to `alignCorners` in the corresponding formula. If set to True, the input and output tensors are aligned by the centers of their corner pixels, preserving the values at the corner pixels. If set to False, the input and output tensors are aligned by the corner points of their corner pixels, and the interpolation uses edge values to fill values outside the boundaries, so that this operation remains consistent across different input sizes. - - - - scalesH (double) input Represents the height dimension multiplier of the output `out`, corresponding to `scalesH` in the corresponding formula. - - - - - scalesW (double) Input Represents the width dimension multiplier of the output `out`, corresponding to `scalesW` in the formula. - - - - - out (aclTensor*) Output Represents the output tensor of the backward computation, corresponding to `gradInput` in the formula. - Empty tensors are not supported.
- The data type, data format, and shape remain consistent with the input `gradOut`.
FLOAT32, FLOAT16, BFLOAT16 NCHW, NHWC 4 √ workspaceSize (uint64_t*) Output Returns the workspace size to be applied for on the Device side. - - - - - executor (aclOpExecutor**) Output Returns the op executor, which contains the operator computation process. - - - - - Atlas training products ,Atlas inference products :The data type of the parameters
gradOutandoutdoes not support BFLOAT16.
Return Value
aclnnStatus: return status code. For details, see aclnn Return Codes.
The first-phase API completes input parameter validation and reports an error in the following scenarios:
Return Code Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 The input gradOut, outputSize, inputSize, or out is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data types or data formats of gradOut and out are not within the supported range. The data types or shapes of gradOut and out are inconsistent. The dimension of gradOut is not 4. The size of outputSize is not equal to 2. An element value of outputSize is less than 1. The size of inputSize is not equal to 4. An element value of inputSize is less than 1. The sizes of gradOut and inputSize differ in the N and C dimensions. The sizes of gradOut in the H and W dimensions are not consistent with outputSize[0] and outputSize[1]. The dimensional sizes of the N/C axes of gradOut and out are not equal.
aclnnUpsampleBilinear2dBackwardV2
Parameters
Parameter Name Input/Output Description workspace Input Workspace memory address applied on the Device side. workspaceSize Input Workspace size applied on the Device side, obtained by the first-phase API aclnnUpsampleBilinear2dBackwardV2GetWorkspaceSize. executor input Operator executor, which contains the operator computation process. stream Input Specifies the stream for task execution. Return Value
aclnnStatus: return code. For details, see aclnn Return Codes.
Constraints
Shape constraints for parameters
gradOutandout:- The value of each dimension is less than or equal to 2^20.
- The N-axis and C-axis of parameter
outremain consistent with those ofgradOut. - Memory usage must be less than 60 GB. The calculation formula for memory usage is as follows:
Where:
- N represents the N axis of the input and output.
- C represents the C axis of the input and output.
- N * C * gradOut_H < 2^31
The parameters inputSize, outputSize, scalesH, and scalesW must satisfy the following constraints:
Deterministic computation:
- aclnnUpsampleBilinear2dBackwardV2 uses deterministic implementation by default.
Call Example
The following sample code is for reference only. For details about compilation and execution, see Compile and Run Samples.
#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_upsample_bilinear_2d_backward_v2.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: 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 memory on the device side.
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 side 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);
// Compute 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_NCHW,
shape.data(),
shape.size(),
*deviceAddr);
return 0;
}
int main()
{
// 1. (Standard practice) Initialize the device/stream. Refer to the acl API manual.
// Set deviceId based on your actual device.
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. Customize the construction based on the API.
std::vector<int64_t> selfShape = {1, 1, 6, 6};
std::vector<int64_t> outShape = {1, 1, 3, 3};
void *selfDeviceAddr = nullptr;
void *outDeviceAddr = nullptr;
aclTensor *self = nullptr;
aclTensor *out = nullptr;
std::vector<float> selfHostData(36, 1);
std::vector<float> outHostData = {0, 0, 0, 0, 0, 0, 0, 0, 0};
// Create self aclTensor
ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create out aclTensor
ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
CHECK_RET(ret == ACL_SUCCESS, return ret);
std::vector<int64_t> outArraySize = {6, 6};
const aclIntArray *outputSize = aclCreateIntArray(outArraySize.data(), outArraySize.size());
CHECK_RET(outputSize != nullptr, return ACL_ERROR_INTERNAL_ERROR);
std::vector<int64_t> inputArraySize = {1, 1, 3, 3};
const aclIntArray *inputSize = aclCreateIntArray(inputArraySize.data(), inputArraySize.size());
CHECK_RET(inputSize != nullptr, return ACL_ERROR_INTERNAL_ERROR);
// 3. Call the CANN operator library API. Replace with the specific API name.
uint64_t workspaceSize = 0;
aclOpExecutor *executor;
// Call the first-phase API of aclnnUpsampleBilinear2dBackwardV2
ret = aclnnUpsampleBilinear2dBackwardV2GetWorkspaceSize(
self, outputSize, inputSize, 1, 2, 2, out, &workspaceSize, &executor);
CHECK_RET(
ret == ACL_SUCCESS, LOG_PRINT("aclnnUpsampleBilinear2dBackwardV2GetWorkspaceSize 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 aclnnUpsampleBilinear2dBackwardV2.
ret = aclnnUpsampleBilinear2dBackwardV2(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnUpsampleBilinear2dBackwardV2 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 value and copy the result from the device memory to the host side. Modify based on the specific API definition.
auto size = GetShapeSize(outShape);
std::vector<float> resultData(size, 0);
ret = aclrtMemcpy(resultData.data(),
resultData.size() * sizeof(resultData[0]),
outDeviceAddr,
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. Release aclTensor and aclScalar. Modify based on the specific API definition.
aclDestroyTensor(self);
aclDestroyTensor(out);
aclDestroyIntArray(outputSize);
aclDestroyIntArray(inputSize);
// 7. Release device resources. Modify based on the specific API definition.
aclrtFree(selfDeviceAddr);
aclrtFree(outDeviceAddr);
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}