aclnnUpsampleNearestExact2dBackward

📄 View Source Code

Applicable Products

ProductSupported
Ascend 950PR/Ascend 950DT×
Atlas A3 training products/Atlas A3 inference products√
Atlas A2 training products/Atlas A2 inference products√
Atlas 200I/500 A2 inference products×
Atlas inference products×
Atlas training products×

Description

  • Description: Backward propagation of aclnnUpsampleNearestExact2d.
  • Formula:gradInput(N,C,floor(scalesH∗(H+0.5)),floor(scalesW∗(W+0.5)))+=gradOutput(N,C,H,W)gradInput(N, C, floor ( scalesH * ( H + 0.5 )), floor ( scalesW * ( W+ 0.5 ))) += gradOutput( N, C, H ,W)

Function Prototype

Each operator is divided into a two-phase API. You must first call the "aclnnUpsampleNearestExact2dBackwardGetWorkspaceSize" API to obtain the workspace size required for computation and the executor that contains the operator computation process, and then call the "aclnnUpsampleNearestExact2dBackward" API to execute the computation.

aclnnStatus aclnnUpsampleNearestExact2dBackwardGetWorkspaceSize(
  const aclTensor   *gradOutput,
  const aclIntArray *outputSize,
  const aclIntArray *inputSize,
  double             scalesH,
  double             scalesW,
  aclTensor         *out,
  uint64_t          *workspaceSize,
  aclOpExecutor    **executor)
aclnnStatus aclnnUpsampleNearestExact2dBackward(
  void          *workspace,
  uint64_t       workspaceSize,
  aclOpExecutor *executor,
  aclrtStream    stream)

aclnnUpsampleNearestExact2dBackwardGetWorkspaceSize

  • Parameters

    Parameter Name Input/Output Description Usage Description Data Type Data Format Dimension (Shape) Non-Contiguous Tensor
    gradOutput (aclTensor*) Input Represents the gradient tensor for backward computation, corresponding to `gradOutput` in the formula.
    • Empty tensor is supported.
    • When the data format is ND, it is processed in NCHW format by default.
    FLOAT32, FLOAT16, BFLOAT16 NCHW, ND 4 √
    outputSize (aclIntArray*) Input Represents the spatial size of the input `gradOutput` in the H and W dimensions. The 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. The size is 4, and each element must be greater than zero. INT64 - - -
    scalesH (double) Input Specifies the height dimension multiplier of the output `out`, corresponding to `scalesH` in the formula. Negative values are not allowed. - - - -
    scalesW (double) Input Represents the multiplier for the width dimension of the output `out`, corresponding to `scalesW` in the formula. Negative values are not allowed. - - - -
    out (aclTensor*) Output Represents the output tensor of the backward computation, corresponding to `gradInput` in the formula.
    • Empty tensor is supported.
    • The data type and data format must be consistent with the input `gradOutput`.
    • The N and C axes of the shape must be consistent with the input `gradOutput`.
    FLOAT32, FLOAT16, BFLOAT16 NCHW, ND 4 √
    workspaceSize (uint64_t*) Output Returns the workspace size to be applied on the Device side. - - - - -
    executor (aclOpExecutor**) Output Returns the op executor, which contains the operator computation flow. - - - - -
  • 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 gradOutput, inputSize, or out is a null pointer.
    ACLNN_ERR_PARAM_INVALID 161002 The data type of gradOutput or out is not within the supported range.
    The data types of gradOutput and out are inconsistent.
    The shape of gradOutput is not 4-dimensional.
    The value of the H or W dimension of inputSize is less than 1.
    The value of scalesH or scalesW is less than 0.
    The data formats of gradOutput and out do not satisfy the constraints.

aclnnUpsampleNearestExact2dBackward

  • Parameters

    Parameter Name Input/Output Description
    workspace Input Workspace memory address applied on the Device side.
    workspaceSize Input Size of the workspace applied on the Device side, obtained through the first-phase API aclnnUpsampleNearestExact2dBackwardGetWorkspaceSize.
    executor Input Operator executor, which contains the operator computation flow.
    stream Input Specifies the Stream on which the task is executed.
  • Return Value

    aclnnStatus: Return status code. For details, see aclnn Return Codes.

Constraints

  • In the input data scaling scenario, the magnification factor must be less than or equal to 50, that is:

    outputSize_H/heightHoftheoutputshape<=50outputSize\_H / height H of the output shape <= 50 outputSize_W/widthWoftheoutputshape<=50outputSize\_W / width W of the output shape <= 50
  • The parameters inputSize, outputSize, scalesH, and scalesW must satisfy the following constraints:

    outputSize_H=floor(inputSize_H∗scalesH)outputSize\_H = floor(inputSize\_H * scalesH) outputSize_W=floor(inputSize_W∗scalesW)outputSize\_W = floor(inputSize\_W * scalesW)
  • Deterministic computation:

    • aclnnUpsampleNearestExact2dBackward uses deterministic implementation by default.

Example Call

The 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_nearest_exact2d_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)
{
    // Standard 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 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 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 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 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. (Boilerplate) 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> inputShape = {1, 1, 4, 2};
    std::vector<int64_t> outShape = {1, 1, 8, 4};
    void *inputDeviceAddr = nullptr;
    void *outDeviceAddr = nullptr;
    aclTensor *input = nullptr;
    aclTensor *out = nullptr;
    std::vector<float> inputHostData = {0, 1, 2, 3, 4, 5, 6, 7};
    std::vector<float> outHostData(32, 0);
    std::vector<int64_t> outputSize = {4, 2};
    std::vector<int64_t> inputSize = {1, 1, 8, 4};
    double scalesH = 0.5;
    double scalesW = 0.5;
    // Create the input aclTensor.
    ret = CreateAclNchTensor(inputHostData, inputShape, &inputDeviceAddr, aclDataType::ACL_FLOAT, &input);
    CHECK_RET(ret == ACL_SUCCESS, return ret);
    // Create the input aclIntArray.
    auto outputSizeArray = aclCreateIntArray(outputSize.data(), 2);
    auto inputSizeArray = aclCreateIntArray(inputSize.data(), 4);
    // Create the output 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 aclnnUpsampleNearestExact2dBackward.
    ret = aclnnUpsampleNearestExact2dBackwardGetWorkspaceSize(
        input, outputSizeArray, inputSizeArray, scalesH, scalesW, out, &workspaceSize, &executor);
    CHECK_RET(
        ret == ACL_SUCCESS, LOG_PRINT("aclnnUpsampleNearestExact2dBackwardGetWorkspaceSize 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 aclnnUpsampleNearestExact2dBackward.
    ret = aclnnUpsampleNearestExact2dBackward(workspaceAddr, workspaceSize, executor, stream);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnUpsampleNearestExact2dBackward 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 side 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 aclIntArray. Modify based on the specific API definition.
    aclDestroyTensor(input);
    aclDestroyTensor(out);

    // 7. Release device resources. Modify based on the specific API definition as needed.
    aclrtFree(inputDeviceAddr);
    aclrtFree(outDeviceAddr);
    if (workspaceSize > 0) {
        aclrtFree(workspaceAddr);
    }
    aclrtDestroyStream(stream);
    aclrtResetDevice(deviceId);
    aclFinalize();
    return 0;
}