aclnnBernoulli&aclnnInplaceBernoulli

📄 View Source Code

Applicable Products

ProductSupported
Ascend 950PR/Ascend 950DT√
Atlas A3 training products/Atlas A3 inference products√
Atlas A2 training products/Atlas A2 inference products√
Atlas 200I/500 A2 inference products×
Atlas inference products×
Atlas training products√

Function

  • Operator function: Extracts binary random numbers (0 or 1) from a Bernoulli distribution. prob is the probability of generating a binary random number, and the input tensor specifies the shape.

  • Formula:

    out∼Bernoulli(prob)out∼Bernoulli(prob)

    Specifically, when using aclnnBernoulli, prob in the formula corresponds to prob in the first-phase API, and out in the formula corresponds to out in the first-phase API. When using aclnnInplaceBernoulli, prob in the formula corresponds to prob in the first-phase API, and out in the formula corresponds to selfRef in the first-phase API.

Function Prototype

  • aclnnBernoulli and aclnnInplaceBernoulli implement the same functionality. The differences are as follows. Choose the appropriate operator based on your actual scenario.

    • aclnnBernoulli: Requires creating a new output tensor object to store the computation result.

    • aclnnInplaceBernoulli: Does not require creating a new output tensor object. The computation result is stored directly in the memory of the input tensor.

  • Each operator uses a two-phase API. You must first call the "aclnnBernoulliGetWorkspaceSize" or "aclnnInplaceBernoulliGetWorkspaceSize" API to obtain the workspace size required for computation and the executor that encapsulates the operator computation process, and then call the "aclnnBernoulli" or "aclnnInplaceBernoulli" API to perform the computation.

    • aclnnStatus aclnnBernoulliGetWorkspaceSize(const aclTensor* self, const aclScalar* prob, int64_t seed, int64_t offset, aclTensor* out, uint64_t* workspaceSize, aclOpExecutor** executor)

    • aclnnStatus aclnnBernoulli(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream)

    • aclnnStatus aclnnInplaceBernoulliGetWorkspaceSize(const aclTensor* selfRef, const aclScalar* prob, int64_t seed, int64_t offset, uint64_t* workspaceSize, aclOpExecutor** executor)

    • aclnnStatus aclnnInplaceBernoulli(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream)

aclnnBernoulliGetWorkspaceSize

  • Parameters:

    • self (aclTensor*, compute input): Specifies the shape of the output out. It is a device-side aclTensor. The data type must be consistent with out. The shape supports 0 to 8 dimensions and must be consistent with out. Non-contiguous tensors are supported (see Non-contiguous Tensor). The data format supports ND (see Data Format).

      • Atlas training products: Data types: FLOAT16, FLOAT, DOUBLE, UINT8, INT8, INT16, INT32, INT64, BOOL.

      • Atlas A2 training products/Atlas A2 inference products, Atlas A3 training products/Atlas A3 inference products, Ascend 950PR/Ascend 950DT: Data types: FLOAT16, FLOAT, DOUBLE, UINT8, INT8, INT16, INT32, INT64, BOOL, BFLOAT16.

    • prob (aclScalar*, compute input): prob in the formula. It is a host-side aclScalar, satisfying 0≤prob≤10≤prob≤1.

      • Atlas training products: The data type supports FLOAT16, FLOAT, and DOUBLE.

      • Atlas A2 training products/Atlas A2 inference products, Atlas A3 training products/Atlas A3 inference products, Ascend 950PR/Ascend 950DT: The data type supports FLOAT16, FLOAT, DOUBLE, and BFLOAT16.

    • seed (int64_t, compute input): A host-side integer that sets the seed of the random number generator.

    • offset (int64_t, compute input): A host-side integer that sets the random number offset.

    • out (aclTensor*, compute output): out in the formula, a device-side aclTensor. The data type must be consistent with self. The shape supports 0 to 8 dimensions and must be consistent with self. It supports non-contiguous tensors. For details, see Non-contiguous Tensor. The data format supports ND. For details, see Data Format.

      • Atlas training products: FLOAT16, FLOAT, DOUBLE, UINT8, INT8, INT16, INT32, INT64, and BOOL are supported.

      • Atlas A2 training products/Atlas A2 inference products, Atlas A3 training products/Atlas A3 inference products, Ascend 950PR/Ascend 950DT: FLOAT16, FLOAT, DOUBLE, UINT8, INT8, INT16, INT32, INT64, BOOL, and BFLOAT16 are supported.

    • workspaceSize (uint64_t*, output parameter): Returns the workspace size to be allocated on the host side.

    • executor (aclOpExecutor**, output parameter): Returns the op executor, which includes computation.

  • Return value

    aclnnStatus: return code. For details, see aclnn Return Codes.

    The first-phase API completes input parameter validation and reports an error in the following scenarios:
    Returns 161001 (ACLNN_ERR_PARAM_NULLPTR): 1. self, prob, or out passed is a null pointer.
    Returns 161002 (ACLNN_ERR_PARAM_INVALID): 1. The Data Type and Data Format of self or out are not within the supported range.
                                          2. The Data Type of prob is not within the supported range.
                                          3. The Data Types of self and out are inconsistent.
                                          4. prob does not satisfy 0≤prob≤1.
                                          5. The number of dimensions of self or out exceeds 8.
                                          6. The shapes of self and out are inconsistent.

aclnnBernoulli

  • Parameters:

  • workspace (void*, input parameter): Device-side allocated workspace memory address.

  • workspaceSize (uint64_t, input parameter): Device-side allocated workspace size, obtained from the first-phase API aclnnBernoulliGetWorkspaceSize.

  • executor (aclOpExecutor*, input parameter): Op executor, which includes the computation process of the operator.

  • stream (aclrtStream, input parameter): Stream on which the task is executed.

  • Return value

    aclnnStatus: return code. For details, see aclnn Return Codes.

aclnnInplaceBernoulliGetWorkspaceSize

  • Parameters:

    • selfRef (aclTensor*, compute input/output): out in the formula, a device-side aclTensor. The shape supports 0 to 8 dimensions. Non-contiguous tensors are supported (see Non-contiguous Tensor). The data format supports ND (see Data Format).

      • Atlas training products: FLOAT16, FLOAT, DOUBLE, UINT8, INT8, INT16, INT32, INT64, and BOOL are supported.

      • Atlas A2 training products/Atlas A2 inference products, Atlas A3 training products/Atlas A3 inference products, Ascend 950PR/Ascend 950DT: FLOAT16, FLOAT, DOUBLE, UINT8, INT8, INT16, INT32, INT64, BOOL, and BFLOAT16 are supported.

    • prob (aclScalar*, compute input): prob in the formula, a host-side aclScalar that satisfies 0≤prob≤10≤prob≤1.

      • Atlas training products: The supported data types are FLOAT16, FLOAT, and DOUBLE.

      • Atlas A2 training products/Atlas A2 inference products, Atlas A3 training products/Atlas A3 inference products, Ascend 950PR/Ascend 950DT: The supported data types are FLOAT16, FLOAT, DOUBLE, and BFLOAT16.

    • seed (int64_t, compute input): Host-side integer. Sets the random number offset.

    • offset (int64_t, compute input): Host-side integer. Sets the random number offset.

    • workspaceSize (uint64_t*, output parameter): Returns the workspace size to be allocated on the Device side.

    • executor (aclOpExecutor**, output parameter): Returns the op executor, which includes the computation process of the operator.

  • Return value

    aclnnStatus: return code. For details, see aclnn Return Codes.

    The first-phase API completes input parameter validation and reports an error in the following scenarios:
    Returns 161001 (ACLNN_ERR_PARAM_NULLPTR): 1. selfRef or prob passed is a null pointer.
    Returns 161002 (ACLNN_ERR_PARAM_INVALID): 1. The Data Type and Data Format of selfRef are not within the supported range.
                                          2. The Data Type of prob is not within the supported range.
                                          3. prob does not satisfy 0≤prob≤1.
                                          4. The number of dimensions of selfRef exceeds 8.

aclnnInplaceBernoulli

  • Parameters:

    • workspace (void*, input parameter): Device-side allocated workspace memory address.

    • workspaceSize (uint64_t, input parameter): Device-side allocated workspace size, obtained from the first-phase API aclnnInplaceBernoulliGetWorkspaceSize.

    • executor (aclOpExecutor*, input parameter): Op executor, which includes the computation process.

    • stream (aclrtStream, input parameter): Stream that specifies the task execution.

  • Return value

    aclnnStatus: return code. For details, see aclnn Return Codes.

Constraints

  • Deterministic computation:

    • aclnnBernoulli&aclnnInplaceBernoulli defaults to a deterministic implementation.

Example

The following provides example code for reference only. For details about compilation and running, see Compile and Run Samples.

aclnnBernoulli

#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_bernoulli.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: 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-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 for 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 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 the device/stream. See the ACL API manual.
  // Enter the deviceId based on your actual device.
  int32_t deviceId = 0;
  aclrtStream stream;
  auto ret = Init(deviceId, &stream);
  // Handle the check result as needed.
  CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);

  // 2. Construct the input and output. Customize the construction based on the API.
  std::vector<int64_t> selfShape = {4, 4};
  std::vector<int64_t> outShape = {4, 4};
  void* selfDeviceAddr = nullptr;
  void* outDeviceAddr = nullptr;
  aclTensor* self = nullptr;
  aclScalar* prob = nullptr;
  aclTensor* out = nullptr;
  std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
  std::vector<float> outHostData(16, 0);
  int64_t seed = 0;
  int64_t offset = 0;
  float probValue = 1.0f;
  // Create the self aclTensor.
  ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
  CHECK_RET(ret == ACL_SUCCESS, return ret);
  // Create the prob aclScalar.
  prob = aclCreateScalar(&probValue,aclDataType::ACL_FLOAT);
  CHECK_RET(prob != nullptr, return ret);
  // Create the out aclTensor.
  ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
  CHECK_RET(ret == ACL_SUCCESS, return ret);

  uint64_t workspaceSize = 0;
  aclOpExecutor* executor;

  // aclnnBernoulli API call example.
  // 3. Call the CANN operator library API.
  // Call the aclnnBernoulli first-phase API.
  ret = aclnnBernoulliGetWorkspaceSize(self, prob, seed, offset, out, &workspaceSize, &executor);
  CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBernoulliGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
  // Apply for device memory based on the 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 aclnnBernoulli second-phase API.
  ret = aclnnBernoulli(workspaceAddr, workspaceSize, executor, stream);
  CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBernoulli failed. ERROR: %d\n", ret); return ret);

  // 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);

  // 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]);
  }

  // 6. Release aclTensor and aclScalar. Modify based on the specific API definition.
  aclDestroyTensor(self);
  aclDestroyScalar(prob);
  aclDestroyTensor(out);

  // 7. Release device resources. Modify based on the specific API definition.
  aclrtFree(selfDeviceAddr);
  aclrtFree(outDeviceAddr);
  if (workspaceSize > 0) {
    aclrtFree(workspaceAddr);
  }
  aclrtDestroyStream(stream);
  aclrtResetDevice(deviceId);
  aclFinalize();
  return 0;
}

aclnnInplaceBernoulli

#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_bernoulli.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: 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-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);

  // 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];
  }

  // 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 the device/stream. For details, see the ACL API manual.
  // Fill in the deviceId based on your actual device.
  int32_t deviceId = 0;
  aclrtStream stream;
  auto ret = Init(deviceId, &stream);
  // Handle the check based on your own needs.
  CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);

  // 2. Construct the input and output. Customize the construction based on the API interface.
  std::vector<int64_t> selfShape = {4, 4};
  void* selfDeviceAddr = nullptr;
  aclTensor* self = nullptr;
  aclScalar* prob = nullptr;
  std::vector<float> selfHostData = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15};
  int64_t seed = 0;
  int64_t offset = 0;
  float probValue = 1.0f;
  // Create the self aclTensor.
  ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT, &self);
  CHECK_RET(ret == ACL_SUCCESS, return ret);
  // Create the prob aclScalar.
  prob = aclCreateScalar(&probValue,aclDataType::ACL_FLOAT);
  CHECK_RET(prob != nullptr, return ret);

  uint64_t workspaceSize = 0;
  aclOpExecutor* executor;

  // Example of calling the aclnnInplaceBernoulli API
  // 3. Call the CANN operator library API.
  // Call the first-phase API of aclnnInplaceBernoulli.
  ret = aclnnInplaceBernoulliGetWorkspaceSize(self, prob, seed, offset, &workspaceSize, &executor);
  CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceBernoulliGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
  // Apply for device memory based on the 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 aclnnInplaceBernoulli.
  ret = aclnnInplaceBernoulli(workspaceAddr, workspaceSize, executor, stream);
  CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnInplaceBernoulli failed. ERROR: %d\n", ret); return ret);

  // 4. (Boilerplate) Synchronously wait for task execution to finish.
  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 based on the specific 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("result[%ld] is: %f\n", i, resultData[i]);
  }

  // 6. Release aclTensor and aclScalar. Modify based on the specific API definition.
  aclDestroyTensor(self);
  aclDestroyScalar(prob);

  // 7. Release device resources. Modify based on the specific API definition.
  aclrtFree(selfDeviceAddr);
  if (workspaceSize > 0) {
    aclrtFree(workspaceAddr);
  }
  aclrtDestroyStream(stream);
  aclrtResetDevice(deviceId);
  aclFinalize();
  return 0;
}