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