已合并
WeightQuantBatchMatmulV2 Aclnn文档整改 #1550
sunduiyang创建于 2月5日
WeightQuantBatchMatmulV2 Aclnn文档整改 #1550
已合并
共 3 个文件变更+661-590
| @@ -1,5 +1,7 @@ | |||
| 1 | # aclnnWeightQuantBatchMatmulV2 | 1 | # aclnnWeightQuantBatchMatmulV2 |
| 2 | 2 | ||
| 3 | +[📄 查看源码](https://gitcode.com/cann/ops-nn/tree/master/matmul/weight_quant_batch_matmul_v2) | ||
| 4 | + | ||
| 3 | ## 产品支持情况 | 5 | ## 产品支持情况 |
| 4 | 6 | ||
| 5 | | 产品 | 是否支持 | | 7 | | 产品 | 是否支持 | |
| @@ -7,7 +9,9 @@ | |||
| 7 | | <term>Ascend 950PR/Ascend 950DT</term> | √ | | 9 | | <term>Ascend 950PR/Ascend 950DT</term> | √ | |
| 8 | | <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ | | 10 | | <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ | |
| 9 | | <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | | 11 | | <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ | |
| 10 | - | 12 | +| <term>Atlas 200I/500 A2 推理产品</term>| × | |
| 13 | +| <term>Atlas 推理系列产品</term>| √ | | ||
| 14 | +| <term>Atlas 训练系列产品</term>| × | | ||
| 11 | 15 | ||
| 12 | ## 功能说明 | 16 | ## 功能说明 |
| 13 | 17 | ||
| @@ -24,7 +28,13 @@ | |||
| 24 | ANTIQUANT(weight) = (weight + antiquantOffset) * antiquantScale | 28 | ANTIQUANT(weight) = (weight + antiquantOffset) * antiquantScale |
| 25 | $$ | 29 | $$ |
| 26 | 30 | ||
| 27 | - 当需要对输出进行量化处理时,其量化公式为 | 31 | + - 当不需要对输出进行量化操作时,其计算公式为 |
| 32 | + | ||
| 33 | + $$ | ||
| 34 | + y = x @ ANTIQUANT(weight) + bias | ||
| 35 | + $$ | ||
| 36 | + | ||
| 37 | + - 当需要对输出再进行量化处理时,其量化公式为 | ||
| 28 | 38 | ||
| 29 | $$ | 39 | $$ |
| 30 | \begin{aligned} | 40 | \begin{aligned} |
| @@ -33,12 +43,6 @@ | |||
| 33 | \end{aligned} | 43 | \end{aligned} |
| 34 | $$ | 44 | $$ |
| 35 | 45 | ||
| 36 | - 当不需要对输出再进行量化操作时,其计算公式为 | ||
| 37 | - | ||
| 38 | - $$ | ||
| 39 | - y = x @ ANTIQUANT(weight) + bias | ||
| 40 | - $$ | ||
| 41 | - | ||
| 42 | ## 函数原型 | 46 | ## 函数原型 |
| 43 | 47 | ||
| 44 | 每个算子分为[两段式接口](../../../docs/zh/context/两段式接口.md),必须先调用“aclnnWeightQuantBatchMatmulV2GetWorkspaceSize”接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用“aclnnWeightQuantBatchMatmulV2”接口执行计算。 | 48 | 每个算子分为[两段式接口](../../../docs/zh/context/两段式接口.md),必须先调用“aclnnWeightQuantBatchMatmulV2GetWorkspaceSize”接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用“aclnnWeightQuantBatchMatmulV2”接口执行计算。 |
| @@ -97,261 +101,198 @@ aclnnStatus aclnnWeightQuantBatchMatmulV2( | |||
| 97 | <tr> | 101 | <tr> |
| 98 | <td>x</td> | 102 | <td>x</td> |
| 99 | <td>输入</td> | 103 | <td>输入</td> |
| 100 | - <td>矩阵乘的左输入矩阵,公式中的输入`x`,device侧的aclTensor。</td> | 104 | + <td>矩阵乘的左输入矩阵,公式中的输入<code>x</code>,device侧的aclTensor。</td> |
| 101 | - <td></td> | 105 | + <td>-</td> |
| 102 | <td>FLOAT16、BFLOAT16</td> | 106 | <td>FLOAT16、BFLOAT16</td> |
| 103 | <td>ND</td> | 107 | <td>ND</td> |
| 104 | - <td>维度支持两维,shape支持(m, k),m表示矩阵第1维的大小,k表示矩阵的第2维的大小,其中Reduce维度k需要与`weight`的Reduce维度k大小相等。</td> | 108 | + <td>2维,shape支持(m, k)</td> |
| 105 | - <td>非连续的Tensor仅支持转置场景。</td> | 109 | + <td>仅转置场景支持</td> |
| 106 | </tr> | 110 | </tr> |
| 107 | <tr> | 111 | <tr> |
| 108 | <td>weight</td> | 112 | <td>weight</td> |
| 109 | <td>输入</td> | 113 | <td>输入</td> |
| 110 | - <td>矩阵乘的右输入矩阵,公式中的输入`weight`,device侧的aclTensor。</td> | 114 | + <td>矩阵乘的右输入矩阵,公式中的输入<code>weight</code>,device侧的aclTensor。</td> |
| 111 | - <td></td> | 115 | + <td>-</td> |
| 112 | - <td>INT8、INT4、FLOAT8_E4M3FN、HIFLOAT8、INT32、FLOAT、FLOAT4_E2M1</td> | 116 | + <td>INT8、INT4、FLOAT8_E4M3FN<sup>2</sup>、HIFLOAT8<sup>2</sup>、INT32、FLOAT<sup>2</sup>、FLOAT4_E2M1<sup>2</sup></td> |
| 113 | <td>ND、FRACTAL_NZ</td> | 117 | <td>ND、FRACTAL_NZ</td> |
| 114 | - <td>支持(k, n),其中k表示矩阵第1维的大小,n表示矩阵第2维的大小。<term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>:k、n大小在[1, 65535]范围内;<term>Ascend 950PR/Ascend 950DT</term>:k,n大小在[1, 2 ^ 31 - 1]。其中若数据类型为INT4或FLOAT4_E2M1,则weight的内轴应为偶数。</td> | 118 | + <td>2维,shape支持(k, n)</td> |
| 115 | - <td>非连续的Tensor仅支持转置场景。</td> | 119 | + <td>仅转置场景支持</td> |
| 116 | </tr> | 120 | </tr> |
| 117 | <tr> | 121 | <tr> |
| 118 | <td>antiquantScale</td> | 122 | <td>antiquantScale</td> |
| 119 | <td>输入</td> | 123 | <td>输入</td> |
| 120 | - <td>实现输入反量化计算的反量化scale参数,反量化公式中的输入`antiquantScale`。</td> | 124 | + <td>实现输入反量化计算的反量化scale参数,反量化公式中的输入<code>antiquantScale</code>。</td> |
| 121 | - <td></td> | 125 | + <td>-</td> |
| 122 | - <td>FLOAT16、BFLOAT16或FLOAT8_E8M0(仅涉及mx<a href="../../../docs/zh/context/量化介绍.md" target="_blank">量化模式</a>),非mx<a href="../../../docs/zh/context/量化介绍.md" target="_blank">量化模式</a>下,数据类型要求和输入`x`的数据类型保持一致。</td> | 126 | + <td>FLOAT16、BFLOAT16、FLOAT8_E8M0<sup>2</sup>、UINT64<sup>1</sup>、INT64<sup>1</sup></td> |
| 123 | <td>ND</td> | 127 | <td>ND</td> |
| 124 | - <td></td> | 128 | + <td>1-2维</td> |
| 125 | - <td></td> | 129 | + <td>仅转置场景支持</td> |
| 126 | </tr> | 130 | </tr> |
| 127 | <tr> | 131 | <tr> |
| 128 | <td>antiquantOffsetOptional</td> | 132 | <td>antiquantOffsetOptional</td> |
| 129 | - <td>输入</td> | 133 | + <td>可选输入</td> |
| 130 | - <td>实现输入反量化计算的反量化offset参数,反量化公式中的`antiquantOffset`,device侧的aclTensor。</td> | 134 | + <td>实现输入反量化计算的反量化offset参数,反量化公式中的<code>antiquantOffset</code>,device侧的aclTensor。</td> |
| 131 | <td>可选输入, 当不需要时为空指针。</td> | 135 | <td>可选输入, 当不需要时为空指针。</td> |
| 132 | - <td></td> | 136 | + <td>FLOAT16、BFLOAT16、INT32<sup>1</sup></td> |
| 133 | <td>ND</td> | 137 | <td>ND</td> |
| 134 | - <td>要求与`antiquantScale`一致。</td> | 138 | + <td>要求与<code>antiquantScale</code>一致。</td> |
| 135 | - <td></td> | 139 | + <td>仅转置场景支持</td> |
| 136 | </tr> | 140 | </tr> |
| 137 | <tr> | 141 | <tr> |
| 138 | <td>quantScaleOptional</td> | 142 | <td>quantScaleOptional</td> |
| 139 | - <td>输入</td> | 143 | + <td>可选输入</td> |
| 140 | <td>实现输出量化计算的量化参数,device侧的aclTensor。</td> | 144 | <td>实现输出量化计算的量化参数,device侧的aclTensor。</td> |
| 141 | - <td>由量化公式中的`quantScale`和`quantOffset`的数据通过`aclnnTransQuantParam`接口转化得到。</td> | 145 | + <td>由量化公式中的<code>quantScale</code>和<code>quantOffset</code>的数据通过<code>aclnnTransQuantParam</code>接口转化得到。不需要时为空指针。</td> |
| 142 | - <td></td> | 146 | + <td>UINT64<sup>1</sup></td> |
| 143 | <td>ND</td> | 147 | <td>ND</td> |
| 144 | - <td></td> | 148 | + <td>1-2维</td> |
| 145 | - <td></td> | 149 | + <td>不支持</td> |
| 146 | </tr> | 150 | </tr> |
| 147 | <tr> | 151 | <tr> |
| 148 | <td>quantOffsetOptional</td> | 152 | <td>quantOffsetOptional</td> |
| 149 | - <td>输入</td> | 153 | + <td>可选输入</td> |
| 150 | - <td>实现输出量化计算的量化offset参数,量化公式中的`quantOffset`,device侧的aclTensor。</td> | 154 | + <td>实现输出量化计算的量化offset参数,量化公式中的<code>quantOffset</code>,device侧的aclTensor。</td> |
| 151 | - <td></td> | 155 | + <td>可选输入, 不需要时为空指针。</td> |
| 152 | - <td></td> | 156 | + <td>FLOAT<sup>1</sup></td> |
| 153 | <td>ND</td> | 157 | <td>ND</td> |
| 154 | - <td></td> | 158 | + <td>要求与<code>quantScaleOptional</code>一致</td> |
| 155 | - <td></td> | 159 | + <td>不支持</td> |
| 156 | </tr> | 160 | </tr> |
| 157 | <tr> | 161 | <tr> |
| 158 | <td>biasOptional</td> | 162 | <td>biasOptional</td> |
| 159 | - <td>输入</td> | 163 | + <td>可选输入</td> |
| 160 | - <td>偏置输入,公式中的`bias`,device侧的aclTensor。</td> | 164 | + <td>偏置输入,公式中的<code>bias</code>,device侧的aclTensor。</td> |
| 161 | <td>可选输入, 当不需要时为空指针。</td> | 165 | <td>可选输入, 当不需要时为空指针。</td> |
| 162 | - <td></td> | 166 | + <td>FLOAT16、FLOAT、BFLOAT16<sup>2</sup></td> |
| 163 | <td>ND</td> | 167 | <td>ND</td> |
| 164 | - <td></td> | 168 | + <td>1-2维</td> |
| 165 | <td>不支持</td> | 169 | <td>不支持</td> |
| 166 | </tr> | 170 | </tr> |
| 167 | <tr> | 171 | <tr> |
| 168 | <td>antiquantGroupSize</td> | 172 | <td>antiquantGroupSize</td> |
| 169 | <td>输入</td> | 173 | <td>输入</td> |
| 170 | - <td>表示在伪量化pergroup和mx<a href="../../../docs/zh/context/量化介绍.md" target="_blank">量化模式</a>下,对输入`weight`进行反量化计算的groupSize输入,描述一组反量化参数对应的待反量化数据量在Reduce方向的大小。当伪量化算法不为pergroup和mx<a href="../../../docs/zh/context/量化介绍.md" target="_blank">量化模式</a>时传入0;当伪量化算法为pergroup<a href="../../../docs/zh/context/量化介绍.md" target="_blank">量化模式</a>时传入值的范围为[32, k-1]且值要求是32的倍数;在mx<a href="../../../docs/zh/context/量化介绍.md" target="_blank">量化模式</a>,仅支持32。</td> | 174 | + <td>表示在伪量化pergroup和mx<a href="../../../docs/zh/context/量化介绍.md" target="_blank">量化模式</a>下,对输入<code>weight</code>进行反量化计算的groupSize输入,描述一组反量化参数对应的待反量化数据量在Reduce方向的大小。</td> |
| 171 | - <td></td> | 175 | + <td>当伪量化算法不为pergroup和mx<a href="../../../docs/zh/context/量化介绍.md" target="_blank">量化模式</a>时传入0;当伪量化算法为pergroup<a href="../../../docs/zh/context/量化介绍.md" target="_blank">量化模式</a>时传入值的范围为[32, k-1]且值要求是32的倍数;在mx<a href="../../../docs/zh/context/量化介绍.md" target="_blank">量化模式</a>,仅支持32。</td> |
| 172 | - <td></td> | 176 | + <td>-</td> |
| 173 | - <td></td> | 177 | + <td>-</td> |
| 174 | - <td></td> | 178 | + <td>-</td> |
| 175 | - <td></td> | 179 | + <td>-</td> |
| 176 | </tr> | 180 | </tr> |
| 177 | <tr> | 181 | <tr> |
| 178 | <td>y</td> | 182 | <td>y</td> |
| 179 | <td>输出</td> | 183 | <td>输出</td> |
| 180 | - <td>计算输出,公式中的`y`,device侧的aclTensor。</td> | 184 | + <td>计算输出,公式中的<code>y</code>,device侧的aclTensor。</td> |
| 181 | - <td></td> | 185 | + <td>-</td> |
| 182 | - <td></td> | 186 | + <td>FLOAT16、BFLOAT16、INT8<sup>1</sup></td> |
| 183 | <td>ND</td> | 187 | <td>ND</td> |
| 184 | - <td></td> | 188 | + <td>2维</td> |
| 185 | <td>不支持</td> | 189 | <td>不支持</td> |
| 186 | </tr> | 190 | </tr> |
| 187 | <tr> | 191 | <tr> |
| 188 | <td>workspaceSize</td> | 192 | <td>workspaceSize</td> |
| 189 | <td>输出</td> | 193 | <td>输出</td> |
| 190 | <td>返回需要在Device侧申请的workspace大小。</td> | 194 | <td>返回需要在Device侧申请的workspace大小。</td> |
| 191 | - <td></td> | 195 | + <td>-</td> |
| 192 | - <td></td> | 196 | + <td>-</td> |
| 193 | - <td></td> | 197 | + <td>-</td> |
| 194 | - <td></td> | 198 | + <td>-</td> |
| 195 | - <td></td> | 199 | + <td>-</td> |
| 196 | </tr> | 200 | </tr> |
| 197 | <tr> | 201 | <tr> |
| 198 | <td>executor</td> | 202 | <td>executor</td> |
| 199 | <td>输出</td> | 203 | <td>输出</td> |
| 200 | <td>返回op执行器,包含了算子计算流程。</td> | 204 | <td>返回op执行器,包含了算子计算流程。</td> |
| 201 | - <td></td> | 205 | + <td>-</td> |
| 202 | - <td></td> | 206 | + <td>-</td> |
| 203 | - <td></td> | 207 | + <td>-</td> |
| 204 | - <td></td> | 208 | + <td>-</td> |
| 205 | - <td></td> | 209 | + <td>-</td> |
| 206 | </tr> | 210 | </tr> |
| 207 | </tbody> | 211 | </tbody> |
| 208 | </table> | 212 | </table> |
| 209 | 213 | ||
| 210 | - - x(aclTensor *, 计算输入): | 214 | + - <term>Ascend 950PR/Ascend 950DT</term>: |
| 211 | - - <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>:`x`矩阵为非转置时,m大小在[1, 2^31-1]范围内;转置时,m大小在[1, 65535]范围内。 | ||
| 212 | - - <term>Ascend 950PR/Ascend 950DT</term>:`x`矩阵m大小在[1, 2^31-1]范围内,不支持转置场景。 | ||
| 213 | - - <term>Atlas 推理系列产品</term>:数据类型支持FLOAT16。shape支持2~6维,输入shape需要为(batch, m, k),其中batch表示矩阵的批次大小,支持0~4维,m表示单个batch矩阵第1维的大小,k表示单个batch矩阵的第2维的大小,batch维度需要与`weight`的batch维度满足[broadcast关系](../../../docs/zh/context/broadcast关系.md)。当伪量化算法模式为pertensor[量化模式](../../../docs/zh/context/量化介绍.md)时,m*k不能超过512000000。 | ||
| 214 | 215 | ||
| 215 | - - weight(aclTensor *, 计算输入): | 216 | + - 上表数据类型列中的角标“1”代表该系列不支持的数据类型; |
| 216 | - - <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>:维度支持2维,Reduce维度k需要与`x`的Reduce维度k大小相等。数据类型支持INT8、INT4、INT32,当`weight`[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ且数据类型为INT4或INT32时,或者当`weight`[数据格式](../../../docs/zh/context/数据格式.md)为ND且数据类型为INT32时,仅在INT4Pack场景支持,需配合`aclnnConvertWeightToINT4Pack`接口完成从INT32到INT4Pack的转换,以及从ND到FRACTAL_NZ的转换,[详情可参考样例](../../convert_weight_to_int4_pack/docs/aclnnConvertWeightToINT4Pack.md),若数据类型为INT4,则`weight`的内轴应为偶数。[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)仅支持转置场景。shape支持(k, n),其中k表示矩阵第1维的大小,n表示矩阵第2维的大小。 | ||
| 217 | - 对于不同伪量化算法模式,`weight`的[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ仅在如下场景下支持: | ||
| 218 | - - perchannel[量化模式](../../../docs/zh/context/量化介绍.md): | ||
| 219 | - - `weight`的数据类型为INT8,y的数据类型为非INT8。 | ||
| 220 | - - `weight`的数据类型为INT4/INT32,`weight`转置,y的数据类型为非INT8。 | ||
| 221 | - - pergroup[量化模式](../../../docs/zh/context/量化介绍.md):`weight`的数据类型为INT4/INT32,`weight`非转置,`x`非转置,antiquantGroupSize为64或128,k为antiquantGroupSize对齐,n为64对齐,y的数据类型为非INT8。 | ||
| 222 | - - <term>Ascend 950PR/Ascend 950DT</term>:维度支持2维,Reduce维度k需要与`x`的Reduce维度k大小相等。数据类型支持INT8、INT4、FLOAT8_E4M3FN、HIFLOAT8、INT32。shape支持(k, n),其中k表示矩阵第1维的大小,n表示矩阵第2维的大小。k、n大小在[1, 65535]范围内。k、n要求32B对齐。其中若数据类型为INT8,FLOAT8_E4M3FN、HIFLOAT8、FLOAT、FLOAT4_E2M1,则k、n大小在[1,2^31-1]范围内,k、n不要求32B对齐。其中若数据类型为INT4或FLOAT4_E2M1,则weight的内轴应为偶数。[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)仅支持转置场景。 | ||
| 223 | - - 数据类型为INT32/FLOAT时,必须配合aclnnConvertWeightToINT4Pack接口完成从INT32/FLOAT到紧密排布的INT4/FLOAT4_E2M1的转换,[详情可参考样例](../../convert_weight_to_int4_pack/docs/aclnnConvertWeightToINT4Pack.md)。 | ||
| 224 | - - 数据类型为FLOAT/FLOAT4_E2M1时,仅支持pergroup[量化模式](../../../docs/zh/context/量化介绍.md)和mx[量化模式](../../../docs/zh/context/量化介绍.md),pergroup[量化模式](../../../docs/zh/context/量化介绍.md)下,要求`antiquantScale`与`x`的数据类型相同,mx[量化模式](../../../docs/zh/context/量化介绍.md)下,要求`antiquantScale`类型为FLOAT8_E8M0类型,且不支持antiquantOffsetOptional输入,且antiquantGroupSize仅支持32。 | ||
| 225 | - - 数据类型为FLOAT8_E4M3FN、HIFLOAT8时,只支持perchannel[量化模式](../../../docs/zh/context/量化介绍.md)。 | ||
| 226 | 217 | ||
| 227 | - 对于不同伪量化算法模式,`weight`的[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ仅在如下场景下支持: | 218 | + - <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>: |
| 228 | - - perchannel[量化模式](../../../docs/zh/context/量化介绍.md):`weight`的数据类型为INT4/INT32,`weight`非转置,`x`非转置,y的数据类型为非INT8。 | ||
| 229 | - - pergroup[量化模式](../../../docs/zh/context/量化介绍.md):`weight`的数据类型为INT4/INT32/FLOAT4_E2M1/FLOAT,`weight`非转置,`x`非转置,k为64对齐,n为64对齐,y的数据类型为非INT8。 | ||
| 230 | - - mx[量化模式](../../../docs/zh/context/量化介绍.md):`weight`的数据类型为FLOAT4_E2M1/FLOAT,`weight`非转置,`x`非转置,y的数据类型为非INT8。 | ||
| 231 | - - <term>Atlas 推理系列产品</term>:维度支持2~6维,batch维度需要与`x`的batch维度满足[broadcast关系](../../../docs/zh/context/broadcast关系.md),数据类型支持INT8。具体如下: | ||
| 232 | - - 当[数据格式](../../../docs/zh/context/数据格式.md)为ND时,输入shape需要为(batch, k, n),其中batch表示矩阵的批次大小,支持0~4维,k表示单个batch矩阵第1维的大小,n表示单个batch矩阵的第2维的大小。 | ||
| 233 | - - 当[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ时: | ||
| 234 | - - 输入shape需要为(batch, n, k),其中batch表示矩阵的批次大小,支持0~4维,k表示单个batch矩阵第1维的大小,n表示单个batch矩阵的第2维的大小。 | ||
| 235 | - - 配合aclnnCalculateMatmulWeightSizeV2以及aclnnTransMatmulWeight完成输入Format从ND到FRACTAL_NZ的转换,[详情可参考样例](../../trans_mat_mul_weight/docs/aclnnCalculateMatmulWeightSizeV2.md)。 | ||
| 236 | 219 | ||
| 237 | - - antiquantScale(aclTensor *, 计算输入): | 220 | + - 上表数据类型列中的角标“2”代表该系列不支持的数据类型。 |
| 238 | - - <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>:数据类型支持FLOAT16、BFLOAT16、UINT64、INT64(当FLOAT16、BFLOAT16时,数据类型要求和输入`x`保持一致;当为UINT64、INT64时,`x`仅支持FLOAT16,不转置,`weight`仅支持INT8,ND转置,模式仅支持perchannel[量化模式](../../../docs/zh/context/量化介绍.md),quantScaleOptional和quantOffsetOptional必须传入空指针,m仅支持[1, 96],k和n要求64对齐,需要首先配合aclnnCast接口完成FLOAT16到FLOAT32的转换,详情请参考[Cast](https://gitcode.com/cann/ops-math/blob/master/math/cast/docs/aclnnCast.md),再配合aclnnTransQuantParamV2接口完成FLOAT32到UINT64的转换,详情请参考[TransQuantParamV2](../../../quant/trans_quant_param_v2/docs/aclnnTransQuantParamV2.md))。[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)仅支持转置场景。 | ||
| 239 | - 对于不同伪量化算法模式,`antiquantScale`支持的shape如下: | ||
| 240 | - - pertensor[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(1,)或(1, 1)。 | ||
| 241 | - - perchannel[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(1, n)或(n,)。 | ||
| 242 | - - pergroup[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(⌈k/group_size⌉, n),其中group_size表示k要分组的每组的大小。 | ||
| 243 | - - <term>Ascend 950PR/Ascend 950DT</term>:数据类型支持FLOAT16、BFLOAT16或FLOAT8_E8M0(仅涉及mx[量化模式](../../../docs/zh/context/量化介绍.md)),非mx[量化模式](../../../docs/zh/context/量化介绍.md)下,数据类型要求和输入`x`的数据类型保持一致。[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)仅支持转置场景并且连续性要求和weight保持一致。 | ||
| 244 | - 对于不同伪量化算法模式,`antiquantScale`支持的shape如下: | ||
| 245 | - - pertensor[量化模式](../../../docs/zh/context/量化介绍.md):(1,)或(1,1)。 | ||
| 246 | - - perchannel[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(1, n)或(n,)。 | ||
| 247 | - - pergroup[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(⌈k/group_size⌉, n),其中group_size表示k要分组的每组的大小。 | ||
| 248 | - - mx[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(⌈k/group_size⌉, n),其中group_size表示k要分组的每组的大小,仅支持32。 | ||
| 249 | - - <term>Atlas 推理系列产品</term>:数据类型支持FLOAT16,数据类型要求和输入`x`保持一致。 | ||
| 250 | - 对于不同伪量化算法模式,`antiquantScale`支持的shape如下: | ||
| 251 | - - pertensor[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(1,)或(1, 1)。 | ||
| 252 | - - perchannel[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(n, 1)或(n,),不支持[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)。 | ||
| 253 | - - pergroup[量化模式](../../../docs/zh/context/量化介绍.md):输入shape与`weight`的数据格式相关,如下: | ||
| 254 | - - 当`weight`的数据格式为ND时,输入shape为(⌈k/group_size⌉, n),其中group_size表示k要分组的每组的大小。 | ||
| 255 | - - 当`weight`的数据格式为FRACTAL_NZ时,输入shape为(n, ⌈k/group_size⌉),其中group_size表示k要分组的每组的大小。 | ||
| 256 | 221 | ||
| 257 | - - antiquantOffsetOptional(aclTensor *, 计算输入): | 222 | + - <term>Atlas 推理系列产品</term>: |
| 258 | - - <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>:数据类型支持FLOAT16、BFLOAT16、INT32,数据类型为FLOAT16、BFLOAT16时,数据类型要求和输入`x`的数据类型保持一致;数据类型为INT32类型时,数据范围限制为[-128, 127],x仅支持FLOAT16,weight仅支持INT8,`antiquantScale`仅支持UINT64/INT64。[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)仅支持转置场景。 | ||
| 259 | - - <term>Ascend 950PR/Ascend 950DT</term>:数据类型支持FLOAT16、BFLOAT16,数据类型要求和输入`x`的数据类型保持一致。[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)仅支持转置场景并且连续性要求和weight保持一致。当x是FLOAT16或者BFLOAT16,同时weight是FLOAT、FLOAT4_E2M1、FLOAT8_E4M3FN或者HIFLOAT8时,不支持该参数,填空指针。 | ||
| 260 | - - <term>Atlas 推理系列产品</term>:数据类型支持FLOAT16,数据类型要求和输入`x`保持一致。 | ||
| 261 | 223 | ||
| 262 | - - quantScaleOptional(aclTensor *, 计算输入): | 224 | + - 上表数据类型列中的角标“3”代表该系列不支持的数据类型。 |
| 263 | - - <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>:数据类型支持UINT64,[数据格式](../../../docs/zh/context/数据格式.md)支持ND。不支持[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)。可选输入,当不需要时为空指针;对于不同的伪量化算法模式,支持的shape如下: | ||
| 264 | - - pertensor[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(1,)或(1, 1)。 | ||
| 265 | - - perchannel[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(1, n)或(n,)。 | ||
| 266 | - - <term>Ascend 950PR/Ascend 950DT</term>:预留参数,暂未使用,固定传入空指针。 | ||
| 267 | - - <term>Atlas 推理系列产品</term>:预留参数,暂未使用,固定传入空指针。 | ||
| 268 | - | ||
| 269 | - - quantOffsetOptional(aclTensor *, 计算输入): | ||
| 270 | - - <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>:数据类型支持FLOAT,[数据格式](../../../docs/zh/context/数据格式.md)支持ND。可选输入, 当不需要时为空指针;存在时shape要求与`quantScaleOptional`一致。不支持[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)。 | ||
| 271 | - - <term>Ascend 950PR/Ascend 950DT</term>:预留参数,暂未使用,固定传入空指针。 | ||
| 272 | - - <term>Atlas 推理系列产品</term>:预留参数,暂未使用,固定传入空指针。 | ||
| 273 | - | ||
| 274 | - - biasOptional(aclTensor *, 计算输入): | ||
| 275 | - - <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>:维度支持1维或2维,shape支持(n,)或(1, n)。数据类型支持FLOAT16、FLOAT。当`x`的数据类型为BFLOAT16时,本参数要求为FLOAT;当`x`的数据类型为FLOAT16时,本参数要求为FLOAT16。 | ||
| 276 | - - <term>Ascend 950PR/Ascend 950DT</term>:维度支持1维或2维,shape支持(n,)或(1, n)。数据类型支持FLOAT16、FLOAT、BFLOAT16。当`x`的数据类型为BFLOAT16时,本参数要求为FLOAT或BFLOAT16;当`x`的数据类型为FLOAT16时,本参数要求为FLOAT16。当`x`的数据类型为BFLOAT16时,同时`weight`类型为FLOAT4_E2M1、FLOAT8_E4M3FN、HIFLOAT8时,本参数要求为BFLOAT16。 | ||
| 277 | - - <term>Atlas 推理系列产品</term>:数据类型支持FLOAT16。维度支持1~6维,带batch时,输入shape需要为(batch,1,n),batch要与x和weight的batch维度broadcast后的batch保持一致,不带batch时,输入shape需要为(n,)或(1, n)。 | ||
| 278 | - | ||
| 279 | - - antiquantGroupSize(int, 计算输入):表示在伪量化pergroup和mx[量化模式](../../../docs/zh/context/量化介绍.md)下,对输入`weight`进行反量化计算的groupSize输入,描述一组反量化参数对应的待反量化数据量在Reduce方向的大小。当伪量化算法不为pergroup和mx[量化模式](../../../docs/zh/context/量化介绍.md)时传入0;当伪量化算法为pergroup[量化模式](../../../docs/zh/context/量化介绍.md)时传入值的范围为[32, k-1]且值要求是32的倍数;在mx[量化模式](../../../docs/zh/context/量化介绍.md),仅支持32。 | ||
| 280 | - | ||
| 281 | - - y(aclTensor *, 计算输出): | ||
| 282 | - - <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>:维度支持2维,shape支持(m, n)。数据类型支持FLOAT16、BFLOAT16、INT8。当`quantScaleOptional`存在时,数据类型为INT8;当`quantScaleOptional`不存在时,数据类型支持FLOAT16、BFLOAT16,且与输入`x`的数据类型一致。 | ||
| 283 | - - <term>Ascend 950PR/Ascend 950DT</term>:维度支持2维,shape支持(m, n)。数据类型支持FLOAT16、BFLOAT16。当`quantScaleOptional`不存在时,与输入`x`的数据类型一致。 | ||
| 284 | - - <term>Atlas 推理系列产品</term>:数据类型支持FLOAT16。维度支持2~6维,shape支持(batch, m, n),batch可不存在,支持x与weight的batch维度broadcast,输出batch与broadcast之后的batch一致,m与x的m一致,n与weight的n一致。 | ||
| 285 | 225 | ||
| 286 | - **返回值:** | 226 | - **返回值:** |
| 287 | 227 | ||
| 288 | aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/zh/context/aclnn返回码.md)。 | 228 | aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/zh/context/aclnn返回码.md)。 |
| 289 | 229 | ||
| 290 | -<table style="undefined;table-layout: fixed;width: 1030px"> | 230 | + 第一段接口完成入参校验,出现以下场景时报错: |
| 291 | - <colgroup> | 231 | + <table style="undefined;table-layout: fixed;width: 1030px"> |
| 292 | - <col style="width: 250px"> | 232 | + <colgroup> |
| 293 | - <col style="width: 130px"> | 233 | + <col style="width: 250px"> |
| 294 | - <col style="width: 650px"> | 234 | + <col style="width: 130px"> |
| 295 | - </colgroup> | 235 | + <col style="width: 650px"> |
| 296 | - <thead> | 236 | + </colgroup> |
| 297 | - <tr> | 237 | + <thead> |
| 298 | - <th>返回值</th> | 238 | + <tr> |
| 299 | - <th>错误码</th> | 239 | + <th>返回值</th> |
| 300 | - <th>描述</th> | 240 | + <th>错误码</th> |
| 301 | - </tr></thead> | 241 | + <th>描述</th> |
| 302 | - <tbody> | 242 | + </tr></thead> |
| 303 | - <tr> | 243 | + <tbody> |
| 304 | - <td>ACLNN_ERR_PARAM_NULLPTR</td> | 244 | + <tr> |
| 305 | - <td>161001</td> | 245 | + <td>ACLNN_ERR_PARAM_NULLPTR</td> |
| 306 | - <td>如果必选参数传入的是空指针。</td> | 246 | + <td>161001</td> |
| 307 | - </tr> | 247 | + <td>如果必选参数传入的是空指针。</td> |
| 308 | - <tr> | 248 | + </tr> |
| 309 | - <td rowspan="13">ACLNN_ERR_PARAM_INVALID</td> | 249 | + <tr> |
| 310 | - <td rowspan="13">161002</td> | 250 | + <td rowspan="13">ACLNN_ERR_PARAM_INVALID</td> |
| 311 | - <td>传入x、weight、antiquantScale、antiquantOffsetOptional、quantScaleOptional、quantOffsetOptional、biasOptional、y的shape维度不符合要求。</td> | 251 | + <td rowspan="13">161002</td> |
| 312 | - </tr> | 252 | + <td>传入x、weight、antiquantScale、antiquantOffsetOptional、quantScaleOptional、quantOffsetOptional、biasOptional、y的shape维度不符合要求。</td> |
| 313 | - <tr> | 253 | + </tr> |
| 314 | - <td>传入x、weight、antiquantScale、antiquantOffsetOptional、quantScaleOptional、quantOffsetOptional、biasOptional、y的数据类型不在支持的范围之内。</td> | 254 | + <tr> |
| 315 | - </tr> | 255 | + <td>传入x、weight、antiquantScale、antiquantOffsetOptional、quantScaleOptional、quantOffsetOptional、biasOptional、y的数据类型不在支持的范围之内。</td> |
| 316 | - <tr> | 256 | + </tr> |
| 317 | - <td>x、weight的reduce维度(k)不相等。</td> | 257 | + <tr> |
| 318 | - </tr> | 258 | + <td>x、weight的reduce维度(k)不相等。</td> |
| 319 | - <tr> | 259 | + </tr> |
| 320 | - <td>antiquantOffsetOptional存在输入时,shape与antiquantScale不相同。</td> | 260 | + <tr> |
| 321 | - </tr> | 261 | + <td>antiquantOffsetOptional存在输入时,shape与antiquantScale不相同。</td> |
| 322 | - <tr> | 262 | + </tr> |
| 323 | - <td>quantOffsetOptional存在输入时,shape与quantScale不相同。</td> | 263 | + <tr> |
| 324 | - </tr> | 264 | + <td>quantOffsetOptional存在输入时,shape与quantScale不相同。</td> |
| 325 | - <tr> | 265 | + </tr> |
| 326 | - <td>biasOptional的shape不符合要求。</td> | 266 | + <tr> |
| 327 | - </tr> | 267 | + <td>biasOptional的shape不符合要求。</td> |
| 328 | - <tr> | 268 | + </tr> |
| 329 | - <td>antiquantGroupSize值不符合要求。</td> | 269 | + <tr> |
| 330 | - </tr> | 270 | + <td>antiquantGroupSize值不符合要求。</td> |
| 331 | - <tr> | 271 | + </tr> |
| 332 | - <td>quantOffsetOptional存在时,quantScaleOptional是空指针。</td> | 272 | + <tr> |
| 333 | - </tr> | 273 | + <td>quantOffsetOptional存在时,quantScaleOptional是空指针。</td> |
| 334 | - <tr> | 274 | + </tr> |
| 335 | - <td>输入的k、n值不在[1, 65535]范围内。</td> | 275 | + <tr> |
| 336 | - </tr> | 276 | + <td>输入的k、n值不在[1, 65535]范围内。</td> |
| 337 | - <tr> | 277 | + </tr> |
| 338 | - <td>x矩阵为非转置时,m不在[1, 2^31-1]范围内;转置时,m不在[1, 65535]范围内。</td> | 278 | + <tr> |
| 339 | - </tr> | 279 | + <td>x矩阵为非转置时,m不在[1, 2^31-1]范围内;转置时,m不在[1, 65535]范围内。</td> |
| 340 | - <tr> | 280 | + </tr> |
| 341 | - <td>不支持空tensor场景。</td> | 281 | + <tr> |
| 342 | - </tr> | 282 | + <td>不支持空tensor场景。</td> |
| 343 | - <tr> | 283 | + </tr> |
| 344 | - <td>传入x、weight、antiquantScale、antiquantOffsetOptional、quantScaleOptional、quantOffsetOptional、biasOptional、y的连续性不符合要求。</td> | 284 | + <tr> |
| 345 | - </tr> | 285 | + <td>传入x、weight、antiquantScale、antiquantOffsetOptional、quantScaleOptional、quantOffsetOptional、biasOptional、y的连续性不符合要求。</td> |
| 346 | - <tr> | 286 | + </tr> |
| 347 | - <td>x为bfloat16,weight为float4_e2m1或者float32时,bias数据类型只支持bfloat16。</td> | 287 | + <tr> |
| 348 | - </tr> | 288 | + <td>x为bfloat16,weight为float4_e2m1或者float32时,bias数据类型只支持bfloat16。</td> |
| 349 | - <tr> | 289 | + </tr> |
| 350 | - <td>ACLNN_ERR_RUNTIME_ERROR</td> | 290 | + <tr> |
| 351 | - <td>361001</td> | 291 | + <td>ACLNN_ERR_RUNTIME_ERROR</td> |
| 352 | - <td>产品型号不支持。</td> | 292 | + <td>361001</td> |
| 353 | - </tr> | 293 | + <td>产品型号不支持。</td> |
| 354 | - </tbody> | 294 | + </tr> |
| 295 | + </tbody> | ||
| 355 | </table> | 296 | </table> |
| 356 | 297 | ||
| 357 | ## aclnnWeightQuantBatchMatmulV2 | 298 | ## aclnnWeightQuantBatchMatmulV2 |
| @@ -373,244 +314,363 @@ aclnnStatus aclnnWeightQuantBatchMatmulV2( | |||
| 373 | 314 | ||
| 374 | aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/zh/context/aclnn返回码.md)。 | 315 | aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/zh/context/aclnn返回码.md)。 |
| 375 | 316 | ||
| 376 | - | ||
| 377 | ## 约束说明 | 317 | ## 约束说明 |
| 378 | -- 确定性说明: | 318 | +- 确定性说明:aclnnWeightQuantBatchMatmulV2默认非确定性实现,支持通过aclrtCtxSetSysParamOpt开启确定性。 |
| 379 | - - <term>Atlas 训练系列产品</term>、<term>Atlas 推理系列产品</term>:aclnnWeightQuantBatchMatmulV2默认非确定性实现,支持通过aclrtCtxSetSysParamOpt开启确定性。 | ||
| 380 | - - <term>Ascend 950PR/Ascend 950DT</term>: aclnnWeightQuantBatchMatmulV2默认非确定性实现,支持通过aclrtCtxSetSysParamOpt开启确定性。 | ||
| 381 | 319 | ||
| 382 | -性能优化建议: | 320 | +<a id="a2_a3_系列产品"></a> |
| 383 | -- <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>: | ||
| 384 | - - pertensor[量化模式](../../../docs/zh/context/量化介绍.md):当[数据格式](../../../docs/zh/context/数据格式.md)为ND时,推荐使用转置后的`weight`输入;当[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ时,推荐使用非转置的`weight`输入。 | ||
| 385 | - - pergroup[量化模式](../../../docs/zh/context/量化介绍.md):推荐使用非转置的weight输入。 | ||
| 386 | - - perchannel[量化模式](../../../docs/zh/context/量化介绍.md):当[数据格式](../../../docs/zh/context/数据格式.md)为ND时,推荐使用转置后的`weight`输入;当[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ时,推荐使用非转置的`weight`输入。m范围为[65, 96]时,推荐使用数据类型为UINT64或INT64的antiquantScale。 | ||
| 387 | 321 | ||
| 388 | -- <term>Ascend 950PR/Ascend 950DT</term>: | 322 | +<details> |
| 389 | - - pertensor[量化模式](../../../docs/zh/context/量化介绍.md):当[数据格式](../../../docs/zh/context/数据格式.md)为ND时,推荐使用转置后的`weight`输入;当[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ时,推荐使用非转置的`weight`输入。 | 323 | +<summary><term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term>、<term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term></summary> |
| 390 | - - perchannel[量化模式](../../../docs/zh/context/量化介绍.md):当[数据格式](../../../docs/zh/context/数据格式.md)为ND时,推荐使用转置后的`weight`输入;当[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ时,推荐使用非转置的`weight`输入。 | 324 | + |
| 391 | - - pergroup[量化模式](../../../docs/zh/context/量化介绍.md)和mx[量化模式](../../../docs/zh/context/量化介绍.md):推荐使用非转置的`weight`输入。 | 325 | + - `x`(aclTensor *, 计算输入):矩阵为非转置时,m大小在[1, 2^31-1]范围内;转置时,m大小在[1, 65535]范围内。 |
| 326 | + - `weight`(aclTensor *, 计算输入):维度支持2维,Reduce维度k需要与`x`的Reduce维度k大小相等。数据类型支持INT8、INT4、INT32,当`weight`[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ且数据类型为INT4或INT32时,或者当`weight`[数据格式](../../../docs/zh/context/数据格式.md)为ND且数据类型为INT32时,仅在INT4Pack场景支持,需配合`aclnnConvertWeightToINT4Pack`接口完成从INT32到INT4Pack的转换,以及从ND到FRACTAL_NZ的转换,[详情可参考样例](../../convert_weight_to_int4_pack/docs/aclnnConvertWeightToINT4Pack.md),若数据类型为INT4,则`weight`的内轴应为偶数。[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)仅支持转置场景。shape支持(k, n),其中k表示矩阵第1维的大小,n表示矩阵第2维的大小。 | ||
| 327 | + 对于不同伪量化算法模式,`weight`的[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ仅在如下场景下支持: | ||
| 328 | + - perchannel[量化模式](../../../docs/zh/context/量化介绍.md): | ||
| 329 | + - `weight`的数据类型为INT8,y的数据类型为非INT8。 | ||
| 330 | + - `weight`的数据类型为INT4/INT32,`weight`转置,y的数据类型为非INT8。 | ||
| 331 | + - pergroup[量化模式](../../../docs/zh/context/量化介绍.md):`weight`的数据类型为INT4/INT32,`weight`非转置,`x`非转置,antiquantGroupSize为64或128,k为antiquantGroupSize对齐,n为64对齐,y的数据类型为非INT8。 | ||
| 332 | + - `antiquantScale`(aclTensor *, 计算输入):数据类型支持FLOAT16、BFLOAT16、UINT64、INT64(当FLOAT16、BFLOAT16时,数据类型要求和输入`x`保持一致;当为UINT64、INT64时,`x`仅支持FLOAT16,不转置,`weight`仅支持INT8,ND转置,模式仅支持perchannel[量化模式](../../../docs/zh/context/量化介绍.md),quantScaleOptional和quantOffsetOptional必须传入空指针,m仅支持[1, 96],k和n要求64对齐,需要首先配合aclnnCast接口完成FLOAT16到FLOAT32的转换,详情请参考[Cast](https://gitcode.com/cann/ops-math/blob/master/math/cast/docs/aclnnCast.md),再配合aclnnTransQuantParamV2接口完成FLOAT32到UINT64的转换,详情请参考[TransQuantParamV2](../../../quant/trans_quant_param_v2/docs/aclnnTransQuantParamV2.md))。[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)仅支持转置场景。 | ||
| 333 | + 对于不同伪量化算法模式,`antiquantScale`支持的shape如下: | ||
| 334 | + - pertensor[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(1,)或(1, 1)。 | ||
| 335 | + - perchannel[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(1, n)或(n,)。 | ||
| 336 | + - pergroup[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(⌈k/group_size⌉, n),其中group_size表示k要分组的每组的大小。 | ||
| 337 | + - `antiquantOffsetOptional`(aclTensor *, 计算输入):数据类型支持FLOAT16、BFLOAT16、INT32,数据类型为FLOAT16、BFLOAT16时,数据类型要求和输入`x`的数据类型保持一致;数据类型为INT32类型时,数据范围限制为[-128, 127],x仅支持FLOAT16,weight仅支持INT8,`antiquantScale`仅支持UINT64/INT64。[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)仅支持转置场景。 | ||
| 338 | + - `quantScaleOptional`(aclTensor *, 计算输入):数据类型支持UINT64,[数据格式](../../../docs/zh/context/数据格式.md)支持ND。不支持[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)。可选输入,当不需要时为空指针;对于不同的伪量化算法模式,支持的shape如下: | ||
| 339 | + - pertensor[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(1,)或(1, 1)。 | ||
| 340 | + - perchannel[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(1, n)或(n,)。 | ||
| 341 | + - `quantOffsetOptional`(aclTensor *, 计算输入):数据类型支持FLOAT,[数据格式](../../../docs/zh/context/数据格式.md)支持ND。可选输入, 当不需要时为空指针;存在时shape要求与`quantScaleOptional`一致。不支持[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)。 | ||
| 342 | + - `biasOptional`(aclTensor *, 计算输入):维度支持1维或2维,shape支持(n,)或(1, n)。数据类型支持FLOAT16、FLOAT。当`x`的数据类型为BFLOAT16时,本参数要求为FLOAT;当`x`的数据类型为FLOAT16时,本参数要求为FLOAT16。 | ||
| 343 | + - `antiquantGroupSize`(int, 计算输入):表示在伪量化pergroup和mx[量化模式](../../../docs/zh/context/量化介绍.md)下,对输入`weight`进行反量化计算的groupSize输入,描述一组反量化参数对应的待反量化数据量在Reduce方向的大小。当伪量化算法不为pergroup和mx[量化模式](../../../docs/zh/context/量化介绍.md)时传入0;当伪量化算法为pergroup[量化模式](../../../docs/zh/context/量化介绍.md)时传入值的范围为[32, k-1]且值要求是32的倍数;在mx[量化模式](../../../docs/zh/context/量化介绍.md),仅支持32。 | ||
| 344 | + - `y`(aclTensor *, 计算输出):维度支持2维,shape支持(m, n)。数据类型支持FLOAT16、BFLOAT16、INT8。当`quantScaleOptional`存在时,数据类型为INT8;当`quantScaleOptional`不存在时,数据类型支持FLOAT16、BFLOAT16,且与输入`x`的数据类型一致。 | ||
| 345 | + | ||
| 346 | + - 性能优化建议: | ||
| 347 | + - pertensor[量化模式](../../../docs/zh/context/量化介绍.md):当[数据格式](../../../docs/zh/context/数据格式.md)为ND时,推荐使用转置后的`weight`输入;当[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ时,推荐使用非转置的`weight`输入。 | ||
| 348 | + - pergroup[量化模式](../../../docs/zh/context/量化介绍.md):推荐使用非转置的weight输入。 | ||
| 349 | + - perchannel[量化模式](../../../docs/zh/context/量化介绍.md):当[数据格式](../../../docs/zh/context/数据格式.md)为ND时,推荐使用转置后的`weight`输入;当[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ时,推荐使用非转置的`weight`输入。m范围为[65, 96]时,推荐使用数据类型为UINT64或INT64的antiquantScale。 | ||
| 350 | + | ||
| 351 | +</details> | ||
| 352 | + | ||
| 353 | +<a id="atlas推理系列产品"></a> | ||
| 354 | + | ||
| 355 | +<details> | ||
| 356 | +<summary><term>Atlas 推理系列产品</term></summary> | ||
| 357 | + | ||
| 358 | + - `x`(aclTensor *, 计算输入): 数据类型支持FLOAT16。shape支持2~6维,输入shape需要为(batch, m, k),其中batch表示矩阵的批次大小,支持0~4维,m表示单个batch矩阵第1维的大小,k表示单个batch矩阵的第2维的大小,batch维度需要与`weight`的batch维度满足[broadcast关系](../../../docs/zh/context/broadcast关系.md)。当伪量化算法模式为pertensor[量化模式](../../../docs/zh/context/量化介绍.md)时,`m*k`不能超过512000000。 | ||
| 359 | + - `weight`(aclTensor *, 计算输入):维度支持2~6维,batch维度需要与`x`的batch维度满足[broadcast关系](../../../docs/zh/context/broadcast关系.md),数据类型支持INT8。具体如下: | ||
| 360 | + - 当[数据格式](../../../docs/zh/context/数据格式.md)为ND时,输入shape需要为(batch, k, n),其中batch表示矩阵的批次大小,支持0~4维,k表示单个batch矩阵第1维的大小,n表示单个batch矩阵的第2维的大小。 | ||
| 361 | + - 当[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ时: | ||
| 362 | + - 输入shape需要为(batch, n, k),其中batch表示矩阵的批次大小,支持0~4维,k表示单个batch矩阵第1维的大小,n表示单个batch矩阵的第2维的大小。 | ||
| 363 | + - 配合aclnnCalculateMatmulWeightSizeV2以及aclnnTransMatmulWeight完成输入Format从ND到FRACTAL_NZ的转换,[详情可参考样例](../../trans_mat_mul_weight/docs/aclnnCalculateMatmulWeightSizeV2.md)。 | ||
| 364 | + - `antiquantScale`(aclTensor *, 计算输入):数据类型支持FLOAT16,数据类型要求和输入`x`保持一致。 | ||
| 365 | + 对于不同伪量化算法模式,`antiquantScale`支持的shape如下: | ||
| 366 | + - pertensor[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(1,)或(1, 1)。 | ||
| 367 | + - perchannel[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(n, 1)或(n,),不支持[非连续的Tensor](../../../docs/zh/context/非连续的Tensor.md)。 | ||
| 368 | + - pergroup[量化模式](../../../docs/zh/context/量化介绍.md):输入shape与`weight`的数据格式相关,如下: | ||
| 369 | + - 当`weight`的数据格式为ND时,输入shape为(⌈k/group_size⌉, n),其中group_size表示k要分组的每组的大小。 | ||
| 370 | + - 当`weight`的数据格式为FRACTAL_NZ时,输入shape为(n, ⌈k/group_size⌉),其中group_size表示k要分组的每组的大小。 | ||
| 371 | + - `antiquantOffsetOptional`(aclTensor *, 计算输入):数据类型支持FLOAT16,数据类型要求和输入`x`保持一致。 | ||
| 372 | + - `quantScaleOptional`(aclTensor *, 计算输入):预留参数,暂未使用,固定传入空指针。 | ||
| 373 | + - `quantOffsetOptional`(aclTensor *, 计算输入):预留参数,暂未使用,固定传入空指针。 | ||
| 374 | + - `biasOptional`(aclTensor *, 计算输入):数据类型支持FLOAT16。维度支持1~6维,带batch时,输入shape需要为(batch,1,n),batch要与x和weight的batch维度broadcast后的batch保持一致,不带batch时,输入shape需要为(n,)或(1, n)。 | ||
| 375 | + - `antiquantGroupSize`(int, 计算输入):数据类型支持FLOAT16。维度支持2~6维,shape支持(batch, m, n),batch可不存在,支持x与weight的batch维度broadcast,输出batch与broadcast之后的batch一致,m与x的m一致,n与weight的n一致。 | ||
| 376 | + - `y`(aclTensor *, 计算输出): | ||
| 377 | + | ||
| 378 | +</details> | ||
| 379 | + | ||
| 380 | +<a id="ascend_950pr_ascend950dt"></a> | ||
| 381 | + | ||
| 382 | +<details> | ||
| 383 | +<summary><term>Ascend 950PR/Ascend 950DT</term></summary> | ||
| 384 | + | ||
| 385 | + - **公共约束** | ||
| 386 | + - `x`和`weight`矩阵m、k、n大小在[1, 2^31-1]范围内。`weight`Reduce维度k需要与`x`的Reduce维度k大小相等。 | ||
| 387 | + - 支持的量化模式:pertensor[量化模式](../../../docs/zh/context/量化介绍.md)、perchannel[量化模式](../../../docs/zh/context/量化介绍.md)、pergroup[量化模式](../../../docs/zh/context/量化介绍.md)和mx[量化模式](../../../docs/zh/context/量化介绍.md)。 | ||
| 388 | + - `x`不支持转置,因此不支持[非连续Tensor](../../../docs/zh/context/非连续的Tensor.md),weight仅转置场景支持非连续的Tensor;antiquantScale、antiquantOffsetOptional非连续Tensor仅支持转置场景并且连续性要求和weight保持一致。 | ||
| 389 | + - `antiquantScale`不同量化模式支持的shape: | ||
| 390 | + - pertensor[量化模式](../../../docs/zh/context/量化介绍.md):(1,)或(1,1)。 | ||
| 391 | + - perchannel[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(1, n)或(n,)。 | ||
| 392 | + - pergroup[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(⌈k/group_size⌉, n),其中group_size表示k要分组的每组的大小。 | ||
| 393 | + - mx[量化模式](../../../docs/zh/context/量化介绍.md):输入shape为(⌈k/group_size⌉, n),其中group_size表示k要分组的每组的大小,仅支持32。 | ||
| 394 | + - `quantScaleOptional`和`quantOffsetOptional`为预留参数,暂未使用,固定传入空指针。 | ||
| 395 | + | ||
| 396 | + <a id="a16w8场景约束"></a> | ||
| 397 | + <details> | ||
| 398 | + <summary>A16W8场景约束</summary> | ||
| 399 | + | ||
| 400 | + - **输入和输出数据类型组合要求** | ||
| 401 | + | ||
| 402 | + | x | weight | weight Format | antiquantScale | antiquantOffsetOptional | quantScaleOptional | quantOffsetOptional | biasOptional | antiquantGroupSize | y | 场景说明 | | ||
| 403 | + | ---- | ------------------| --------------| -------------- | ------------------------| ------------------ | ------------------- | ------------ | ------------------ | ---- | ------- | | ||
| 404 | + | FLOAT16/BFLOAT16 | INT8 | ND | 与x一致 | 与x一致/null | null | null | 与x一致/FLOAT(仅x为BFLOAT16)/null | pergroup: [32, k-1]且为32倍数<br>其他: 0 | 与x一致 | T & C & G 量化 | | ||
| 405 | + | FLOAT16/BFLOAT16 | HIFLOAT8/FLOAT8_E4M34FN | ND | 与x一致 | null | null | null | 与x一致/null | pergroup: [32, k-1]且为32倍数<br>其他: 0 | 与x一致 | C 量化 | | ||
| 406 | + | ||
| 407 | + </details> | ||
| 408 | + | ||
| 409 | + <a id="a16w4场景约束"></a> | ||
| 410 | + <details> | ||
| 411 | + <summary>A16W4场景约束</summary> | ||
| 412 | + | ||
| 413 | + - **输入和输出数据类型组合要求** | ||
| 414 | + | ||
| 415 | + | x | weight | weight Format | antiquantScale | antiquantOffsetOptional | quantScaleOptional | quantOffsetOptional | biasOptional | antiquantGroupSize | y | 场景说明 | | ||
| 416 | + | ---- | ------------------| --------------| -------------- | ------------------------| ------------------ | ------------------- | ------------ | ------------------ | ---- | ------- | | ||
| 417 | + | FLOAT16/BFLOAT16 | INT4/INT32 | ND | 与x一致 | 与x一致/null | null | null | 与x一致/FLOAT(仅x为BFLOAT16)/null | 0 | 与x一致 | T 量化 | | ||
| 418 | + | FLOAT16/BFLOAT16 | INT4/INT32 | ND/FRACTAL_NZ | 与x一致 | 与x一致/null | null | null | 与x一致/FLOAT(仅x为BFLOAT16)/null | pergroup: [32, k-1]且为32倍数<br>其他: 0 | 与x一致 | C & G 量化 | | ||
| 419 | + | FLOAT16/BFLOAT16 | FLOAT4_E2M1 | FRACTAL_NZ | 与x一致 | 与x一致/null | null | null | 与x一致/null | [32, k-1]且为32倍数 | 与x一致 | G 量化 | | ||
| 420 | + | FLOAT16/BFLOAT16 | FLOAT | FRACTAL_NZ | 与x一致 | 与x一致/null | null | null | 与x一致/FLOAT(仅x为BFLOAT16)/null | [32, k-1]且为32倍数 | 与x一致 | G 量化 | | ||
| 421 | + | FLOAT16/BFLOAT16 | FLOAT4_E2M1 | ND/FRACTAL_NZ | FLOAT8_E8M0 | null | null | null | 与x一致/null | 32 | 与x一致 | MX 量化 | | ||
| 422 | + | FLOAT16/BFLOAT16 | FLOAT | ND/FRACTAL_NZ | FLOAT8_E8M0 | null | null | null | 与x一致/FLOAT(仅x为BFLOAT16)/null | 32 | 与x一致 | MX 量化 | | ||
| 423 | + | ||
| 424 | + - **约束说明** | ||
| 425 | + | ||
| 426 | + 除[公共约束](#公共约束)外,A16W4场景其余约束如下: | ||
| 427 | + - 若`weight`数据类型为FLOAT4_E2M1时,k、n要求32B对齐;若`weight`数据类型为INT4或FLOAT4_E2M1,则weight的内轴应为偶数。 | ||
| 428 | + - 若`weight`数据类型为INT32/FLOAT时,必须配合`aclnnConvertWeightToINT4Pack`接口完成从INT32/FLOAT到紧密排布的INT4/FLOAT4_E2M1的转换,[详情可参考样例](../../convert_weight_to_int4_pack/docs/aclnnConvertWeightToINT4Pack.md)。 | ||
| 429 | + - `weight`的[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ仅在如下场景下支持: | ||
| 430 | + - perchannel[量化模式](../../../docs/zh/context/量化介绍.md):`weight`的数据类型为INT4/INT32,`weight`非转置,`x`非转置 | ||
| 431 | + - pergroup[量化模式](../../../docs/zh/context/量化介绍.md):`weight`的数据类型为INT4/INT32/FLOAT4_E2M1/FLOAT,`weight`非转置,`x`非转置,k为64对齐,n为64对齐。 | ||
| 432 | + - mx[量化模式](../../../docs/zh/context/量化介绍.md):`weight`的数据类型为FLOAT4_E2M1/FLOAT,`weight`非转置,`x`非转置。 | ||
| 433 | + | ||
| 434 | + <a id="ascend_950pr_ascend950dt_性能优化建议"></a> | ||
| 435 | + - **性能优化建议** | ||
| 436 | + | ||
| 437 | + - pertensor[量化模式](../../../docs/zh/context/量化介绍.md):当[数据格式](../../../docs/zh/context/数据格式.md)为ND时,推荐使用转置后的`weight`输入;当[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ时,推荐使用非转置的`weight`输入。 | ||
| 438 | + - perchannel[量化模式](../../../docs/zh/context/量化介绍.md):当[数据格式](../../../docs/zh/context/数据格式.md)为ND时,推荐使用转置后的`weight`输入;当[数据格式](../../../docs/zh/context/数据格式.md)为FRACTAL_NZ时,推荐使用非转置的`weight`输入。 | ||
| 439 | + - pergroup[量化模式](../../../docs/zh/context/量化介绍.md)和mx[量化模式](../../../docs/zh/context/量化介绍.md):推荐使用非转置的`weight`输入。 | ||
| 440 | + | ||
| 441 | + </details> | ||
| 442 | +</details> | ||
| 392 | 443 | ||
| 393 | ## 调用示例 | 444 | ## 调用示例 |
| 394 | 示例代码如下,仅供参考,具体编译和执行过程请参考[编译与运行样例](../../../docs/zh/context/编译与运行样例.md)。 | 445 | 示例代码如下,仅供参考,具体编译和执行过程请参考[编译与运行样例](../../../docs/zh/context/编译与运行样例.md)。 |
| 395 | 446 | ||
| 396 | ```cpp | 447 | ```cpp |
| 397 | #include <iostream> | 448 | #include <iostream> |
| 449 | +#include <memory> | ||
| 398 | #include <vector> | 450 | #include <vector> |
| 399 | #include "acl/acl.h" | 451 | #include "acl/acl.h" |
| 400 | #include "aclnnop/aclnn_cast.h" | 452 | #include "aclnnop/aclnn_cast.h" |
| 401 | #include "aclnnop/aclnn_weight_quant_batch_matmul_v2.h" | 453 | #include "aclnnop/aclnn_weight_quant_batch_matmul_v2.h" |
| 402 | 454 | ||
| 403 | #define CHECK_RET(cond, return_expr) \ | 455 | #define CHECK_RET(cond, return_expr) \ |
| 404 | - do { \ | 456 | + do { \ |
| 405 | - if (!(cond)) { \ | 457 | + if (!(cond)) { \ |
| 406 | - return_expr; \ | 458 | + return_expr; \ |
| 407 | - } \ | 459 | + } \ |
| 408 | - } while (0) | 460 | + } while (0) |
| 409 | 461 | ||
| 410 | -#define LOG_PRINT(message, ...) \ | 462 | +#define CHECK_FREE_RET(cond, return_expr) \ |
| 411 | - do { \ | 463 | + do { \ |
| 412 | - printf(message, ##__VA_ARGS__); \ | 464 | + if (!(cond)) { \ |
| 413 | - } while (0) | 465 | + Finalize(deviceId, stream); \ |
| 466 | + return_expr; \ | ||
| 467 | + } \ | ||
| 468 | + } while (0) | ||
| 414 | 469 | ||
| 415 | -int64_t GetShapeSize(const std::vector<int64_t>& shape) { | 470 | +#define LOG_PRINT(message, ...) \ |
| 416 | - int64_t shapeSize = 1; | 471 | + do { \ |
| 417 | - for (auto i : shape) { | 472 | + printf(message, ##__VA_ARGS__); \ |
| 418 | - shapeSize *= i; | 473 | + } while (0) |
| 419 | - } | 474 | + |
| 420 | - return shapeSize; | 475 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) |
| 476 | +{ | ||
| 477 | + int64_t shapeSize = 1; | ||
| 478 | + for (auto i : shape) { | ||
| 479 | + shapeSize *= i; | ||
| 480 | + } | ||
| 481 | + return shapeSize; | ||
| 421 | } | 482 | } |
| 422 | 483 | ||
| 423 | -int Init(int32_t deviceId, aclrtStream* stream) { | 484 | +int Init(int32_t deviceId, aclrtStream* stream) |
| 424 | - // 固定写法,资源初始化 | 485 | +{ |
| 425 | - auto ret = aclInit(nullptr); | 486 | + // 固定写法,资源初始化 |
| 426 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | 487 | + auto ret = aclInit(nullptr); |
| 427 | - ret = aclrtSetDevice(deviceId); | 488 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); |
| 428 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | 489 | + ret = aclrtSetDevice(deviceId); |
| 429 | - ret = aclrtCreateStream(stream); | 490 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); |
| 430 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | 491 | + ret = aclrtCreateStream(stream); |
| 431 | - return 0; | 492 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); |
| 493 | + return 0; | ||
| 494 | +} | ||
| 495 | + | ||
| 496 | +void Finalize(int32_t deviceId, aclrtStream stream) | ||
| 497 | +{ | ||
| 498 | + aclrtDestroyStream(stream); | ||
| 499 | + aclrtResetDevice(deviceId); | ||
| 500 | + aclFinalize(); | ||
| 432 | } | 501 | } |
| 433 | 502 | ||
| 434 | template <typename T> | 503 | template <typename T> |
| 435 | -int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | 504 | +int CreateAclTensor( |
| 436 | - aclDataType dataType, aclTensor** tensor) { | 505 | + const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, |
| 437 | - auto size = GetShapeSize(shape) * sizeof(T); | 506 | + aclTensor** tensor) |
| 438 | - // 调用aclrtMalloc申请device侧内存 | 507 | +{ |
| 439 | - auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | 508 | + auto size = GetShapeSize(shape) * sizeof(T); |
| 440 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | 509 | + // 调用aclrtMalloc申请device侧内存 |
| 441 | - // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | 510 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); |
| 442 | - ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | 511 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); |
| 443 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | 512 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 |
| 513 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 514 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 444 | 515 | ||
| 445 | - // 计算连续tensor的strides | 516 | + // 计算连续tensor的strides |
| 446 | - std::vector<int64_t> strides(shape.size(), 1); | 517 | + std::vector<int64_t> strides(shape.size(), 1); |
| 447 | - for (int64_t i = shape.size() - 2; i >= 0; i--) { | 518 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { |
| 448 | - strides[i] = shape[i + 1] * strides[i + 1]; | 519 | + strides[i] = shape[i + 1] * strides[i + 1]; |
| 449 | - } | 520 | + } |
| 450 | 521 | ||
| 451 | - // 调用aclCreateTensor接口创建aclTensor | 522 | + // 调用aclCreateTensor接口创建aclTensor |
| 452 | - *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | 523 | + *tensor = aclCreateTensor( |
| 453 | - shape.data(), shape.size(), *deviceAddr); | 524 | + shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), |
| 454 | - return 0; | 525 | + *deviceAddr); |
| 526 | + return 0; | ||
| 455 | } | 527 | } |
| 456 | 528 | ||
| 457 | -int main() { | 529 | +void PrintMat(std::vector<float> resultData, std::vector<int64_t> resultShape) |
| 458 | - // 1. (固定写法)device/stream初始化,参考acl API手册 | 530 | +{ |
| 459 | - // 根据自己的实际device填写deviceId | 531 | + int64_t m = resultShape[0]; |
| 460 | - int32_t deviceId = 0; | 532 | + int64_t n = resultShape[1]; |
| 461 | - aclrtStream stream; | 533 | + for (size_t i = 0; i < m; i++) { |
| 462 | - auto ret = Init(deviceId, &stream); | 534 | + printf(i == 0 ? "[[" : " ["); |
| 463 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | 535 | + for (size_t j = 0; j < n; j++) { |
| 536 | + printf(j == n - 1 ? "%.1f" : "%.1f, ", resultData[i * n + j]); | ||
| 537 | + if (j == 2 && j + 3 < n) { | ||
| 538 | + printf("..., "); | ||
| 539 | + j = n - 4; | ||
| 540 | + } | ||
| 541 | + } | ||
| 542 | + printf(i < m - 1 ? "],\n" : "]]\n"); | ||
| 543 | + if (i == 2 && i + 3 < m) { | ||
| 544 | + printf(" ... \n"); | ||
| 545 | + i = m - 4; | ||
| 546 | + } | ||
| 547 | + } | ||
| 548 | +} | ||
| 464 | 549 | ||
| 465 | - // 2. 构造输入与输出,需要根据API的接口自定义构造 | 550 | +int AclnnWeightQuantBatchMatmulV2Test(int32_t deviceId, aclrtStream stream) |
| 466 | - std::vector<int64_t> xShape = {16, 32}; | 551 | +{ |
| 467 | - std::vector<int64_t> weightShape = {32, 16}; | 552 | + int64_t m = 16; |
| 468 | - std::vector<int64_t> yShape = {16, 16}; | 553 | + int64_t k = 32; |
| 469 | - void* xDeviceAddr = nullptr; | 554 | + int64_t n = 16; |
| 470 | - void* weightDeviceAddr = nullptr; | 555 | + std::vector<int64_t> xShape = {m, k}; |
| 471 | - void* yDeviceAddr = nullptr; | 556 | + std::vector<int64_t> weightShape = {k, n}; |
| 472 | - aclTensor* x = nullptr; | 557 | + std::vector<int64_t> antiquantScaleShape = {n}; |
| 473 | - aclTensor* weight = nullptr; | 558 | + std::vector<int64_t> yShape = {m, n}; |
| 474 | - aclTensor* y = nullptr; | 559 | + void* xDeviceAddr = nullptr; |
| 475 | - std::vector<float> xHostData(512, 1); | 560 | + void* weightDeviceAddr = nullptr; |
| 476 | - std::vector<int8_t> weightHostData(512, 1); | 561 | + void* antiquantScaleDeviceAddr = nullptr; |
| 477 | - std::vector<float> yHostData(256, 0); | 562 | + void* yDeviceAddr = nullptr; |
| 563 | + aclTensor* x = nullptr; | ||
| 564 | + aclTensor* weight = nullptr; | ||
| 565 | + aclTensor* antiquantScale = nullptr; | ||
| 566 | + aclTensor* y = nullptr; | ||
| 567 | + std::vector<uint16_t> xHostData(GetShapeSize(xShape), 0b0011110000000000); // fp16的1.0 | ||
| 568 | + std::vector<int8_t> weightHostData(GetShapeSize(weightShape), 1); | ||
| 569 | + std::vector<uint16_t> antiquantScaleHostData(GetShapeSize(antiquantScaleShape), 0b0011110000000000); | ||
| 570 | + std::vector<float> yHostData(GetShapeSize(yShape), 0); | ||
| 478 | 571 | ||
| 479 | - std::vector<int64_t> antiquantScaleShape = {16}; | 572 | + // 创建x aclTensor |
| 480 | - void* antiquantScaleDeviceAddr = nullptr; | 573 | + auto ret = CreateAclTensor(xHostData, xShape, &xDeviceAddr, aclDataType::ACL_FLOAT16, &x); |
| 481 | - aclTensor* antiquantScale = nullptr; | 574 | + std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> xTensorPtr(x, aclDestroyTensor); |
| 482 | - std::vector<float> antiquantScaleHostData(16, 1); | 575 | + std::unique_ptr<void, aclError (*)(void*)> xDeviceAddrPtr(xDeviceAddr, aclrtFree); |
| 576 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 577 | + // 创建other aclTensor | ||
| 578 | + ret = CreateAclTensor(weightHostData, weightShape, &weightDeviceAddr, aclDataType::ACL_INT8, &weight); | ||
| 579 | + std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> weightTensorPtr(weight, aclDestroyTensor); | ||
| 580 | + std::unique_ptr<void, aclError (*)(void*)> weightDeviceAddrPtr(weightDeviceAddr, aclrtFree); | ||
| 581 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 582 | + // 创建y aclTensor | ||
| 583 | + ret = CreateAclTensor(yHostData, yShape, &yDeviceAddr, aclDataType::ACL_FLOAT, &y); | ||
| 584 | + std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> yTensorPtr(y, aclDestroyTensor); | ||
| 585 | + std::unique_ptr<void, aclError (*)(void*)> yDeviceAddrPtr(yDeviceAddr, aclrtFree); | ||
| 586 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 587 | + // 创建antiquantScale aclTensor | ||
| 588 | + ret = CreateAclTensor( | ||
| 589 | + antiquantScaleHostData, antiquantScaleShape, &antiquantScaleDeviceAddr, aclDataType::ACL_FLOAT16, | ||
| 590 | + &antiquantScale); | ||
| 591 | + std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> antiquantScaleTensorPtr( | ||
| 592 | + antiquantScale, aclDestroyTensor); | ||
| 593 | + std::unique_ptr<void, aclError (*)(void*)> antiquantScaleDeviceAddrPtr(antiquantScaleDeviceAddr, aclrtFree); | ||
| 594 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 483 | 595 | ||
| 484 | - // 创建x aclTensor | 596 | + // 创建yFp16 aclTensor |
| 485 | - ret = CreateAclTensor(xHostData, xShape, &xDeviceAddr, aclDataType::ACL_FLOAT, &x); | 597 | + void* yFp16DeviceAddr = nullptr; |
| 486 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | 598 | + aclTensor* yFp16 = nullptr; |
| 487 | - // 创建other aclTensor | 599 | + ret = CreateAclTensor(yHostData, yShape, &yFp16DeviceAddr, aclDataType::ACL_FLOAT16, &yFp16); |
| 488 | - ret = CreateAclTensor(weightHostData, weightShape, &weightDeviceAddr, aclDataType::ACL_INT8, &weight); | 600 | + std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> yFp16TensorPtr(yFp16, aclDestroyTensor); |
| 489 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | 601 | + std::unique_ptr<void, aclError (*)(void*)> yFp16deviceAddrPtr(yFp16DeviceAddr, aclrtFree); |
| 490 | - // 创建y aclTensor | 602 | + CHECK_RET(ret == ACL_SUCCESS, return ret); |
| 491 | - ret = CreateAclTensor(yHostData, yShape, &yDeviceAddr, aclDataType::ACL_FLOAT, &y); | ||
| 492 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 493 | - // 创建antiquantScale aclTensor | ||
| 494 | - ret = CreateAclTensor(antiquantScaleHostData, antiquantScaleShape, &antiquantScaleDeviceAddr, aclDataType::ACL_FLOAT, &antiquantScale); | ||
| 495 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 496 | 603 | ||
| 497 | - // 创建xFp16 aclTensor | 604 | + // 3. 调用CANN算子库API,需要修改为具体的Api名称 |
| 498 | - void* xFp16DeviceAddr = nullptr; | 605 | + uint64_t workspaceSize = 0; |
| 499 | - aclTensor* xFp16 = nullptr; | 606 | + aclOpExecutor* executor; |
| 500 | - ret = CreateAclTensor(xHostData, xShape, &xFp16DeviceAddr, aclDataType::ACL_FLOAT16, &xFp16); | 607 | + void* workspaceAddr = nullptr; |
| 501 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 502 | - // 创建antiquantScale aclTensor | ||
| 503 | - void* antiquantScaleFp16DeviceAddr = nullptr; | ||
| 504 | - aclTensor* antiquantScaleFp16 = nullptr; | ||
| 505 | - ret = CreateAclTensor(antiquantScaleHostData, antiquantScaleShape, &antiquantScaleFp16DeviceAddr, aclDataType::ACL_FLOAT16, &antiquantScaleFp16); | ||
| 506 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 507 | - // 创建yFp16 aclTensor | ||
| 508 | - void* yFp16DeviceAddr = nullptr; | ||
| 509 | - aclTensor* yFp16 = nullptr; | ||
| 510 | - ret = CreateAclTensor(yHostData, yShape, &yFp16DeviceAddr, aclDataType::ACL_FLOAT16, &yFp16); | ||
| 511 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 512 | 608 | ||
| 513 | - // 3. 调用CANN算子库API,需要修改为具体的Api名称 | 609 | + // 调用aclnnWeightQuantBatchMatmulV2第一段接口 |
| 514 | - uint64_t workspaceSize = 0; | 610 | + ret = aclnnWeightQuantBatchMatmulV2GetWorkspaceSize( |
| 515 | - aclOpExecutor* executor; | 611 | + x, weight, antiquantScale, nullptr, nullptr, nullptr, nullptr, 0, yFp16, &workspaceSize, &executor); |
| 516 | - void* workspaceAddr = nullptr; | 612 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnWeightQuantBatchMatmulV2GetWorkspaceSize failed. ERROR: %d\n", ret); |
| 613 | + return ret); | ||
| 614 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 615 | + std::unique_ptr<void, aclError (*)(void*)> workspaceAddrPtr(nullptr, aclrtFree); | ||
| 616 | + if (workspaceSize > 0) { | ||
| 617 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 618 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 619 | + workspaceAddrPtr.reset(workspaceAddr); | ||
| 620 | + } | ||
| 621 | + // 调用aclnnWeightQuantBatchMatmulV2第二段接口 | ||
| 622 | + ret = aclnnWeightQuantBatchMatmulV2(workspaceAddr, workspaceSize, executor, stream); | ||
| 623 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnWeightQuantBatchMatmulV2 failed. ERROR: %d\n", ret); return ret); | ||
| 517 | 624 | ||
| 518 | - // 调用cast生成FP16的输入 | 625 | + // 4. (固定写法)同步等待任务执行结束 |
| 519 | - ret = aclnnCastGetWorkspaceSize(x, aclDataType::ACL_FLOAT16, xFp16, &workspaceSize, &executor); | 626 | + ret = aclrtSynchronizeStream(stream); |
| 520 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCastGetWorkspaceSize0 failed. ERROR: %d\n", ret); return ret); | 627 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); |
| 521 | - // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 522 | 628 | ||
| 523 | - if (workspaceSize > 0) { | 629 | + // 将输出转为FP32 |
| 524 | - ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | 630 | + workspaceSize = 0; |
| 525 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | 631 | + executor = nullptr; |
| 526 | - } | 632 | + ret = aclnnCastGetWorkspaceSize(yFp16, aclDataType::ACL_FLOAT, y, &workspaceSize, &executor); |
| 527 | - ret = aclnnCast(workspaceAddr, workspaceSize, executor, stream); | 633 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCastGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); |
| 528 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCast0 failed. ERROR: %d\n", ret); return ret); | 634 | + // 根据第一段接口计算出的workspaceSize申请device内存 |
| 635 | + void* workspaceCastAddr = nullptr; | ||
| 636 | + std::unique_ptr<void, aclError (*)(void*)> workspaceCastAddrPtr(nullptr, aclrtFree); | ||
| 637 | + if (workspaceSize > 0) { | ||
| 638 | + ret = aclrtMalloc(&workspaceCastAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 639 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 640 | + workspaceCastAddrPtr.reset(workspaceCastAddr); | ||
| 641 | + } | ||
| 642 | + ret = aclnnCast(workspaceCastAddr, workspaceSize, executor, stream); | ||
| 643 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCast failed. ERROR: %d\n", ret); return ret); | ||
| 644 | + ret = aclrtSynchronizeStream(stream); | ||
| 645 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 529 | 646 | ||
| 530 | - ret = aclrtSynchronizeStream(stream); | 647 | + // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 |
| 531 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | 648 | + auto size = GetShapeSize(yShape); |
| 649 | + std::vector<float> resultData(size, 0); | ||
| 650 | + ret = aclrtMemcpy( | ||
| 651 | + resultData.data(), resultData.size() * sizeof(resultData[0]), yDeviceAddr, size * sizeof(resultData[0]), | ||
| 652 | + ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 653 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 532 | 654 | ||
| 533 | - ret = aclnnCastGetWorkspaceSize(antiquantScale, aclDataType::ACL_FLOAT16, antiquantScaleFp16, &workspaceSize, &executor); | 655 | + PrintMat(resultData, yShape); |
| 534 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCastGetWorkspaceSize1 failed. ERROR: %d\n", ret); return ret); | 656 | + return ACL_SUCCESS; |
| 535 | - // 根据第一段接口计算出的workspaceSize申请device内存 | 657 | +} |
| 536 | 658 | ||
| 537 | - if (workspaceSize > 0) { | 659 | +int main() |
| 538 | - ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | 660 | +{ |
| 539 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | 661 | + // 1. (固定写法)device/stream初始化,参考acl API手册 |
| 540 | - } | 662 | + // 根据自己的实际device填写deviceId |
| 541 | - ret = aclnnCast(workspaceAddr, workspaceSize, executor, stream); | 663 | + int32_t deviceId = 0; |
| 542 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCast1 failed. ERROR: %d\n", ret); return ret); | 664 | + aclrtStream stream; |
| 665 | + auto ret = Init(deviceId, &stream); | ||
| 666 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 543 | 667 | ||
| 544 | - ret = aclrtSynchronizeStream(stream); | 668 | + // 2. 构造输入与输出,需要根据API的接口自定义构造 |
| 545 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | 669 | + ret = AclnnWeightQuantBatchMatmulV2Test(deviceId, stream); |
| 670 | + CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("AclnnWeightQuantBatchMatmulV2Test failed. ERROR: %d\n", ret); | ||
| 671 | + return ret); | ||
| 546 | 672 | ||
| 547 | - // 调用aclnnWeightQuantBatchMatmulV2第一段接口 | 673 | + Finalize(deviceId, stream); |
| 548 | - ret = aclnnWeightQuantBatchMatmulV2GetWorkspaceSize(xFp16, weight, antiquantScaleFp16, nullptr, nullptr, nullptr, nullptr, 0, yFp16, &workspaceSize, &executor); | 674 | + return 0; |
| 549 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnWeightQuantBatchMatmulV2GetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 550 | - // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 551 | - | ||
| 552 | - if (workspaceSize > 0) { | ||
| 553 | - ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 554 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 555 | - } | ||
| 556 | - // 调用aclnnWeightQuantBatchMatmulV2第二段接口 | ||
| 557 | - ret = aclnnWeightQuantBatchMatmulV2(workspaceAddr, workspaceSize, executor, stream); | ||
| 558 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnWeightQuantBatchMatmulV2 failed. ERROR: %d\n", ret); return ret); | ||
| 559 | - | ||
| 560 | - // 4. (固定写法)同步等待任务执行结束 | ||
| 561 | - ret = aclrtSynchronizeStream(stream); | ||
| 562 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 563 | - | ||
| 564 | - // 将输出转为FP32 | ||
| 565 | - ret = aclnnCastGetWorkspaceSize(yFp16, aclDataType::ACL_FLOAT, y, &workspaceSize, &executor); | ||
| 566 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCastGetWorkspaceSize2 failed. ERROR: %d\n", ret); return ret); | ||
| 567 | - // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 568 | - | ||
| 569 | - if (workspaceSize > 0) { | ||
| 570 | - ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 571 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 572 | - } | ||
| 573 | - ret = aclnnCast(workspaceAddr, workspaceSize, executor, stream); | ||
| 574 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCast2 failed. ERROR: %d\n", ret); return ret); | ||
| 575 | - | ||
| 576 | - ret = aclrtSynchronizeStream(stream); | ||
| 577 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 578 | - | ||
| 579 | - // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 580 | - auto size = GetShapeSize(yShape); | ||
| 581 | - std::vector<float> resultData(size, 0); | ||
| 582 | - ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), yDeviceAddr, | ||
| 583 | - size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 584 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 585 | - for (int64_t i = 0; i < size; i++) { | ||
| 586 | - LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]); | ||
| 587 | - } | ||
| 588 | - | ||
| 589 | - // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改 | ||
| 590 | - aclDestroyTensor(x); | ||
| 591 | - aclDestroyTensor(weight); | ||
| 592 | - aclDestroyTensor(antiquantScale); | ||
| 593 | - aclDestroyTensor(y); | ||
| 594 | - aclDestroyTensor(xFp16); | ||
| 595 | - aclDestroyTensor(antiquantScaleFp16); | ||
| 596 | - aclDestroyTensor(yFp16); | ||
| 597 | - | ||
| 598 | - // 7. 释放device资源 | ||
| 599 | - aclrtFree(xDeviceAddr); | ||
| 600 | - aclrtFree(weightDeviceAddr); | ||
| 601 | - aclrtFree(antiquantScaleDeviceAddr); | ||
| 602 | - aclrtFree(yDeviceAddr); | ||
| 603 | - aclrtFree(xFp16DeviceAddr); | ||
| 604 | - aclrtFree(antiquantScaleFp16DeviceAddr); | ||
| 605 | - aclrtFree(yFp16DeviceAddr); | ||
| 606 | - | ||
| 607 | - if (workspaceSize > 0) { | ||
| 608 | - aclrtFree(workspaceAddr); | ||
| 609 | - } | ||
| 610 | - aclrtDestroyStream(stream); | ||
| 611 | - aclrtResetDevice(deviceId); | ||
| 612 | - aclFinalize(); | ||
| 613 | - | ||
| 614 | - return 0; | ||
| 615 | } | 675 | } |
| 616 | ``` | 676 | ``` |
| @@ -1,11 +1,12 @@ | |||
| 1 | /** | 1 | /** |
| 2 | * This program is free software, you can redistribute it and/or modify. | 2 | * This program is free software, you can redistribute it and/or modify. |
| 3 | - * Copyright (c) 2025 Huawei Technologies Co., Ltd. | 3 | + * Copyright (c) 2025-2026 Huawei Technologies Co., Ltd. |
| 4 | * This file is a part of the CANN Open Software. | 4 | * This file is a part of the CANN Open Software. |
| 5 | * Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). | 5 | * Licensed under CANN Open Software License Agreement Version 2.0 (the "License"). |
| 6 | * Please refer to the License for details. You may not use this file except in compliance with the License. | 6 | * Please refer to the License for details. You may not use this file except in compliance with the License. |
| 7 | - * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. | 7 | + * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING |
| 8 | - * See LICENSE in the root of the software repository for the full text of the License. | 8 | + * BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE. See LICENSE in the root of |
| 9 | + * the software repository for the full text of the License. | ||
| 9 | */ | 10 | */ |
| 10 | 11 | ||
| 11 | 12 | ||
| @@ -16,213 +17,223 @@ | |||
| 16 | 17 | ||
| 17 | 18 | ||
| 18 | 19 | ||
| 19 | - do { \ | 20 | + do { \ |
| 20 | - if (!(cond)) { \ | 21 | + if (!(cond)) { \ |
| 21 | - return_expr; \ | 22 | + return_expr; \ |
| 22 | - } \ | 23 | + } \ |
| 23 | - } while (0) | 24 | + } while (0) |
| 24 | 25 | ||
| 25 | -#define LOG_PRINT(message, ...) \ | 26 | +#define CHECK_FREE_RET(cond, return_expr) \ |
| 26 | - do { \ | 27 | + do { \ |
| 27 | - printf(message, ##__VA_ARGS__); \ | 28 | + if (!(cond)) { \ |
| 28 | - } while (0) | 29 | + Finalize(deviceId, stream); \ |
| 30 | + return_expr; \ | ||
| 31 | + } \ | ||
| 32 | + } while (0) | ||
| 29 | 33 | ||
| 30 | -int64_t GetShapeSize(const std::vector<int64_t>& shape) { | 34 | +#define LOG_PRINT(message, ...) \ |
| 31 | - int64_t shapeSize = 1; | 35 | + do { \ |
| 32 | - for (auto i : shape) { | 36 | + printf(message, ##__VA_ARGS__); \ |
| 33 | - shapeSize *= i; | 37 | + } while (0) |
| 34 | - } | 38 | + |
| 35 | - return shapeSize; | 39 | +int64_t GetShapeSize(const std::vector<int64_t>& shape) |
| 40 | +{ | ||
| 41 | + int64_t shapeSize = 1; | ||
| 42 | + for (auto i : shape) { | ||
| 43 | + shapeSize *= i; | ||
| 44 | + } | ||
| 45 | + return shapeSize; | ||
| 36 | } | 46 | } |
| 37 | 47 | ||
| 38 | -int Init(int32_t deviceId, aclrtStream* stream) { | 48 | +int Init(int32_t deviceId, aclrtStream* stream) |
| 39 | - // 固定写法,资源初始化 | 49 | +{ |
| 40 | - auto ret = aclInit(nullptr); | 50 | + // 固定写法,资源初始化 |
| 41 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); | 51 | + auto ret = aclInit(nullptr); |
| 42 | - ret = aclrtSetDevice(deviceId); | 52 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret); |
| 43 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); | 53 | + ret = aclrtSetDevice(deviceId); |
| 44 | - ret = aclrtCreateStream(stream); | 54 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret); |
| 45 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); | 55 | + ret = aclrtCreateStream(stream); |
| 46 | - return 0; | 56 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret); |
| 57 | + return 0; | ||
| 58 | +} | ||
| 59 | + | ||
| 60 | +void Finalize(int32_t deviceId, aclrtStream stream) | ||
| 61 | +{ | ||
| 62 | + aclrtDestroyStream(stream); | ||
| 63 | + aclrtResetDevice(deviceId); | ||
| 64 | + aclFinalize(); | ||
| 47 | } | 65 | } |
| 48 | 66 | ||
| 49 | template <typename T> | 67 | template <typename T> |
| 50 | -int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, | 68 | +int CreateAclTensor( |
| 51 | - aclDataType dataType, aclTensor** tensor) { | 69 | + const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr, aclDataType dataType, |
| 52 | - auto size = GetShapeSize(shape) * sizeof(T); | 70 | + aclTensor** tensor) |
| 53 | - // 调用aclrtMalloc申请device侧内存 | 71 | +{ |
| 54 | - auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); | 72 | + auto size = GetShapeSize(shape) * sizeof(T); |
| 55 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); | 73 | + // 调用aclrtMalloc申请device侧内存 |
| 56 | - // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 | 74 | + auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST); |
| 57 | - ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | 75 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret); |
| 58 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | 76 | + // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上 |
| 77 | + ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE); | ||
| 78 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret); | ||
| 59 | 79 | ||
| 60 | - // 计算连续tensor的strides | 80 | + // 计算连续tensor的strides |
| 61 | - std::vector<int64_t> strides(shape.size(), 1); | 81 | + std::vector<int64_t> strides(shape.size(), 1); |
| 62 | - for (int64_t i = shape.size() - 2; i >= 0; i--) { | 82 | + for (int64_t i = shape.size() - 2; i >= 0; i--) { |
| 63 | - strides[i] = shape[i + 1] * strides[i + 1]; | 83 | + strides[i] = shape[i + 1] * strides[i + 1]; |
| 64 | - } | 84 | + } |
| 65 | 85 | ||
| 66 | - // 调用aclCreateTensor接口创建aclTensor | 86 | + // 调用aclCreateTensor接口创建aclTensor |
| 67 | - *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, | 87 | + *tensor = aclCreateTensor( |
| 68 | - shape.data(), shape.size(), *deviceAddr); | 88 | + shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND, shape.data(), shape.size(), |
| 69 | - return 0; | 89 | + *deviceAddr); |
| 90 | + return 0; | ||
| 70 | } | 91 | } |
| 71 | 92 | ||
| 72 | -int main() { | 93 | +void PrintMat(std::vector<float> resultData, std::vector<int64_t> resultShape) |
| 73 | - // 1. (固定写法)device/stream初始化,参考acl API手册 | 94 | +{ |
| 74 | - // 根据自己的实际device填写deviceId | 95 | + int64_t m = resultShape[0]; |
| 75 | - int32_t deviceId = 0; | 96 | + int64_t n = resultShape[1]; |
| 76 | - aclrtStream stream; | 97 | + for (size_t i = 0; i < m; i++) { |
| 77 | - auto ret = Init(deviceId, &stream); | 98 | + printf(i == 0 ? "[[" : " ["); |
| 78 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | 99 | + for (size_t j = 0; j < n; j++) { |
| 100 | + printf(j == n - 1 ? "%.1f" : "%.1f, ", resultData[i * n + j]); | ||
| 101 | + if (j == 2 && j + 3 < n) { | ||
| 102 | + printf("..., "); | ||
| 103 | + j = n - 4; | ||
| 104 | + } | ||
| 105 | + } | ||
| 106 | + printf(i < m - 1 ? "],\n" : "]]\n"); | ||
| 107 | + if (i == 2 && i + 3 < m) { | ||
| 108 | + printf(" ... \n"); | ||
| 109 | + i = m - 4; | ||
| 110 | + } | ||
| 111 | + } | ||
| 112 | +} | ||
| 79 | 113 | ||
| 80 | - // 2. 构造输入与输出,需要根据API的接口自定义构造 | 114 | +int AclnnWeightQuantBatchMatmulV2Test(int32_t deviceId, aclrtStream stream) |
| 81 | - std::vector<int64_t> xShape = {16, 32}; | 115 | +{ |
| 82 | - std::vector<int64_t> weightShape = {32, 16}; | 116 | + int64_t m = 16; |
| 83 | - std::vector<int64_t> yShape = {16, 16}; | 117 | + int64_t k = 32; |
| 84 | - void* xDeviceAddr = nullptr; | 118 | + int64_t n = 16; |
| 85 | - void* weightDeviceAddr = nullptr; | 119 | + std::vector<int64_t> xShape = {m, k}; |
| 86 | - void* yDeviceAddr = nullptr; | 120 | + std::vector<int64_t> weightShape = {k, n}; |
| 87 | - aclTensor* x = nullptr; | 121 | + std::vector<int64_t> antiquantScaleShape = {n}; |
| 88 | - aclTensor* weight = nullptr; | 122 | + std::vector<int64_t> yShape = {m, n}; |
| 89 | - aclTensor* y = nullptr; | 123 | + void* xDeviceAddr = nullptr; |
| 90 | - std::vector<float> xHostData(512, 1); | 124 | + void* weightDeviceAddr = nullptr; |
| 91 | - std::vector<int8_t> weightHostData(512, 1); | 125 | + void* antiquantScaleDeviceAddr = nullptr; |
| 92 | - std::vector<float> yHostData(256, 0); | 126 | + void* yDeviceAddr = nullptr; |
| 127 | + aclTensor* x = nullptr; | ||
| 128 | + aclTensor* weight = nullptr; | ||
| 129 | + aclTensor* antiquantScale = nullptr; | ||
| 130 | + aclTensor* y = nullptr; | ||
| 131 | + std::vector<uint16_t> xHostData(GetShapeSize(xShape), 0b0011110000000000); // fp16的1.0 | ||
| 132 | + std::vector<int8_t> weightHostData(GetShapeSize(weightShape), 1); | ||
| 133 | + std::vector<uint16_t> antiquantScaleHostData(GetShapeSize(antiquantScaleShape), 0b0011110000000000); | ||
| 134 | + std::vector<float> yHostData(GetShapeSize(yShape), 0); | ||
| 93 | 135 | ||
| 94 | - std::vector<int64_t> antiquantScaleShape = {16}; | 136 | + // 创建x aclTensor |
| 95 | - void* antiquantScaleDeviceAddr = nullptr; | 137 | + auto ret = CreateAclTensor(xHostData, xShape, &xDeviceAddr, aclDataType::ACL_FLOAT16, &x); |
| 96 | - aclTensor* antiquantScale = nullptr; | 138 | + std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> xTensorPtr(x, aclDestroyTensor); |
| 97 | - std::vector<float> antiquantScaleHostData(16, 1); | 139 | + std::unique_ptr<void, aclError (*)(void*)> xDeviceAddrPtr(xDeviceAddr, aclrtFree); |
| 140 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 141 | + // 创建other aclTensor | ||
| 142 | + ret = CreateAclTensor(weightHostData, weightShape, &weightDeviceAddr, aclDataType::ACL_INT8, &weight); | ||
| 143 | + std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> weightTensorPtr(weight, aclDestroyTensor); | ||
| 144 | + std::unique_ptr<void, aclError (*)(void*)> weightDeviceAddrPtr(weightDeviceAddr, aclrtFree); | ||
| 145 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 146 | + // 创建y aclTensor | ||
| 147 | + ret = CreateAclTensor(yHostData, yShape, &yDeviceAddr, aclDataType::ACL_FLOAT, &y); | ||
| 148 | + std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> yTensorPtr(y, aclDestroyTensor); | ||
| 149 | + std::unique_ptr<void, aclError (*)(void*)> yDeviceAddrPtr(yDeviceAddr, aclrtFree); | ||
| 150 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 151 | + // 创建antiquantScale aclTensor | ||
| 152 | + ret = CreateAclTensor( | ||
| 153 | + antiquantScaleHostData, antiquantScaleShape, &antiquantScaleDeviceAddr, aclDataType::ACL_FLOAT16, | ||
| 154 | + &antiquantScale); | ||
| 155 | + std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> antiquantScaleTensorPtr( | ||
| 156 | + antiquantScale, aclDestroyTensor); | ||
| 157 | + std::unique_ptr<void, aclError (*)(void*)> antiquantScaleDeviceAddrPtr(antiquantScaleDeviceAddr, aclrtFree); | ||
| 158 | + CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 98 | 159 | ||
| 99 | - // 创建x aclTensor | 160 | + // 创建yFp16 aclTensor |
| 100 | - ret = CreateAclTensor(xHostData, xShape, &xDeviceAddr, aclDataType::ACL_FLOAT, &x); | 161 | + void* yFp16DeviceAddr = nullptr; |
| 101 | - std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> xTensorPtr(x, aclDestroyTensor); | 162 | + aclTensor* yFp16 = nullptr; |
| 102 | - std::unique_ptr<void, aclError (*)(void*)> xDeviceAddrPtr(xDeviceAddr, aclrtFree); | 163 | + ret = CreateAclTensor(yHostData, yShape, &yFp16DeviceAddr, aclDataType::ACL_FLOAT16, &yFp16); |
| 103 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | 164 | + std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> yFp16TensorPtr(yFp16, aclDestroyTensor); |
| 104 | - // 创建other aclTensor | 165 | + std::unique_ptr<void, aclError (*)(void*)> yFp16deviceAddrPtr(yFp16DeviceAddr, aclrtFree); |
| 105 | - ret = CreateAclTensor(weightHostData, weightShape, &weightDeviceAddr, aclDataType::ACL_INT8, &weight); | 166 | + CHECK_RET(ret == ACL_SUCCESS, return ret); |
| 106 | - std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> weightTensorPtr(weight, aclDestroyTensor); | ||
| 107 | - std::unique_ptr<void, aclError (*)(void*)> weightDeviceAddrPtr(weightDeviceAddr, aclrtFree); | ||
| 108 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 109 | - // 创建y aclTensor | ||
| 110 | - ret = CreateAclTensor(yHostData, yShape, &yDeviceAddr, aclDataType::ACL_FLOAT, &y); | ||
| 111 | - std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> yTensorPtr(y, aclDestroyTensor); | ||
| 112 | - std::unique_ptr<void, aclError (*)(void*)> yDeviceAddrPtr(yDeviceAddr, aclrtFree); | ||
| 113 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 114 | - // 创建antiquantScale aclTensor | ||
| 115 | - ret = CreateAclTensor(antiquantScaleHostData, antiquantScaleShape, &antiquantScaleDeviceAddr, aclDataType::ACL_FLOAT, &antiquantScale); | ||
| 116 | - std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> antiquantScaleTensorPtr(antiquantScale, aclDestroyTensor); | ||
| 117 | - std::unique_ptr<void, aclError (*)(void*)> antiquantScaleDeviceAddrPtr(antiquantScaleDeviceAddr, aclrtFree); | ||
| 118 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 119 | 167 | ||
| 120 | - // 创建xFp16 aclTensor | 168 | + // 3. 调用CANN算子库API,需要修改为具体的Api名称 |
| 121 | - void* xFp16DeviceAddr = nullptr; | 169 | + uint64_t workspaceSize = 0; |
| 122 | - aclTensor* xFp16 = nullptr; | 170 | + aclOpExecutor* executor; |
| 123 | - ret = CreateAclTensor(xHostData, xShape, &xFp16DeviceAddr, aclDataType::ACL_FLOAT16, &xFp16); | 171 | + void* workspaceAddr = nullptr; |
| 124 | - std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> xFp16TensorPtr(xFp16, aclDestroyTensor); | ||
| 125 | - std::unique_ptr<void, aclError (*)(void*)> xFp16DeviceAddrPtr(xFp16DeviceAddr, aclrtFree); | ||
| 126 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 127 | - // 创建antiquantScaleFp16 aclTensor | ||
| 128 | - void* antiquantScaleFp16DeviceAddr = nullptr; | ||
| 129 | - aclTensor* antiquantScaleFp16 = nullptr; | ||
| 130 | - ret = CreateAclTensor(antiquantScaleHostData, antiquantScaleShape, &antiquantScaleFp16DeviceAddr, aclDataType::ACL_FLOAT16, &antiquantScaleFp16); | ||
| 131 | - std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> antiquantScaleFp16TensorPtr(antiquantScaleFp16, aclDestroyTensor); | ||
| 132 | - std::unique_ptr<void, aclError (*)(void*)> antiquantScaleFp16DeviceAddrPtr(antiquantScaleFp16DeviceAddr, aclrtFree); | ||
| 133 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 134 | - // 创建yFp16 aclTensor | ||
| 135 | - void* yFp16DeviceAddr = nullptr; | ||
| 136 | - aclTensor* yFp16 = nullptr; | ||
| 137 | - ret = CreateAclTensor(yHostData, yShape, &yFp16DeviceAddr, aclDataType::ACL_FLOAT16, &yFp16); | ||
| 138 | - std::unique_ptr<aclTensor, aclnnStatus (*)(const aclTensor*)> yFp16TensorPtr(yFp16, aclDestroyTensor); | ||
| 139 | - std::unique_ptr<void, aclError (*)(void*)> yFp16deviceAddrPtr(yFp16DeviceAddr, aclrtFree); | ||
| 140 | - CHECK_RET(ret == ACL_SUCCESS, return ret); | ||
| 141 | 172 | ||
| 142 | - // 3. 调用CANN算子库API,需要修改为具体的Api名称 | 173 | + // 调用aclnnWeightQuantBatchMatmulV2第一段接口 |
| 143 | - uint64_t workspaceSize = 0; | 174 | + ret = aclnnWeightQuantBatchMatmulV2GetWorkspaceSize( |
| 144 | - aclOpExecutor* executor; | 175 | + x, weight, antiquantScale, nullptr, nullptr, nullptr, nullptr, 0, yFp16, &workspaceSize, &executor); |
| 145 | - void* workspaceAddr = nullptr; | 176 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnWeightQuantBatchMatmulV2GetWorkspaceSize failed. ERROR: %d\n", ret); |
| 177 | + return ret); | ||
| 178 | + // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 179 | + std::unique_ptr<void, aclError (*)(void*)> workspaceAddrPtr(nullptr, aclrtFree); | ||
| 180 | + if (workspaceSize > 0) { | ||
| 181 | + ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 182 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 183 | + workspaceAddrPtr.reset(workspaceAddr); | ||
| 184 | + } | ||
| 185 | + // 调用aclnnWeightQuantBatchMatmulV2第二段接口 | ||
| 186 | + ret = aclnnWeightQuantBatchMatmulV2(workspaceAddr, workspaceSize, executor, stream); | ||
| 187 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnWeightQuantBatchMatmulV2 failed. ERROR: %d\n", ret); return ret); | ||
| 146 | 188 | ||
| 147 | - // 调用cast生成FP16的输入 | 189 | + // 4. (固定写法)同步等待任务执行结束 |
| 148 | - ret = aclnnCastGetWorkspaceSize(x, aclDataType::ACL_FLOAT16, xFp16, &workspaceSize, &executor); | 190 | + ret = aclrtSynchronizeStream(stream); |
| 149 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCastGetWorkspaceSize0 failed. ERROR: %d\n", ret); return ret); | 191 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); |
| 150 | - // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 151 | 192 | ||
| 152 | - if (workspaceSize > 0) { | 193 | + // 将输出转为FP32 |
| 153 | - ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | 194 | + workspaceSize = 0; |
| 154 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | 195 | + executor = nullptr; |
| 155 | - } | 196 | + ret = aclnnCastGetWorkspaceSize(yFp16, aclDataType::ACL_FLOAT, y, &workspaceSize, &executor); |
| 156 | - ret = aclnnCast(workspaceAddr, workspaceSize, executor, stream); | 197 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCastGetWorkspaceSize failed. ERROR: %d\n", ret); return ret); |
| 157 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCast0 failed. ERROR: %d\n", ret); return ret); | 198 | + // 根据第一段接口计算出的workspaceSize申请device内存 |
| 199 | + void* workspaceCastAddr = nullptr; | ||
| 200 | + std::unique_ptr<void, aclError (*)(void*)> workspaceCastAddrPtr(nullptr, aclrtFree); | ||
| 201 | + if (workspaceSize > 0) { | ||
| 202 | + ret = aclrtMalloc(&workspaceCastAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 203 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 204 | + workspaceCastAddrPtr.reset(workspaceCastAddr); | ||
| 205 | + } | ||
| 206 | + ret = aclnnCast(workspaceCastAddr, workspaceSize, executor, stream); | ||
| 207 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCast failed. ERROR: %d\n", ret); return ret); | ||
| 208 | + ret = aclrtSynchronizeStream(stream); | ||
| 209 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 158 | 210 | ||
| 159 | - ret = aclrtSynchronizeStream(stream); | 211 | + // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 |
| 160 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | 212 | + auto size = GetShapeSize(yShape); |
| 213 | + std::vector<float> resultData(size, 0); | ||
| 214 | + ret = aclrtMemcpy( | ||
| 215 | + resultData.data(), resultData.size() * sizeof(resultData[0]), yDeviceAddr, size * sizeof(resultData[0]), | ||
| 216 | + ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 217 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 161 | 218 | ||
| 162 | - ret = aclnnCastGetWorkspaceSize(antiquantScale, aclDataType::ACL_FLOAT16, antiquantScaleFp16, &workspaceSize, &executor); | 219 | + PrintMat(resultData, yShape); |
| 163 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCastGetWorkspaceSize1 failed. ERROR: %d\n", ret); return ret); | 220 | + return ACL_SUCCESS; |
| 164 | - // 根据第一段接口计算出的workspaceSize申请device内存 | 221 | +} |
| 165 | 222 | ||
| 166 | - if (workspaceSize > 0) { | 223 | +int main() |
| 167 | - ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | 224 | +{ |
| 168 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | 225 | + // 1. (固定写法)device/stream初始化,参考acl API手册 |
| 169 | - } | 226 | + // 根据自己的实际device填写deviceId |
| 170 | - ret = aclnnCast(workspaceAddr, workspaceSize, executor, stream); | 227 | + int32_t deviceId = 0; |
| 171 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCast1 failed. ERROR: %d\n", ret); return ret); | 228 | + aclrtStream stream; |
| 229 | + auto ret = Init(deviceId, &stream); | ||
| 230 | + CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret); | ||
| 172 | 231 | ||
| 173 | - ret = aclrtSynchronizeStream(stream); | 232 | + // 2. 构造输入与输出,需要根据API的接口自定义构造 |
| 174 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | 233 | + ret = AclnnWeightQuantBatchMatmulV2Test(deviceId, stream); |
| 234 | + CHECK_FREE_RET(ret == ACL_SUCCESS, LOG_PRINT("AclnnWeightQuantBatchMatmulV2Test failed. ERROR: %d\n", ret); | ||
| 235 | + return ret); | ||
| 175 | 236 | ||
| 176 | - // 调用aclnnWeightQuantBatchMatmulV2第一段接口 | 237 | + Finalize(deviceId, stream); |
| 177 | - ret = aclnnWeightQuantBatchMatmulV2GetWorkspaceSize(xFp16, weight, antiquantScaleFp16, nullptr, nullptr, nullptr, nullptr, 0, yFp16, &workspaceSize, &executor); | 238 | + return 0; |
| 178 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnWeightQuantBatchMatmulV2GetWorkspaceSize failed. ERROR: %d\n", ret); return ret); | ||
| 179 | - // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 180 | - | ||
| 181 | - if (workspaceSize > 0) { | ||
| 182 | - ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 183 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 184 | - } | ||
| 185 | - // 调用aclnnWeightQuantBatchMatmulV2第二段接口 | ||
| 186 | - ret = aclnnWeightQuantBatchMatmulV2(workspaceAddr, workspaceSize, executor, stream); | ||
| 187 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnWeightQuantBatchMatmulV2 failed. ERROR: %d\n", ret); return ret); | ||
| 188 | - | ||
| 189 | - // 4. (固定写法)同步等待任务执行结束 | ||
| 190 | - ret = aclrtSynchronizeStream(stream); | ||
| 191 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 192 | - | ||
| 193 | - // 将输出转为FP32 | ||
| 194 | - ret = aclnnCastGetWorkspaceSize(yFp16, aclDataType::ACL_FLOAT, y, &workspaceSize, &executor); | ||
| 195 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCastGetWorkspaceSize2 failed. ERROR: %d\n", ret); return ret); | ||
| 196 | - // 根据第一段接口计算出的workspaceSize申请device内存 | ||
| 197 | - | ||
| 198 | - if (workspaceSize > 0) { | ||
| 199 | - ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST); | ||
| 200 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret); | ||
| 201 | - } | ||
| 202 | - ret = aclnnCast(workspaceAddr, workspaceSize, executor, stream); | ||
| 203 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCast2 failed. ERROR: %d\n", ret); return ret); | ||
| 204 | - | ||
| 205 | - ret = aclrtSynchronizeStream(stream); | ||
| 206 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret); | ||
| 207 | - | ||
| 208 | - // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改 | ||
| 209 | - auto size = GetShapeSize(yShape); | ||
| 210 | - std::vector<float> resultData(size, 0); | ||
| 211 | - ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), yDeviceAddr, | ||
| 212 | - size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST); | ||
| 213 | - CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret); | ||
| 214 | - int64_t max_print_size = 8; | ||
| 215 | - for (int64_t i = 0; i < max_print_size; i++) { | ||
| 216 | - LOG_PRINT("result[%ld] is: %f\n", i, resultData[i]); | ||
| 217 | - } | ||
| 218 | - | ||
| 219 | - // 6. 释放device资源 | ||
| 220 | - if (workspaceSize > 0) { | ||
| 221 | - aclrtFree(workspaceAddr); | ||
| 222 | - } | ||
| 223 | - aclrtDestroyStream(stream); | ||
| 224 | - aclrtResetDevice(deviceId); | ||
| 225 | - aclFinalize(); | ||
| 226 | - | ||
| 227 | - return 0; | ||
| 228 | } | 239 | } |
| @@ -23,8 +23,7 @@ namespace ge { | |||
| 23 | 23 | ||
| 24 | * @par Inputs: | 24 | * @par Inputs: |
| 25 | * @li x: A matrix tensor. Shape supports (m,k)/(k,m), Format supports ND. | 25 | * @li x: A matrix tensor. Shape supports (m,k)/(k,m), Format supports ND. |
| 26 | -* The type support float16, bfloat16. The m value must be in [1, 65535] when | 26 | +* The type support float16, bfloat16. The m value must be in [1, 2147483647]. The k value |
| 27 | -* transpose_x is true or [1, 2147483647] when transpose_x is false. The k value | ||
| 28 | * must be at least 1. | 27 | * must be at least 1. |
| 29 | * @li weight: A matrix tensor of quantized weight. Shape supports (n,k)/(k,n), | 28 | * @li weight: A matrix tensor of quantized weight. Shape supports (n,k)/(k,n), |
| 30 | * Format supports ND/NZ. The type support int8, int4, int32, float8_e4m3fn, hifloat8, float4_e2m1. \n | 29 | * Format supports ND/NZ. The type support int8, int4, int32, float8_e4m3fn, hifloat8, float4_e2m1. \n |
| @@ -64,7 +63,8 @@ namespace ge { | |||
| 64 | * This parameter must not exist when type of antiquant_scale is uint64/int64. | 63 | * This parameter must not exist when type of antiquant_scale is uint64/int64. |
| 65 | * @li bias: An Optional tensor. Shape supports (n)/(1,n), Format supports ND. | 64 | * @li bias: An Optional tensor. Shape supports (n)/(1,n), Format supports ND. |
| 66 | * When type of x is float16, the type of bias should be float16. When type of x | 65 | * When type of x is float16, the type of bias should be float16. When type of x |
| 67 | -* is bfloat16, the type of bias should be float32 or bfloat16. \n | 66 | +* is bfloat16, the type of bias should be bfloat16. When type of x is bfloat16 |
| 67 | +* and weight is int4 or int8, the type of bias should be float32. \n | ||
| 68 | * Specifically, these optional inputs support the shape (0,). At this point, | 68 | * Specifically, these optional inputs support the shape (0,). At this point, |
| 69 | * it means that the optional input doesn't exist. | 69 | * it means that the optional input doesn't exist. |
| 70 | 70 | ||