HCgemvBatched
产品支持情况
| 产品 | 是否支持 |
|---|---|
| Atlas 200I/500 A2 推理产品 | × |
| Atlas 推理系列产品 | × |
| Atlas 训练系列产品 | × |
| Atlas A3 训练系列产品/Atlas A3 推理系列产品 | √ |
| Atlas A2 训练系列产品/Atlas A2 推理系列产品 | √ |
| Ascend 950PR/Ascend 950DT | × |
功能说明
-
接口功能:
- asdBlasMakeHCgemvBatchedPlan:初始化该句柄对应的算子配置。
- asdBlasHCgemvBatched:用于计算批量复数矩阵与向量的乘积。
-
计算公式:
y=alpha∗op(A)∗x+beta∗yy= alpha * op(A)*x + beta * y\\
其中,op表示矩阵A做“共轭转置”或者“非转置”的操作。
示例:
输入“A[i]”为:
[ [ 1+i, 1+2i ], [ 1+3i, 1+4i ] ]
输入“x[i]”为:
[ 1+i, 1+i ]
输入“trans”为:N,表示矩阵A非转置。
输入“m”为:2,输入“n”为:2,输入“alpha”为:1+0i,“beta”为:0+0i。
输入“lda”为:2。
输入“batchCount”为:2。
调用“asdBlasHCgemvBatched”算子后,输出“y[i]”为:
[-1+5i, -5+9i]
函数原型
AspbStatus asdBlasMakeHCgemvBatchedPlan(
asdBlasHandle handle,
asdBlasOperation_t trans,
const int64_t m)
AspbStatus asdBlasHCgemvBatched(
asdBlasHandle handle,
asdBlasOperation_t trans,
const int64_t m,
const int64_t n,
const std::complex<op::fp16_t> & alpha,
aclTensor * A,
const int64_t lda,
aclTensor * x,
const int64_t incx,
const std::complex<op::fp16_t> & beta,
aclTensor * y,
const int64_t incy,
const int64_t batchCount)
asdBlasMakeHCgemvBatchedPlan
-
参数说明:
参数名 输入/输出 描述 handle(asdBlasHandle) 输入 算子的句柄 trans(asdBlasOperation_t) 输入 指定矩阵A是否需要转置。 - ASDBLAS_OP_N:不转置
- ASDBLAS_OP_T:转置
- ASDBLAS_OP_C:共轭转置
m(int64_t) 输入 单批次矩阵A的行数。 -
返回值:
返回状态码,具体参见SiP返回码。
asdBlasHCgemvBatched
-
参数说明:
参数名 输入/输出 描述 handle(asdBlasHandle) 输入 算子的句柄 trans(asdBlasOperation_t) 输入 指定矩阵A是否需要转置。 - ASDBLAS_OP_N:不转置
- ASDBLAS_OP_T:转置
- ASDBLAS_OP_C:共轭转置
m(int64_t) 输入 单批次矩阵A的行数。 n(int64_t) 输入 单批次矩阵A的列数。 alpha(std::complex<op::fp16_t> &) 输入 对应公式中的alpha,复数标量,用于乘以矩阵和向量乘法的结果,当前版本alpha的取值只能为1+0i。 A(aclTensor *) 输入 - 输入的矩阵,对应公式中的'A'。
- 行主序。
- 数据类型支持COMPLEX32。
- 数据格式支持ND。
- shape为[batchCount,m,n]。
lda(int64_t) 输入 A左右相邻元素间的内存地址偏移量(当前约束为m)。 x(aclTensor *) 输入 - 输入的矩阵,对应公式中的'x'。
- 数据类型支持COMPLEX32。
- 数据格式支持ND。
- 当“trans”取值为非转置:shape为[batchCount, n]。
- 当“trans”取值为共轭转置:shape为[batchCount, m]。
incx(int64_t) 输入 向量x的步长(当前约束为1)。 beta(std::complex<op::fp16_t> &) 输入 对应公式中的beta,复数标量,用于乘以向量y,当前版本beta的取值只能为0+0i。 y(aclTensor *) 输入/输出 - 对应公式中的'y'。
- 数据类型支持COMPLEX32。
- 数据格式支持ND。
- 当“trans”取值为非转置:shape为[batchCount,m]。
- 当“trans”取值为共轭转置:shape为[batchCount, n]。
incy(int64_t) 输入 向量y的步长(当前约束为1)。 batchCount(int64_t) 输入 批次数量。取值范围为[2 - 314496]。 -
返回值:
返回状态码,具体参见SiP返回码。
约束说明
无
调用示例
示例代码如下,该样例旨在提供快速上手、开发和调试算子的最小化实现,其核心目标是使用最精简的代码展示算子的核心功能,而非提供生产级的安全保障。不推荐用户直接将示例代码作为业务代码,若用户将示例代码应用在自身的真实业务场景中且发生了安全问题,则需用户自行承担。
#include <iostream>
#include <vector>
#include <complex>
#include "asdsip.h"
#include "acl/acl.h"
#include "acl_meta.h"
using namespace AsdSip;
#define ASD_STATUS_CHECK(err) \
do { \
AsdSip::AspbStatus err_ = (err); \
if (err_ != AsdSip::ErrorType::ACL_SUCCESS) { \
std::cout << "Execute failed." << std::endl; \
exit(-1); \
} else { \
std::cout << "Execute successfully." << std::endl; \
} \
} while (0)
void printTensor(const std::complex<op::fp16_t> *tensorData, int64_t batch, int64_t rows, int64_t cols)
{
for(int64_t b = 0; b < batch; b++) {
for (int64_t i = 0; i < rows; i++) {
for (int64_t j = 0; j < cols; j++) {
auto data = tensorData[b * rows * cols + i * cols + j];
std::cout << "(" << (float)data.real() << "," << (float)data.imag() << ")" << " ";
}
std::cout << std::endl;
}
std::cout << std::endl;
}
}
#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)
{
// 固定写法,acl初始化
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(int argc, char **argv)
{
int 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);
int64_t batch = 3;
int64_t m = 3;
int64_t n = 3;
int64_t lda = m;
int incx = 1;
int incy = 1;
std::complex<op::fp16_t> alpha = std::complex<op::fp16_t>(1.0, 0.0);
std::complex<op::fp16_t> beta = std::complex<op::fp16_t>(0.0, 0.0);
asdBlasOperation_t trans = asdBlasOperation_t::ASDBLAS_OP_N;
int64_t aSize = batch * m * n;
int64_t xSize = batch * n;
int64_t ySize = batch * m;
std::vector<std::complex<op::fp16_t>> tensorInAData;
tensorInAData.reserve(aSize);
for (int64_t b = 0; b < batch; b++) {
for (int64_t i = 0; i < m; i++) {
for (int64_t j = 0; j < n; j++) {
tensorInAData[b * m * n + i * n + j] = std::complex<op::fp16_t>(i + 0.0f, i + 0.0f);
}
}
}
std::vector<std::complex<op::fp16_t>> tensorInXData;
tensorInXData.reserve(xSize);
for (int64_t b = 0; b < batch; b++) {
for (int64_t i = 0; i < n; i++) {
tensorInXData[b * n + i] = std::complex<op::fp16_t>(i + 1.0f, 2.0f);
}
}
std::vector<std::complex<op::fp16_t>> tensorInYData;
tensorInYData.reserve(ySize);
for (int64_t b = 0; b < batch; b++) {
for (int64_t i = 0; i < m; i++) {
tensorInYData[b * m + i] = std::complex<op::fp16_t>(1.0f, 1.0f);
}
}
std::cout << "trans = " << static_cast<int32_t>(trans) << std::endl;
std::cout << "alpha = " << "(" << (float)alpha.real() << "," << (float)alpha.imag() << ")" << std::endl;
std::cout << "beta = " << "(" << (float)beta.real() << "," << (float)beta.imag() << ")" << std::endl;
std::cout << "------- input TensorInA -------" << std::endl;
printTensor(tensorInAData.data(), batch, m, n);
std::cout << "------- input TensorInX -------" << std::endl;
printTensor(tensorInXData.data(), batch, 1, n);
std::cout << "------- input TensorInY -------" << std::endl;
printTensor(tensorInYData.data(), batch, 1, m);
std::vector<int64_t> aShape = {batch, m, n};
std::vector<int64_t> xShape = {batch, n};
std::vector<int64_t> yShape = {batch, m};
aclTensor *inputA = nullptr;
aclTensor *inputX = nullptr;
aclTensor *inputY = nullptr;
void *inputADeviceAddr = nullptr;
void *inputXDeviceAddr = nullptr;
void *inputYDeviceAddr = nullptr;
ret = CreateAclTensor(tensorInAData, aShape, &inputADeviceAddr, aclDataType::ACL_COMPLEX32, &inputA);
CHECK_RET(ret == ::ACL_SUCCESS, return ret);
ret = CreateAclTensor(tensorInXData, xShape, &inputXDeviceAddr, aclDataType::ACL_COMPLEX32, &inputX);
CHECK_RET(ret == ::ACL_SUCCESS, return ret);
ret = CreateAclTensor(tensorInYData, yShape, &inputYDeviceAddr, aclDataType::ACL_COMPLEX32, &inputY);
CHECK_RET(ret == ::ACL_SUCCESS, return ret);
asdBlasHandle handle;
asdBlasCreate(handle);
size_t lwork = 0;
void *buffer = nullptr;
asdBlasMakeHCgemvBatchedPlan(handle, trans, m);
asdBlasGetWorkspaceSize(handle, lwork);
std::cout << "lwork = " << lwork << std::endl;
if (lwork > 0) {
ret = aclrtMalloc(&buffer, static_cast<int64_t>(lwork), ACL_MEM_MALLOC_HUGE_FIRST);
CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
}
asdBlasSetWorkspace(handle, buffer);
asdBlasSetStream(handle, stream);
ASD_STATUS_CHECK(asdBlasHCgemvBatched(handle, trans, m, n, alpha, inputA, lda, inputX, incx, beta, inputY, incy, batch));
asdBlasSynchronize(handle);
asdBlasDestroy(handle);
ret = aclrtMemcpy(tensorInYData.data(),
ySize * sizeof(std::complex<op::fp16_t>),
inputYDeviceAddr,
ySize * sizeof(std::complex<op::fp16_t>),
ACL_MEMCPY_DEVICE_TO_HOST);
CHECK_RET(ret == ::ACL_SUCCESS, LOG_PRINT("copy y from device to host failed. ERROR: %d\n", ret); return ret);
std::cout << "------- output TensorInY -------" << std::endl;
printTensor(tensorInYData.data(), batch, 1, m);
aclDestroyTensor(inputX);
aclDestroyTensor(inputY);
aclDestroyTensor(inputA);
aclrtFree(inputXDeviceAddr);
aclrtFree(inputYDeviceAddr);
aclrtFree(inputADeviceAddr);
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}