aclnnGridSampler3D

📄 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

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

  • Formula:

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

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

Where N in input, grid, and output is consistent, C in input and output is consistent, DoutD_{out}, HoutH_{out}, WoutW_{out} in grid and output are consistent, and the last dimension of grid has a size of 3, indicating that the input pixel position information is (x, y, z), with the value ranges of x, y, and z normalized to [-1, 1].

  • For out-of-range coordinates, different processing is applied based on paddingMode:
    • paddingMode=0 indicates that out-of-bounds positions are filled with 0.
    • paddingMode=1 indicates that out-of-bounds positions are filled with boundary values.
    • paddingMode=2 indicates that out-of-bounds positions are filled with the symmetric values of boundary values.
    • When sampling input, different processing is performed based on interpolationMode:
      • interpolationMode="bilinear" indicates taking the weighted average of the eight coordinates around (x, y, z) in input.
      • interpolationMode="nearest" indicates taking 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 "aclnnGridSampler3DGetWorkspaceSize" API to obtain the workspace size required for computation and the executor that includes the operator computation process, and then call the "aclnnGridSampler3D" API to execute the computation.

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

aclnnGridSampler3DGetWorkspaceSize

  • Parameters

    Parameter Name Input/Output Description Usage Description Data Type Data Format Dimensions (shape) Non-contiguous Tensor
    input (aclTensor*) Input Input tensor for interpolation computation, corresponding to `input` described in the formula.
    • Supports empty tensor.
    • When the data format is ND, it is processed in NCDHW format; NDHWC is supported only when the conditions are met (data type is FLOAT32 && interpolationMode is 0 && the C axis size is a multiple of 4).
    FLOAT16, FLOAT32, DOUBLE, BFLOAT16 NCDHW, NDHWC, ND 5 √
    grid (aclTensor*) input The sampling grid, corresponding to the `grid` described in the formula.
    • Supports empty tensor.
    • The data type is consistent with the data type of the input parameter `input`.
    • Supports shape (N, Dout, Hout, Wout, 3), where N is consistent with N in the shape of the input parameter `input`.
    FLOAT16, FLOAT32, DOUBLE, BFLOAT16 ND 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 out-of-bounds grid padding mode. That is, when the grid contains values outside the [-1, 1] range, 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 Specifies how feature map coordinates correspond to feature values. If True, the extreme values -1 and 1 are treated as the centers of the corner pixels of the reference input. If False, they are treated as the corners of the corner pixels of the reference input. - - - -
    out (aclTensor*) Output Final output result of the interpolation computation, corresponding to the `output` described in the formula.
    • Supports empty tensor.
    • The data format and data type are consistent with input.
    • The N axis and C axis of the shape are consistent with input, and the D axis, H axis, and W axis of the shape are consistent with grid.
    FLOAT16, FLOAT32, DOUBLE, BFLOAT16 NCDHW, NDHWC, ND 5 √
    workspaceSize (uint64_t*) output Returns the workspace size to be applied for on the Device side. - - - - -
    executor (aclOpExecutor**) Output Returns the op executor, which includes the operator computation process. - - - - -
    • Atlas training products:

      The data type of parameters input, grid, and out does not support BFLOAT16.

  • Return Value

    aclnnStatus: return 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 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 data format of input, grid, or out is not within the supported range.
    The value of interpolationMode or paddingMode is not within the supported range.
    The dimension relationship among input, grid, and out does not match.

aclnnGridSampler3D

  • 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 side, obtained by the first-phase API aclnnGridSampler3DGetWorkspaceSize.
    executor Input Operator executor, which includes 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

  • The input input must satisfy (Daxis_size×Haxis_size×Waxis_size<INT32_MAX)(D_{axis\_size} \times H_{axis\_size} \times W_{axis\_size} < \text{INT32\_MAX}).
  • Deterministic computation:
    • aclnnGridSampler3D uses deterministic implementation by default.

Example of Calling

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

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

int main()
{
    // 1. (Boilerplate) 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, 1, 3, 3};
    std::vector<int64_t> gridShape = {1, 1, 2, 2, 3};
    std::vector<int64_t> outShape = {1, 1, 1, 2, 2};
    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};
    std::vector<float> gridHostData = {-1, -1, 0, -1, 1, -1, -1, 0, 0, 0, 1, 0};
    std::vector<float> outHostData = {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 aclnnGridSampler3D.
    ret = aclnnGridSampler3DGetWorkspaceSize(
        input, grid, interpolationMode, paddingMode, alignCorners, out, &workspaceSize, &executor);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGridSampler3DGetWorkspaceSize 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 aclnnGridSampler3D.
    ret = aclnnGridSampler3D(workspaceAddr, workspaceSize, executor, stream);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGridSampler3D failed. ERROR: %d\n", ret); return ret);

    // 4. (Boilerplate) Synchronously 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 resultData from device to host failed. ERROR: %d\n", ret);
              return ret);
    for (int64_t i = 0; i < size; i++) {
        LOG_PRINT("resultData[%ld] is: %f\n", i, resultData[i]);
    }

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

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