当前位置: 首页 > news >正文

CANN/sip二维FFT接口文档

FFT_2D

【免费下载链接】sip本项目是CANN提供的一款高效、可靠的高性能信号处理算子加速库,基于华为Ascend AI处理器,专门为信号处理领域而设计。项目地址: https://gitcode.com/cann/sip

产品支持情况

产品是否支持
Atlas 200I/500 A2 推理产品×
Atlas 推理系列产品×
Atlas 训练系列产品×
Atlas A3 训练系列产品/Atlas A3 推理系列产品
Atlas A2 训练系列产品/Atlas A2 推理系列产品
Ascend 950PR/Ascend 950DT×

功能说明

  • 接口功能:
    asdFftMakePlan2D:初始化二维FFT配置。
    asdFftExecC2C:执行复数到复数的FFT变换。
    asdFftExecC2R:执行复数到实数的FFT变换。
    asdFftExecR2C:执行实数到复数的FFT变换。

  • 计算公式:
    傅里叶变换(Fourier transform)是一种线性积分变换,用于信号在时域和频域之间的变换,在物理学和工程学中有许多应用。对应给定长度为N的信号,其离散形式DFT(Discrete Fourier Transform)表达式如下:

    ![公式](https://raw.gitcode.com/cann/sip/raw/a2117be171dfaa15a42cf12676e3050617f06f2d/docs/zh/API Reference/figures/FFT_2D_1.png?utm_source=gitcode_repo_files)

    将系数矩阵(NN)和时域信号(N1)看做两个Tensor,在NPU上直接使用矩阵乘,可完成DFT,但时间复杂度太高,因此需要快速傅里叶变换。其基本原理是利用三角函数在复数域的旋转对称性,将序列拆分成子序列,通过蝶形运算以降低计算的复杂度:
    ![公式](https://raw.gitcode.com/cann/sip/raw/a2117be171dfaa15a42cf12676e3050617f06f2d/docs/zh/API Reference/figures/FFT_ID_2.png?utm_source=gitcode_repo_files)

函数原型

AspbStatus asdFftMakePlan2D( asdFftHandle handle, int64_t fftSizeX, int64_t fftSizeY, asdFftType fftType, asdFftDirection direction, int32_t batchSize)
AspbStatus asdFftExecC2C( asdFftHandle handle, const aclTensor * input, const aclTensor * output)
AspbStatus asdFftExecC2R( asdFftHandle handle, const aclTensor * input, const aclTensor * output)
AspbStatus asdFftExecR2C( asdFftHandle handle, const aclTensor * input, const aclTensor * output)

asdFftMakePlan2D

  • 参数说明:

    参数名输入/输出描述
    handle(asdFftHandle)输入算子的句柄,需要手动申请创建asdFftHandle对象。
    fftSizeX(int64_t)输入对应公式中的'M',FFT信号长度(第一维)。
    fftSizeY(int64_t)输入对应公式中的'N',FFT信号长度(第二维)。
    fftType(asdFftType)输入FFT变换类型
    • ASCEND_FFT_C2C:复数到复数的快速傅里叶变换。
    • ASCEND_FFT_C2R:复数到实数的快速傅里叶变换。
    • ASCEND_FFT_R2C:实数到复数的快速傅里叶变换。
    direction(asdFftDirection)输入选择FFT执行正向变换或反向变换
    • ASCEND_FFT_FORWARD:正向快速傅里叶变换。
    • ASCEND_FFT_INVERSE:逆向快速傅里叶变换。
    batchSize(int32_t)输入FFT变换批处理操作中的数据批次数量。
  • 返回值

    返回状态码,具体参见SiP返回码。

asdFftExecC2C

  • 参数说明:

    参数名输入/输出描述
    handle(asdFftHandle)输入算子的句柄,需要手动申请创建asdFftHandle对象。
    input( const aclTensor *)输入
    • 对应公式中的'x'。
    • 数据类型支持COMPLEX64。
    • 数据格式支持ND。
    • 输入的shape为(batchSize,fftSizeX,fftSizeY)。
    output(const aclTensor *)输出
    • 对应公式中的'y'。
    • 数据类型支持COMPLEX64。
    • 数据格式支持ND。
    • 输出的shape为(batchSize,fftSizeX,fftSizeY)。
  • 返回值

    返回状态码,具体参见SiP返回码。

asdFftExecC2R

  • 参数说明:

    参数名输入/输出描述
    handle(asdFftHandle)输入算子的句柄,需要手动申请创建asdFftHandle对象。
    input( const aclTensor *)输入
    • 对应公式中的'x'。
    • 数据类型支持COMPLEX64。
    • 数据格式支持ND。
    • 输入的shape为(batchSize,fftSizeX,fftSizeY/2+1)。
    output(const aclTensor *)输出
    • 对应公式中的'y'。
    • 数据类型支持FLOAT32。
    • 数据格式支持ND。
    • 输入的shape为(batchSize,fftSizeX,fftSizeY)。
  • 返回值

    返回状态码,具体参见SiP返回码。

asdFftExecR2C

  • 参数说明:

    参数名输入/输出描述
    handle(asdFftHandle)输入算子的句柄,需要手动申请创建asdFftHandle对象。
    input( const aclTensor *)输入
    • 对应公式中的'x'。
    • 数据类型支持FLOAT32。
    • 数据格式支持ND。
    • 输入的shape为(batchSize,fftSizeX,fftSizeY)。
    output(const aclTensor *)输出
    • 对应公式中的'y'。
    • 数据类型支持COMPLEX64。
    • 数据格式支持ND。
    • 输入的shape为(batchSize,fftSizeX,fftSizeY/2+1)。
  • 返回值

    返回状态码,具体参见SiP返回码。

约束说明

asdFftMakePlan2D

  • fftSizeX、fftSizeY需保证不超过$2^{27}$且分解质因数后不包含超过199的质因子。
  • batchSize在存储允许范围内应无额外约束。
  • 输入的元素个数理论支持[1,$2^{30}$]。
  • 输入的元素不支持inf、-inf和nan,如果输入中包含这些值, 那么结果为未定义。

调用示例

示例代码如下,该样例旨在提供快速上手、开发和调试算子的最小化实现,其核心目标是使用最精简的代码展示算子的核心功能,而非提供生产级的安全保障。不推荐用户直接将示例代码作为业务代码,若用户将示例代码应用在自身的真实业务场景中且发生了安全问题,则需用户自行承担。

  • C2C_2D
#include <iostream> #include <vector> #include "asdsip.h" #include "acl/acl.h" #include "aclnn/acl_meta.h" using namespace AsdSip; #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define LOG_PRINT(message, ...) \ do { \ printf(message, ##__VA_ARGS__); \ } while (0) #define ASD_STATUS_CHECK(err) \ do { \ AsdSip::AspbStatus err_ = (err); \ if (err_ != AsdSip::ErrorType::ACL_SUCCESS) { \ std::cout << "Execute failed." << std::endl; \ exit(-1); \ } \ } 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) { // 固定写法,AscendCL初始化 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); // 调用aclrtMalloc申请device侧内存 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); // 调用aclrtMemcpy将host侧数据复制到device侧内存上 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); // 计算连续tensor的strides 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]; } // 调用aclCreateTensor接口创建aclTensor *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } int main() { 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); // 创造tensor的Host侧数据 // int batch = 2, Nfft1 = 199 * 199, Nfft2 = 4096; int batch = 2, Nfft1 = 64, Nfft2 = 64; // core dd const int64_t inSignal = Nfft2; const int64_t outSignal = Nfft2; const int64_t tensorInSize = batch * Nfft1 * inSignal; const int64_t tensorOutSize = batch * Nfft1 * outSignal; std::vector<int64_t> selfShape = {batch, Nfft1, inSignal}; std::vector<int64_t> outShape = {batch, Nfft1, outSignal}; std::vector<std::complex<float>> inputHostData(tensorInSize, std::complex<float>(0, 0)); for (int i = 0; i < tensorInSize; i++) { inputHostData[i] = std::complex<float>(i, i + 1); } std::vector<std::complex<float>> outHostData(tensorOutSize, std::complex<float>(0, 0)); void *inputDeviceAddr = nullptr; void *outDeviceAddr = nullptr; aclTensor *input = nullptr; aclTensor *out = nullptr; ret = CreateAclTensor(inputHostData, selfShape, &inputDeviceAddr, aclDataType::ACL_COMPLEX64, &input); CHECK_RET(ret == ::ACL_SUCCESS, return ret); ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_COMPLEX64, &out); CHECK_RET(ret == ::ACL_SUCCESS, return ret); asdFftHandle handle; asdFftCreate(handle); asdFftMakePlan2D(handle, Nfft1, Nfft2, asdFftType::ASCEND_FFT_C2C, asdFftDirection::ASCEND_FFT_FORWARD, batch); size_t work_size; asdFftGetWorkspaceSize(handle, work_size); void *workspaceAddr = nullptr; if (work_size > 0) { ret = aclrtMalloc(&workspaceAddr, static_cast<int64_t>(work_size), ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); } asdFftSetWorkspace(handle, (uint8_t *)workspaceAddr); asdFftSetStream(handle, stream); ASD_STATUS_CHECK(asdFftExecC2C(handle, input, out)); ret = aclrtSynchronizeStream(stream); CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); asdFftDestroy(handle); auto size = GetShapeSize(outShape); std::vector<std::complex<float>> outData(size, 0); ret = aclrtMemcpy(outData.data(), outData.size() * sizeof(outData[0]), outDeviceAddr, size * sizeof(outData[0]), ACL_MEMCPY_DEVICE_TO_HOST); // 打印输出tensor值中前16个 for (int64_t i = 0; i < 16; i++) { std::cout << static_cast<std::complex<float>>(outData[i]) << "\t"; } std::cout << "\nend result" << std::endl; std::cout << "Execute successfully." << std::endl; aclDestroyTensor(input); aclDestroyTensor(out); aclrtFree(inputDeviceAddr); aclrtFree(outDeviceAddr); if (work_size > 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }
  • C2R_2D
#include <iostream> #include <vector> #include "asdsip.h" #include "acl/acl.h" #include "aclnn/acl_meta.h" using namespace AsdSip; #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define LOG_PRINT(message, ...) \ do { \ printf(message, ##__VA_ARGS__); \ } while (0) #define ASD_STATUS_CHECK(err) \ do { \ AsdSip::AspbStatus err_ = (err); \ if (err_ != AsdSip::ErrorType::ACL_SUCCESS) { \ std::cout << "Execute failed." << std::endl; \ exit(-1); \ } \ } 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) { // 固定写法,AscendCL初始化 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); // 调用aclrtMalloc申请device侧内存 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); // 调用aclrtMemcpy将host侧数据复制到device侧内存上 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); // 计算连续tensor的strides 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]; } // 调用aclCreateTensor接口创建aclTensor *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } int main() { 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); // 创造tensor的Host侧数据 // int batch = 32, Nfft = 128; // int batch = 32, Nfft = 8192; // int batch = 32, Nfft = 15000; // 创造tensor的Host侧数据 int batch = 2, Nfft1 = 128, Nfft2 = 128; const int64_t inSignal = Nfft2 / 2 + 1; const int64_t outSignal = Nfft2; const int64_t tensorInSize = batch * Nfft1 * inSignal; const int64_t tensorOutSize = batch * Nfft1 * outSignal; std::vector<int64_t> selfShape = {batch, Nfft1, inSignal}; std::vector<int64_t> outShape = {batch, Nfft1, outSignal}; std::vector<std::complex<float>> inputHostData(tensorInSize, std::complex<float>(0, 0)); for (int i = 0; i < tensorInSize; i++) { inputHostData[i] = std::complex<float>(i, i + 1); } std::vector<float> outHostData(tensorOutSize, 0); void *inputDeviceAddr = nullptr; void *outDeviceAddr = nullptr; aclTensor *input = nullptr; aclTensor *out = nullptr; ret = CreateAclTensor(inputHostData, selfShape, &inputDeviceAddr, aclDataType::ACL_COMPLEX64, &input); CHECK_RET(ret == ::ACL_SUCCESS, return ret); ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out); CHECK_RET(ret == ::ACL_SUCCESS, return ret); asdFftHandle handle; asdFftCreate(handle); asdFftMakePlan2D(handle, Nfft1, Nfft2, asdFftType::ASCEND_FFT_C2R, asdFftDirection::ASCEND_FFT_FORWARD, batch); size_t work_size; asdFftGetWorkspaceSize(handle, work_size); void *workspaceAddr = nullptr; if (work_size > 0) { ret = aclrtMalloc(&workspaceAddr, static_cast<int64_t>(work_size), ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); } asdFftSetWorkspace(handle, (uint8_t *)workspaceAddr); asdFftSetStream(handle, stream); ASD_STATUS_CHECK(asdFftExecC2R(handle, input, out)); ret = aclrtSynchronizeStream(stream); CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); asdFftDestroy(handle); auto size = GetShapeSize(outShape); std::vector<float> outData(size, 0); ret = aclrtMemcpy(outData.data(), outData.size() * sizeof(outData[0]), outDeviceAddr, size * sizeof(outData[0]), ACL_MEMCPY_DEVICE_TO_HOST); // 打印输出tensor值中前16个 for (int64_t i = 0; i < 16; i++) { std::cout << static_cast<float>(outData[i]) << "\t"; } std::cout << "\nend result" << std::endl; std::cout << "Execute successfully." << std::endl; aclDestroyTensor(input); aclDestroyTensor(out); aclrtFree(inputDeviceAddr); aclrtFree(outDeviceAddr); if (work_size > 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }
  • R2C_2D
#include <iostream> #include <vector> #include "asdsip.h" #include "acl/acl.h" #include "aclnn/acl_meta.h" using namespace AsdSip; #define CHECK_RET(cond, return_expr) \ do { \ if (!(cond)) { \ return_expr; \ } \ } while (0) #define LOG_PRINT(message, ...) \ do { \ printf(message, ##__VA_ARGS__); \ } while (0) #define ASD_STATUS_CHECK(err) \ do { \ AsdSip::AspbStatus err_ = (err); \ if (err_ != AsdSip::ErrorType::ACL_SUCCESS) { \ std::cout << "Execute failed." << std::endl; \ exit(-1); \ } \ } 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) { // 固定写法,AscendCL初始化 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); // 调用aclrtMalloc申请device侧内存 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); // 调用aclrtMemcpy将host侧数据复制到device侧内存上 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); // 计算连续tensor的strides 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]; } // 调用aclCreateTensor接口创建aclTensor *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), *deviceAddr); return 0; } int main() { 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); // 创造tensor的Host侧数据 int batch = 2, Nfft1 = 1024, Nfft2 = 4096; const int64_t inSignal = Nfft2; const int64_t outSignal = Nfft2 / 2 + 1; const int64_t tensorInSize = batch * Nfft1 * inSignal; const int64_t tensorOutSize = batch * Nfft1 * outSignal; std::vector<int64_t> selfShape = {batch, Nfft1, inSignal}; std::vector<int64_t> outShape = {batch, Nfft1, outSignal}; std::vector<float> inputHostData(tensorInSize, 0); for (int i = 0; i < tensorInSize; i++) { inputHostData[i] = i; } std::vector<std::complex<float>> outHostData(tensorOutSize, std::complex<float>(0, 0)); void *inputDeviceAddr = nullptr; void *outDeviceAddr = nullptr; aclTensor *input = nullptr; aclTensor *out = nullptr; ret = CreateAclTensor(inputHostData, selfShape, &inputDeviceAddr, aclDataType::ACL_FLOAT, &input); CHECK_RET(ret == ::ACL_SUCCESS, return ret); ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_COMPLEX64, &out); CHECK_RET(ret == ::ACL_SUCCESS, return ret); asdFftHandle handle; asdFftCreate(handle); asdFftMakePlan2D(handle, Nfft1, Nfft2, asdFftType::ASCEND_FFT_R2C, asdFftDirection::ASCEND_FFT_FORWARD, batch); size_t work_size; asdFftGetWorkspaceSize(handle, work_size); void *workspaceAddr = nullptr; if (work_size > 0) { ret = aclrtMalloc(&workspaceAddr, static_cast<int64_t>(work_size), ACL_MEM_MALLOC_HUGE_FIRST); CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); } asdFftSetWorkspace(handle, (uint8_t *)workspaceAddr); asdFftSetStream(handle, stream); ASD_STATUS_CHECK(asdFftExecR2C(handle, input, out)); ret = aclrtSynchronizeStream(stream); CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); asdFftDestroy(handle); auto size = GetShapeSize(outShape); std::vector<std::complex<float>> outData(size, 0); ret = aclrtMemcpy(outData.data(), outData.size() * sizeof(outData[0]), outDeviceAddr, size * sizeof(outData[0]), ACL_MEMCPY_DEVICE_TO_HOST); // 打印输出tensor值中前16个 for (int64_t i = 0; i < 16; i++) { std::cout << static_cast<std::complex<float>>(outData[i]) << "\t"; } std::cout << "\nend result" << std::endl; std::cout << "Execute successfully." << std::endl; aclDestroyTensor(input); aclDestroyTensor(out); aclrtFree(inputDeviceAddr); aclrtFree(outDeviceAddr); if (work_size > 0) { aclrtFree(workspaceAddr); } aclrtDestroyStream(stream); aclrtResetDevice(deviceId); aclFinalize(); return 0; }

【免费下载链接】sip本项目是CANN提供的一款高效、可靠的高性能信号处理算子加速库,基于华为Ascend AI处理器,专门为信号处理领域而设计。项目地址: https://gitcode.com/cann/sip

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

http://www.jsqmd.com/news/986573/

相关文章:

  • 2026年广州GEO优化激战正酣,五大玩家格局深度透视 - 智鸥科技
  • 基于微信小程序实现校园服务平台管理系统【项目源码+论文说明】计算机毕业设计
  • 2026年江浙沪厂区热能利用方案公司推荐:专业服务商助力绿色制造转型 - 品牌2026
  • 6月深圳水贝华强北黄金回收排行:禹竞名奢汇S级头部机构 两区全覆盖无隐形收费 - 名奢变现站
  • 高性能跨平台.NET数据可视化库架构解析与最佳实践
  • 常州家电维修平台推荐:本地用户反馈较多的几家服务商(2026最新发布) - 欧米到家
  • DeepDPM:无需预先指定聚类数量的革命性深度聚类算法完全指南
  • 解决DXRPathTracer常见问题:纹理缺失、性能瓶颈与兼容性修复
  • 如何用Claudian插件在Obsidian中创建智能日历
  • 2026上海商铺装修公司市场适配推荐:聚焦商铺门店的合规高效装修服务商深度调研 - 信息热点
  • 2026年6月最新|实验室金相砂纸厂家推荐哪家好?按材质 / 精度 / 预算精准匹配指南 - 商业新知
  • 性能优化指南:如何让bart-large-mnli-openmind推理速度提升300%
  • 终极Tolgee本地化平台:5分钟搭建免费开源翻译管理服务
  • 2026年好评多的长沙小程序软件开发/长沙企业官网软件开发/长沙定制软件开发专业推荐平台 - 第三方测评
  • 2026年6月最新|洛氏硬度计厂家推荐不踩雷?业内人士揭秘精度与耐用性真相 - 商业新知
  • 2026福州全市各区管道疏通透明收费 找瑞成疏通管道更放心 - 润富黄金回收
  • AutoRound VLM量化指南:多模态模型低比特优化与性能评估
  • Timeflake隐私风险与规避策略:开发者必须知道的5个注意事项
  • 2026年佛山碗碟篮与高柜拉篮供应商全景评测:定制家居五金破局指南 - 企业名录优选推荐
  • 彻底打破套路“投票管家”小程序:无隐藏收费,任何版本都免费的高清全功能评选旗舰 - 半夏时光~
  • 手里的盒马鲜生礼品卡不想用?试试正规渠道回收变现 - 团团收购物卡回收
  • WebGui安全指南:保护WebAssembly IMGUI应用的最佳实践
  • uuid-readable词汇库揭秘:探索莎士比亚风格的数据集
  • 如何在macOS上安装ChatMLX:5分钟快速启动本地大语言模型对话
  • 2026 沈阳深耕多年黄金回收商家盘点,本地贵金属变现顶尖靠谱选择 - 奢侈品回收评测
  • Path of Building PoE2:10分钟掌握流放之路2最强BD规划神器
  • Unity窗口控制终极方案:5分钟打造跨平台透明应用
  • Hydra项目完全指南:从零开始搭建实时3D场景图构建环境
  • 2026最新 国内以及天津/河北地区铁皮保温施工生产厂家实力排行及采购参考 气凝胶 / 气凝胶涂料 /气凝胶隔热保温涂料 / 气凝胶保温涂料 / 气凝胶隔热涂料 / 气凝胶保温隔热涂料 - 奔跑123
  • 从0到1:EnvPane新手安装指南(含Apple Silicon适配方案)[特殊字符]