aclnnAtan2

产品支持情况

产品 是否支持
Atlas A2 训练系列产品/Atlas 800I A2 推理产品/A200I A2 Box 异构组件

功能说明

  • 接口功能:计算两个输入张量 x1(分子)和 x2(分母)的逐元素反正切值,结果范围 (−π, π],可正确处理所有象限(包括 x=0 的边界情况)。

  • 计算公式:

outi=atan2(x1i, x2i)\text{out}_i = \text{atan2}(x1_i,\ x2_i)

函数原型

每个算子分为两段式接口,必须先调用"aclnnAtan2GetWorkspaceSize"接口获取计算所需 workspace 大小以及包含了算子计算流程的执行器,再调用"aclnnAtan2"接口执行计算。

aclnnStatus aclnnAtan2GetWorkspaceSize(
  const aclTensor *x1,
  const aclTensor *x2,
  aclTensor       *y,
  uint64_t        *workspaceSize,
  aclOpExecutor  **executor)
aclnnStatus aclnnAtan2(
  void           *workspace,
  uint64_t        workspaceSize,
  aclOpExecutor  *executor,
  aclrtStream     stream)

aclnnAtan2GetWorkspaceSize

  • 参数说明:

    参数名 输入/输出 描述 使用说明 数据类型 数据格式 维度(shape) 非连续Tensor
    x1 输入 分子张量,公式中的 y 分量。
    • 支持空Tensor。
    • x1 与 x2 的 shape 必须一致。
    • x1 与 x2 的数据类型必须一致。
    FLOAT16、FLOAT、BFLOAT16 ND 0-8
    x2 输入 分母张量,公式中的 x 分量。
    • 支持空Tensor。
    • x1 与 x2 的 shape 必须一致。
    • x1 与 x2 的数据类型必须一致。
    FLOAT16、FLOAT、BFLOAT16 ND 0-8
    y 输出 输出张量,逐元素 atan2 结果,值域 (−π, π]。
    • 输出 shape 与 x1 一致。
    • 输出数据类型与 x1 一致。
    FLOAT16、FLOAT、BFLOAT16 ND 0-8
    workspaceSize 输出 返回需要在 Device 侧申请的 workspace 大小。 - - - - -
    executor 输出 返回 op 执行器,包含了算子计算流程。 - - - - -
  • 返回值:

    aclnnStatus:返回状态码,具体参见aclnn返回码。 第一段接口会完成入参校验,出现以下场景时报错:

    返回码 错误码 描述
    ACLNN_ERR_PARAM_NULLPTR 161001 传入的 x1、x2 或 y 是空指针。
    ACLNN_ERR_PARAM_INVALID 161002 x1 或 x2 的数据类型不在支持的范围之内(仅支持 FLOAT16、FLOAT、BFLOAT16)。
    x1 与 x2 的数据类型不同。
    x1 与 x2 的 shape 不同。

aclnnAtan2

  • 参数说明:

    参数名 输入/输出 描述
    workspace 输入 在 Device 侧申请的 workspace 内存地址。
    workspaceSize 输入 在 Device 侧申请的 workspace 大小,由第一段接口 aclnnAtan2GetWorkspaceSize 获取。
    executor 输入 op 执行器,包含了算子计算流程。
    stream 输入 指定执行任务的 Stream。
  • 返回值:

    aclnnStatus:返回状态码,具体参见aclnn返回码

约束说明

无。

调用示例

示例代码如下,仅供参考,具体编译和执行过程请参考编译与运行样例

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

  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];
  }
  *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
                            shape.data(), shape.size(), *deviceAddr);
  return 0;
}

int main() {
  // 1. device/stream 初始化
  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. 构造输入与输出
  std::vector<int64_t> shape = {4, 4};
  // x1: y 分量;x2: x 分量
  std::vector<float> x1HostData = {-3, -2, -1, 0, 1, 2, 3, -3, -2, -1, 0, 1, 2, 3, -3, -2};
  std::vector<float> x2HostData = { 0,  1,  2, 3,-3,-2,-1,  0,  1,  2, 3,-3,-2,-1,  0,  1};
  std::vector<float> yHostData(16, 0.0f);

  void* x1DeviceAddr = nullptr;
  void* x2DeviceAddr = nullptr;
  void* yDeviceAddr  = nullptr;
  aclTensor* x1 = nullptr;
  aclTensor* x2 = nullptr;
  aclTensor* y  = nullptr;

  ret = CreateAclTensor(x1HostData, shape, &x1DeviceAddr, aclDataType::ACL_FLOAT, &x1);
  CHECK_RET(ret == ACL_SUCCESS, return ret);
  ret = CreateAclTensor(x2HostData, shape, &x2DeviceAddr, aclDataType::ACL_FLOAT, &x2);
  CHECK_RET(ret == ACL_SUCCESS, return ret);
  ret = CreateAclTensor(yHostData,  shape, &yDeviceAddr,  aclDataType::ACL_FLOAT, &y);
  CHECK_RET(ret == ACL_SUCCESS, return ret);

  // 3. 调用 aclnnAtan2 两段式接口
  uint64_t workspaceSize = 0;
  aclOpExecutor* executor;
  ret = aclnnAtan2GetWorkspaceSize(x1, x2, y, &workspaceSize, &executor);
  CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAtan2GetWorkspaceSize failed. ERROR: %d\n", ret); return ret);

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

  ret = aclnnAtan2(workspaceAddr, workspaceSize, executor, stream);
  CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnAtan2 failed. ERROR: %d\n", ret); return ret);

  // 4. 同步等待
  ret = aclrtSynchronizeStream(stream);
  CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);

  // 5. 拷贝结果并打印
  auto size = GetShapeSize(shape);
  std::vector<float> outData(size, 0);
  ret = aclrtMemcpy(outData.data(), outData.size() * sizeof(float), yDeviceAddr,
                    size * sizeof(float), ACL_MEMCPY_DEVICE_TO_HOST);
  CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result failed. ERROR: %d\n", ret); return ret);
  for (int64_t i = 0; i < size; i++) {
    LOG_PRINT("result[%ld] = %f  (ref: %f)\n", i, outData[i], std::atan2(x1HostData[i], x2HostData[i]));
  }

  // 6. 释放资源
  aclDestroyTensor(x1);
  aclDestroyTensor(x2);
  aclDestroyTensor(y);
  aclrtFree(x1DeviceAddr);
  aclrtFree(x2DeviceAddr);
  aclrtFree(yDeviceAddr);
  if (workspaceSize > 0) { aclrtFree(workspaceAddr); }
  aclrtDestroyStream(stream);
  aclrtResetDevice(deviceId);
  aclFinalize();
  return 0;
}