aclnnIou
Applicable Products
| Product | Supported |
|---|---|
| √ | |
| √ | |
| √ | |
| × | |
| √ | |
| × |
Function
- Operator function: Computes the Intersection over Union (IOU) or Intersection over Foreground (IOF) for two input sets of rectangular boxes, used to evaluate the overlap degree between predicted boxes (bBox) and ground truth boxes (gtBox).
- Formula: Where Area_1 is the area of bBox, Area_2 is the area of gtBox, and Area_3 is the area of their overlapping region. For definitions of x and y, see the Parameters.
Function Prototype
Each operator is divided into a two-phase API. You must first call the "aclnnIouGetWorkspaceSize" API to obtain the workspace size required for computation and the executor that encapsulates the operator computation process, and then call the "aclnnIou" API to perform the computation.
aclnnStatus aclnnIouGetWorkspaceSize(
const aclTensor* bBoxes,
const aclTensor* gtBoxes,
const char* mode,
float eps,
bool aligned,
aclTensor* overlap,
uint64_t* workspaceSize,
aclOpExecutor** executor)aclnnStatus aclnnIou(
void* workspace,
uint64_t workspaceSize,
aclOpExecutor* executor,
aclrtStream stream)aclnnIouGetWorkspaceSize
Parameters
Parameter Name Input/Output Description Description Data Type Data Format Dimension (Shape) Non-contiguous Tensor bBoxes (aclTensor*) Input Predicted bounding boxes. - m in shape indicates the number of bounding boxes.
- 4 in shape refers to [x0, y0, x1, y1], where (x0, y0) and (x1, y1) represent the top-left and bottom-right corners of the bounding box, respectively, and must satisfy x1 > x0, y1 > y0.
FLOAT, FLOAT16, BFLOAT16 ND is (m, 4). √ gtBoxes (aclTensor*) Input Ground truth bounding boxes. - n is the number of bounding boxes.
- 4 refers to [x2, y2, x3, y3], where (x2, y2) and (x3, y3) represent the top-left and bottom-right corners of the bounding box, respectively, and must satisfy x3 > x2, y3 > y2.
- The data type must be consistent with bBoxes.
FLOAT, FLOAT16, BFLOAT16 ND (n, 4). ✓ mode (char*) Input Selects the calculation mode: "iou" or "iof". - "iou": Computes the intersection over union.
- "iof": Computes the intersection over foreground.
String - - - eps (float) Input To prevent division by zero, eps is added to both the length and width when calculating the area. - FLOAT - - - aligned (bool) Input Indicates whether the shapes of the two inputs are the same. - True: bBoxes and gtBoxes have the same shape, both being (m, 4), and the output shape is (m, 1).
- False: bBoxes and gtBoxes have different shapes, being (m, 4) and (n, 4) respectively, and the output shape is (m, n).
BOOL - - - overlap (aclTensor*) Output The IOU/IOF computed from the two inputs. The data type must be consistent with bBoxes. FLOAT, FLOAT16, BFLOAT16 ND Shape: (m, n) or (m, 1). √ workspaceSize (uint64_t*) Output Returns the workspace size to be requested on the Device side. - - - - - executor (aclOpExecutor**) Output Returns the op executor, which includes the operator computation flow. - - - - - Atlas inference products : The BFLOAT16 data type is not supported.
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 Value Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 The input bBoxes, gtBoxes, and output overlap are null pointers. ACLNN_ERR_PARAM_INVALID 161002 bBoxes, gtBoxes, or overlap is not two-dimensional. The data types of bBoxes, gtBoxes, and overlap are inconsistent. The data type or format of bBoxes, gtBoxes, or overlap is not within the supported range. The second dimension of bBoxes or gtBoxes is not 4. When aligned is true, the first dimension of bBoxes and gtBoxes is different. When aligned is true, the second dimension of overlap is not 1. mode is neither "iou" nor "iof". eps is less than 0. ACLNN_ERR_INNER_NULLPTR 561103 API internal validation error, typically caused by input data or attribute specifications that are outside the supported range. ACLNN_ERR_RUNTIME_ERROR 361001 An exception occurred when the API called the npu runtime API, for example, SocVersion is not supported.
aclnnIou
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 for on the Device side, obtained through the first-phase API aclnnIouGetWorkspaceSize. executor Input The 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
- Deterministic computation:
- aclnnIou 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.
#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/level2/aclnn_iou.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) {
// Boilerplate: initialize resources.
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 data from the host side 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);
// Calculate 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. 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 inputs and outputs. Customize the construction based on the API.
// input
std::vector<float> bBoxesHostData = {1.0, 1.0, 5.0, 3.0, 1.0, 1.0, 5.0, 3.0};
std::vector<float> gtBoxesHostData = {4.0, 2.0, 9.0, 5.0, 4.0, 2.0, 9.0, 5.0};
std::vector<float> overlapHostData = {0.045455, 0.045455};
std::vector<int64_t> bBoxesShape = {2, 4};
std::vector<int64_t> gtBoxesShape = {2, 4};
std::vector<int64_t> overlapShape = {2, 1};
void* bBoxesDeviceAddr = nullptr;
void* gtBoxesDeviceAddr = nullptr;
void* overlapDeviceAddr = nullptr;
aclTensor* bBoxes = nullptr;
aclTensor* gtBoxes = nullptr;
aclTensor* overlap = nullptr;
ret = CreateAclTensor(bBoxesHostData, bBoxesShape, &bBoxesDeviceAddr, aclDataType::ACL_FLOAT, &bBoxes);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(gtBoxesHostData, gtBoxesShape, >BoxesDeviceAddr, aclDataType::ACL_FLOAT, >Boxes);
CHECK_RET(ret == ACL_SUCCESS, return ret);
ret = CreateAclTensor(overlapHostData, overlapShape, &overlapDeviceAddr, aclDataType::ACL_FLOAT, &overlap);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// attr
const char* mode = "iou";
float eps = 0.0f;
bool aligned = true;
uint64_t workspaceSize = 0;
aclOpExecutor* executor;
// 3. Call the CANN operator library API. Replace with the specific API name.
ret = aclnnIouGetWorkspaceSize(bBoxes, gtBoxes, mode, eps, aligned, overlap, &workspaceSize, &executor);
CHECK_RET(
ret == ACL_SUCCESS,
LOG_PRINT("aclnnIouGetWorkspaceSize failed. ERROR: %d\n", ret);
return ret);
// Allocate 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);
}
// aclnnIou
ret = aclnnIou(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS,
LOG_PRINT("aclnnIou 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. Copy the result from device memory to host memory. Modify according to the specific API definition.
auto size = GetShapeSize(overlapShape);
std::vector<float> resultData(size, 0);
ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), overlapDeviceAddr,
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("result[%ld] is: %f\n", i, resultData[i]);
}
// 6. Release aclTensor and aclScalar. Modify according to the specific API definition.
aclDestroyTensor(bBoxes);
aclDestroyTensor(gtBoxes);
aclDestroyTensor(overlap);
// 7. Release device resources.
aclrtFree(bBoxesDeviceAddr);
aclrtFree(gtBoxesDeviceAddr);
aclrtFree(overlapDeviceAddr);
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}