aclnnGridSampler2D

📄 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√

Function

  • Description: Given an input tensor and a corresponding grid, the operator fills the pixel values from the corresponding positions in the input into the positions specified by the grid, based on the coordinate information provided at each grid position, to produce the final output.

  • Formula:

    The dimensions of the input, grid, and output are as follows:

    input:(N,C,Hin,Win)grid:(N,Hout,Wout,2)output:(N,C,Hout,Wout)input: (N, C, H_{in}, W_{in})\\ grid: (N, H_{out}, W_{out}, 2)\\ output: (N, C, H_{out}, W_{out})

Here, N is consistent across input, grid, and output; C is consistent across input and output; Hout and Wout are consistent across grid and output. The last dimension of grid has a size of 2, representing the pixel position information (x, y) in input. The values of x and y are normalized to the range [-1, 1], where (-1, -1) represents the top-left corner and (1, 1) represents the bottom-right corner.

  • For out-of-range coordinates, different processing is applied based on the padding mode:

    • paddingMode=0: out-of-bounds positions are filled with zero (zero padding).

    • paddingMode=1: out-of-bounds positions are filled with the boundary value (border padding).

    • paddingMode=2: out-of-bounds positions are filled with the symmetric value of the boundary value (reflection padding).

    • When sampling input, different processing is performed based on interpolationMode:

      • interpolationMode=0, indicating that the weighted average of the four coordinates around (x, y) is taken.
      • interpolationMode=1, indicating that the coordinate value in input closest to (x, y) is taken.
      • interpolationMode=2, indicating that the weighted average of the sixteen coordinates around (x, y) is taken.

Function Prototype

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

aclnnStatus aclnnGridSampler2DGetWorkspaceSize(
  const aclTensor *input,
  const aclTensor *grid,
  int64_t          interpolationMode,
  int64_t          paddingMode,
  bool             alignCorners,
  aclTensor       *out,
  uint64_t        *workspaceSize,
  aclOpExecutor  **executor)
aclnnStatus aclnnGridSampler2D(
  void          *workspace,
  uint64_t       workspaceSize,
  aclOpExecutor *executor,
  aclrtStream    stream)

aclnnGridSampler2DGetWorkspaceSize

  • Parameters

    Parameter Name Input/Output Description Usage Description Data Type Data Format Dimension (shape) Non-contiguous Tensor
    input (aclTensor*) Input Input tensor for interpolation computation, corresponding to `input` described in the formula.
    • Empty tensor is supported.
    • Supports shape (N, C, Hin, Win). H*W < maximum value of INT32. The last two dimensions of the `input` shape cannot be 0.
    FLOAT32, FLOAT16, DOUBLE, BFLOAT16 ND 4 √
    grid (aclTensor*) Input The grid for sampling, corresponding to the `grid` described in the formula.
    • Empty tensor is supported.
    • The data type is consistent with that of the input parameter `input`.
    • Supports shape of (N, Hout, Wout, 2), where N is consistent with N in the shape of the input parameter `input`.
    FLOAT32, FLOAT16, DOUBLE, BFLOAT16 ND 4 √
    interpolationMode (int64_t) Input Indicates the interpolation mode, corresponding to `interpolationMode` in the formula description. Supports three modes: 0: bilinear (bilinear interpolation), 1: nearest (nearest neighbor interpolation), 2: bicubic (bicubic interpolation). - - - -
    paddingMode (int64_t) Input Indicates the padding mode, i.e., when (x, y) exceeds the sampling range of the input feature map, a specific value is returned. Corresponds to `paddingMode` in the formula description. Supports three modes: 0: zeros, 1: border, 2: reflection. - - - -
    alignCorners (bool) Input Specifies how feature map coordinates correspond to eigenvalues. When set to true, eigenvalues are located at pixel centers. When set to false, eigenvalues are located at pixel corners. When set to true, the eigenvalue is located at the pixel center. When set to false, the eigenvalue is located at the pixel corners. - - - -
    out (aclTensor*) Output The final output result of the interpolation computation, corresponding to `output` described in the corresponding formula.
    • Empty tensor is supported.
    • The data type is the same as the data type of input.
    • The supported shape is (N, C, Hout, Wout), where N and C are the same as N and C in the shape of input, and Hout and Wout are the same as Hout and Wout in the shape of grid.
    FLOAT32, FLOAT16, DOUBLE, BFLOAT16 ND 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 training products:

      • The input parameter interpolationMode does not support interpolation mode 2: bicubic (bicubic interpolation).
      • The data type of the parameters input, grid, and out does not support BFLOAT16.
    • Atlas A2 training products/Atlas A2 inference products, Atlas A3 training products/Atlas A3 inference products:

      • For the input parameter interpolationMode, mode 2: bicubic (bicubic interpolation) is supported only when the data type of input is FLOAT32 or FLOAT16.
      • The data type of the parameters input, grid, and out does not support BFLOAT16.
    • Atlas 200I/500 A2 inference products:

      When the API runs on AI Core, the following conditions must be met:

      • The input parameter interpolationMode is bilinear interpolation.
      • The input parameter paddingMode is zero padding.
      • The data type of the parameters input, grid, and out is FLOAT16.
      • The shape of the parameter input must satisfy that the value of the C dimension is 32.
    • Atlas inference products:

      When the API runs on AI Core, the following conditions must be met:

      • The input parameter interpolationMode is bilinear.
      • The input parameter paddingMode is zeros.
      • The data type of the parameters input, grid, and out is FLOAT16.
      • The shape of the parameter input must satisfy that the value of the C dimension is 32 or CHW < 20480.
      • The data format of the parameter input does not support NHWC.
  • Return Value

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

The first API performs input parameter validation and reports an error in the following scenarios:

Return Code Error Code Description
ACLNN_ERR_PARAM_NULLPTR 161001 The input, grid, or out passed in is a null pointer.
ACLNN_ERR_PARAM_INVALID 161002 The data type of input, grid, or out is not within the supported range, or the data types are inconsistent.
The value of interpolationMode or paddingMode is not within the supported range.
When interpolationMode is bicubic, the data type of input, grid, or output is not FLOAT32 or FLOAT16.
The dimension relationship among input, grid, and output does not match.
The last two dimensions of input are empty.

aclnnGridSampler2D

  • Parameters

    Parameter Name Input/Output Description
    workspace Input The workspace memory address allocated on the Device side.
    workspaceSize Input The workspace size allocated on the Device side, obtained through the first-phase API aclnnGridSampler2DGetWorkspaceSize.
    executor Input The 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 data format of the input, grid, and out parameters supports only (N, C, H, W). When other data formats are input, they are processed in the (N, C, H, W) format by default.
  • The product of the input input (size of the H axis * size of the W axis) must be less than the maximum value of INT32.
  • When the grid input value multiplied by the image dimension (height or width) exceeds a 24-bit binary number (16777216), the sampling point may have errors, and the precision may deviate.
  • If the grid contains a large number of values outside the [-1, 1] range, the computation results will contain a large number of repeated values when the zeros or border padding strategy is used.
  • Atlas A2 training products/Atlas A2 inference products, Atlas A3 training products/Atlas A3 inference products:
    • If the grid contains data outside the [-1, 1] range, when using bicubic interpolation, errors may occur in the computation of small-value-range data, and precision may deviate.
    • When using bilinear or bicubic interpolation, workspace memory is required for the FLOAT16 data type.
  • Atlas training products: When using bilinear interpolation, workspace memory is required for the FLOAT16 data type.
  • Deterministic computation:
    • aclnnGridSampler2D uses deterministic implementation by default.

Example Call

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_grid_sampler2d.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 allocate 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 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. (Standard practice) Initialize the 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 the input and output. Customize the construction based on the API.
    int64_t interpolationMode = 0;
    int64_t paddingMode = 0;
    bool alignCorners = false;
    std::vector<int64_t> inputShape = {1, 1, 5, 8};
    std::vector<int64_t> gridShape = {1, 3, 3, 2};
    std::vector<int64_t> outShape = {1, 1, 3, 3};
    void* inputDeviceAddr = nullptr;
    void* gridDeviceAddr = nullptr;
    void* outDeviceAddr = nullptr;
    aclTensor* input = nullptr;
    aclTensor* grid = nullptr;
    aclTensor* out = nullptr;

    std::vector<float> inputHostData = {1,  2,  3,  4,  5,  6,  7,  8,  9,  10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
                                        21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40};
    std::vector<float> gridHostData = {-1, -1, 0, -1, 1, -1, -1, 0, 0, 0, 1, 0, -1, 1, 0, 1, 1, 1};
    std::vector<float> outHostData = {0, 0, 0, 0, 0, 0, 0, 0, 0};

    // 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 output aclTensor.
    ret = CreateAclTensor(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 aclnnGridSampler2D.
    ret = aclnnGridSampler2DGetWorkspaceSize(
        input, grid, interpolationMode, paddingMode, alignCorners, out, &workspaceSize, &executor);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGridSampler2DGetWorkspaceSize failed. ERROR: %d.\n[ERROR msg]%s", ret, aclGetRecentErrMsg()); 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[ERROR msg]%s", ret, aclGetRecentErrMsg()); return ret);
    }
    // Call the second-phase API of aclnnGridSampler2D.
    ret = aclnnGridSampler2D(workspaceAddr, workspaceSize, executor, stream);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGridSampler2D failed. ERROR: %d.\n[ERROR msg]%s", ret, aclGetRecentErrMsg()); return ret);

    // 4. (Standard practice) Synchronously wait for task execution to complete.
    ret = aclrtSynchronizeStream(stream);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d.\n[ERROR msg]%s", ret, aclGetRecentErrMsg()); return ret);

    // 5. Obtain the output value and copy the result from the device memory to the host side. Modify according to 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 resultData from device to host failed. ERROR: %d.\n[ERROR msg]%s", ret, aclGetRecentErrMsg());
              return ret);
    for (int64_t i = 0; i < size; i++) {
        LOG_PRINT("resultData[%ld] is: %f\n", i, resultData[i]);
    }

    // 6. Release aclTensor. Modify according to the specific API definition.
    aclDestroyTensor(input);
    aclDestroyTensor(grid);
    aclDestroyTensor(out);

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

    return 0;
}