aclnnUpsampleBilinear2dBackward
Applicable Products
| Product | Supported |
|---|---|
| √ | |
| √ | |
| √ | |
| × | |
| √ | |
| √ |
Function
- Description: Backward propagation of aclnnUpsampleBilinear2d.
- Formula:
- Core algorithm logic of the forward pass:
- Map each point of the target image back to the source image, obtaining a coordinate with decimal values.
- Based on this floating-point coordinate, calculate the adjacent points in the original 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 calculation logic:
The scaling method is divided into corner alignment and edge alignment. Corner alignment means aligning by the pixel center of the top-left corner of the original image, while edge alignment means aligning by the top-left vertex and two edges of the original image. Differences exist in the calculation of scaling factors and coordinate positions. For a two-dimensional 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 affected by the original image input , then:
- Core algorithm logic of the forward pass:
Function Prototype
Each operator is divided into a two-phase API. You must first call the "aclnnUpsampleBilinear2dBackwardGetWorkspaceSize" API to obtain the required workspace size and the executor that contains the operator computation process, and then call the "aclnnUpsampleBilinear2dBackward" API to perform the computation.
aclnnStatus aclnnUpsampleBilinear2dBackwardGetWorkspaceSize(
const aclTensor *gradOut,
const aclIntArray *outputSize,
const aclIntArray *inputSize,
bool alignCorners,
double scalesH,
double scalesW,
aclTensor *out,
uint64_t *workspaceSize,
aclOpExecutor **executor)aclnnStatus aclnnUpsampleBilinear2dBackward(
void* workspace,
uint64_t workspace_size,
aclOpExecutor* executor,
aclrtStream stream)aclnnUpsampleBilinear2dBackwardGetWorkspaceSize
Parameters
Parameter Name Input/Output Description Usage Notes Data Type Data Format Dimension (shape) Non-Contiguous Tensor gradOut (aclTensor*) Input Represents the gradient tensor for backward computation, corresponding to `gradOutput` in the formula. Empty tensors are not supported. FLOAT32, FLOAT16, BFLOAT16 NCHW, NHWC 4 √ outputSize (aclIntArray*) Input Represents the spatial size of the input `gradOutput` 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. Corresponding formula: `inputSize`. 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 formula. If set to True, the input and output tensors are aligned by the center points of their corner pixels, preserving the values at 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 value padding for out-of-boundary values, making this operation independent of the input size scalesH and scalesW when kept unchanged. - - - - scalesH (double) Input Represents the height dimensional multiplier of the output `out`, corresponding to `scalesH` in the formula. - - - - - scalesW (double) Input Represents the width dimensional multiplier of the output `out`, corresponding to `scalesW` in the corresponding 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 format must be consistent with the input `gradOut`.
FLOAT32, FLOAT16, BFLOAT16 NCHW, NHWC 4 √ workspaceSize (uint64_t*) Output Returns the workspace size to be applied on the Device side. - - - - - executor (aclOpExecutor**) Output Returns the operator executor, which contains the operator computation flow. - - - - - Atlas inference products ,Atlas training products ,Atlas A2 training products/Atlas A2 inference products ,Atlas A3 training products/Atlas A3 inference products :- The data type of the parameters
gradOutandoutdoes not support BFLOAT16. - The data type of the parameter
outmust be consistent with the data type ofgradOut.
- The data type of the parameters
Ascend 950PR/Ascend 950DT :- When the data type of
gradOutis not FLOAT, the data type ofoutis consistent with that ofgradOut. - When the data type of
gradOutis FLOAT, the data type ofoutcan be FLOAT32, FLOAT16, or BFLOAT16.
- When the data type of
Return Value
aclnnStatus: Return code. For details, see aclnn Return Codes.
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 gradOut, outputSize, inputSize, or out is a null pointer. |
| ACLNN_ERR_PARAM_INVALID | 161002 | The data type of gradOut is not within the supported range. |
| The data types of gradOut and out are inconsistent. | ||
| The dimension of gradOut is not 4-dimensional. | ||
| 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 inconsistent with outputSize[0] and outputSize[1]. | ||
| The dimensional sizes of the N/C axes of gradOut and out are not equal. | ||
| The data formats of gradOut and out are not within the supported range. |
aclnnUpsampleBilinear2dBackward
Parameters
Parameter Name Input/Output Description workspace Input Side-Applied workspace memory address on the Device. workspaceSize Input Size of the workspace applied on the Device side, obtained through the first-phase API aclnnUpsampleBilinear2dBackwardGetWorkspaceSize. executor Input Operator executor, which contains the operator computation flow. stream Input Specifies the stream for task execution. Return Value
aclnnStatus: Return code. For details, see aclnn Return Codes.
Constraints
The parameters inputSize, outputSize, scalesH, and scalesW must satisfy the following constraints:
Deterministic computation:
- aclnnUpsampleBilinear2dBackward uses deterministic implementation by default.
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.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 device-side 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-side data to the device-side 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 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 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);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
// 2. Construct 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 the self aclTensor.
ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the 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 aclnnUpsampleBilinear2dBackward.
ret = aclnnUpsampleBilinear2dBackwardGetWorkspaceSize(
self, outputSize, inputSize, 1, 2, 2, out, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnUpsampleBilinear2dBackwardGetWorkspaceSize 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 aclnnUpsampleBilinear2dBackward.
ret = aclnnUpsampleBilinear2dBackward(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnUpsampleBilinear2dBackward 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. 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;
}