aclnnGridSampler3DBackward

📄 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: The backward propagation of aclnnGridSampler3D, which computes the gradients of the input tensor and the grid tensor.

  • Formula:

    • Calculation Process:

      1. Based on the (x, y, z) values stored in grid, compute the coordinates mapped onto input. These coordinates are related to alignCorners and paddingMode.
      2. Based on the input interpolationMode, the coordinates select either bilinear or nearest interpolation mode to compute the output value.
      3. The gradient values stored in grad are multiplied by the corresponding point weights to compute the final results for dx and dgrid.
    • Where:

      The dimensions of grad, input, grid, dx, and dgrid are as follows:

      grad:(N,C,Dout,Hout,Wout)input:(N,C,Din,Hin,Win)grid:(N,Dout,Hout,Wout,3)dx:(N,C,Din,Hin,Win)dgrid:(N,Dout,Hout,Wout,3)grad: (N, C, D_{out}, H_{out}, W_{out})\\ input: (N, C, D_{in}, H_{in}, W_{in})\\ grid: (N, D_{out}, H_{out}, W_{out}, 3)\\ dx: (N, C, D_{in}, H_{in}, W_{in})\\ dgrid: (N, D_{out}, H_{out}, W_{out}, 3)

      Here, N is consistent across grad, input, grid, dx, and dgrid; C is consistent across grad, input, and dx; DinD_{in}, HinH_{in}, WinW_{in} are consistent across input and dx; DoutD_{out}, HoutH_{out}, WoutW_{out} are consistent across grad, grid, and dgrid; the last dimension of grid has a size of 3, indicating that the input pixel position information is (x, y, z), and the value ranges of x, y, and z are normalized to [-1, 1].

      • For out-of-range coordinates, different processing is applied based on paddingMode:

        • paddingMode="zeros": out-of-bounds positions are filled with 0.
        • paddingMode="border": out-of-bounds positions are filled with boundary values.
        • paddingMode="reflection": out-of-bounds positions are filled with the reflected values of the boundary values.
      • When sampling input, different processing is performed based on interpolationMode:

        • interpolationMode="bilinear": takes the weighted average of the eight coordinates surrounding (x, y, z) in input.
        • interpolationMode="nearest": takes the coordinate value closest to (x, y, z) in input.

Function Prototype

Each operator is divided into a two-phase API. You must first call the "aclnnGridSampler3DBackwardGetWorkspaceSize" API to obtain the workspace size required for computation and the executor containing the operator computation process, and then call the "aclnnGridSampler3DBackward" API to perform the computation.

aclnnStatus aclnnGridSampler3DBackwardGetWorkspaceSize(
  const aclTensor*    gradOutput,
  const aclTensor*    input,
  const aclTensor*    grid,
  int64_t             interpolationMode,
  int64_t             paddingMode,
  bool                alignCorners,
  const aclBoolArray* outputMask,
  aclTensor*          inputGrad,
  aclTensor*          gridGrad,
  uint64_t*           workspaceSize,
  aclOpExecutor**     executor)
aclnnStatus aclnnGridSampler3DBackward(
  void*          workspace,
  uint64_t       workspaceSize,
  aclOpExecutor* executor,
  aclrtStream    stream)

aclnnGridSampler3DBackwardGetWorkspaceSize

  • Parameters

    Parameter Name Input/Output Description Usage Description Data Type Data Format Dimension (Shape) Non-Contiguous Tensor
    gradOutput (aclTensor*) Input Represents the output gradient from the previous layer during backward propagation, corresponding to `grad` in the formula description.
    • Supports null Tensor.
    • The data type is consistent with the data type of `input`.
    • When the data type is DOUBLE, the data format does not support NDHWC.
    BFLOAT16, FLOAT16, FLOAT32, DOUBLE NCDHW, NDHWC 5 √
    input (aclTensor*) Input Represents the input tensor for backward propagation, corresponding to `input` in the formula description.
    • Supports null Tensor.
    • When the data type is DOUBLE, the data format does not support NDHWC.
    • The N and C axes of `input` and `gradOutput` must have the same values, and the D, H, and W values of `input` cannot be 0.
    BFLOAT16, FLOAT16, FLOAT32, DOUBLE NCDHW, NDHWC 5 √
    grid (aclTensor*) Input Represents the tensor of pixel positions, corresponding to `grid` in the formula description.
    • Supports null Tensor.
    • The data type is consistent with that of `input`.
    • The values of the N, D, H, and W axes of `grid` and `gradOutput` must be consistent, and the value of the C axis must be 3.
    BFLOAT16, FLOAT16, FLOAT32, DOUBLE NDHWC 5 ✓
    interpolationMode (int64_t) Input Indicates the interpolation mode, corresponding to `interpolationMode` in the formula description. Supports two modes: 0: bilinear, 1: nearest. - - - -
    paddingMode (int64_t) Input Indicates the padding mode. When the grid contains values outside the range [-1, 1], the corresponding output is processed according to the method defined by paddingMode. Corresponds to `paddingMode` in the formula description. Supports three modes: 0: zeros, 1: border, 2: reflection. - - - -
    alignCorners (bool) Input Indicates the correspondence between feature map coordinates and feature values, corresponding to `alignCorners` in the formula description. If set to True, the extreme values -1 and 1 are treated as the center points of the corner pixels of the reference input. If set to False, they are treated as the corner points of the corner pixels of the reference input. - - - -
    outputMask (aclBoolArray*) Input Mask used to indicate the output. outputMask[0] is True/False, indicating whether to obtain the output inputGrad; outputMask[1] is True/False, indicating whether to obtain the output gridGrad. BOOLARRAY - - -
    inputGrad (aclTensor*) Output Represents the output gradient of backward propagation, corresponding to `dx` in the formula description.
    • Supports null Tensor.
    • The data type, data format, and shape are consistent with those of `input`.
    • When the data type is DOUBLE, the data format does not support NDHWC.
    BFLOAT16, FLOAT16, FLOAT32, DOUBLE NCDHW, NDHWC 5 √
    gridGrad (aclTensor*) Output Represents the grid gradient, corresponding to `dgrid` in the formula description.
    • Supports null Tensor.
    • The data type, data format, and shape are consistent with those of grid.
    BFLOAT16, FLOAT16, FLOAT32, DOUBLE NDHWC 5 √
    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 training products:

      The data type of the parameters gradOutput, input, grid, inputGrad, and gridGrad does not support BFLOAT16.

  • Return Value

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

    The first segment of the 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, input, grid, inputGrad, or gridGrad is a null pointer.
    ACLNN_ERR_PARAM_INVALID 161002 The data type of gradOutput, input, grid, inputGrad, or gridGrad is not within the supported range, or the data types are inconsistent.
    The values of interpolationMode and paddingMode are not within the supported range.
    The dimensional relationship among gradOutput, input, grid, inputGrad, and gridGrad does not match.

aclnnGridSampler3DBackward

  • Parameters

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

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

Constraints

  • Deterministic computation:
    • aclnnGridSampler3DBackward uses a non-deterministic implementation by default, and supports enabling deterministic computation via aclrtCtxSetSysParamOpt.

Example

The sample code is as follows, for reference only. For specific compilation and execution processes, see Compile and Run Samples.

#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_grid_sampler3d_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 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_ND, shape.data(), shape.size(),
        *deviceAddr);
    return 0;
}

int main()
{
    // 1. (Boilerplate) Initialize the device/stream. Refer to 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 the input and output. Customize the construction based on the API.
    int64_t interpolationMode = 0;
    int64_t paddingMode = 0;
    bool alignCorners = false;
    aclBoolArray* outputMask = nullptr;
    std::vector<int64_t> gradOutputShape = {1, 1, 1, 2, 2};
    std::vector<int64_t> inputShape = {1, 1, 1, 3, 3};
    std::vector<int64_t> gridShape = {1, 1, 2, 2, 3};
    std::vector<int64_t> inputGradShape = {1, 1, 1, 3, 3};
    std::vector<int64_t> gridGradShape = {1, 1, 2, 2, 3};
    void* gradOutputDeviceAddr = nullptr;
    void* inputDeviceAddr = nullptr;
    void* gridDeviceAddr = nullptr;
    void* inputGradDeviceAddr = nullptr;
    void* gridGradDeviceAddr = nullptr;
    aclTensor* gradOutput = nullptr;
    aclTensor* input = nullptr;
    aclTensor* grid = nullptr;
    aclTensor* inputGrad = nullptr;
    aclTensor* gridGrad = nullptr;

    std::vector<float> gradOutputHostData = {1, 1, 1, 1};
    std::vector<float> inputHostData = {
        1, 2, 3, 4, 5, 6, 7, 8, 9,
    };
    std::vector<float> gridHostData = {-1, -1, 0, -1, 1, -1, -1, 0, 0, 0, 1, 0};
    std::vector<float> inputGradHostData = {0, 0, 0, 0, 0, 0, 0, 0, 0};
    std::vector<float> gridGradHostData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};

    bool maskValue[2] = {true, true};
    const uint64_t kNum = 2U;
    outputMask = aclCreateBoolArray(&(maskValue[0]), kNum);

    // Create the gradOutput aclTensor.
    ret = CreateAclTensor(
        gradOutputHostData, gradOutputShape, &gradOutputDeviceAddr, aclDataType::ACL_FLOAT, &gradOutput);
    CHECK_RET(ret == ACL_SUCCESS, return ret);
    // Create the input aclTensor.
    ret = CreateAclTensor(inputHostData, inputShape, &inputDeviceAddr, aclDataType::ACL_FLOAT, &input);
    CHECK_RET(ret == ACL_SUCCESS, return ret);
    // Create the grid aclTensor.
    ret = CreateAclTensor(gridHostData, gridShape, &gridDeviceAddr, aclDataType::ACL_FLOAT, &grid);
    CHECK_RET(ret == ACL_SUCCESS, return ret);
    // Create the inputGrad aclTensor.
    ret = CreateAclTensor(inputGradHostData, inputGradShape, &inputGradDeviceAddr, aclDataType::ACL_FLOAT, &inputGrad);
    CHECK_RET(ret == ACL_SUCCESS, return ret);
    // Create the gridGrad aclTensor.
    ret = CreateAclTensor(gridGradHostData, gridGradShape, &gridGradDeviceAddr, aclDataType::ACL_FLOAT, &gridGrad);
    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 aclnnGridSampler3DBackward API.
    ret = aclnnGridSampler3DBackwardGetWorkspaceSize(
        gradOutput, input, grid, interpolationMode, paddingMode, alignCorners, outputMask, inputGrad, gridGrad,
        &workspaceSize, &executor);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGridSampler3DBackwardGetWorkspaceSize 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 aclnnGridSampler3DBackward API.
    ret = aclnnGridSampler3DBackward(workspaceAddr, workspaceSize, executor, stream);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGridSampler3DBackward failed. ERROR: %d\n", ret); return ret);

    // 4. (Boilerplate) Wait synchronously for the 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 inputGradSize = GetShapeSize(inputGradShape);
    std::vector<float> inputGradResultData(inputGradSize, 0);
    ret = aclrtMemcpy(
        inputGradResultData.data(), inputGradResultData.size() * sizeof(inputGradResultData[0]), inputGradDeviceAddr,
        inputGradSize * sizeof(inputGradResultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy inputGradResultData from device to host failed. ERROR: %d\n", ret);
              return ret);
    for (int64_t i = 0; i < inputGradSize; i++) {
        LOG_PRINT("inputGradResultData[%ld] is: %f\n", i, inputGradResultData[i]);
    }

    auto gridGradSize = GetShapeSize(gridGradShape);
    std::vector<float> gridGradResultData(gridGradSize, 0);
    ret = aclrtMemcpy(
        gridGradResultData.data(), gridGradResultData.size() * sizeof(gridGradResultData[0]), gridGradDeviceAddr,
        gridGradSize * sizeof(gridGradResultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy gridGradResultData from device to host failed. ERROR: %d\n", ret);
              return ret);
    for (int64_t i = 0; i < gridGradSize; i++) {
        LOG_PRINT("gridGradResultData[%ld] is: %f\n", i, gridGradResultData[i]);
    }

    // 6. Release aclTensor and aclBoolArray. Modify based on the specific API definition.
    aclDestroyTensor(gradOutput);
    aclDestroyTensor(input);
    aclDestroyTensor(grid);
    aclDestroyTensor(inputGrad);
    aclDestroyTensor(gridGrad);
    aclDestroyBoolArray(outputMask);

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