文件最后提交记录最后更新时间
1 个月前
1 个月前
2 个月前
README

Syr2算子

算子概述

syr2 (Symmetric Rank-2 Update) 实现对称秩-2更新操作。该算子将两个向量的外积组合加到对称矩阵的指定三角区域。

数学表达式:

A = alpha * x * y^T + alpha * y * x^T + A

包含以下接口:

接口名 功能简述
aclblasSsyr2 单精度对称秩-2更新

算子执行接口

aclblasSsyr2

产品支持情况

  • Ascend 950PR / Ascend 950DT:支持
  • Atlas A3 训练系列产品 / Atlas A3 推理系列产品:支持
  • Atlas A2 训练系列产品 / Atlas A2 推理系列产品:支持

函数原型

aclblasStatus_t aclblasSsyr2(aclblasHandle_t handle, aclblasFillMode_t uplo, int n, const float *alpha, const float *x, int incx, const float *y, int incy, float *A, int lda)

参数说明

参数名 输入/输出 参数类型 说明
handle 输入 aclblasHandle_t ops-blas 库上下文句柄,携带 stream,Host 内存
uplo 输入 aclblasFillMode_t 指定矩阵 A 的存储格式。ACLBLAS_LOWER(122): 下三角,ACLBLAS_UPPER(121): 上三角,Host 内存
n 输入 int 向量 x 和 y 中的元素个数,矩阵 A 的行列数。n >= 0,Host 内存
alpha 输入 const float*(FP32) 标量 alpha 指针,向量乘积缩放因子,Host 内存
x 输入 const float*(FP32) 输入向量,对应公式中的 x。数据类型支持 FLOAT32,数据格式支持 ND,shape 为 [n],Device 内存
incx 输入 int x 相邻元素间的内存地址偏移量,incx != 0,Host 内存
y 输入 const float*(FP32) 输入向量,对应公式中的 y。数据类型支持 FLOAT32,数据格式支持 ND,shape 为 [n],Device 内存
incy 输入 int y 相邻元素间的内存地址偏移量,incy != 0,Host 内存
A 输入/输出 float*(FP32) 输入/输出矩阵,对应公式中的 A。数据类型支持 FLOAT32,数据格式支持 ND,shape 为 [n, n],Device 内存
lda 输入 int 矩阵 A 的每列元素的存储步长,lda >= max(1, n),Host 内存

约束说明

  • n >= 0,n==0 时直接返回成功
  • incx != 0,incy != 0
  • lda >= max(1, n)
  • 算子输入 shape 为 [n]、[n]、[n, n],输出 shape 为 [n, n]
  • 算子实际计算时,不支持 ND 高维度运算(不支持维度 >= 3 的运算)
  • Host 侧不做流同步,调用方需自行管理同步

调用示例

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

#include <cstdio>
#include <memory>
#include <vector>

#include "acl/acl.h"
#include "cann_ops_blas.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)

class AclContext {
public:
    explicit AclContext(int32_t deviceId) : deviceId_(deviceId) {}

    ~AclContext()
    {
        if (stream_ != nullptr) {
            aclrtDestroyStream(stream_);
            stream_ = nullptr;
        }
        if (deviceSet_) {
            aclrtResetDevice(deviceId_);
            deviceSet_ = false;
        }
        if (aclInited_) {
            aclFinalize();
            aclInited_ = false;
        }
    }

    int Init()
    {
        auto ret = aclInit(nullptr);
        CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
        aclInited_ = true;

        ret = aclrtSetDevice(deviceId_);
        CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
        deviceSet_ = true;

        ret = aclrtCreateStream(&stream_);
        CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
        return ACL_SUCCESS;
    }

    aclrtStream Stream() const { return stream_; }

private:
    int32_t deviceId_;
    aclrtStream stream_ = nullptr;
    bool aclInited_ = false;
    bool deviceSet_ = false;
};
int aclblasSsyr2Test(AclContext& ctx)
{
    aclrtStream stream = ctx.Stream();

    aclblasHandle_t rawHandle = nullptr;
    auto blasRet = aclblasCreate(&rawHandle);
    CHECK_RET(blasRet == ACLBLAS_STATUS_SUCCESS, LOG_PRINT("aclblasCreate failed. ERROR: %d\n", blasRet);
              return blasRet);
    std::unique_ptr<void, aclblasStatus_t (*)(void*)> handlePtr(rawHandle, aclblasDestroy);

    blasRet = aclblasSetStream(static_cast<aclblasHandle_t>(handlePtr.get()), stream);
    CHECK_RET(blasRet == ACLBLAS_STATUS_SUCCESS, LOG_PRINT("aclblasSetStream failed. ERROR: %d\n", blasRet);
              return blasRet);

    constexpr int n = 2;
    constexpr int incx = 1;
    constexpr int incy = 1;
    constexpr int lda = n;
    constexpr size_t vSize = n * sizeof(float);
    constexpr size_t aSize = n * n * sizeof(float);

    std::vector<float> hX = {1.0f, 2.0f};
    std::vector<float> hY = {3.0f, 4.0f};
    std::vector<float> hA(n * n, 0.0f);
    float alpha = 1.0f;

    void* rawX = nullptr;
    aclError aclRet;
    aclRet = aclrtMalloc(&rawX, vSize, ACL_MEM_MALLOC_HUGE_FIRST);
    CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMalloc for x failed. ERROR: %d\n", aclRet); return aclRet);
    std::unique_ptr<void, aclError (*)(void*)> dXPtr(rawX, aclrtFree);

    void* rawY = nullptr;
    aclRet = aclrtMalloc(&rawY, vSize, ACL_MEM_MALLOC_HUGE_FIRST);
    CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMalloc for y failed. ERROR: %d\n", aclRet); return aclRet);
    std::unique_ptr<void, aclError (*)(void*)> dYPtr(rawY, aclrtFree);

    void* rawA = nullptr;
    aclRet = aclrtMalloc(&rawA, aSize, ACL_MEM_MALLOC_HUGE_FIRST);
    CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMalloc for A failed. ERROR: %d\n", aclRet); return aclRet);
    std::unique_ptr<void, aclError (*)(void*)> dAPtr(rawA, aclrtFree);

    aclRet = aclrtMemcpy(dXPtr.get(), vSize, hX.data(), vSize, ACL_MEMCPY_HOST_TO_DEVICE);
    CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy for x failed. ERROR: %d\n", aclRet); return aclRet);

    aclRet = aclrtMemcpy(dYPtr.get(), vSize, hY.data(), vSize, ACL_MEMCPY_HOST_TO_DEVICE);
    CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy for y failed. ERROR: %d\n", aclRet); return aclRet);

    aclRet = aclrtMemcpy(dAPtr.get(), aSize, hA.data(), aSize, ACL_MEMCPY_HOST_TO_DEVICE);
    CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy for A failed. ERROR: %d\n", aclRet); return aclRet);

    blasRet = aclblasSsyr2(
        static_cast<aclblasHandle_t>(handlePtr.get()), ACLBLAS_LOWER, n, &alpha,
        static_cast<const float*>(dXPtr.get()), incx, static_cast<const float*>(dYPtr.get()), incy,
        static_cast<float*>(dAPtr.get()), lda);
    CHECK_RET(blasRet == ACLBLAS_STATUS_SUCCESS, LOG_PRINT("aclblasSsyr2 failed. ERROR: %d\n", blasRet);
              return blasRet);

    aclRet = aclrtSynchronizeStream(stream);
    CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", aclRet); return aclRet);

    std::vector<float> aResult(n * n, 0.0f);
    aclRet = aclrtMemcpy(aResult.data(), aSize, dAPtr.get(), aSize, ACL_MEMCPY_DEVICE_TO_HOST);
    CHECK_RET(aclRet == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy result failed. ERROR: %d\n", aclRet); return aclRet);
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n; j++) {
            LOG_PRINT("A[%d][%d] = %f\n", i, j, aResult[j * lda + i]);
        }
    }

    LOG_PRINT("aclblasSsyr2 test passed\n");
    return ACL_SUCCESS;
}

int main()
{
    AclContext ctx(0);
    auto ret = ctx.Init();
    CHECK_RET(ret == ACL_SUCCESS, return ret);

    ret = aclblasSsyr2Test(ctx);
    CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclblasSsyr2Test failed. ERROR: %d\n", ret); return ret);
    return 0;
}