aclnnBucketize
产品支持情况
| 产品 | 是否支持 |
|---|---|
| Ascend 950PR/Ascend 950DT | √ |
| Atlas A3 训练系列产品/Atlas A3 推理系列产品 | × |
| Atlas A2 训练系列产品/Atlas A2 推理系列产品 | × |
| Atlas 200I/500 A2 推理产品 | × |
| Atlas 推理系列产品 | × |
| Atlas 训练系列产品 | × |
功能说明
-
接口功能:根据给定的边界数组(boundaries)确定输入张量中每个元素所属的区间索引。对于输入值 xx 和边界数组 boundaries=[b0,b1,...,bn−1]boundaries = [b_0, b_1, ..., b_{n-1}],输出索引 yiy_i 满足:
- 如果 x≤b0x \le b_0,则 yi=0y_i = 0
- 如果 bi−1<x≤bib_{i-1} < x \le b_i,则 yi=iy_i = i(默认左开右闭区间)
- 如果 x>bn−1x > b_{n-1},则 yi=ny_i = n
-
计算公式:
当right=False时(默认,左开右闭区间):
yi=min{j∣xi≤bj}y_i = \min\{j \mid x_i \le b_j\}
当right=True时(左闭右开区间):
yi=min{j∣xi<bj}y_i = \min\{j \mid x_i < b_j\}
函数原型
每个算子分为两段式接口,必须先调用"aclnnBucketizeGetWorkspaceSize"接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用"aclnnBucketize"接口执行计算。
aclnnStatus aclnnBucketizeGetWorkspaceSize(
const aclTensor *self,
const aclTensor *boundaries,
const bool outInt32,
const bool right,
aclTensor *out,
uint64_t *workspaceSize,
aclOpExecutor **executor)
aclnnStatus aclnnBucketize(
void *workspace,
uint64_t workspaceSize,
aclOpExecutor *executor,
aclrtStream stream)
aclnnBucketizeGetWorkspaceSize
-
参数说明
参数名 输入/输出 描述 使用说明 数据类型 数据格式 维度(shape) 非连续Tensor self(aclTensor*) 输入 输入张量,待确定区间索引的数据。 - 支持空Tensor。
- 数据类型与boundaries的数据类型需满足互推导关系。
FLOAT、FLOAT16、BFLOAT16、INT8、INT16、INT32、INT64、UINT8 ND 0-8 √ boundaries(aclTensor*) 输入 边界数组,必须是一维张量且单调递增。 - 不支持空Tensor。
- 必须为一维张量。
- 必须单调递增且不重复。
FLOAT、FLOAT16、BFLOAT16、INT8、INT16、INT32、INT64、UINT8 ND 1 √ outInt32(bool) 输入 输出数据类型控制参数。 - True表示输出数据类型为INT32。
- False表示输出数据类型为INT64。
- - - - right(bool) 输入 区间边界控制参数。 - True表示区间包含左边界(左闭右开)。
- False表示区间不包含左边界(左开右闭)。
- - - - out(aclTensor*) 输出 输出张量,每个元素为对应的区间索引。 - 支持空Tensor。
- shape必须与self相同。
- 数据类型由outInt32决定。
INT32、INT64 ND 与self一致 √ workspaceSize(uint64_t*) 输出 返回需要在Device侧申请的workspace大小。 - - - - - executor(aclOpExecutor**) 输出 返回op执行器,包含了算子计算流程。 - - - - - -
返回值 aclnnStatus:返回状态码,具体参见aclnn返回码。
第一段接口完成入参校验,出现以下场景时报错:
返回值 错误码 描述 ACLNN_ERR_PARAM_NULLPTR 161001 self、boundaries、out存在空指针。 ACLNN_ERR_PARAM_INVALID 161002 self或boundaries的数据类型不在支持的范围之内。 self和boundaries的数据类型不满足互推导关系。 boundaries的维度不为1。 out的shape与self的shape不匹配。 out的数据类型与outInt32参数不匹配。
aclnnBucketize
-
参数说明
参数名 输入/输出 描述 workspace 输入 在Device侧申请的workspace内存地址。 workspaceSize 输入 在Device侧申请的workspace大小,由第一段接口aclnnBucketizeGetWorkspaceSize获取。 executor 输入 op执行器,包含了算子计算流程。 stream 输入 指定执行任务的Stream。 -
返回值 aclnnStatus:返回状态码,具体参见aclnn返回码。
约束说明
- 确定性说明:aclnnBucketize默认确定性实现。
- boundaries必须是一维张量。
- boundaries必须单调递增且不重复(软件层面无法校验,需用户保证)。
- self和boundaries的数据类型需要满足互推导关系。
- out的shape必须与self相同。
- outInt32为True时,out的数据类型必须为INT32;outInt32为False时,out的数据类型必须为INT64。
调用示例
示例代码如下,仅供参考,具体编译和执行过程请参考编译与运行样例。
-
Ascend 950PR/Ascend 950DT:
#include <iostream> #include <vector> #include "acl/acl.h" #include "aclnnop/aclnn_bucketize.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) { 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; } 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> selfShape = {3, 2}; std::vector<int64_t> boundariesShape = {3}; std::vector<int64_t> outShape = {3, 2}; void* selfDeviceAddr = nullptr; void* boundariesDeviceAddr = nullptr; void* outDeviceAddr = nullptr; aclTensor* self = nullptr; aclTensor* boundaries = nullptr; aclTensor* out = nullptr; std::vector<float> selfHostData = {-5, 10000, 150, 10, 5, 100}; std::vector<float> boundariesHostData = {0, 10, 100}; std::vector<int64_t> outHostData = {0, 0, 0, 0, 0, 0}; ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(boundariesHostData, boundariesShape, &boundariesDeviceAddr, aclDataType::ACL_FLOAT, &boundaries); CHECK_RET(ret == ACL_SUCCESS, return ret); ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_INT64, &out); CHECK_RET(ret == ACL_SUCCESS, return ret); uint64_t workspaceSize = 0; aclOpExecutor* executor; bool outInt32 = false; bool right = false; ret = aclnnBucketizeGetWorkspaceSize(self, boundaries, outInt32, right, out, &workspaceSize, &executor); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBucketizeGetWorkspaceSize 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 = aclnnBucketize(workspaceAddr, workspaceSize, executor, stream); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBucketize 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); auto size = GetShapeSize(outShape); std::vector<int64_t> resultData(size, 0); ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr, size * sizeof(int64_t), ACL_MEMCPY_DEVICE_TO_HOST); CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); for (int64_t i = 0; i < size; i++) { LOG_PRINT("result[%ld] is: %ld\n", i, resultData[i]); } aclDestroyTensor(self); aclDestroyTensor(boundaries); aclDestroyTensor(out); aclrtFree(selfDeviceAddr); aclrtFree(boundariesDeviceAddr); aclrtFree(outDeviceAddr); if (workspaceSize > 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }
参考
Pytorch AtenIR
- func: bucketize.Tensor_out(Tensor self, Tensor boundaries, *, bool outInt32=False, bool right=False, Tensor(a!) out) -> Tensor(a!)
dispatch:
CPU: bucketize_out_cpu
CUDA: bucketize_out_cuda
AtenIR参数描述
| 类型 | 名称 | 描述 | GPU支持的数据类型 | CPU支持的数据类型 |
|---|---|---|---|---|
| 输入 | input | 输入张量 | FLOAT、FLOAT16、BFLOAT16、INT8、INT16、INT32、INT64、UINT8、DOUBLE | FLOAT、FLOAT16、BFLOAT16、INT8、INT16、INT32、INT64、UINT8、DOUBLE |
| 输入 | boundaries | 边界数组,必须是一维且单调递增 | FLOAT、FLOAT16、BFLOAT16、INT8、INT16、INT32、INT64、UINT8、DOUBLE | FLOAT、FLOAT16、BFLOAT16、INT8、INT16、INT32、INT64、UINT8、DOUBLE |
| 属性 | outInt32 | 输出数据类型是否为int32 | bool | bool |
| 属性 | right | 区间是否包含右边界 | bool | bool |
| 输入 | out | 指定的输出tensor | INT32、INT64 | INT32、INT64 |
| 输出 | output | 输出tensor | INT32、INT64 | INT32、INT64 |