aclnnUpsampleBilinear2d
Applicable Products
| Product | Supported |
|---|---|
| √ | |
| √ | |
| √ | |
| × | |
| √ | |
| √ |
Description
Description: Applies 2D bilinear upsampling to an input signal consisting of multiple input channels.
- For input shape: If the input shape is (N, C, H, W), the output shape is (N, C, outputSize[0], outputSize[1]).
- For center alignment selection: Pixels are generally treated as a grid. When alignCorners = True, pixels are treated as points at the top-left corners of the grid cells, and the pixels at the output corners are aligned with the corner pixel centers of the original image, with equal spacing between points in the same direction. When alignCorners = False, pixels are treated as points on the grid intersection lines, and the pixels at the output corners remain the corner pixels of the original image, but the spacing between points in the same direction is unequal.
Formula:
- Core 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.
- Compute the weights from each adjacent point to the corresponding target point, then multiply and accumulate by the weights 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 center point of the top-left pixel 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:
Denote:
Then the following formula holds:
- Core algorithm logic:
Function Prototype
Each operator is divided into a two-phase API. You must first call the "aclnnUpsampleBilinear2dGetWorkspaceSize" API to obtain the workspace size required for computation and the executor that contains the operator computation process, and then call the "aclnnUpsampleBilinear2d" API to perform the computation.
aclnnStatus aclnnUpsampleBilinear2dGetWorkspaceSize(
const aclTensor *self,
const aclIntArray *outputSize,
const bool alignCorners,
const double scalesH,
const double scalesW,
aclTensor *out,
uint64_t *workspaceSize,
aclOpExecutor **executor)aclnnStatus aclnnUpsampleBilinear2d(
void *workspace,
uint64_t workspaceSize,
aclOpExecutor *executor,
aclrtStream stream)aclnnUpsampleBilinear2dGetWorkspaceSize
Parameters
Parameter Name Input/Output Description Usage Notes Data Type Data Format Dimension (shape) Non-contiguous Tensor self (aclTensor*) Input Represents the input tensor for upsampling, corresponding to `self` in the formula. - Empty tensors are not supported.
- When the data type is DOUBLE, only the NHWC format is supported.
FLOAT32, BFLOAT16, FLOAT16, DOUBLE NCHW, NHWC 4 √ outputSize (aclIntArray*) Input Specifies the output spatial size, indicating the spatial size of `out` in the H and W dimensions. Corresponds to `outputSize` in the corresponding formula. size is 2, 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 center points 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 edge values are used to pad values outside the boundaries. - - - - scalesH (double) Input Specifies the multiplier for the height dimension of the spatial size, corresponding to `scalesH` in the formula. Negative values are not allowed. - - - - scalesW (double) Input Specifies the multiplier for the width dimension of the spatial size, corresponding to `scalesW` in the corresponding formula. Negative values are not allowed. - - - - out (aclTensor*) Output Represents the output tensor after sampling, corresponding to `out` in the formula. - Empty tensors are not supported.
- The data type and data format must be consistent with those of the input `self`.
- When the data type is DOUBLE, only the NHWC format is supported.
- The shape supports only 4 dimensions, and the N and C axes must be consistent with those of the input `self` shape.
FLOAT32, BFLOAT16, FLOAT16, DOUBLE NCHW, NHWC 4 √ workspaceSize (uint64_t*) output Returns the workspace size to be allocated on the Device side. - - - - - executor (aclOpExecutor**) Output Returns the op executor, which contains the operator computation flow. - - - - - Atlas inference products ,Atlas training products :The data type of parameters
selfandoutdoes 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 Internal API validation error, typically caused by input data or attribute specifications being outside the supported range. ACLNN_ERR_PARAM_INVALID 161002 The data type of self is not within the supported range. The dimension sizes of the N and C axes of self and out are not equal. The data format of self and out is not within the supported range. The value of scalesH or scalesW is negative.
aclnnUpsampleBilinear2d
Parameters
Parameter Name Input/Output Description workspace Input The workspace memory address applied on the Device side. workspaceSize Input Size of the workspace applied on the Device, obtained through the first-phase API aclnnUpsampleBilinear2dGetWorkspaceSize. executor Input Operator executor, which encapsulates the operator computation flow. stream Input Specifies the stream on which the task is executed. Return Value
aclnnStatus: return code. For details, see aclnn Return Codes.
Constraints
The parameters self, outputSize, scalesH, and scalesW must satisfy the following constraints:
Deterministic computation:
- aclnnUpsampleBilinear2d uses deterministic implementation by default.
Example
The following sample code is 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_upsample_bilinear_2d.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: 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 CreateAclNchTensor(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);
// 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 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. (Boilerplate) Initialize the device/stream. See 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, 4, 2};
std::vector<int64_t> outShape = {1, 1, 8, 4};
void *selfDeviceAddr = nullptr;
void *outDeviceAddr = nullptr;
aclTensor *self = nullptr;
aclTensor *out = nullptr;
std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7};
std::vector<float> outHostData(32, 0);
std::vector<int64_t> outputSize = {8, 4};
bool alignCorners = true;
double scalesH = 2.0;
double scalesW = 2.0;
// Create the self aclTensor.
ret = CreateAclNchTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the self aclIntArray.
auto outputSizeArray = aclCreateIntArray(outputSize.data(), 2);
// Create the out aclTensor.
ret = CreateAclNchTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// 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 aclnnUpsampleBilinear2d.
ret = aclnnUpsampleBilinear2dGetWorkspaceSize(
self, outputSizeArray, alignCorners, scalesH, scalesW, out, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnUpsampleBilinear2dGetWorkspaceSize 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 aclnnUpsampleBilinear2d.
ret = aclnnUpsampleBilinear2d(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnUpsampleBilinear2d 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 device memory to host memory.
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. Modify according to the specific API definition.
aclDestroyTensor(self);
aclDestroyTensor(out);
// 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;
}