aclnnTriu&aclnnInplaceTriu
Supported Products
| Product | Supported |
|---|---|
| √ | |
| √ | |
| × | |
| √ | |
| √ |
Function
Description: Sets the elements of the input tensor
self(last two dimensions) to0in the lower triangular part below the main diagonal. The diagonal parameter can be set to a positive or negative value. The default value is0. A positive value indicates diagonals above the main diagonal. A negative value indicates diagonals below the main diagonal.Formula: In the following formula,
iindicates the sequence number of the element in the second-to-last dimension (iis the row index),jindicates the sequence number of the element in the last dimension (jis the column index), anddindicates diagonal. In the two-dimensional coordinate diagram corresponding to (i, j), i+d==j indicates that the element is on the diagonal.Example:
,
The result of triu(self, diagonal=0) is as follows:
;
Adjust the value of
diagonal. The result of triu(self, diagonal=1) is as follows:;
Adjust the value of
diagonalto-1. The result of triu(self, diagonal=-1) is as follows:.
Prototype
aclnnTriuandaclnnInplaceTriuimplement the same function in different ways. Select a proper operator based on your requirements.aclnnTriu: An output tensor object needs to be created to store the computation result.aclnnInplaceTriu: 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,
aclnnTriuGetWorkspaceSizeoraclnnInplaceTriuGetWorkspaceSizeis called to obtain input parameters and calculate the required workspace size based on the computation process. Then,aclnnTriuoraclnnInplaceTriuis called to perform computation.
aclnnStatus aclnnTriuGetWorkspaceSize(
const aclTensor* self,
int64_t diagonal,
aclTensor* out,
uint64_t* workspaceSize,
aclOpExecutor** executor)aclnnStatus aclnnTriu(
void* workspace,
uint64_t workspaceSize,
aclOpExecutor* executor,
aclrtStream stream)aclnnStatus aclnnInplaceTriuGetWorkspaceSize(
aclTensor* selfRef,
int64_t diagonal,
uint64_t* workspaceSize,
aclOpExecutor** executor)aclnnStatus aclnnInplaceTriu(
void* workspace,
uint64_t workspaceSize,
aclOpExecutor* executor,
aclrtStream stream)aclnnTriuGetWorkspaceSize
Parameters
Name Input/Output Description Precaution Data Type Data Format Dimension (Shape) Non-contiguous Tensor self Input Target tensor to be converted, corresponding to selfin the formula.Empty tensors are supported. UINT64, INT64, UINT32, INT32, UINT16, INT16, UINT8, INT8, FLOAT16, FLOAT32, DOUBLE, BOOL, BFLOAT16, COMPLEX32, COMPLEX64 ND, NCHW, NHWC, HWCN, NDHWC, NCDHW 2–8 dimensions - diagonal Input Diagonal offset. - int64_t - - - out Output Indicates the result tensor after conversion, that is, outin the formula.The data type and shape must consistent with those of self.
Empty tensors are supported.UINT64, INT64, UINT32, INT32, UINT16, INT16, UINT8, INT8, FLOAT16, FLOAT32, DOUBLE, BOOL, BFLOAT16, COMPLEX32, COMPLEX64 ND, NCHW, NHWC, HWCN, NDHWC, NCDHW 2–8 dimensions - workspaceSize Output Size of the workspace required to be allocated on the device. - - - - - executor Output Operator executor, containing the operator computation process. - - - - - Returns
aclnnStatus: status code. For details, see aclnn Return Codes.The first-phase API performs input parameter validation. The following errors may be returned:
Return Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 selforoutis a null pointer.ACLNN_ERR_PARAM_INVALID 161002 The data type of selforoutis not supported.The data format of selforoutis private.The data types of selfandoutare different.The shapes of selfandoutare different.The data formats of selfandoutare different.The shape of selfis greater than 8D or less than 2D.
aclnnTriu
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 aclnnTriuGetWorkspaceSize.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.
aclnnInplaceTriuGetWorkspaceSize
Parameters
Name Input/Output Description Precaution Data Type Data Format Dimension (Shape) Non-contiguous Tensor selfRef Input Indicates input and output tensors. - UINT64, INT64, UINT32, INT32, UINT16, INT16, UINT8, INT8, FLOAT16, FLOAT32, DOUBLE, BOOL, BFLOAT16 ND, NCHW, NHWC, HWCN, NDHWC, NCDHW 2–8 dimensions or empty tensors. - diagonal Input Diagonal offset. - int64_t - - - workspaceSize Output Size of the workspace required to be allocated on the device. - - - - - executor Output Operator executor, containing the operator computation process. - - - - - Returns
aclnnStatus: status code. For details, see aclnn Return Codes.The first-phase API performs input parameter validation. The following errors may be returned:
Return Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 selfRefis a null pointer.ACLNN_ERR_PARAM_INVALID 161002 The data type of selfRefis not supported.The data format of selfRefis private.The shape of selfRefis greater than 8D or less than 2D
aclnnInplaceTriu
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 aclnnInplaceTriuGetWorkspaceSize.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:
aclnnTriu&aclnnInplaceTriudefaults 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_triu.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) {
// (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 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 data to the device 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 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. (Boilerplate) Initialize the device and stream. For details, see the ACL API manual.
// Set device ID based on the 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 based on the API definition.
std::vector<int64_t> selfShape = {4, 4};
std::vector<int64_t> outShape = {4, 4};
int64_t diagonal = 1;
void* selfDeviceAddr = nullptr;
void* outDeviceAddr = nullptr;
aclTensor* self = nullptr;
aclTensor* out = nullptr;
std::vector<float> selfHostData = {0, 1.123, -2.001, 303.45, 40009, -50.1234, 60.666, -7.6543,
8000, -9.009, 1024, -11.23345, 12, 1356, -14.99, -15.34023};
std::vector<float> outHostData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
// Create a self aclTensor.
ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create an out aclTensor.
ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// 3. Call the CANN operator library API. Change the API name to the actual one.
uint64_t workspaceSize = 0;
aclOpExecutor* executor;
// Call the first-phase API of aclnnTriu.
ret = aclnnTriuGetWorkspaceSize(self, diagonal, out, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnTriuGetWorkspaceSize 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 aclnnTriu.
ret = aclnnTriu(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnTriu failed. ERROR: %d\n", ret); return ret);
uint64_t inplaceWorkspaceSize = 0;
aclOpExecutor* inplaceExecutor;
// Call the first-phase API of aclnnInplaceTriu.
ret = aclnnInplaceTriuGetWorkspaceSize(self, diagonal, &inplaceWorkspaceSize, &inplaceExecutor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceTriuGetWorkspaceSize 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 aclnnInplaceTriu.
ret = aclnnInplaceTriu(inplaceWorkspaceAddr, inplaceWorkspaceSize, inplaceExecutor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceTriu failed. ERROR: %d\n", ret); return ret);
// 4. (Boilerplate) 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(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 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: %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(float), 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("inplaceResult[%ld] is: %f\n", i, inplaceResultData[i]);
}
// 6. Release aclTensors and aclScalars. Modify the code based on the API definition.
aclDestroyTensor(self);
aclDestroyTensor(out);
// 7. Release device resources. Modify the code based on the API definition.
aclrtFree(selfDeviceAddr);
aclrtFree(outDeviceAddr);
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}