aclnnGroupedMatmulV4
须知:该接口后续版本会废弃,请使用最新aclnnGroupedMatmulV5接口。
产品支持情况
| 产品 | 是否支持 |
|---|---|
| Ascend 950PR/Ascend 950DT | √ |
| Atlas A3 训练系列产品/Atlas A3 推理系列产品 | √ |
| Atlas A2 训练系列产品/Atlas A2 推理系列产品 | √ |
| Atlas 200I/500 A2 推理产品 | × |
| Atlas 推理系列产品 | √ |
| Atlas 训练系列产品 | × |
功能说明
-
接口功能:实现分组矩阵乘计算,每组矩阵乘的维度大小可以不同。基本功能为矩阵乘,如yi[mi,ni]=xi[mi,ki]×weighti[ki,ni],i=1...gy_i[m_i,n_i]=x_i[m_i,k_i] \times weight_i[k_i,n_i], i=1...g,其中g为分组个数,mi/ki/nim_i/k_i/n_i为对应的维度。输入输出参数类型均为aclTensorList,对应的功能为:
- k轴分组:kik_i各不相同,但mi/nim_i/n_i每组相同,此时xi/weightix_i/weight_i可以在kik_i上拼接。
- m轴分组:kik_i各组相同,weighti/yiweight_i/y_i可以在nin_i上拼接。
相较于GroupedMatmulV3接口,此接口新增:
- 支持groupListOptional中数值为分组轴上每组大小。
- Atlas A2 训练系列产品/Atlas A2 推理系列产品、Atlas A3 训练系列产品/Atlas A3 推理系列产品:
- 支持静态量化(pertensor+perchannel)(量化方式请参见量化介绍,下同)BFLOAT16和FLOAT16输出,带激活及不带激活场景
- 支持动态量化(pertoken+perchannel)BFLOAT16和FLOAT16输出,带激活及不带激活场景。
- 支持伪量化weight是INT4的输入,不带激活场景,支持perchannel和pergroup两种模式。
- Ascend 950PR/Ascend 950DT:
- 支持静态量化,量化方式包括:1. pertensor-perchannel(T-C);2. pertensor-pertensor(T-T)。支持BFLOAT16、FLOAT16和FLOAT32输出,且支持带bias场景。
- 支持动态量化,量化方式包括:1. pertoken-perchannel(K-C);2. pertoken-pertensor(K-T);3. pertensor-pertensor(T-T);4. pertensor-perchannel(T-C);5. MX量化;6. pergroup-perblock(G-B)。支持BFLOAT16、FLOAT16和FLOAT32输出,且支持带bias场景。
- 支持伪量化weight是INT4、FLOAT8_E5M2、FLOAT8_E4M3FN、HIFLOAT8的输入,不带激活场景,仅支持perchannel模式。
说明:
-
单tensor指一个tensor list中所有分组的tensor在groupType指定的分组轴上合并为1个;否则为多tensor。
-
tensor转置:指若tensor shape为[M,K]时,则stride为[1,M],数据排布为[K,M]的场景,即非连续tensor。
-
计算公式:
-
非量化场景:
yi=xi×weighti+biasi y_i=x_i\times weight_i + bias_i
-
量化场景(静态量化,T-C && T-T量化,无perTokenScaleOptional):
yi=(xi×weighti)∗scalei+offseti y_i=(x_i\times weight_i) * scale_i + offset_i
- x为INT8,bias为INT32
yi=(xi×weighti+biasi)∗scalei+offseti y_i=(x_i\times weight_i + bias_i) * scale_i + offset_i
- x为INT8,bias为BFLOAT16/FLOAT16/FLOAT32,无offset
yi=(xi×weighti)∗scalei+biasi y_i=(x_i\times weight_i) * scale_i + bias_i
- x为INT8,bias为INT32
-
量化场景(动态量化,T-T && T-C && K-T && K-C量化):
yi=(xi×weighti)∗scalei∗per_token_scalei y_i=(x_i\times weight_i) * scale_i * per\_token\_scale_i
- x为INT8,bias为INT32
yi=(xi×weighti+biasi)∗scalei∗per_token_scalei y_i=(x_i\times weight_i + bias_i) * scale_i * per\_token\_scale_i
- x为INT8,bias为BFLOAT16/FLOAT16/FLOAT32
yi=(xi×weighti)∗scalei∗per_token_scalei+biasi y_i=(x_i\times weight_i) * scale_i * per\_token\_scale_i + bias_i
- x为INT8,bias为INT32
-
量化场景(动态量化,MX && G-B量化):
yi[m,n]=∑j=0kLoops−1((∑k=0gsK−1(xSlicei∗weightSlicei))∗(per_token_scalei[m/gsM,j]∗scalei[j,n/gsN]))+biasi[n]y_i[m,n] = \sum_{j=0}^{kLoops-1} ((\sum_{k=0}^{gsK-1} (xSlice_i * weightSlice_i)) * (per\_token\_scale_i[m/gsM, j] * scale_i[j, n/gsN])) + bias_i[n]
其中,gsM,gsN和gsK分别代表M/N/K轴的量化的block size,xSliceixSlice_i代表xix_i第m行长度为gsK的向量,weightSliceiweightSlice_i代表weightiweight_i第n列长度为gsK的向量,K轴均从j * gsK起始切片,j的取值范围[0, kLoops), kLoops=ceil(KiK_i / gsK),支持最后的切片长度不足gsK。
-
伪量化场景:
yi=xi×(weighti+antiquant_offseti)∗antiquant_scalei+biasi y_i=x_i\times (weight_i + antiquant\_offset_i) * antiquant\_scale_i + bias_i
-
函数原型
每个算子分为两段式接口,必须先调用“aclnnGroupedMatmulV4GetWorkspaceSize”接口获取入参并根据计算流程计算所需workspace大小,再调用“aclnnGroupedMatmulV4”接口执行计算。
aclnnStatus aclnnGroupedMatmulV4GetWorkspaceSize(
const aclTensorList *x,
const aclTensorList *weight,
const aclTensorList *biasOptional,
const aclTensorList *scaleOptional,
const aclTensorList *offsetOptional,
const aclTensorList *antiquantScaleOptional,
const aclTensorList *antiquantOffsetOptional,
const aclTensorList *perTokenScaleOptional,
const aclTensor *groupListOptional,
const aclTensorList *activationInputOptional,
const aclTensorList *activationQuantScaleOptional,
const aclTensorList *activationQuantOffsetOptional,
int64_t splitItem,
int64_t groupType,
int64_t groupListType,
int64_t actType,
aclTensorList *out,
aclTensorList *activationFeatureOutOptional,
aclTensorList *dynQuantScaleOutOptional,
uint64_t *workspaceSize,
aclOpExecutor **executor)
aclnnStatus aclnnGroupedMatmulV4(
void *workspace,
uint64_t workspaceSize,
aclOpExecutor *executor,
aclrtStream stream)
aclnnGroupedMatmulV4GetWorkspaceSize
-
参数说明:
参数名 输入/输出 描述 使用说明 数据类型 数据格式 维度(shape) 非连续tensor x(aclTensorList) 输入 公式中的输入x。 tensorList长度支持[1, 128]或者[1, 1024]。 FLOAT16、BFLOAT16、FLOAT32、INT8、INT4、FLOAT8_E4M3FN、FLOAT8_E5M2、HIFLOAT8、FLOAT4_E2M1 ND - - weight(aclTensorList) 输入 公式中的weight。 tensorList长度支持[1, 128]或者[1, 1024]。 FLOAT16、BFLOAT16、FLOAT32、INT8、INT4、FLOAT8_E4M3FN、FLOAT8_E5M2、HIFLOAT8、FLOAT4_E2M1 ND、FRACTAL_NZ - - biasOptional(aclTensorList) 输入 公式中的bias。 长度与weight相同。 INT32、BFLOAT16、FLOAT16、FLOAT32、INT8 ND - - scaleOptional(aclTensorList) 输入 代表量化参数中的缩放因子。 一般情况下,长度与weight相同。 UINT64、INT64、BFLOAT16、FLOAT32、FLOAT8_E8M0 ND - - offsetOptional(aclTensorList) 输入 代表量化参数中的偏移量。 长度与weight相同。 FLOAT32 ND - - antiquantScaleOptional(aclTensorList) 输入 代表伪量化参数中的缩放因子。 长度与weight相同。 FLOAT16、BFLOAT16 ND - - antiquantOffsetOptional(aclTensorList) 输入 代表伪量化参数中的偏移量。 长度与weight相同。 FLOAT16、BFLOAT16 ND - - perTokenScaleOptional(aclTensorList) 输入 代表量化参数中的由x量化引入的缩放因子。 仅支持x、weight、out均为单tensor。 FLOAT32、FLOAT8_E8M0 ND - - groupListOptional(aclTensorList) 输入 代表输入和输出分组轴方向的matmul大小分布。 - INT64 ND - - activationInputOptional(aclTensorList) 输入 当前只支持传入nullptr。 当前只支持传入nullptr。 - - - - activationQuantScaleOptional(aclTensorList) 输入 当前只支持传入nullptr。 当前只支持传入nullptr。 - - - - activationQuantOffsetOptional(aclTensorList) 输入 当前只支持传入nullptr。 当前只支持传入nullptr。 - - - - splitItem(int64_t) 输入 整数型参数,代表输出是否要做tensor切分。 0/1代表输出为多tensor;2/3代表输出为单tensor。 - - - - groupType(int64_t) 输入 整数型参数,代表需要分组的轴。 枚举值-1、0、2。如矩阵乘为C[m,n]=A[m,k]xB[k,n],则groupType取值-1:不分组,0:m轴分组,2:k轴分组。 - - - - groupListType(int64_t) 输入 - 枚举值0、1、2。综合约束请参见约束说明。 - - - - actType(int64_t) 输入 代表激活函数类型。 取值范围为0-5。
0:GMM_ACT_TYPE_NONE;
1:GMM_ACT_TYPE_RELU;
2:GMM_ACT_TYPE_GELU_TANH;
3:GMM_ACT_TYPE_GELU_ERR_FUNC;
4:GMM_ACT_TYPE_FAST_GELU;
5:GMM_ACT_TYPE_SILU;
综合约束请参见约束说明。INT64 - - - out(aclTensorList) 输出 公式中的输出y。 tensorList长度支持[1, 128]或者[1, 1024]。 FLOAT16、BFLOAT16、INT8、FLOAT32、INT32 ND - - activationFeatureOutOptional(aclTensorList) 输出 激活函数的输入数据。 当前只支持传入nullptr。 - - - - dynQuantScaleOutOptional(aclTensorList) 输出 当前只支持传入nullptr。 当前只支持传入nullptr。 - - - - workspaceSize(uint64_t) 输出 返回需要在Device侧申请的workspace大小。 - - - - - executor(aclOpExecutor) 输出 返回op执行器,包含了算子计算流程。 - - - - - - Atlas A2 训练系列产品/Atlas A2 推理系列产品、Atlas A3 训练系列产品/Atlas A3 推理系列产品:
- x支持FLOAT16、BFLOAT16、FLOAT32、INT8、INT4
- weight支持FLOAT16、BFLOAT16、FLOAT32、INT8、INT4,格式支持ND、FRACTAL_NZ
- biasOptional支持FLOAT16、FLOAT32、INT32
- scaleOptional支持UINT64、BFLOAT16、FLOAT32
- perTokenScaleOptional支持FLOAT32
- 输入参数x、weight,输出参数out支持最多128个tensor。
- Ascend 950PR/Ascend 950DT:
- x支持FLOAT8_E4M3FN、FLOAT8_E5M2、INT8、HIFLOAT8、FLOAT16、BFLOAT16、FLOAT32、FLOAT4_E2M1
- weight支持FLOAT8_E4M3FN、FLOAT8_E5M2、INT8、INT4、HIFLOAT8、FLOAT16、BFLOAT16、FLOAT32、FLOAT4_E2M1,格式仅支持ND格式。
- biasOptional支持INT32、BFLOAT16、FLOAT16、FLOAT32,在输入x为INT8、FLOAT16、BFLOAT16、FLOAT32时支持INT32、BFLOAT16、FLOAT16、FLOAT32,在输入x为FLOAT4_E2M1时仅支持FLOAT32,其它类型输入需传空指针
- scaleOptional支持UINT64、INT64、BFLOAT16、FLOAT32、FLOAT8_E8M0
- perTokenScaleOptional支持FLOAT32、FLOAT8_E8M0
- 全量化场景下groupListType支持取2,其余场景不支持
- actType支持0、1、2、4、5。综合约束请参见约束说明。
- 不支持offsetOptional
- groupType支持m轴分组,仅非量化和量化支持k轴分组,仅非量化和伪量化支持不分组
- 输入参数x、weight,输出参数out在非量化场景支持最多1024个tensor,在伪量化场景支持最多128个tensor,在全量化场景仅支持单tensor。
- Atlas A2 训练系列产品/Atlas A2 推理系列产品、Atlas A3 训练系列产品/Atlas A3 推理系列产品:
-
返回值:
返回aclnnStatus状态码,具体参见aclnn返回码。
第一阶段接口完成入参校验,出现以下场景时报错:
返回值 错误码 描述 ACLNN_ERR_PARAM_NULLPTR 161001 传入参数是必选输入、输出或者必选属性,且是空指针。 ACLNN_ERR_PARAM_INVALID 161002 x、weight、biasOptional、scaleOptional、offsetOptional、antiquantScaleOptional、antiquantOffsetOptional、groupListOptional、out的数据类型和数据格式不在支持的范围内。 weight的长度不在支持范围。 若bias不为空,bias的长度不等于weight的长度。 groupListOptional维度不在支持范围内。 splitItem为2、3的场景,out长度不等于1。 splitItem为0、1的场景,out长度不等于weight的长度,groupListOptional长度不等于weight的长度。
aclnnGroupedMatmulV4
-
参数说明:
参数说明 输入/输出 描述 workspace 输入 在Device侧申请的workspace内存地址。 workspaceSize 输入 在Device侧申请的workspace大小,由第一段接口aclnnGroupedMatmulV4GetWorkspaceSize获取。 executor 输入 op执行器,包含了算子计算流程。 stream 输入 指定执行任务的Stream。 -
返回值:
返回aclnnStatus状态码,具体参见aclnn返回码。
场景分类
-
GroupedMatmul算子根据计算过程中对输入数据(x, weight)和输出矩阵(out)的精度处理方式,其支持场景主要分为:非量化,伪量化,全量化。
-
Atlas A2 训练系列产品/Atlas A2 推理系列产品、Atlas A3 训练系列产品/Atlas A3 推理系列产品:
场景名 x weight out 约束说明 计算公式 非量化 FLOAT32 FLOAT32 FLOAT32 非量化场景约束 计算公式 非量化 BFLOAT16 BFLOAT16 BFLOAT16 非量化场景约束 计算公式 非量化 FLOAT16 FLOAT16 FLOAT16 非量化场景约束 计算公式 全量化-A8W8 INT8 INT8 BFLOAT16/FLOAT16/INT32/INT8 A8W8场景约束 计算公式 全量化-A4W4 INT4 INT4 BFLOAT16/FLOAT16 A4W4场景约束 计算公式 伪量化-A8W4 INT8 INT4 BFLOAT16/FLOAT16 A8W4场景约束 计算公式 伪量化-A16W8 BFLOAT16/FLOAT16 INT8 BFLOAT16/FLOAT16 A16W8场景约束 计算公式 伪量化-A16W4 BFLOAT16/FLOAT16 INT4 BFLOAT16/FLOAT16 A16W4场景约束 计算公式 -
Ascend 950PR/Ascend 950DT:
-
-
-
非量化场景:
yi=xi×weighti+biasiy_i=x_i\times weight_i + bias_i
-
全量化场景(无perTokenScaleOptional):
-
x为INT8,bias为INT32
yi=(xi×weighti+biasi)∗scalei+offsetiy_i=(x_i\times weight_i + bias_i) * scale_i + offset_i
-
-
全量化场景(有perTokenScaleOptional):
-
x为INT8,bias为INT32
yi=(xi×weighti+biasi)∗scalei∗per_token_scaleiy_i=(x_i\times weight_i + bias_i) * scale_i * per\_token\_scale_i
-
x为INT8,bias为BFLOAT16
yi=(xi×weighti)∗scalei∗per_token_scalei+biasiy_i=(x_i\times weight_i) * scale_i * per\_token\_scale_i + bias_i
-
x为INT4,无bias
yi=xi×(weighti∗scalei)∗per_token_scaleiy_i=x_i\times (weight_i * scale_i) * per\_token\_scale_i
-
-
伪量化场景:
-
x为Float16、BFloat16,weight为INT4、INT8(仅支持x、weight、y均为单tensor的场景)。
yi=xi×(weighti+antiquant_offseti)∗antiquant_scalei+biasiy_i=x_i\times (weight_i + antiquant\_offset_i) * antiquant\_scale_i + bias_i
-
x为INT8,weight为INT4(仅支持x、weight、y均为单tensor的场景)。其中biasbias为必选参数,是离线计算的辅助结果,且 biasi=8×weighti∗scaleibias_i=8\times weight_i * scale_i ,并沿k轴规约。
yi=((xi−8)×weighti∗scalei+biasi)∗per_token_scaleiy_i=((x_i - 8) \times weight_i * scale_i+bias_i ) * per\_token\_scale_i
-
-
约束说明
-
确定性计算:
- aclnnGroupedMatmulV4默认确定性实现。
Atlas A2 训练系列产品/Atlas A2 推理系列产品、Atlas A3 训练系列产品/Atlas A3 推理系列产品
-
- x和weight若需要转置,转置对应的tensor必须非连续。
- x和weight中每一组tensor的最后一维大小都应小于65536。xix_i的最后一维指当x不转置时xix_i的K轴或当x转置时xix_i的M轴。weightiweight_i的最后一维指当weight不转置时weightiweight_i的N轴或当weight转置时weightiweight_i的K轴。
- 当weight数据格式为FRACTAL_NZ格式时,要求weight的Shape满足FRACTAL_NZ格式要求。
- perTokenScaleOptional:一般情况下,只支持1维且长度与x的M相同。仅支持x、weight、out均为单tensor(TensorList长度为1)场景。
- groupListOptional:当输出中TensorList的长度为1时,groupListOptional约束了输出数据的有效部分,groupListOptional中未指定的部分将不会参与更新。
- groupListType为0时要求groupListOptional中数值为非负单调非递减数列,表示分组轴大小的cumsum结果(累积和),groupListType为1时要求groupListOptional中数值为非负数列,表示分组轴上每组大小,groupListType为2时要求 groupListOptional中数值为非负数列,shape为[E, 2],E表示Group大小,数据排布为[[groupIdx0, groupSize0], [groupIdx1, groupSize1]...],其中groupSize为分组轴上每组大小,详见groupListOptional配置示例。
- groupType代表需要分组的轴,如矩阵乘为C[m,n]=A[m,k]xB[k,n],则groupType取值-1:不分组,0:m轴分组,2:k轴分组。详细参考groupType支持场景约束。
- actType(int64_t,计算输入):整数型参数,代表激活函数类型,取值范围为0-5。
A8W8场景约束
-
数据类型要求
x weight bias scale offset antiquantScale antiquantOffset perTokenScale groupList activationInput activationQuantScale activationQuantOffset out INT8 INT8 (ND) INT32/null UINT64 null null null null INT64 null null null INT8 INT8 INT8 (ND/NZ) INT32/null BFLOAT16 null null null FLOAT/null INT64 null null null BFLOAT16 INT8 INT8 (NZ) BFLOAT16/null FLOAT/BFLOAT16 null null null FLOAT/null INT64 null null null BFLOAT16 INT8 INT8 (ND/NZ) INT32/null FLOAT null null null FLOAT/null INT64 null null null FLOAT16 INT8 INT8 (ND/NZ) INT32/null null null null null null INT64 null null null INT32 -
约束说明
除公共约束外,A8W8场景其余约束如下
- 仅支持GroupType=0(M轴分组)
- 当前仅支持x、weight、out均为长度为1的TensorList
- x不支持转置
- x仅支持2维Tensor,Shape为(M,K)
- weight仅支持3维Tensor,Shape为(E,K,N)或(E,N,K)
- 如果需要启用定轴算法以优化性能,需同时满足以下输入形状与参数配置条件:
-
输入形状条件(满足任意一组即可)
x 的 shape 为 (M, 7168),weight 的 shape 为 (7168, 4096)。
x 的 shape 为 (M, 2048),weight 的 shape 为 (2048, 7168)。
-
参数配置条件
tuningConfigOptional 的第一个元素:设为大于 128 且小于 512。
tuningConfigOptional 的第二个元素:设为 0。
tuningConfigOptional 的第三个元素:设为 -1,或设为大于等于 M × N × 4 的数值。
-
A8W4场景约束
-
数据类型要求
x weight bias scale offset antiquantScale antiquantOffset perTokenScale groupList activationInput activationQuantScale activationQuantOffset out INT8 INT4 (ND/NZ) FLOAT UINT64 null null null FLOAT INT64 null null null BFLOAT16 INT8 INT4 (ND/NZ) FLOAT UINT64 FLOAT/null null null FLOAT INT64 null null null FLOAT16 -
约束说明
除公共约束外,A8W4场景其余约束如下:
- 仅支持GroupType=0(M轴分组),actType=0
- 当前仅支持x、weight、out均为长度为1的TensorList
- x不支持转置、weight不支持转置
- x仅支持2维Tensor,Shape为(M,K)
- weight默认支持3维Tensor,Shape为(E,K,N)
- Bias为计算过程中离线计算的辅助结果,值要求为8×weight×scale8\times weight \times scale,并在第1维累加,shape要求为[E,N][E, N]。
- 当weight传入数据类型为INT32时,会将每个INT32视为8个INT4。
- offset为空时
- 该场景下仅支持groupListType为1(算子不会检查groupListType的值,会认为groupListType为1),k要求为quantGroupSize的整数倍,且要求k <= 18432。其中quantGroupSize为k方向上pergroup量化长度,当前支持quantGroupSize=256。
- 该场景下要求n为8的整数倍。
- 该场景下scale为pergroup与perchannel离线融合后的结果,shape要求为[E,quantGroupNum,N][E, quantGroupNum, N],其中quantGroupNum=k÷quantGroupSizequantGroupNum=k \div quantGroupSize。
- 该场景下,各个专家处理的token数的预期值大于n/4时,即tuningConfigOptional中第一个值大于n/4时,通常会取得更好的性能,此时显存占用会增加g×k×ng\times k \times n字节(其中g为matmul组数即分组数)。
- offset不为空时
- scale为pergroup与perchannel离线融合后的结果,shape要求为[E,1,N][E, 1, N]。
- 该场景下offsetOptional不为空。非对称量化offsetOptional为计算过程中离线计算辅助结果,即antiquantOffset×scaleantiquantOffset \times scale,shape要求为[E,1,N][E, 1, N],dtype为FLOAT32。
- tuningConfigOptional数组第二个元素可置1,以使能A8W4场景中weight的特殊格式模板,以优化算子性能(性能优势的shape范围参考:K >= 2048 && N >= 2048)。需要说明的是,该模板要求weight的shape为(E,N,K),然后再对其进行ND2NZ转换后作为算子输入。
A16W4场景约束
-
数据类型要求
x weight bias scale offset antiquantScale antiquantOffset perTokenScale groupList activationInput activationQuantScale activationQuantOffset out FLOAT16 INT4 (ND) FLOAT16/null null null FLOAT16 FLOAT16 null INT64 null null null FLOAT16 BFLOAT16 INT4 (ND) FLOAT/null null null BFLOAT16 BFLOAT16 null INT64 null null null BFLOAT16 -
约束说明
除公共约束外,a16w4场景其余约束如下:
-
x不支持转置
-
仅支持GroupType=-1、0,actType=0,groupListType=0/1
-
weight中每一组tensor的最后一维大小都应是偶数,最后一维指weight不转置时weightiweight_i的N轴或当weight转置时weightiweight_i的K轴。
-
对称量化支持perchannel和pergroup量化模式,若为pergroup,pergroup数G或GiG_i必须要能整除对应的kik_i。
-
非对称量化仅支持perchannel模式。
-
在pergroup场景下,当weight转置时,要求pergroup长度sis_i是偶数。
-
若weight为多tensor,定义pergroup长度si=ki/Gis_i = k_i / G_i,要求所有si(i=1,2,...g)s_i(i=1,2,...g)都相等。
-
伪量化参数antiquantScaleOptional和antiquantOffsetOptional的shape要满足下表(其中g为matmul组数,G为pergroup数,GiG_i为第i个tensor的pergroup数):
使用场景 子场景 shape限制 伪量化perchannel weight单 [E,N][E, N] 伪量化perchannel weight多 [Ni][N_i] 伪量化pergroup weight单 [E,G,N][E, G, N] 伪量化pergroup weight多 [Gi,Ni][G_i, N_i]
-
A16W8场景约束
-
数据类型要求
x weight bias scale offset antiquantScale antiquantOffset perTokenScale groupList activationInput activationQuantScale activationQuantOffset out FLOAT16 INT8 (ND) FLOAT16/null null null FLOAT16 FLOAT16 null INT64 null null null FLOAT16 BFLOAT16 INT8 (ND) FLOAT/null null null BFLOAT16 BFLOAT16 null INT64 null null null BFLOAT16 -
约束说明
除公共约束外,a16w8场景其余约束如下:
-
x不支持转置
-
仅支持GroupType=-1、0,actType=0,groupListType=0/1
-
仅支持perchannel量化模式。
-
若weight为多tensor,定义pergroup长度si=ki/Gis_i = k_i / G_i,要求所有si(i=1,2,...g)s_i(i=1,2,...g)都相等。
-
伪量化参数antiquantScaleOptional和antiquantOffsetOptional的shape要满足下表(其中g为matmul组数):
使用场景 子场景 shape限制 伪量化perchannel weight单 [E,N][E, N] 伪量化perchannel weight多 [Ni][N_i]
-
A4W4场景约束
-
数据类型要求
x weight bias scale offset antiquantScale antiquantOffset perTokenScale groupList activationInput activationQuantScale activationQuantOffset out INT4 INT4 (ND/NZ) null UINT64 null null null FLOAT/null INT64 null null null FLOAT16/BFLOAT16 -
约束说明
除公共约束外,A4W4场景其余约束如下:
- 仅支持GroupType=0(M轴分组),actType=0,groupListType=0/1
- 当前仅支持x、weight、out均为长度为1的TensorList
- x不支持转置,weight不支持转置
- x仅支持2维Tensor,Shape为(M,K)
- weight仅支持3维Tensor,Shape为(E,K,N)
- weight的数据格式为ND时,要求n为8的整数倍。
- 支持perchannel和pergroup量化。perchannel场景的scale的shape需为[E,N][E, N],pergroup场景需为[E,G,N][E, G, N]。
- pergroup场景下,GG必须要能整除kk,且k/Gk/G需为偶数。
非量化场景约束
-
数据类型要求
x weight bias scale offset antiquantScale antiquantOffset perTokenScale groupList activationInput activationQuantScale activationQuantOffset out FLOAT FLOAT (ND) FLOAT/null null null null null null INT64 null null null FLOAT FLOAT16 FLOAT16 (ND/NZ) FLOAT16/null null null null null null INT64 null null null FLOAT16 BFLOAT16 BFLOAT16(ND/NZ) FLOAT/null null null null null null INT64 null null null BFLOAT16 -
约束说明
除公共约束外,非量化场景其余约束如下:
- 支持GroupType=-1、0、2,actType=0,groupListType=0/1
groupType支持场景
-
a16w8、a16w4场景仅支持groupType为-1和0场景。
-
A8W8、A8W4、A4W4场景仅支持groupType为0场景中x tensor数为单。
-
x、weight、y的输入类型为aclTensorList,表示一个aclTensor类型的数组对象。下面表格支持场景用"单"表示由一个aclTensor组成的aclTensorList,"多"表示由多个aclTensor组成的aclTensorList。例如"单多单",分别表示x为单tensor、weight为多tensor、y为单tensor。
groupType x tensor数 weight tensor数 y tensor数 splitItem groupListOptional 转置 其余场景限制 -1 多个 多个 多个 0/1 groupListOptional必须传空 1)x不支持转置;
2)支持weight转置,但weight的tensorList中每个tensor是否转置需保持统一x中tensor要求维度一致,支持2维,weight中tensor需为2维,y中tensor维度和x保持一致 0 单个 单个 单个 2/3 1)必须传groupListOptional;
2)当groupListType为0时,最后一个值应小于等于x中tensor的第一维;当groupListType为1时,数值的总和应小于等于x中tensor的第一维;当groupListType为2时,第二列数值的总和应小于等于x中tensor的第一维;
3)groupListOptional第1维最大支持1024,即最多支持1024个group1)x不支持转置;
2)支持weight转置,A8W4与A4W4场景不支持weight转置weight中tensor需为3维,x,y中tensor需为2维 0 单个 多个 单个 2/3 1)必须传groupListOptional;
2)当groupListType为0时,最后一个值应小于等于x中tensor的第一维;当groupListType为1时,数值的总和应小于等于x中tensor的第一维;当groupListType为2时,第二列数值的总和应小于等于x中tensor的第一维;
3)groupListOptional第1维最大支持128,即最多支持128个group1)x不支持转置;
2)支持weight转置,但weight的tensorList中每个tensor是否转置需保持统一1)x,weight,y中tensor需为2维;
2)weight中每个tensor的N轴必须相等0 多个 多个 单个 2/3 1)groupListOptional可选;
2)若传入groupListOptional,当groupListType为0时,groupListOptional的差值需与x中tensor的第一维一一对应;当groupListType为1时,groupListOptional的数值需与x中tensor的第一维一一对应;当groupListType为2时,groupListOptional第二列的数值需与x中tensor的第一维一一对应;
3)groupListOptional第1维最大支持128,即最多支持128个group1)x不支持转置;
2)支持weight转置,但weight的tensorList中每个tensor是否转置需保持统一1)x,weight,y中tensor需为2维;
2)weight中每个tensor的N轴必须相等2 单个 单个 单个 2/3 1)必须传groupListOptional;
2)当groupListType为0时,最后一个值应小于等于x中tensor的第二维;当groupListType为1时,数值的总和与x应小于等于tensor的第二维;当groupListType为2时,第二列数值的总和应小于等于x中tensor的第二维;
3)groupListOptional第1维最大支持1024, 即最多支持1024个group1)x必须转置;
2)weight不能转置1)x,weight中tensor需为2维,y中tensor需为3维;
2)bias必须传空2 单个 多个 多个 0/1 groupListOptional必须传空 1)x必须转置;
2)weight不能转置1)x,weight,y中tensor需为2维。
2)weight长度最大支持128,即最多支持128个group;
3)原始shape中weight每个tensor的第一维之和不应超过x第一维;
4)bias必须传空
groupListOptional配置示例
-
shape信息 M = 789、 K=4096、 N=7168 、E = 9(0,2,5个专家有需要处理的token,0处理123个token, 2/5处理333个token) X的shape是[[789, 4096]] W的shape是[[9, 4096, 7168]] Y的shape是[[789, 7168]]
-
groupListType为0时groupList配置如下
- groupListOptional:
[123, 123, 456, 456, 456, 789, 789, 789, 789]
- groupListOptional:
-
groupListType为1时groupList配置如下
- groupListOptional:
[123, 0, 333, 0, 0, 333, 0, 0, 0]
- groupListOptional:
-
groupListType为2时groupList配置如下
- groupListOptional在该模式会将所有非0的group移动到前面,适用于非激活专家较多场景。
- groupListOptional:
[[0, 123], [2, 333], [5, 333], [1, 0], [3, 0], [4, 0], [6, 0], [7, 0], [8, 0]]
Ascend 950PR/Ascend 950DT
-
公共约束:
- groupListType:支持取值0、1、2。
- 当groupListType为0时,groupListOptional必须为非负单调非递减数列;
- 当groupListType为1时,groupListOptional必须为非负数列。
- 仅全量化且groupType为0场景下支持groupListType为2,此时要求 groupListOptional中数值为非负数列,shape为[E, 2],E表示Group大小,数据排布为[[groupIdx0, groupSize0], [groupIdx1, groupSize1]...],其中groupSize为分组轴上每组大小,此时groupedSize为零的组置于groupList末尾,非零组被前置,详见groupListOptional配置示例 。
- actType(int64_t,计算输入):整数型参数,代表激活函数类型,取值范围为0-5。
静态量化场景约束
-
以下入参为空:offsetOptional、antiquantScaleOptional、antiquantOffsetOptional、 perTokenScaleOptional、 activationInputOptional
-
不为空的参数支持的数据类型组合要满足下表:
groupType x weight biasOptional scaleOptional out 0 INT8 INT8 INT32/null UINT64/INT64 BFLOAT16/FLOAT16/INT8 0 INT8 INT8 INT32/null null/UINT64/INT64 INT32 0 INT8 INT8 INT32/BFLOAT16/FLOAT32/null BFLOAT16/FLOAT32 BFLOAT16 0 INT8 INT8 INT32/FLOAT16/FLOAT32/null FLOAT32 FLOAT16 0 HIFLOAT8 HIFLOAT8 null UINT64/INT64 BFLOAT16/FLOAT16/ FLOAT32 0/2 HIFLOAT8 HIFLOAT8 null FLOAT32 BFLOAT16/FLOAT16/FLOAT32 0 FLOAT8_E5M2/FLOAT8_E4M3FN FLOAT8_E5M2/FLOAT8_E4M3FN null UINT64/INT64 BFLOAT16/FLOAT16/FLOAT32 0/2 FLOAT8_E5M2/FLOAT8_E4M3FN FLOAT8_E5M2/FLOAT8_E4M3FN null FLOAT32 BFLOAT16/FLOAT16/FLOAT32 -
scaleOptional要满足下表(其中g为matmul组数即分组数):
groupType 使用场景 shape限制 0/2 weight单tensor perchannel场景:每个tensor 2维, shape为(g, N); pertensor场景:每个tensor 2维或1维,shape为 (g, 1)或(g,),输出为INT8时不支持pertensor场景
动态量化(T-T && T-C && K-T && K-C量化)场景约束
-
以下入参为空:offsetOptional、antiquantScaleOptional、antiquantOffsetOptional、 activationInputOptional
-
不为空的参数支持的数据类型组合要满足下表:
groupType x weight biasOptional scaleOptional perTokenScaleOptional out 0 INT8 INT8 INT32/BFLOAT16/FLOAT32/null BFLOAT16/FLOAT32 FLOAT32 BFLOAT16 0 INT8 INT8 INT32/FLOAT16/FLOAT32/null FLOAT32 FLOAT32 FLOAT16 0/2 HIFLOAT8 HIFLOAT8 null FLOAT32 FLOAT32 BFLOAT16/ FLOAT16/FLOAT32 0/2 FLOAT8_E5M2/FLOAT8_E4M3FN FLOAT8_E5M2/FLOAT8_E4M3FN null FLOAT32 FLOAT32 BFLOAT16/ FLOAT16/FLOAT32 -
scaleOptional要满足下表(其中g为matmul组数即分组数),推荐在pertensor场景scaleOptional的shape使用(g,),防止与G-B量化模式混淆:
groupType 使用场景 shape限制 0/2 weight单tensor perchannel场景:每个tensor 2维,shape为(g, N); pertensor场景:每个tensor 2维或1维,shape为(g, 1)或(g,) -
perTokenScaleOptional要满足下表:
groupType 使用场景 shape限制 0 x单tensor pertoken场景:每个tensor 1维,shape为(M,);pertensor场景:每个tensor 2维或1维,shape为(g, 1)或 (g,),输入为INT8时不支持pertensor场景 2 x单tensor pertoken场景:每个tensor 2维,shape为(g, M);pertensor场景:每个tensor 2维或1维,shape为(g, 1) 或(g,)
动态量化(mx量化)场景约束
-
以下入参为空:offsetOptional、antiquantScaleOptional、antiquantOffsetOptional、 activationInputOptional
-
计算公式中量化block size为:gsM = gsN = 1,gsK = 32。mx量化是特殊的pergroup量化。
-
不为空的参数支持的数据类型组合要满足下表:
groupType x weight biasOptional scaleOptional perTokenScaleOptional out 0/2 FLOAT8_E5M2/FLOAT8_E4M3FN FLOAT8_E5M2/FLOAT8_E4M3FN null FLOAT8_E8M0 FLOAT8_E8M0 BFLOAT16/FLOAT16/FLOAT32 0 FLOAT4_E2M1 FLOAT4_E2M1 FLOAT32/null FLOAT8_E8M0 FLOAT8_E8M0 BFLOAT16/FLOAT16/FLOAT32 -
scaleOptional要满足下表(其中g为matmul组数即分组数,g_i为第i个分组(下标从0开 始)):
groupType 使用场景 shape限制 0 weight单tensor 每个tensor 4维,当weight转置时,shape为(g, N, ceil(K / 64), 2);当weight不转置时,shape为(g, ceil(K / 64), N, 2) 2 weight单tensor 每个tensor 3维,shape为((K / 64) + g, N, 2),scale_i起始地址偏移为((K_0 + K_1 + ...+ K_{i-1})/ 64 + g_i) * N * 2,即scale_0的起始地 址偏移为0,scale_1的起始地址偏移为(K_0 / 64 + 1)* N * 2, scale_2的起始地址偏移为((K_0 + K_1) / 64 + 2) * N * 2, 依此类推 -
perTokenScaleOptional要满足下表:
groupType 使用场景 shape限制 0 x单tensor 每个tensor 3维,shape为(M, ceil(K / 64), 2) 2 x单tensor 每个tensor 3维,shape为((K / 64) + g, M, 2), 起始地址偏移与scale 同理 -
对于mx量化中输入x为FLOAT4_E2M1时,需要满足K为偶数且K不为2。当weight非转置时还需满足N为偶数。
动态量化(G-B量化)场景约束
-
以下入参为空:biasOptional、offsetOptional、antiquantScaleOptional、antiquantOffsetOptional、activationInputOptional
-
计算公式量化block size为:当前仅支持gsM = 1, gsN = gsK = 128。
-
不为空的参数支持的数据类型组合要满足下表:
groupType x weight scaleOptional perTokenScaleOptional out 0/2 HIFLOAT8 HIFLOAT8 FLOAT32 FLOAT32 BFLOAT16/FLOAT16/ FLOAT32 0/2 FLOAT8_E5M2/FLOAT8_E4M3FN FLOAT8_E5M2/FLOAT8_E4M3FN FLOAT32 FLOAT32 BFLOAT16/FLOAT16/FLOAT32 -
scaleOptional要满足下表(其中g为matmul组数即分组数,g_i为第i个分组(下标从0开 始)):
groupType 使用场景 shape限制 0 weight单tensor 每个tensor 3维,weight转置时shape为(g, ceil(N / gsN), ceil (K / gsK)),weight非转置时shape为(g, ceil(K / gsK), ceil(N / gsN)) 2 weight单tensor 每个tensor 2维,shape为(K / gsK + g, ceil(N / gsN)),scale_i地址偏移为((K_0 + K_1 + ...+ K_{i-1})/ gsK + g_i)* ceil(N / gsN),即scale_0的起始地址偏移为0,scale_1的起始地址偏移为(K_0 / gsK + 1)* ceil(N / gsN), scale_2的起始地址偏移为((K_0 + K_1) / gsK + 2) * ceil(N / gsN), 依此类推 -
perTokenScaleOptional要满足下表:
groupType 使用场景 shape限制 0 x单tensor 每个tensor 2维,shape为(M, ceil(K / gsK)) 2 x单tensor 每个tensor 2维,shape为(K / gsK + g, M),per_token_scale_i地址偏移为((K_0 + K_1 + ...+ K_{i-1}) / gsK + g_i)* M,即 per_token_scale_0的起始地址偏移为0,per_token_scale_1的起始地址偏移为(K_0 / gsK + 1)* M, per_token_scale_2的起始地址偏移为((K_0 + K_1) / gsK + 2) * M, 依此类推 -
动态量化特殊场景处理:
- 在动态量化场景M分组或K分组情况下,当N等于1且scaleOptional的shape为(g, 1)时,weight既可以pertensor量化也可以perchannel量化时, 优先选择pertensor量化模式。
- 在动态量化场景M分组情况下,当g = M且perTokenScaleOptional的shape为(g,)时,x选择pertoken量化模式;当g = M,K <= 128且perTokenScaleOptional的shape 为(g, 1)时,根据weight的量化模式选择x的量化模式(weight如果是perchannel或者pertensor量化,x选择pertensor量化;weight如果是perblock量化,x选择pergroup量化)。
- 在动态量化场景K分组情况下,K小于128,N小于等于128且scaleOptional的shape为(g, 1)时,按照现有量化模式区分规则,既可以为非pergroup量化,又可以为G-B量化,此种场景现一律按照G-B量化处理。
- 在动态量化场景K分组情况下,当M等于1且perTokenScaleOptional的shape为(g, 1)时,x既可以pertoken量化也可以pertensor量化时, 优先选择pertensor量化模式。
- 在动态量化场景K分组情况下,K小于128, M等于1且perTokenScaleOptional的shape为(g, 1)时,如果N小于等于128,x则选择pergroup量化;如果N大于128,根据weight的量化模式选择x的量化模式(weight如果是perchannel或者pertensor量化,x选择 pertensor量化;weight 如果是perblock量化,x选择pergroup量化)。
- 在动态量化场景K分组情况下,K小于128, M不等于1时,如果N小于等于128,x则选择pergroup量化;如果N大于128,根据weight的量化模式选择x的量化模式(weight如果是 perchannel或者pertensor量化,x选择pertoken量化;weight如果是perblock量化,x选择pergroup量化)。
非量化场景约束
- 非量化场景支持的数据类型为:
-
以下入参为空:scaleOptional、offsetOptional、antiquantScaleOptional、antiquantOffsetOptional、perTokenScaleOptional、activationInputOptional、activationQuantScaleOptional、activationQuantOffsetOptional、activationFeatureOutOptional
-
不为空的参数支持的数据类型组合要满足下表
groupType x weight biasOptional out -1/0/2 BFLOAT16 BFLOAT16 BFLOAT16/FLOAT32/null BFLOAT16 -1/0/2 FLOAT16 FLOAT16 FLOAT16/FLOAT32/null FLOAT16 -1/0/2 FLOAT32 FLOAT32 FLOAT32/null FLOAT32
-
伪量化场景约束
- 伪量化场景支持的数据类型为:
-
以下入参为空:scaleOptional、offsetOptional、perTokenScaleOptional、activationInputOptional、activationQuantScaleOptional、activationQuantOffsetOptional
-
不为空的参数支持的数据类型组合要满足下表
groupType x weight biasOptional antiquantScaleOptional antiquantOffsetOptional out -1/0 BFLOAT16 INT8/INT4 BFLOAT16/FLOAT32/null BFLOAT16 BFLOAT16/ null BFLOAT16 -1/0 FLOAT16 INT8/INT4 FLOAT16/null FLOAT16 FLOAT16/null FLOAT16 0 BFLOAT16 FLOAT8_E5M2/FLOAT8_E4M3FN/HIFLOAT8 BFLOAT16/FLOAT32/ null BFLOAT16 null BFLOAT16 0 FLOAT16 FLOAT8_E5M2/FLOAT8_E4M3FN/HIFLOAT8 FLOAT16/null FLOAT16 null FLOAT16 -
当weight的数据类型为FLOAT8_E5M2、FLOAT8_E4M3FN、HIFLOAT8时,antiquantOffsetOptional仅支持传入空指针或空tensorList,weight仅支持转置。
-
若weight的类型为INT4,则weight中每一组tensor的最后一维大小都应是偶数。weightiweight_i的最后一维指weight不转置时weightiweight_i的N轴或当weight转置时weightiweight_i的K轴。
-
antiquantScaleOptional和非空的biasOptional、antiquantOffsetOptional要满足下表(其中g为matmul组数即分组数):
groupType 使用场景 shape限制 -1 weight多tensor 每个tensor 1维,shape为(nin_i),不允许存在一个tensorList中部分tensor的shape为(nin_i)部分tensor为空的情况 0 weight单tensor 每个tensor 2维,shape为(g, N)
-
不同groupType约束
- 不同groupType支持场景:
-
支持场景中单表示单tensor,多表示多tensor,表示顺序为x,weight,out,例如单多单表示支持x为单tensor,weight多tensor,out单tensor的场景。
groupType 支持场景 场景限制 -1 多多多 1)仅支持splitItem为0/1
2)非量化x,out中tensor需为2维,shape分别为(mim_i, kik_i)和(mim_i, nin_i);伪量化场景x中tensor要求维度一致,支持2-6维,y中tensor维度和x保持一致;weight中tensor需为2维,shape为(nin_i, kik_i)或(kik_i, nin_i);bias中tensor需为1维,shape为(nin_i)
3) groupListOptional必须传空
4)支持weight转置,但weight的tensorList中每个tensor是否转置需保持统一
5)x不支持转置
6)仅支持非量化和伪量化
7)仅支持ND进ND出0 单单单 1)仅支持splitItem为2/3
2)weight中tensor需为3维,shape为(g, N, K)或(g, K, N);x,out中tensor需为2维,shape分别为(M, K)和(M, N);bias中tensor需为2维,shape为(g, N)
3)必须传groupListOptional,且当groupListType为0时,最后一个值不大于x中tensor的第一维,当groupListType为1时,数值的总和不大于x中tensor的第一维,当groupListType为2时,第二列数值的总和不大于x中tensor的第一维
4)groupListOptional第1维最大支持1024,即最多支持1024个group
5)支持x不转置,weight转置、不转置均支持
6)仅支持ND进ND出0 单多单 1)仅支持splitItem为2/3
2)必须传groupListOptional,且当groupListType为0时,最后一个值与x中tensor的第一维相等,当groupListType为1时,数值的总和与x中tensor的第一维相等,长度最大1024
3)x,out中tensor需为2维,shape分别为(M, K)和(M, N);weight中tensor需为2维,shape为(N, K)或(K, N);bias中tensor需为1维,shape为(N)
4)weight中每个tensor的N轴必须相等
5)支持weight转置,但weight的tensorList中每tensor是否转置需保持统一
6)x不支持转置
7)仅支持非量化
8)仅支持ND进ND出0 多多单 1)仅支持splitItem为2
2)x,out中tensor需为2维, shape分别为(M, K)和(M, N);weight中tensor需为2维,shape为(N, K)或(K, N);bias中tensor需为1维,shape为(N)
3)weight中每个tensor的N轴必须相等
4)若传入groupListOptional,当groupListType为0时,groupListOptional的差值需与x中tensor的第一维一一对应,当groupListType为1时,groupListOptional的数值需与x中tensor的第一维一一对应,且长度最大为1024
5)支持weight转置,但weight的tensorList中每个tensor是否转置需保持统一
6)x不支持转置
7)仅支持非量化
8)仅支持ND进ND出2 单单单 1)仅支持splitItem为2/3
2)x,weight中tensor需为2维,shape分别为(K, M)和(K, N);out中tensor需为3维, shape为(g, M, N)
3)必须传groupListOptional,且当groupListType为0时,最后一个值不大于x中tensor的第一维,当groupListType为1时,数值的总和不大于x中tensor的第一维
4)groupListOptional第1维最大支持1024,即最多支持1024个group
5)x必须转置,weight不能转置
6)仅支持非量化和量化
7)仅支持ND进ND出
8)不支持bias2 单多多 1)仅支持splitItem为0/1
2)x,weight中tensor需为2维,shape分别为(K, M)和(K, N);y中tensor需为2维, shape为(M, N)
3)groupListOptional可以传空,如果传groupListOptional,当groupListType为0时,最后一个值不大于x中tensor的第一维,当groupListType为1时,数值的总和不大于x中tensor的第一维
4)groupListOptional第1维最大支持1024,即最多支持1024个group
5)x必须转置,weight不能转置
6)仅支持ND进ND出
7)不支持bias
8)仅支持非量化
-
- groupListType:支持取值0、1、2。
调用示例
调用示例代码如下,仅供参考,具体编译和执行过程请参考编译与运行样例。
#include <iostream>
#include <vector>
#include "acl/acl.h"
#include "aclnnop/aclnn_grouped_matmul_v4.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_New(const std::vector<int64_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;
}
template <typename T>
int CreateAclTensor(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侧内存上
std::vector<T> hostData(size, 0);
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 CreateAclTensorList(const std::vector<std::vector<int64_t>>& shapes, void** deviceAddr,
aclDataType dataType, aclTensorList** tensor) {
int size = shapes.size();
std::vector<aclTensor*> tensors(size);
for (int i = 0; i < size; i++) {
int ret = CreateAclTensor<uint16_t>(shapes[i], deviceAddr + i, dataType, tensors.data() + i);
CHECK_RET(ret == ACL_SUCCESS, return ret);
}
*tensor = aclCreateTensorList(tensors.data(), size);
return ACL_SUCCESS;
}
int main() {
// 1. (固定写法)device/stream初始化,参考acl API手册
// 根据自己的实际device填写deviceId
int32_t deviceId = 0;
aclrtStream stream;
auto ret = Init(deviceId, &stream);
// check根据自己的需要处理
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
// 2. 构造输入与输出,需要根据API的接口自定义构造
std::vector<std::vector<int64_t>> xShape = {{512, 256}};
std::vector<std::vector<int64_t>> weightShape= {{2, 256, 256}};
std::vector<std::vector<int64_t>> biasShape = {{2, 256}};
std::vector<std::vector<int64_t>> yShape = {{512, 256}};
std::vector<int64_t> groupListShape = {{2}};
std::vector<int64_t> groupListData = {256, 512};
void* xDeviceAddr[1];
void* weightDeviceAddr[1];
void* biasDeviceAddr[1];
void* yDeviceAddr[1];
void* groupListDeviceAddr;
aclTensorList* x = nullptr;
aclTensorList* weight = nullptr;
aclTensorList* bias = nullptr;
aclTensor* groupedList = nullptr;
aclTensorList* scale = nullptr;
aclTensorList* offset = nullptr;
aclTensorList* antiquantScale = nullptr;
aclTensorList* antiquantOffset = nullptr;
aclTensorList* perTokenScale = nullptr;
aclTensorList* activationInput = nullptr;
aclTensorList* activationQuantScale = nullptr;
aclTensorList* activationQuantOffset = nullptr;
aclTensorList* out = nullptr;
aclTensorList* activationFeatureOut = nullptr;
aclTensorList* dynQuantScaleOut = nullptr;
int64_t splitItem = 3;
int64_t groupType = 0;
int64_t groupListType = 0;
int64_t actType = 0;
// 创建x aclTensorList
ret = CreateAclTensorList(xShape, xDeviceAddr, aclDataType::ACL_FLOAT16, &x);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// 创建weight aclTensorList
ret = CreateAclTensorList(weightShape, weightDeviceAddr, aclDataType::ACL_FLOAT16, &weight);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// 创建bias aclTensorList
ret = CreateAclTensorList(biasShape, biasDeviceAddr, aclDataType::ACL_FLOAT16, &bias);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// 创建y aclTensorList
ret = CreateAclTensorList(yShape, yDeviceAddr, aclDataType::ACL_FLOAT16, &out);
CHECK_RET(ret == ACL_SUCCESS, return ret);
// 创建group_list aclTensor
ret = CreateAclTensor_New<int64_t>(groupListData, groupListShape, &groupListDeviceAddr, aclDataType::ACL_INT64, &groupedList);
CHECK_RET(ret == ACL_SUCCESS, return ret);
uint64_t workspaceSize = 0;
aclOpExecutor* executor;
// 3. 调用CANN算子库API
// 调用aclnnGroupedMatmulV4第一段接口
ret = aclnnGroupedMatmulV4GetWorkspaceSize(x, weight, bias, scale, offset, antiquantScale, antiquantOffset, perTokenScale, groupedList, activationInput, activationQuantScale, activationQuantOffset, splitItem, groupType, groupListType, actType, out, activationFeatureOut, dynQuantScaleOut, &workspaceSize, &executor);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGroupedMatmulGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
// 根据第一段接口计算出的workspaceSize申请device内存
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);
}
// 调用aclnnGroupedMatmulV4第二段接口
ret = aclnnGroupedMatmulV4(workspaceAddr, workspaceSize, executor, stream);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnGroupedMatmul 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. 获取输出的值,将Device侧内存上的结果拷贝至Host侧,需要根据具体API的接口定义修改
for (int i = 0; i < 1; i++) {
auto size = GetShapeSize(yShape[i]);
std::vector<uint16_t> resultData(size, 0);
ret = aclrtMemcpy(resultData.data(), size * sizeof(resultData[0]), yDeviceAddr[i],
size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
for (int64_t j = 0; j < size; j++) {
LOG_PRINT("result[%ld] is: %d\n", j, resultData[j]);
}
}
// 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改
aclDestroyTensorList(x);
aclDestroyTensorList(weight);
aclDestroyTensorList(bias);
aclDestroyTensorList(out);
// 7. 释放device资源,需要根据具体API的接口定义修改
for (int i = 0; i < 1; i++) {
aclrtFree(xDeviceAddr[i]);
aclrtFree(weightDeviceAddr[i]);
aclrtFree(biasDeviceAddr[i]);
aclrtFree(yDeviceAddr[i]);
}
if (workspaceSize > 0) {
aclrtFree(workspaceAddr);
}
aclrtDestroyStream(stream);
aclrtResetDevice(deviceId);
aclFinalize();
return 0;
}