aclnnRReluWithNoise&aclnnInplaceRReluWithNoise
Applicable Products
| Product | Supported |
|---|---|
| ✗ | |
| ✓ | |
| ✓ | |
| ✗ | |
| ✗ | |
| ✓ |
Function
Description: Implements the RReLU (Randomized Leaky Rectified Linear Unit) activation function with noise. When the input is less than or equal to 0, the slope is a; when the input is greater than 0, the slope is 1.
Formula:
where a is a random variable that follows a uniform distribution (lower, upper). In training mode (training == true), the noise is calculated as follows:
Function Prototype
aclnnRReluWithNoise and aclnnInplaceRReluWithNoise implement the same functionality. The differences in usage are as follows. Select the appropriate API based on your actual scenario.
aclnnRReluWithNoise: Requires creating a new output tensor object to store the computation result.
aclnnInplaceRReluWithNoise: Does not require creating a new output tensor object and directly stores the computation result in the memory of the input tensor.
Each API uses a two-phase API. You must first call the "aclnnRReluWithNoiseGetWorkspaceSize" or "aclnnInplaceRReluWithNoiseGetWorkspaceSize" API to obtain the input parameters and calculate the required workspace size based on the process, and then call the "aclnnRReluWithNoise" or "aclnnInplaceRReluWithNoise" API to perform the computation.
aclnnStatus aclnnRReluWithNoiseGetWorkspaceSize(
const aclTensor *self,
const aclTensor *noise,
const aclScalar *lower,
const aclScalar *upper,
bool training,
int64_t seed,
int64_t offset,
aclTensor *out,
uint64_t *workspaceSize,
aclOpExecutor **executor)aclnnStatus aclnnRReluWithNoise(
void* workspace,
uint64_t workspaceSize,
aclOpExecutor* executor,
const aclrtStream stream)aclnnStatus aclnnInplaceRReluWithNoiseGetWorkspaceSize(
const aclTensor* self,
const aclTensor* noise,
const aclScalar* lower,
const aclScalar* upper,
bool training,
int64_t seed,
int64_t offset,
uint64_t* workspaceSize,
aclOpExecutor** executor)aclnnStatus aclnnInplaceRReluWithNoise(
void* workspace,
uint64_t workspaceSize,
aclOpExecutor* executor,
const aclrtStream stream)aclnnRReluWithNoiseGetWorkspaceSize
Parameters:
Parameter Input/Output Description Instruction Data Type Data Format Dimension (Shape) Non-contiguous Tensor self (aclTensor*) Input The input parameter for RReluWithNoise computation, corresponding to self in the formula. - The number of supported shape dimensions does not exceed 32.
- The data type must be consistent with that of out.
- The shape must be consistent with that of out.
- The data format must be consistent with that of out.
- Empty tensors are supported.
BFLOAT16, FLOAT16, FLOAT ND 0-32 √ noise (aclTensor*) Input noise_i in the formula. - Size must be no smaller than self (shape is recommended to be consistent with self).
- The data type must be consistent with the data type of self.
- The shape must be consistent with the shape of self.
- The supported dimension of shape does not exceed 32.
- Empty tensor is supported.
BFLOAT16, FLOAT16, FLOAT ND 0-32 √ lower (aclScalar*) Input The lower bound of the uniform distribution U. The data type must satisfy the data type deduction rule with self and out (see deduction relationship). BFLOAT16, FLOAT16, FLOAT - - - upper (aclScalar*) Input Upper bound of the uniform distribution U. The data type must satisfy the data type deduction rules with self and out (see Deduction Relationship). BFLOAT16, FLOAT16, FLOAT - - - training (bool) Input Distinguishes between training and inference. - - - - - seed (int64_t) Input Seed for the random number generator, which affects the generated random number sequence. - - - - - offset (int64_t) Input Offset of the random number generator, which affects the position in the generated random number sequence. After the offset is set, the generated random number sequence starts from the specified position. - - - - out (aclTensor*) Output Upper bound of the uniform distribution U. - The data type must be consistent with that of self.
- The shape must be consistent with that of self.
- The data format must be consistent with that of self.
BFLOAT16, FLOAT16, FLOAT - - - workspaceSize (uint64_t*) Output Returns the workspace size to be requested on the Device side. - - - - - executor (aclOpExecutor**) Output Returns the op executor, which contains the operator computational flow. - - - - - Atlas training products : The data type supports FLOAT16 and FLOAT.
Return value
aclnnStatus: return status. For details, see aclnn Return Code. The first-phase API performs input parameter validation and reports an error in the following scenarios:
Return Code Error Code Description ACLNN_ERR_PARAM_NULLPTR 161001 The passed self, noise, or out is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data type of self or noise is not within the supported range. The size of self is larger than the size of noise. The data types or data formats of self, noise, and out are inconsistent. The shapes of self and out are inconsistent. The shape dimension of self or noise exceeds 32.
aclnnRReluWithNoise
Parameters:
Parameter Input/Output Description workspace Input Address of the workspace memory applied for on the Device side. workspaceSize Input Size of the workspace applied for on the Device side, obtained from the first-phase API aclnnRReluWithNoiseGetWorkspaceSize. executor Input Operator executor, which contains the computational flow of the operator. stream Input Specifies the stream on which the task is executed. Return value
aclnnStatus: return code. For details, see aclnn Return Code.
aclnnInplaceRReluWithNoiseGetWorkspaceSize
Parameters:
Parameter Input/Output Description Instruction Data Type Data Format Dimension (Shape) Non-contiguous Tensor self Input self in the formula. The supported dimension of shape does not exceed 32. BFLOAT16, FLOAT16, FLOAT ND 0-32 √ noise Input noise_i in the formula. - Size must be no smaller than self (the shape is recommended to be consistent with self).
- The data type must be consistent with the data type of self.
- The data format must be consistent with the data format of self.
- The shape supports no more than 32 dimensions.
BFLOAT16, FLOAT16, FLOAT ND 0-32 √ lower Input The lower bound in the uniform distribution U. The data type must be the same as self. BFLOAT16, FLOAT16, FLOAT - - - upper Input Upper bound of the uniform distribution U. The data type must be the same as self. BFLOAT16, FLOAT16, FLOAT - - - training Input Distinguishes between training and inference. - BOOL - - - seed Input Seed for the random number generator, which affects the generated random number sequence. - INT64 - - - offset Input Offset of the random number generator, which affects the position of the generated random number sequence. After the offset is set, the generated random number sequence starts from the specified position. INT64 - - - workspaceSize Output Returns the workspace size to be requested on the Device side. - - - - - executor Output Returns the op executor, which contains the operator computation flow. - - - - - Atlas training products : The data type supports FLOAT16 and FLOAT.
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 or noise is a null pointer. ACLNN_ERR_PARAM_INVALID 161002 The data type of self or noise is not within the supported range. The size of self is larger than the size of noise. The data type or data format of self and noise is inconsistent. The number of dimensions of self or noise exceeds 32.
aclnnInplaceRReluWithNoise
Parameters:
Parameter Input/Output Description workspace Input Workspace memory address applied for on the Device side. workspaceSize Input Workspace size applied for on the Device side, obtained from the first-phase API aclnnInplaceRReluWithNoiseGetWorkspaceSize. executor Input Operator executor, which contains the computational flow of the operator. stream Input Specifies the stream for task execution. Return value
aclnnStatus: return code. For details, see aclnn Return Code.
Constraints
Deterministic computation:
- aclnnRReluWithNoise & aclnnInplaceRReluWithNoise default to a deterministic implementation.
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_rrelu_with_noise.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: resource initialization.
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 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);
// Copy host-side data to device-side memory by calling aclrtMemcpy.
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];
}
// Create an aclTensor by calling aclCreateTensor.
*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.
// Set deviceId based on your actual device.
int32_t deviceId = 0;
aclrtStream stream;
auto ret = Init(deviceId, &stream);
// Handle based on your own needs.
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
// 2. Construct inputs and outputs. Customize the construction based on the API.
std::vector<int64_t> selfShape = {2, 2};
std::vector<int64_t> outShape = {2, 2};
std::vector<int64_t> noiseShape = {2, 2};
void* selfDeviceAddr = nullptr;
void* outDeviceAddr = nullptr;
void* noiseDeviceAddr = nullptr;
aclTensor* self = nullptr;
aclTensor* out = nullptr;
aclTensor* noise = nullptr;
aclScalar* lower = nullptr;
aclScalar* upper = nullptr;
std::vector<float> selfHostData = {1, 2, 3, 4};
std::vector<float> outHostData = {0, 0, 0, 0};
std::vector<float> noiseHostData = {4, 3, 2, 1};
float lowerValue = 0.1f;
float upperValue = 0.3f;
// Create the self aclTensor.
ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the out aclTensor.
ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the noise aclTensor.
ret = CreateAclTensor(noiseHostData, noiseShape, &noiseDeviceAddr, aclDataType::ACL_FLOAT, &noise);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// Create the lower aclScalar.
lower = aclCreateScalar(&lowerValue, aclDataType::ACL_FLOAT);
CHECK_RET(lower != nullptr, return ret);
// Create the upper aclScalar.
upper = aclCreateScalar(&upperValue, aclDataType::ACL_FLOAT);
CHECK_RET(upper != nullptr, return ret);
bool training = false;
int64_t seed = 0;
int64_t offset = 0;
uint64_t workspaceSize = 0;
aclOpExecutor* executor;
// Example of aclnnRReluWithNoise API call
// 3. Call the first-phase API of aclnnRReluWithNoise.
ret = aclnnRReluWithNoiseGetWorkspaceSize(self, noise, lower, upper, training, seed, offset,
out, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnRReluWithNoiseGetWorkspaceSize 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 aclnnRReluWithNoise.
ret = aclnnRReluWithNoise(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnRReluWithNoise failed. ERROR: %d\n", ret); return ret);
// 4. (Boilerplate) Wait synchronously for the 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 memory to the host memory. Modify this 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]);
}
// Example of calling the aclnnInplaceRReluWithNoise API
// Step 3. Call the first-phase API of aclnnInplaceRReluWithNoise.
ret = aclnnInplaceRReluWithNoiseGetWorkspaceSize(self, noise, lower, upper, training, seed, offset,
&workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceRReluWithNoiseGetWorkspaceSize failed. ERROR: %d\n", ret);
return ret);
// Apply for device memory based on the workspaceSize calculated by the first-phase API.
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 aclnnInplaceRReluWithNoise.
ret = aclnnInplaceRReluWithNoise(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceRReluWithNoise failed. ERROR: %d\n", ret); return ret);
// Step 4. (Boilerplate) Synchronize and wait for task execution to complete.
ret = aclrtSynchronizeStream(stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
// Step 5. Obtain the output value and copy the result from the device memory to the host memory. Modify based on the specific API definition.
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]);
}
// 6. Release aclTensor. Modify based on the specific API definition.
aclDestroyTensor(self);
aclDestroyTensor(out);
aclDestroyTensor(noise);
aclDestroyScalar(lower);
aclDestroyScalar(upper);
// 7. Release device resources. Define the parameters based on the specific API.
aclrtFree(selfDeviceAddr);
aclrtFree(outDeviceAddr);
aclrtFree(noiseDeviceAddr);
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}