aclnnThreshold&aclnnInplaceThreshold
Applicable Products
| Product | Supported |
|---|---|
| × | |
| √ | |
| √ | |
| × | |
| × | |
| √ |
Function
Description: Performs a threshold operation on the input x. When elements in x are greater than threshold, the elements are returned; otherwise, value is returned.
Formula:
Function Prototype
aclnnThreshold and aclnnInplaceThreshold implement the same function. The differences are as follows. Select the appropriate operator based on your actual scenario.
aclnnThreshold: A new output tensor object needs to be created to store the computation result.
aclnnInplaceThreshold: No need to create a new output tensor object. The computation result is stored directly in the memory of the input tensor.
Each operator is divided into a two-phase API. You must first call the "aclnnThresholdGetWorkspaceSize" or "aclnnInplaceThresholdGetWorkspaceSize" API to obtain the workspace size required for computation and the executor that contains the operator computation process, and then call the "aclnnThreshold" or "aclnnInplaceThreshold" API to execute the computation.
aclnnStatus aclnnThresholdGetWorkspaceSize(
const aclTensor* self,
const aclScalar* threshold,
const aclScalar* value,
aclTensor* out,
uint64_t* workspaceSize,
aclOpExecutor** executor)aclnnStatus aclnnThreshold(
void* workspace,
uint64_t workspaceSize,
aclOpExecutor* executor,
aclrtStream stream)aclnnStatus aclnnInplaceThresholdGetWorkspaceSize(
aclTensor* selfRef,
const aclScalar* threshold,
const aclScalar* value,
uint64_t* workspaceSize,
aclOpExecutor** executor)aclnnStatus aclnnInplaceThreshold(
void* workspace,
uint64_t workspaceSize,
aclOpExecutor* executor,
aclrtStream stream)aclnnThresholdGetWorkspaceSize
Parameters
Atlas training products : BFLOAT16 data type is not supported.
Return value
aclnnStatus: return code. For details, see aclnn Return Code.
The first-phase API performs input parameter validation and returns an error in the following scenarios:
Return Code Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 The passed self, threshold, value, or out is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data type of self is not within the supported range. self, threshold, and value do not satisfy the data type derivation rule. The data type derived from self, threshold, and value cannot be converted to the specified output out type. The shape of self and out exceeds 8 dimensions, or the two shapes are inconsistent.
aclnnThreshold
Parameters:
Parameter Input/Output Description workspace Input Workspace memory address applied by the Device side. workspaceSize Input Workspace size applied by the Device side, obtained through the first-phase API aclnnThresholdGetWorkspaceSize. executor Input Operator executor, which contains the operator computation flow. stream Input Specifies the stream that executes the task. Return value
aclnnStatus: return code. For details, see aclnn Return Code.
aclnnInplaceThresholdGetWorkspaceSize
Parameters:
Parameter Input/Output/Attribute Description Data Type Data Format selfRef (aclTensor*) Input/Output Represents the input/output tensor, i.e., x/out in the formula. BFLOAT16, FLOAT16, FLOAT32, INT32, INT8, UINT8, INT16, INT64 ND threshold (aclScalar*) Input Represents the threshold, which is the input threshold in the formula. BFLOAT16, FLOAT16, FLOAT32, INT32, INT8, UINT8, INT16, INT64 - value (aclScalar*) Input. Represents the return value when the element of input self is less than the threshold, i.e., the input value in the formula. BFLOAT16, FLOAT16, FLOAT32, INT32, INT8, UINT8, INT16, INT64 - Atlas training products : BFLOAT16 data type is not supported.
Return Value
aclnnStatus: return code. For details, see aclnn Return Code.
The first-phase API performs input parameter validation and returns an error in the following scenarios:
Return Code Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 The passed selfRef, threshold, or value is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data type of selfRef is not within the supported range. selfRef, threshold, and value do not satisfy the data type deduction rule. The shape of selfRef exceeds 8 dimensions.
aclnnInplaceThreshold
Parameters
Parameter Input/Output Description workspace Input Workspace memory address applied by the Device side. workspaceSize Input Workspace size applied by the Device side, obtained through the first-phase API aclnnInplaceThresholdGetWorkspaceSize. executor Input Operator executor, which contains the operator computation flow. stream Input Specifies the stream for task execution. Return Value
aclnnStatus: return code. For details, see aclnn Return Code.
Constraints
Deterministic computation:
- aclnnThreshold and aclnnInplaceThreshold default to a deterministic implementation.
When the input is of the INT32 type and the value is outside the range [-16777216, 16777216], precision errors may occur.
Example
The following provides example code for reference only. For details about compilation and running, see Compile and Run Samples.
#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_threshold.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 apply for 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 host-side data to 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);
// Compute 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 device/stream. See the ACL API manual.
// Fill in the deviceId 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);
// Construct the input and output. Custom construction is required based on the API.
std::vector<int64_t> selfShape = {8};
std::vector<int64_t> outShape = {8};
void* selfDeviceAddr = nullptr;
void* outDeviceAddr = nullptr;
aclTensor* self = nullptr;
aclScalar* threshold = nullptr;
aclScalar* value = nullptr;
aclTensor* out = nullptr;
std::vector<float> selfHostData = {0, 1, 2, 3, 4.1, 5, 6, 7};
std::vector<float> outHostData = {0, 0, 0, 0, 0, 0, 0, 0};
float thresholdVal = 4.1f;
float valueVal = 10.0f;
// Create the self aclTensor.
ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the threshold aclScalar.
threshold = aclCreateScalar(&thresholdVal, aclDataType::ACL_FLOAT);
CHECK_RET(threshold != nullptr, return ret);
// Create the value aclScalar.
value = aclCreateScalar(&valueVal, aclDataType::ACL_FLOAT);
CHECK_RET(value != nullptr, return ret);
// Create the 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. Replace with the specific API name.
uint64_t workspaceSize = 0;
aclOpExecutor* executor;
// Call the first-phase API of aclnnThreshold.
ret = aclnnThresholdGetWorkspaceSize(self, threshold, value, out, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnThresholdGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
// Apply for 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);
}
// Call the second-phase API of aclnnThreshold.
ret = aclnnThreshold(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnThreshold failed. ERROR: %d\n", ret); return ret);
// Example of aclnnInplaceThreshold API Call
uint64_t inplaceWorkspaceSize = 0;
aclOpExecutor* inplaceExecutor;
// Call the first-phase API of aclnnInplaceThreshold.
ret = aclnnInplaceThresholdGetWorkspaceSize(self, threshold, value, &inplaceWorkspaceSize, &inplaceExecutor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceThresholdGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
// Apply for device memory based on the workspaceSize calculated 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 aclnnInplaceThreshold.
ret = aclnnInplaceThreshold(inplaceWorkspaceAddr, inplaceWorkspaceSize, inplaceExecutor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceThreshold 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 and copy the result from the device side memory to the host side. Modify based on the specific 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]), outDeviceAddr, 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("aclnnInplaceThreshold result[%ld] is: %f\n", i, inplaceResultData[i]);
}
// 6. Release aclTensor and aclScalar. Modify based on the specific API definition.
aclDestroyTensor(self);
aclDestroyScalar(threshold);
aclDestroyScalar(value);
aclDestroyTensor(out);
// 7. Release device resources. Modify based on the specific API definition.
aclrtFree(selfDeviceAddr);
aclrtFree(outDeviceAddr);
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
if (inplaceWorkspaceSize > 0) {
aclrtFree(inplaceWorkspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}