aclnnIndexCopy&aclnnInplaceIndexCopy
Supported Products
| Product | Supported |
|---|---|
| √ | |
| √ | |
| × | |
| × | |
| √ |
Function
Takes the element value in the index tensor as the index and copies elements from source to the corresponding positions in selfRef or out based on the specified axis dim.
Prototype
- aclnnIndexCopy and aclnnInplaceIndexCopy implement the same function in different ways. Select a proper operator based on your requirements.
- aclnnIndexCopy: An output tensor object needs to be created to store the computation result.
- aclnnInplaceIndexCopy: No output tensor object needs to be created, and the computation result is stored in the memory of the input tensor.
- Each operator has two-phase API calls. First, aclnnIndexCopyGetWorkspaceSize or aclnnInplaceIndexCopyGetWorkspaceSize is called to obtain the workspace size required for computation and the executor that contains the operator computation process. Then, aclnnIndexCopy or aclnnInplaceIndexCopy is called to perform computation.
aclnnStatus aclnnIndexCopyGetWorkspaceSize(
aclTensor* selfRef,
int64_t dim,
const aclTensor* index,
const aclTensor* source,
aclTensor* outRef,
uint64_t* workspaceSize,
aclOpExecutor** executor)aclnnStatus aclnnIndexCopy(
void *workspace,
uint64_t workspaceSize,
aclOpExecutor *executor,
aclrtStream stream)aclnnStatus aclnnInplaceIndexCopyGetWorkspaceSize(
aclTensor* selfRef,
int64_t dim,
const aclTensor* index,
const aclTensor* source,
uint64_t* workspaceSize,
aclOpExecutor** executor)aclnnStatus aclnnInplaceIndexCopy(
void *workspace,
uint64_t workspaceSize,
aclOpExecutor *executor,
aclrtStream stream)aclnnIndexCopyGetWorkspaceSize
Parameters
Name Input/Output Description Precaution Data Type Data Format Dimension (Shape) Non-contiguous Tensor selfRef Input aclTensor to be input. - FLOAT, BFLOAT16, FLOAT16, INT32, UINT32, INT64, UINT64, INT16, INT8, UINT8, DOUBLE, BOOL, COMPLEX128, COMPLEX64 ND - √ dim Input aclTensor to be input. The value range is [–selfRef.dim(), selfRef.dim() – 1]. int64 - - - index Input aclTensor to be input. - The dimension cannot be greater than 1. The number of elements must be the same as the size of the dim axis in the source tensor.
- When index has duplicate index values, the result order is not guaranteed.
- Index data in index cannot be out of bounds.
INT32, INT64 ND - √ source Input aclTensor to be input. The size of the dim axis is the same as the number of elements in index, and the size of other dimensions is the same as the shape of selfRef. Same as that of selfRef. ND Same as that of selfRef. d√ outRef Output aclTensor to be output. - Same as that of selfRef. - Same as that of selfRef. - workspaceSize Output Size of the workspace required to be allocated on the device. - - - - - executor Output Operator executor, containing the operator computation process. - - - - - Atlas A2 training products/Atlas A2 inference products andAtlas A3 training series products/Atlas A3 inference series products : The data type cannot be UINT32 or UINT64.Atlas training series products : The data type cannot be BFLOAT16, UINT32, or UINT64.
Returns
aclnnStatus: status code. For details, see aclnn Return Codes.
The first-phase API implements input parameter verification. The following errors may be thrown.
Return Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 The passed selfRef, index, source, or out is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data type of selfRef or index is not supported. The data types of selfRef and source are different. The size of source on the dim axis is different from the number of elements in index. The shapes of selfRef and source are inconsistent on non-dim axes. The dimension of index is greater than 1. When source is a scalar, the number of index elements is not 1. When source and selfRef are not scalars, their dimensions are inconsistent. The shape or data type of selfRef is different from that of out. dim is out of bounds.
aclnnIndexCopy
Parameters
Name Input/Output Description workspace Input Address of the workspace to be allocated on the device. workspaceSize Input Size of the workspace to be allocated on the device, which is obtained by calling the first-phase API aclnnIndexCopyGetWorkspaceSize. executor Input Operator executor, containing the operator computation process. stream Input Stream for executing the task. Returns
aclnnStatus: status code. For details, see aclnn Return Codes.
aclnnInplaceIndexCopyGetWorkspaceSize
Parameters
Name Input/Output Description Precaution Data Type Data Format Dimension (Shape) Non-contiguous Tensor selfRef Input aclTensor to be input. - FLOAT, BFLOAT16, FLOAT16, INT32, UINT32, INT64, UINT64, INT16, INT8, UINT8, DOUBLE, BOOL, COMPLEX128, COMPLEX64 ND - √ dim Input aclTensor to be input. The value range is [–selfRef.dim(), selfRef.dim() – 1]. int64 - - - index Input aclTensor to be input. - The dimension cannot be greater than 1. The number of elements must be the same as the size of the dim axis in the source tensor.
- When index has duplicate index values, the result order is not guaranteed.
INT32, INT64 ND - √ source Input aclTensor to be input. The size of the dim axis is the same as the number of elements in index, and the size of other dimensions is the same as the shape of selfRef. Same as that of selfRef. ND Same as that of selfRef. d√ workspaceSize Output Size of the workspace required to be allocated on the device. - - - - - executor Output Operator executor, containing the operator computation process. - - - - - Atlas A2 training products/Atlas A2 inference products andAtlas A3 training series products/Atlas A3 inference series products : The data type cannot be UINT32 or UINT64.Atlas training series products : The data type cannot be BFLOAT16, UINT32, or UINT64.
Returns
aclnnStatus: status code. For details, see aclnn Return Codes.
The first-phase API implements input parameter verification. The following errors may be thrown.
Return Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 The passed selfRef, index, source, or out is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data type of selfRef or index is not supported. The data types of selfRef and source are different. The size of source on the dim axis is different from the number of elements in index. The shapes of selfRef and source are inconsistent on non-dim axes. The dimension of index is greater than 1. When source is a scalar, the number of index elements is not 1. When source and selfRef are not scalars, their dimensions are inconsistent. dim is out of bounds.
aclnnInplaceIndexCopy
Parameters
Name Input/Output Description workspace Input Address of the workspace to be allocated on the device. workspaceSize Input Size of the workspace to be allocated on the device, which is obtained by calling the first-phase API aclnnInplaceIndexCopyGetWorkspaceSize. executor Input Operator executor, containing the operator computation process. stream Input Stream for executing the task. Returns
aclnnStatus: status code. For details, see aclnn Return Codes.
Constraints
- Deterministic computation:
- aclnnIndexCopy and aclnnInplaceIndexCopy default to a deterministic implementation.
Example
The following example is for reference only. For details, see Compilation and Running Sample.
#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_index_copy.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) {
// (Fixed writing) 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 memory on the device.
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 the data on the host to the memory on the device.
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 aclCreateTensor 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. (Fixed writing) Initialize the device and stream. For details, see the ACL API manual.
// Set the device ID in use.
int32_t deviceId = 0;
aclrtStream stream;
auto ret = Init(deviceId, &stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init failed. ERROR: %d\n", ret); return ret);
// 2. Construct inputs and outputs based on the API definition.
std::vector<int64_t> selfShape = {4, 2};
std::vector<int64_t> indexShape = {4};
std::vector<int64_t> sourceShape = {4, 2};
std::vector<int64_t> outShape = {4, 2};
void* selfDeviceAddr = nullptr;
void* indexDeviceAddr = nullptr;
void* sourceDeviceAddr = nullptr;
void* outDeviceAddr = nullptr;
aclTensor* self = nullptr;
aclTensor* index = nullptr;
aclTensor* source = nullptr;
aclTensor* out = nullptr;
int64_t dim=0;
std::vector<float> selfHostData = {0,0,0,0,0,0,0,0};
std::vector<int64_t> indexHostData = {3,2,1,0};
std::vector<float> sourceHostData={1,2,3,4,5,6,7,8};
std::vector<float> outHostData = {0,0,0,0,0,0,0,0};
// Create a self aclTensor.
ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_INT32, &self);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create an index aclTensor.
ret = CreateAclTensor(indexHostData, indexShape, &indexDeviceAddr, aclDataType::ACL_INT64, &index);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create a source aclTensor.
ret = CreateAclTensor(sourceHostData, sourceShape, &sourceDeviceAddr, aclDataType::ACL_INT32, &source);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create an out aclTensor.
ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_INT32, &out);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// 3. Call the CANN operator library API, which needs to be replaced with the actual API.
uint64_t workspaceSize = 0;
aclOpExecutor* executor;
// Call the first-phase API of aclnnIndexCopy.
ret = aclnnIndexCopyGetWorkspaceSize(self, dim, index, source, out, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnIndexCopyGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
// Allocate device memory based on workspaceSize computed 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 aclnnIndexCopy.
ret = aclnnIndexCopy(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnIndexCopy failed. ERROR: %d\n", ret); return ret);
uint64_t inplaceWorkspaceSize = 0;
aclOpExecutor* inplaceExecutor;
// Call the first-phase API of aclnnInplaceIndexCopy.
ret = aclnnInplaceIndexCopyGetWorkspaceSize(self, dim, index, source, &inplaceWorkspaceSize, &inplaceExecutor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceIndexCopyGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
// Allocate device memory based on workspaceSize computed by the first-phase API.
void* inplaceWorkspaceAddr = nullptr;
if (inplaceWorkspaceSize > 0) {
ret = aclrtMalloc(&inplaceWorkspaceAddr, inplaceWorkspaceSize, 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 aclnnInplaceIndexCopy.
ret = aclnnInplaceIndexCopy(inplaceWorkspaceAddr, inplaceWorkspaceSize, inplaceExecutor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceIndexCopy failed. ERROR: %d\n", ret); return ret);
// 4. (Fixed writing) Wait until the task execution is 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 memory to the host. Modify the code based on the API definition.
auto size = GetShapeSize(selfShape);
std::vector<float> resultData(size, 0);
ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), selfDeviceAddr,
size * sizeof(resultData[0]), 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("aclnnIndexCopy result[%ld] is: %f\n", i, resultData[i]);
}
auto inplaceSize = GetShapeSize(selfShape);
std::vector<float> inplaceResultData(inplaceSize, 0);
ret = aclrtMemcpy(inplaceResultData.data(), inplaceResultData.size() * sizeof(inplaceResultData[0]), selfDeviceAddr,
inplaceSize * sizeof(inplaceResultData[0]), 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 < inplaceSize; i++) {
LOG_PRINT("aclnnInplaceIndexCopy result[%ld] is: %f\n", i, inplaceResultData[i]);
}
// 6. Release aclTensor and aclScalar. Modify the code based on the API definition.
aclDestroyTensor(self);
aclDestroyTensor(index);
aclDestroyTensor(source);
aclDestroyTensor(out);
// 7. Release device resources. Modify the code based on the API definition.
aclrtFree(selfDeviceAddr);
aclrtFree(indexDeviceAddr);
aclrtFree(sourceDeviceAddr);
aclrtFree(outDeviceAddr);
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}