aclnnRoiPoolingWithArgMax

📄 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: Performs pooling on the input feature map by ROI (Region of Interest). Within each ROI, the spatial area is divided into pooled_h × pooled_w grids, and max pooling is applied to each grid. The pooling results and the one-dimensional index (argmax) of the maximum value within the channel are output.

  • Formula:

    The input feature map xx has a shape of (N,C,H,W)(N, C, H, W), and the ROI tensor rois\text{rois} has a shape of (num_rois,5)(\text{num\_rois}, 5), where each row represents (bn,x1,y1,x2,y2)(b_n, x_1, y_1, x_2, y_2). The scalar parameters are shs_h, sws_w (spatial_scale), pooled_h\text{pooled\_h}, and pooled_w\text{pooled\_w}. The subscript nn denotes the ROI index, cc denotes the channel, and (ph,pw)(\text{ph}, \text{pw}) denotes the pooling grid cell.

    • Mapping ROI to feature map: Multiply the ROI coordinates by spatial_scale to obtain the floating-point interval on the feature map:

      x~1=x1sw,y~1=y1sh,x~2=(x2+1)sw,y~2=(y2+1)sh\tilde{x}_1 = x_1 s_w,\quad \tilde{y}_1 = y_1 s_h,\quad \tilde{x}_2 = (x_2+1)s_w,\quad \tilde{y}_2 = (y_2+1)s_h Wroi=x~2−x~1,Hroi=y~2−y~1W_{\text{roi}} = \tilde{x}_2 - \tilde{x}_1,\qquad H_{\text{roi}} = \tilde{y}_2 - \tilde{y}_1

      If Wroi≤0W_{\text{roi}} \le 0 or Hroi≤0H_{\text{roi}} \le 0, all yy values of this ROI are 0, and all argmax\text{argmax} values are -1.

    • Bin step size and interval: Each pooling cell (ph, pw) corresponds to a bin within the ROI. The step size and floating-point interval are:

      Δw=Wroipooled_w,Δh=Hroipooled_h\Delta w = \frac{W_{\text{roi}}}{\text{pooled\_w}},\qquad \Delta h = \frac{H_{\text{roi}}}{\text{pooled\_h}} w~1=pw⋅Δw+x~1,w~2=(pw+1)⋅Δw+x~1\tilde{w}_1 = \text{pw} \cdot \Delta w + \tilde{x}_1,\quad \tilde{w}_2 = (\text{pw}+1) \cdot \Delta w + \tilde{x}_1 h~1=ph⋅Δh+y~1,h~2=(ph+1)⋅Δh+y~1\tilde{h}_1 = \text{ph} \cdot \Delta h + \tilde{y}_1,\quad \tilde{h}_2 = (\text{ph}+1) \cdot \Delta h + \tilde{y}_1

      Round and clip to [0,W)×[0,H)[0,W) \times [0,H):

      w1=clip(⌊w~1⌋, 0, W),w2=clip(⌈w~2⌉, 0, W)w_1 = \text{clip}(\lfloor\tilde{w}_1\rfloor,\, 0,\, W),\quad w_2 = \text{clip}(\lceil\tilde{w}_2\rceil,\, 0,\, W) h1=clip(⌊h~1⌋, 0, H),h2=clip(⌈h~2⌉, 0, H)h_1 = \text{clip}(\lfloor\tilde{h}_1\rfloor,\, 0,\, H),\quad h_2 = \text{clip}(\lceil\tilde{h}_2\rceil,\, 0,\, H)

      where clip(a,l,u)=min⁡(max⁡(a,l),u)\text{clip}(a,l,u) = \min(\max(a,l), u). If w2≤w1w_2 \le w_1 or h2≤h1h_2 \le h_1, the bin is empty: y=0y=0, argmax=−1\text{argmax}=-1.

    • Pooling Output and Argmax: Let b=rois[n,0]b = \text{rois}[n,0], and the bin region R={(h,w):h1≤h<h2, w1≤w<w2}R = \{(h,w) : h_1 \le h < h_2,\, w_1 \le w < w_2\}, then

      y[n,c,ph,pw]=max⁡(h,w)∈Rx[b,c,h,w]y[n,c,\text{ph},\text{pw}] = \max_{(h,w) \in R} x[b,c,h,w]

      (0 when RR is empty.)

      argmax[n,c,ph,pw]=h∗W+w∗\text{argmax}[n,c,\text{ph},\text{pw}] = h^* W + w^*

      (h∗,w∗)(h^*, w^*) is the position of the maximum value within the bin (the first one is taken when multiple solutions exist); empty RR is -1.

    • Output Shape:

      OutputShapeData Type
      yy(num_rois, C, pooled_h, pooled_w)(\text{num\_rois},\, C,\, \text{pooled\_h},\, \text{pooled\_w})Same as xx
      argmax\text{argmax}Same as aboveINT32

Function Prototype

Each operator is divided into a two-phase API. You must first call the "aclnnRoiPoolingWithArgMaxGetWorkspaceSize" API to obtain the workspace size required for computation and the executor that encapsulates the operator's computation process, and then call the "aclnnRoiPoolingWithArgMax" API to execute the computation.

aclnnStatus aclnnRoiPoolingWithArgMaxGetWorkspaceSize(
  const aclTensor   *x,
  const aclTensor   *rois,
  int64_t            pooled_h,
  int64_t            pooled_w,
  float              spatial_scale_h,
  float              spatial_scale_w,
  aclTensor         *y,
  aclTensor         *argmax,
  uint64_t          *workspaceSize,
  aclOpExecutor    **executor)
aclnnStatus aclnnRoiPoolingWithArgMax(
  void          *workspace,
  uint64_t       workspaceSize,
  aclOpExecutor *executor,
  aclrtStream    stream)

aclnnRoiPoolingWithArgMaxGetWorkspaceSize

  • Parameters

    Parameter Name Input/Output Description Description Data Type Data Format Dimension (Shape) Non-contiguous Tensor
    x (aclTensor*) Input Input feature map in NCHW format, (N, C, H, W).
    • Empty tensors are not supported.
    • The input must be 4-dimensional.
    FLOAT32, FLOAT16 ND 4 √
    rois (aclTensor*) Input ROI box, with 5 elements per row: batch_idx, x1, y1, x2, y2. Shape is (num_rois, 5). Empty tensor is not supported. FLOAT32, FLOAT16 ND 2 √
    pooled_h (int64_t) Input Pooling output height. Must be greater than 0. - - - -
    pooled_w (int64_t) Input Pooling output width. Must be greater than 0. - - - -
    spatial_scale_h(float) Input Scaling ratio in the height direction when mapping ROI coordinates to the feature map. Must be greater than 0. - - - -
    spatial_scale_w (float) Input Scaling ratio in the width direction when mapping ROI coordinates to the feature map. Must be greater than 0. - - - -
    y (aclTensor*) Output Pooling result, with shape (num_rois, C, pooled_h, pooled_w).
    • Empty tensors are not supported.
    • The data type is the same as that of x.
    FLOAT32, FLOAT16 ND 4 √
    argmax (aclTensor*) Output Linear offset index of the maximum value within each pooling grid cell along the channel dimension.
    • Empty tensors are not supported.
    • The shape is the same as that of y.
    INT32 ND 4 √
    workspaceSize (uint64_t*) Output Returns the workspace size to be requested on the Device side. - - - - -
    executor(aclOpExecutor**) Output Returns the op executor, which contains the operator computation process. - - - - -
  • Return Value

    aclnnStatus: return status 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 input parameter is a required input, output, or required attribute, and is a null pointer.
    ACLNN_ERR_PARAM_INVALID 161002
    The data type or format of x, rois, y, or argmax is not within the supported range.
    The shape of x is not 4-dimensional (NCHW).
    The second dimension of the shape of rois is not 5.
    pooled_h, pooled_w, spatial_scale_h, or spatial_scale_w is not greater than 0.

aclnnRoiPoolingWithArgMax

  • Parameters

    Parameter Name Input/Output Description
    workspace Input The workspace memory address allocated on the Device side.
    workspaceSize Input The workspace size to be applied on the Device side, obtained through the first-phase API aclnnRoiPoolingWithArgMaxGetWorkspaceSize.
    executor Input Operator executor, which contains the operator computation process.
    stream Input Specifies the stream for executing the task.
  • Return Value

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

Constraints

  • Deterministic computation:
    • aclnnRoiPoolingWithArgMax uses deterministic implementation by default.

Example

The sample code is as follows, for reference only. For the specific compilation and execution process, see Compile and Run Samples. During actual invocation, you need to first generate aclnnop/aclnn_roi_pooling_with_arg_max.h through opgen. If the generated header file or API signature differs, the generated API shall prevail.

#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_roi_pooling_with_arg_max.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 shape_size = 1;
  for (auto i : shape) {
    shape_size *= i;
  }
  return shape_size;
}

int Init(int32_t deviceId, aclrtStream* stream) {
  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);
  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);
  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);
  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];
  }
  *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
                            shape.data(), shape.size(), *deviceAddr);
  return 0;
}

template <typename T>
int CreateAclTensorOutput(const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType,
                          aclTensor** tensor) {
  auto size = GetShapeSize(shape) * sizeof(T);
  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);
  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];
  }
  *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
                            shape.data(), shape.size(), *deviceAddr);
  return 0;
}

int main() {
  int32_t deviceId = 0;
  aclrtStream stream;
  auto ret = Init(deviceId, &stream);
  CHECK_RET(ret == 0, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);

  std::vector<int64_t> xShape = {2, 16, 25, 42};
  std::vector<int64_t> roisShape = {2, 5};
  std::vector<int64_t> yShape = {2, 16, 3, 3};
  std::vector<int64_t> argmaxShape = {2, 16, 3, 3};

  void* xDeviceAddr = nullptr;
  void* roisDeviceAddr = nullptr;
  void* yDeviceAddr = nullptr;
  void* argmaxDeviceAddr = nullptr;
  aclTensor* x = nullptr;
  aclTensor* rois = nullptr;
  aclTensor* y = nullptr;
  aclTensor* argmax = nullptr;

  int64_t xSize = GetShapeSize(xShape);
  int64_t roisSize = GetShapeSize(roisShape);
  std::vector<float> xHostData(xSize, 1.0f);
  std::vector<float> roisHostData(roisSize, 0.0f);
  roisHostData[0] = 0.0f;
  roisHostData[1] = 0.0f;
  roisHostData[2] = 0.0f;
  roisHostData[3] = 24.0f;
  roisHostData[4] = 41.0f;
  roisHostData[5] = 1.0f;
  roisHostData[6] = 0.0f;
  roisHostData[7] = 0.0f;
  roisHostData[8] = 24.0f;
  roisHostData[9] = 41.0f;

  ret = CreateAclTensor(xHostData, xShape, &xDeviceAddr, aclDataType::ACL_FLOAT, &x);
  CHECK_RET(ret == ACL_SUCCESS, return ret);
  ret = CreateAclTensor(roisHostData, roisShape, &roisDeviceAddr, aclDataType::ACL_FLOAT, &rois);
  CHECK_RET(ret == ACL_SUCCESS, return ret);
  ret = CreateAclTensorOutput<float>(yShape, &yDeviceAddr, aclDataType::ACL_FLOAT, &y);
  CHECK_RET(ret == ACL_SUCCESS, return ret);
  ret = CreateAclTensorOutput<int32_t>(argmaxShape, &argmaxDeviceAddr, aclDataType::ACL_INT32, &argmax);
  CHECK_RET(ret == ACL_SUCCESS, return ret);

  int64_t pooledH = 3;
  int64_t pooledW = 3;
  float spatialScaleH = 1.0f;
  float spatialScaleW = 1.0f;

  uint64_t workspaceSize = 0;
  aclOpExecutor* executor = nullptr;
  ret = aclnnRoiPoolingWithArgMaxGetWorkspaceSize(x, rois, pooledH, pooledW, spatialScaleH, spatialScaleW,
                                                  y, argmax, &workspaceSize, &executor);
  CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnRoiPoolingWithArgMaxGetWorkspaceSize failed. ERROR: %d\n", ret);
            return ret);

  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);
  }

  ret = aclnnRoiPoolingWithArgMax(workspaceAddr, workspaceSize, executor, stream);
  CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnRoiPoolingWithArgMax failed. ERROR: %d\n", ret); return ret);

  ret = aclrtSynchronizeStream(stream);
  CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);

  int64_t yElem = GetShapeSize(yShape);
  std::vector<float> yResult(yElem, 0.0f);
  ret = aclrtMemcpy(yResult.data(), yElem * sizeof(float), yDeviceAddr, yElem * sizeof(float),
                    ACL_MEMCPY_DEVICE_TO_HOST);
  CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy y from device to host failed. ERROR: %d\n", ret); return ret);

  int64_t argmaxElem = GetShapeSize(argmaxShape);
  std::vector<int32_t> argmaxResult(argmaxElem, 0);
  ret = aclrtMemcpy(argmaxResult.data(), argmaxElem * sizeof(int32_t), argmaxDeviceAddr,
                    argmaxElem * sizeof(int32_t), ACL_MEMCPY_DEVICE_TO_HOST);
  CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy argmax from device to host failed. ERROR: %d\n", ret); return ret);

  aclDestroyTensor(x);
  aclDestroyTensor(rois);
  aclDestroyTensor(y);
  aclDestroyTensor(argmax);
  aclrtFree(xDeviceAddr);
  aclrtFree(roisDeviceAddr);
  aclrtFree(yDeviceAddr);
  aclrtFree(argmaxDeviceAddr);
  if (workspaceSize > 0) {
    aclrtFree(workspaceAddr);
  }
  aclrtDestroyStream(stream);
  aclrtResetDevice(deviceId);
  aclFinalize();
  return 0;
}