已合并
WeightQuantBatchMatmulV2 Aclnn文档整改 #1550
sunduiyang创建于 2月5日
WeightQuantBatchMatmulV2 Aclnn文档整改 #1550
已合并
sunduiyang创建于 2月5日
3 个文件变更+661-590
Mmatmul/weight_quant_batch_matmul_v2/docs/aclnnWeightQuantBatchMatmulV2.md+458-398
@@ -1,5 +1,7 @@
1# aclnnWeightQuantBatchMatmulV21# 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) * antiquantScale28 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、BFLOAT16FLOAT8_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、BFLOAT16FLOAT8_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## aclnnWeightQuantBatchMatmulV2298## 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```cpp447```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 
434template <typename T>503template <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的strides516+ // 计算连续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接口创建aclTensor522+ // 调用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填写deviceId531+ 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 aclTensor596+ // 创建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 aclTensor599+ 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 aclTensor602+ 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 aclTensor604+ // 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```
Mmatmul/weight_quant_batch_matmul_v2/examples/test_aclnn_weight_quant_batch_matmul_v2.cpp+200-189
@@ -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#include <iostream>12#include <iostream>
@@ -16,213 +17,223 @@
16#include "aclnnop/aclnn_weight_quant_batch_matmul_v2.h"17#include "aclnnop/aclnn_weight_quant_batch_matmul_v2.h"
17 18 
18#define CHECK_RET(cond, return_expr) \19#define CHECK_RET(cond, return_expr) \
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 
49template <typename T>67template <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的strides80+ // 计算连续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接口创建aclTensor86+ // 调用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填写deviceId95+ 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 aclTensor160+ // 创建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 aclTensor165+ 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 aclTensor168+ // 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}
Mmatmul/weight_quant_batch_matmul_v2/op_graph/weight_quant_batch_matmul_v2_proto.h+3-3
@@ -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] when26+* 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. \n29* 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 x65* 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. \n66+* 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