已合并
修复md中空格 #6127
吴瑶创建于 6月16日
修复md中空格 #6127
已合并
吴瑶创建于 6月16日
已删除 :9.1.0合入到cann/ops-nn9.1.0
6 个文件变更+734-17
Mdocs/zh/install/quick_install.md+3-3
@@ -42,11 +42,11 @@
42> - 镜像文件比较大,下载需要一定时间,请您耐心等待。关于docker命令的选项介绍可通过`docker --help`查询。42> - 镜像文件比较大,下载需要一定时间,请您耐心等待。关于docker命令的选项介绍可通过`docker --help`查询。
43> - 环境默认安装最新商发版CANN包,源码下载时注意与软件配套。43> - 环境默认安装最新商发版CANN包,源码下载时注意与软件配套。
44 44 
451.**安装驱动与固件(运行态依赖)**451. **安装驱动与固件(运行态依赖)**
46 46 
47驱动与固件是运行态依赖,若仅编译算子,可以不安装。使用`npu-sim info`检查是否有NPU相关信息,若没有,请参考《[CANN快速安装](https://www.hiascend.com/cann/download)》完成驱动与固件安装。47驱动与固件是运行态依赖,若仅编译算子,可以不安装。使用`npu-sim info`检查是否有NPU相关信息,若没有,请参考《[CANN快速安装](https://www.hiascend.com/cann/download)》完成驱动与固件安装。
48 48 
492.**下载镜像**492. **下载镜像**
50 50 
51- 步骤1:以root用户登录宿主机。确保宿主机已安装Docker引擎(版本1.11.2及以上),使用`docker --version`检查Docker版本,若没有,请参考[Docker官方安装指南](https://docs.docker.com/engine/install/)。51- 步骤1:以root用户登录宿主机。确保宿主机已安装Docker引擎(版本1.11.2及以上),使用`docker --version`检查Docker版本,若没有,请参考[Docker官方安装指南](https://docs.docker.com/engine/install/)。
52- 步骤2:从[昇腾镜像仓库](https://www.hiascend.com/developer/ascendhub/detail/17da20d1c2b6493cb38765adeba85884)拉取已预集成CANN软件包及`ops-nn`所需依赖的镜像。52- 步骤2:从[昇腾镜像仓库](https://www.hiascend.com/developer/ascendhub/detail/17da20d1c2b6493cb38765adeba85884)拉取已预集成CANN软件包及`ops-nn`所需依赖的镜像。
@@ -58,7 +58,7 @@
58 docker pull swr.cn-south-1.myhuaweicloud.com/ascendhub/cann:9.1.0-beta.1-910b-openeuler24.03-py3.12-devel58 docker pull swr.cn-south-1.myhuaweicloud.com/ascendhub/cann:9.1.0-beta.1-910b-openeuler24.03-py3.12-devel
59 ```59 ```
60 60 
613.**运行Docker**613. **运行Docker**
62 62 
63拉取镜像后,需要以特定参数启动容器,以便容器内能访问宿主的昇腾设备。63拉取镜像后,需要以特定参数启动容器,以便容器内能访问宿主的昇腾设备。
64 64 
Mexamples/fast_kernel_launch_example/README.md+1-1
@@ -43,7 +43,7 @@
43 python3 -m pip install dist/*.whl --force-reinstall --no-deps43 python3 -m pip install dist/*.whl --force-reinstall --no-deps
44 ```44 ```
45 45 
465.(可选)再次构建前建议先执行以下命令清理编译缓存465. (可选)再次构建前建议先执行以下命令清理编译缓存
47 47 
48 ```sh48 ```sh
49 python setup.py clean49 python setup.py clean
Mindex/expand_into_jagged_permute/docs/aclnnExpandIntoJaggedPermute.md+3-3
@@ -232,11 +232,11 @@ aclnnStatus aclnnExpandIntoJaggedPermute(
232- 确定性计算:232- 确定性计算:
233 - aclnnExpandIntoJaggedPermute默认确定性实现。233 - aclnnExpandIntoJaggedPermute默认确定性实现。
234 234 
2351.inputOffset、outputOffset的shape要相同。2351. inputOffset、outputOffset的shape要相同。
236 236 
2372.permute、inputOffset、outputOffset、outputPermuteOut的数据类型需要相同。2372. permute、inputOffset、outputOffset、outputPermuteOut的数据类型需要相同。
238 238 
2393.outputOffset的值要求严格单调递增且最后一个值等于outputSize。2393. outputOffset的值要求严格单调递增且最后一个值等于outputSize。
240 240 
241## 调用示例241## 调用示例
242 242 
Amatmul/mat_mul_v3/docs/aclnnMatmulWeightNz.md+717-0
@@ -0,0 +1,717 @@
1# aclnnMatmulWeightNz
2 
3## 产品支持情况
4 
5| 产品 | 是否支持 |
6| :----------------------------------------------------------- | :------: |
7| <term>Ascend 950PR/Ascend 950DT</term> | √ |
8| <term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term> | √ |
9| <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term> | √ |
10| <term>Atlas 200I/500 A2 推理产品</term> | × |
11| <term>Atlas 推理系列产品</term> | × |
12| <term>Atlas 训练系列产品</term> | × |
13 
14## 功能说明
15 
16- 接口功能:完成张量self与张量mat2的矩阵乘计算,mat2仅支持NZ格式,只支持self为2维, mat2为4维。
17 相似接口有aclnnMatmul(mat2仅支持ND)、 aclnnMm(支持2维Tensor作为输入的矩阵乘)和aclnnBatchMatmul(仅支持3维的矩阵乘,其中第1维为batch)。
18- 计算公式:
19 
20 $$
21 result=self @ mat2
22 $$
23 
24## 函数原型
25 
26每个算子分为[两段式接口](../../../docs/zh/context/两段式接口.md),必须先调用“aclnnMatmulWeightNzGetWorkspaceSize”接口获取计算所需workspace大小以及包含了算子计算流程的执行器,再调用“aclnnMatmulWeightNz”接口执行计算。
27 
28```cpp
29aclnnStatus aclnnMatmulWeightNzGetWorkspaceSize(
30 const aclTensor *self,
31 const aclTensor *mat2,
32 aclTensor *out,
33 int8_t cubeMathType,
34 uint64_t *workspaceSize,
35 aclOpExecutor **executor)
36```
37 
38```cpp
39aclnnStatus aclnnMatmulWeightNz(
40 void *workspace,
41 uint64_t workspaceSize,
42 aclOpExecutor *executor,
43 aclrtStream stream)
44```
45 
46## aclnnMatmulWeightNzGetWorkspaceSize
47 
48- **参数说明**
49 <table style="undefined;table-layout: fixed; width: 1508px"><colgroup>
50 <col style="width: 151px">
51 <col style="width: 121px">
52 <col style="width: 301px">
53 <col style="width: 331px">
54 <col style="width: 237px">
55 <col style="width: 111px">
56 <col style="width: 111px">
57 <col style="width: 145px">
58 </colgroup>
59 <thead>
60 <tr>
61 <th>参数名</th>
62 <th>输入/输出</th>
63 <th>描述</th>
64 <th>使用说明</th>
65 <th>数据类型</th>
66 <th>数据格式</th>
67 <th>维度(shape)</th>
68 <th>非连续tensor</th>
69 </tr></thead>
70 <tbody>
71 <tr>
72 <td>self</td>
73 <td>输入</td>
74 <td>表示矩阵乘的第一个矩阵,公式中的self。</td>
75 <td>数据类型需要与mat2满足数据类型推导规则(参见<a href="../../../docs/zh/context/互推导关系.md">互推导关系</a>和<a href="#约束说明">约束说明</a>)。<br>
76 - 在self不转置的情况下各个维度表示:(m,k)<br>
77 - 在self转置的情况下各个维度表示:(k,m)<br></td>
78 <td>BFLOAT16、FLOAT16</td>
79 <td>ND</td>
80 <td>2</td>
81 <td>√</td>
82 </tr>
83 <tr>
84 <td>mat2</td>
85 <td>输入</td>
86 <td>表示矩阵乘的第二个矩阵,公式中的mat2。</td>
87 <td>数据类型需要与self满足数据类型推导规则(参见<a href="../../../docs/zh/context/互推导关系.md">互推导关系</a>和<a href="#约束说明">约束说明</a>)。<br>
88 mat2的Reduce维度需要与self的Reduce维度大小相等。<br>
89 当B矩阵不转置时, NZ格式各个维度表示:(n1,k1,k0,n0),其中k0 = 16, n0为16。self shape中的k和mat2 shape中的k1需要满足以下关系:ceil(k,k0) = k1, mat2 shape中的n1与out的n满足以下关系: ceil(n, n0) = n1。<br>
90 当B矩阵转置时, NZ格式各个维度表示:(k1,n1,n0,k0),其中n0 = 16, k0为16。self shape中的k和mat2 shape中的k1需要满足以下关系:ceil(k,k0) = k1, mat2 shape中的n1与out的n满足以下关系: ceil(n, n0) = n1。<br>
91 </td>
92 <td>BFLOAT16、FLOAT16、FLOAT32</td>
93 <td>NZ</td>
94 <td>4</td>
95 <td>-</td>
96 </tr>
97 <tr>
98 <td>out</td>
99 <td>输出</td>
100 <td>表示矩阵乘的输出矩阵,公式中的out。</td>
101 <td>数据类型需要与self与mat2推导之后的数据类型保持一致(参见<a href="../../../docs/zh/context/互推导关系.md">互推导关系</a>和<a href="#约束说明">约束说明</a>)。<br> 各个维度表示:(m,n),m与self的m一致,n与mat2的n1以及n0满足ceil(n / n0) = n1的关系。</td>
102 <td>BFLOAT16、FLOAT16、FLOAT32</td>
103 <td>ND</td>
104 <td>2</td>
105 <td>-</td>
106 </tr>
107 <tr>
108 <td>cubeMathType</td>
109 <td>输入</td>
110 <td>用于指定Cube单元的计算逻辑。</td>
111 <td>如果输入的数据类型存在互推导关系,该参数默认对互推导后的数据类型进行处理。支持的枚举值如下:<ul>
112 <li>0:KEEP_DTYPE,保持输入的数据类型进行计算。</li>
113 <li>1:ALLOW_FP32_DOWN_PRECISION,支持将输入数据降精度计算,当输入数据类型为FLOAT32时,会转换为HFLOAT32计算,当输入为其他数据类型时不做处理。</li>
114 <li>2:USE_FP16,支持将输入降精度至FLOAT16计算,当输入数据类型为BFLOAT16时不支持该选项。</li>
115 <li>3:USE_HF32,支持将输入降精度至数据类型HFLOAT32计算,当输入数据类型为FLOAT32时,会转换为HFLOAT32计算,当输入为其他数据类型时不支持该选项。</li>
116 <li>4:USE_FP32_ADD,支持使用高精度方式进行计算。</li></ul>
117 </td>
118 <td>INT8</td>
119 <td>-</td>
120 <td>-</td>
121 <td>-</td>
122 </tr>
123 <tr>
124 <td>workspaceSize</td>
125 <td>出参</td>
126 <td>返回需要在Device侧申请的workspace大小。</td>
127 <td>-</td>
128 <td>-</td>
129 <td>-</td>
130 <td>-</td>
131 <td>-</td>
132 </tr>
133 <tr>
134 <td>executor</td>
135 <td>出参</td>
136 <td>返回op执行器,包含了算子计算流程。</td>
137 <td>-</td>
138 <td>-</td>
139 <td>-</td>
140 <td>-</td>
141 <td>-</td>
142 </tr>
143 </tbody></table>
144 
145 - <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term><term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>
146 - 调用此接口之前,必须使用aclnnTransMatmulWeight接口完成mat2的原始输入Format从ND到NZ格式的转换。
147 - cubeMathType=4,当输入数据类型为FLOAT32且k轴大于2048时,会使用分组累加进行计算,当输入为其他数据类型或k轴小于2048时不做处理。
148 - <term>Ascend 950PR/Ascend 950DT</term>
149 - 调用此接口之前,必须使用aclnnNpuFormatCast接口完成mat2的原始输入Format从ND到NZ格式的转换。
150 - 不支持 cubeMathType为1:ALLOW_FP32_DOWN_PRECISION 的选项
151 - 不支持 cubeMathType为3:USE_HF32 的选项
152 - 不支持 cubeMathType为4:USE_FP32_ADD 的选项
153 
154- **返回值**
155 
156 aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/zh/context/aclnn返回码.md)。
157 
158 第一段接口完成入参校验,出现如下场景时报错:
159 <table style="undefined;table-layout: fixed;width: 1030px"><colgroup>
160 <col style="width: 250px">
161 <col style="width: 130px">
162 <col style="width: 650px">
163 </colgroup>
164 <thead>
165 <tr>
166 <th>返回值</th>
167 <th>错误码</th>
168 <th>描述</th>
169 </tr>
170 </thead>
171 <tbody>
172 <tr>
173 <td>ACLNN_ERR_PARAM_NULLPTR</td>
174 <td>161001</td>
175 <td>传入的self、mat2或out是空指针。</td>
176 </tr>
177 <tr>
178 <td rowspan="5">ACLNN_ERR_PARAM_INVALID</td>
179 <td rowspan="5">161002</td>
180 <td>self和mat2的数据类型和数据格式不在支持的范围之内。</td>
181 </tr>
182 <tr>
183 <td>self和mat2无法做数据类型推导。</td>
184 </tr>
185 <tr>
186 <td>推导出的数据类型无法转换为指定输出out的类型。</td>
187 </tr>
188 </tbody>
189 </table>
190 
191## aclnnMatmulWeightNz
192 
193- **参数说明**
194 
195 <div style="overflow-x: auto;">
196 <table style="undefined;table-layout: fixed; width: 1030px"><colgroup>
197 <col style="width: 250px">
198 <col style="width: 130px">
199 <col style="width: 650px">
200 </colgroup>
201 <thead>
202 <tr>
203 <th>参数名</th>
204 <th>输入/输出</th>
205 <th>描述</th>
206 </tr></thead>
207 <tbody>
208 <tr>
209 <td>workspace</td>
210 <td>输入</td>
211 <td>在Device侧申请的workspace内存地址。</td>
212 </tr>
213 <tr>
214 <td>workspaceSize</td>
215 <td>输入</td>
216 <td>在Device侧申请的workspace大小,由第一段接口aclnnMatmulWeightNzGetWorkspaceSize获取。</td>
217 </tr>
218 <tr>
219 <td>executor</td>
220 <td>输入</td>
221 <td>op执行器,包含了算子计算流程。</td>
222 </tr>
223 <tr>
224 <td>stream</td>
225 <td>输入</td>
226 <td>指定执行任务的stream。</td>
227 </tr>
228 </tbody>
229 </table>
230 </div>
231 
232- **返回值**
233 
234 aclnnStatus:返回状态码,具体参见[aclnn返回码](../../../docs/zh/context/aclnn返回码.md)。
235 
236## 约束说明
237 
238- 确定性说明:
239 - <term>Atlas 训练系列产品</term><term>Atlas 推理系列产品</term><term>Ascend 950PR/Ascend 950DT</term>:aclnnMatmulWeightNz默认确定性实现。
240 
241- 当输入self、mat2的数据类型都为FLOAT16或BFLOAT16,并且指定out数据类型为FLOAT32时,输出y的数据类型为FLOAT32。
242 
243- 计算一致性说明
244 - <term>Atlas 训练系列产品</term><term>Atlas 推理系列产品</term>
245 - 当开启强一致性计算功能时,计算结果时确定的,多次执行将产生相同的输出。此外,计算结果与数据的位置无关。
246 - aclnnMatmulWeightNz默认非一致性实现,支持通过aclrtCtxSetSysParamOpt开启一致性。
247 - 例如,在进行矩阵乘时,不同基本块的累加顺序可能不同,这可能会导致相同数据在不同行的计算结果出现细微差异。然而,在开启强一致性计算的情况下,即使在不同的行中,只要输入相同,计算结果也将相同。
248 
249- 不支持两个输入分别为BFLOAT16和FLOAT16的数据类型推导。
250- self只支持2维, mat2只支持昇腾私有格式,调用此接口之前,必须完成mat2从ND到昇腾私有格式的转换。
251- 不支持mat2最后两根轴其中一根轴为1,即k=1或者n=1。
252- 建议使用场景:建议在mte2 bound场景下使用,例如M轴较小,A矩阵存在重复搬运,B矩阵无重复搬运的情况。
253 
254## 调用示例
255 
256- <term>Atlas A2 训练系列产品/Atlas A2 推理系列产品</term><term>Atlas A3 训练系列产品/Atlas A3 推理系列产品</term>
257 self和mat2数据类型为float16,mat2为NZ格式场景下的示例代码如下,仅供参考,具体编译和执行过程请参考[编译与运行样例](../../../docs/zh/context/编译与运行样例.md)。
258
259 ```Cpp
260 #include <iostream>
261 #include <vector>
262 #include <cmath>
263 #include "acl/acl.h"
264 #include "aclnnop/aclnn_matmul.h"
265 #include "aclnnop/aclnn_trans_matmul_weight.h"
266 #include "aclnnop/aclnn_cast.h"
267 
268 #define CHECK_RET(cond, return_expr) \
269 do { \
270 if (!(cond)) { \
271 return_expr; \
272 } \
273 } while (0)
274 
275 #define LOG_PRINT(message, ...) \
276 do { \
277 printf(message, ##__VA_ARGS__); \
278 } while (0)
279 
280 int64_t GetShapeSize(const std::vector<int64_t>& shape) {
281 int64_t shapeSize = 1;
282 for (auto i : shape) {
283 shapeSize *= i;
284 }
285 return shapeSize;
286 }
287 
288 // 将FP16的uint16_t表示转换为float表示
289 float Fp16ToFloat(uint16_t h) {
290 int s = (h >> 15) & 0x1; // sign
291 int e = (h >> 10) & 0x1F; // exponent
292 int f = h & 0x3FF; // fraction
293 if (e == 0) {
294 // Zero or Denormal
295 if (f == 0) {
296 return s ? -0.0f : 0.0f;
297 }
298 // Denormals
299 float sig = f / 1024.0f;
300 float result = sig * pow(2, -24);
301 return s ? -result : result;
302 } else if (e == 31) {
303 // Infinity or NaN
304 return f == 0 ? (s ? -INFINITY : INFINITY) : NAN;
305 }
306 // Normalized
307 float result = (1.0f + f / 1024.0f) * pow(2, e - 15);
308 return s ? -result : result;
309 }
310 
311 int Init(int32_t deviceId, aclrtStream* stream) {
312 // 固定写法,资源初始化
313 auto ret = aclInit(nullptr);
314 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
315 ret = aclrtSetDevice(deviceId);
316 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
317 ret = aclrtCreateStream(stream);
318 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
319 return 0;
320 }
321 
322 template <typename T>
323 int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
324 aclDataType dataType, aclTensor** tensor) {
325 auto size = GetShapeSize(shape) * sizeof(T);
326 // 调用aclrtMalloc申请device侧内存
327 auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
328 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
329 // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
330 ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
331 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
332 
333 // 计算连续tensor的strides
334 std::vector<int64_t> strides(shape.size(), 1);
335 for (int64_t i = shape.size() - 2; i >= 0; i--) {
336 strides[i] = shape[i + 1] * strides[i + 1];
337 }
338 
339 // 调用aclCreateTensor接口创建aclTensor
340 *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
341 shape.data(), shape.size(), *deviceAddr);
342 return 0;
343 }
344 
345 template <typename T>
346 int CreateAclTensorWeight(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
347 aclDataType dataType, aclTensor** tensor) {
348 auto size = static_cast<uint64_t>(GetShapeSize(shape));
349 
350 const aclIntArray* mat2Size = aclCreateIntArray(shape.data(), shape.size());
351 auto ret = aclnnCalculateMatmulWeightSize(mat2Size, &size);
352 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnCalculateMatmulWeightSize failed. ERROR: %d\n", ret); return ret);
353 size *= sizeof(T);
354 
355 // 调用aclrtMalloc申请device侧内存
356 ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
357 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
358 // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
359 ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
360 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
361 
362 // 计算连续tensor的strides
363 std::vector<int64_t> strides(shape.size(), 1);
364 for (int64_t i = shape.size() - 2; i >= 0; i--) {
365 strides[i] = shape[i + 1] * strides[i + 1];
366 }
367 
368 std::vector<int64_t> storageShape;
369 storageShape.push_back(GetShapeSize(shape));
370 
371 // 调用aclCreateTensor接口创建aclTensor
372 *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
373 storageShape.data(), storageShape.size(), *deviceAddr);
374 return 0;
375 }
376 
377 int main() {
378 // 1. (固定写法)device/stream初始化,参考acl API手册
379 // 根据自己的实际device填写deviceId
380 int32_t deviceId = 0;
381 aclrtStream stream;
382 auto ret = Init(deviceId, &stream);
383 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
384 
385 // 2. 构造输入与输出,需要根据API的接口自定义构造
386 std::vector<int64_t> selfShape = {16, 32};
387 std::vector<int64_t> mat2Shape = {32, 16};
388 std::vector<int64_t> outShape = {16, 16};
389 void* selfDeviceAddr = nullptr;
390 void* mat2DeviceAddr = nullptr;
391 void* outDeviceAddr = nullptr;
392 aclTensor* self = nullptr;
393 aclTensor* mat2 = nullptr;
394 aclTensor* out = nullptr;
395 std::vector<uint16_t> selfHostData(512, 0x3C00); // float16_t 用0x3C00表示int_16的1
396 std::vector<uint16_t> mat2HostData(512, 0x3C00); // float16_t 用0x3C00表示int_16的1
397 std::vector<uint16_t> outHostData(256, 0);
398 // 创建self aclTensor
399 ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT16, &self);
400 CHECK_RET(ret == ACL_SUCCESS, return ret);
401 // 创建other aclTensor
402 ret = CreateAclTensorWeight(mat2HostData, mat2Shape, &mat2DeviceAddr, aclDataType::ACL_FLOAT16, &mat2);
403 CHECK_RET(ret == ACL_SUCCESS, return ret);
404 // 创建out aclTensor
405 ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT16, &out);
406 CHECK_RET(ret == ACL_SUCCESS, return ret);
407 
408 // 3. 调用CANN算子库API,需要修改为具体的Api名称
409 int8_t cubeMathType = 1;
410 uint64_t workspaceSize = 0;
411 aclOpExecutor* executor;
412 // 调用TransWeight
413 ret = aclnnTransMatmulWeightGetWorkspaceSize(mat2, &workspaceSize, &executor);
414 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnTransMatmulWeightGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
415 
416 // 根据第一段接口计算出的workspaceSize申请device内存
417 void* workspaceAddr = nullptr;
418 if (workspaceSize > 0) {
419 ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
420 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
421 }
422 
423 // 调用aclnnTransMatmulWeight第二段接口
424 ret = aclnnTransMatmulWeight(workspaceAddr, workspaceSize, executor, stream);
425 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnTransMatmulWeight failed. ERROR: %d\n", ret); return ret);
426 
427 // 调用aclnnMatmulWeightNz第一段接口
428 uint64_t workspaceSizeMm = 0;
429 ret = aclnnMatmulWeightNzGetWorkspaceSize(self, mat2, out, cubeMathType, &workspaceSizeMm, &executor);
430 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnMatmulWeightNzGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
431 
432 // 根据第一段接口计算出的workspaceSize申请device内存
433 void* workspaceAddrMm = nullptr;
434 if (workspaceSizeMm > 0) {
435 ret = aclrtMalloc(&workspaceAddrMm, workspaceSizeMm, ACL_MEM_MALLOC_HUGE_FIRST);
436 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
437 }
438 // 调用aclnnMatmulWeightNz第二段接口
439 ret = aclnnMatmulWeightNz(workspaceAddrMm, workspaceSizeMm, executor, stream);
440 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnMatmulWeightNz failed. ERROR: %d\n", ret); return ret);
441 
442 // 4. (固定写法)同步等待任务执行结束
443 ret = aclrtSynchronizeStream(stream);
444 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
445 
446 // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
447 auto size = GetShapeSize(outShape);
448 std::vector<uint16_t> resultData(size, 0);
449 ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr,
450 size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
451 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
452 // C语言中无法直接打印fp16的数据,需要用uint16读出来,自行通过二进制转成float表示的fp16
453 for (int64_t i = 0; i < size; i++) {
454 float fp16Float = Fp16ToFloat(resultData[i]);
455 LOG_PRINT("result[%ld] is: %f\n", i, fp16Float);
456 }
457 
458 // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改
459 aclDestroyTensor(self);
460 aclDestroyTensor(mat2);
461 aclDestroyTensor(out);
462 
463 // 7. 释放device资源,需要根据具体API的接口定义修改
464 aclrtFree(selfDeviceAddr);
465 aclrtFree(mat2DeviceAddr);
466 aclrtFree(outDeviceAddr);
467 
468 if (workspaceSize > 0) {
469 aclrtFree(workspaceAddr);
470 }
471 if (workspaceSizeMm > 0) {
472 aclrtFree(workspaceAddrMm);
473 }
474 aclrtDestroyStream(stream);
475 aclrtResetDevice(deviceId);
476 aclFinalize();
477 return 0;
478 }
479 ```
480 
481- <term>Ascend 950PR/Ascend 950DT</term>
482 self和mat2数据类型为bfloat16,mat2为NZ格式场景下的示例代码如下,仅供参考,具体编译和执行过程请参考[编译与运行样例](../../../docs/zh/context/编译与运行样例.md)。
483 
484 ```Cpp
485 #include <iostream>
486 #include <vector>
487 #include "acl/acl.h"
488 #include "aclnnop/aclnn_matmul.h"
489 #include "aclnnop/aclnn_npu_format_cast.h"
490 
491 #define CHECK_RET(cond, return_expr) \
492 do { \
493 if (!(cond)) { \
494 return_expr; \
495 } \
496 } while (0)
497 
498 #define LOG_PRINT(message, ...) \
499 do { \
500 printf(message, ##__VA_ARGS__); \
501 } while (0)
502 
503 int64_t GetShapeSize(const std::vector<int64_t>& shape) {
504 int64_t shapeSize = 1;
505 for (auto i : shape) {
506 shapeSize *= i;
507 }
508 return shapeSize;
509 }
510 
511 // 将bfloat16的uint16_t表示转换为float表示
512 float Bf16ToFloat(uint16_t h) {
513 uint32_t sign = (h & 0x8000U) ? 0x80000000U : 0x00000000U; // sign bit
514 uint32_t exponent = (h >> 7) & 0x00FFU; // exponent bits
515 uint32_t mantissa = h & 0x007FU; // mantissa bits
516 
517 // 指数偏移不变
518 // mantissa 左移 23 - 7 ,其余补0
519 uint32_t f_bits = sign | (exponent << 23) | (mantissa << (23 - 7));
520 // 强转float
521 return *reinterpret_cast<float*>(&f_bits);
522 }
523 
524 int Init(int32_t deviceId, aclrtStream* stream) {
525 // 固定写法,资源初始化
526 auto ret = aclInit(nullptr);
527 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
528 ret = aclrtSetDevice(deviceId);
529 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
530 ret = aclrtCreateStream(stream);
531 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
532 return 0;
533 }
534 
535 template <typename T>
536 int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
537 aclDataType dataType, aclTensor** tensor) {
538 auto size = GetShapeSize(shape) * sizeof(T);
539 // 调用aclrtMalloc申请device侧内存
540 auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
541 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
542 // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
543 ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
544 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
545 
546 // 计算连续tensor的strides
547 std::vector<int64_t> strides(shape.size(), 1);
548 for (int64_t i = shape.size() - 2; i >= 0; i--) {
549 strides[i] = shape[i + 1] * strides[i + 1];
550 }
551 
552 // 调用aclCreateTensor接口创建aclTensor
553 *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
554 shape.data(), shape.size(), *deviceAddr);
555 return 0;
556 }
557 
558 template <typename T>
559 int CreateAclTensorWithFormat(const std::vector<T>& hostData, const std::vector<int64_t>& shape,
560 int64_t** storageShape, uint64_t* storageShapeSize, void** deviceAddr,
561 aclDataType dataType, aclTensor** tensor, aclFormat format) {
562 auto size = hostData.size() * sizeof(T);
563 // 调用aclrtMalloc申请device侧内存
564 auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
565 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
566 // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
567 ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
568 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
569 
570 // 计算连续tensor的strides
571 std::vector<int64_t> strides(shape.size(), 1);
572 for (int64_t i = shape.size() - 2; i >= 0; i--) {
573 strides[i] = shape[i + 1] * strides[i + 1];
574 }
575 
576 *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0,
577 format, *storageShape, *storageShapeSize, *deviceAddr);
578 return 0;
579 }
580 
581 int main() {
582 // 1. device/stream初始化,参考acl API手册(固定写法)
583 // 根据自己的实际device填写deviceId
584 int32_t deviceId = 0;
585 aclrtStream stream;
586 auto ret = Init(deviceId, &stream);
587 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
588 
589 // 2. 构造输入与输出,需要根据API的接口自定义构造
590 int64_t m = 16;
591 int64_t k = 32;
592 int64_t n = 16;
593 std::vector<int64_t> selfShape = {m, k};
594 std::vector<int64_t> mat2Shape = {k, n};
595 std::vector<int64_t> outShape = {m, n};
596 void* selfDeviceAddr = nullptr;
597 void* mat2DeviceAddr = nullptr;
598 void* outDeviceAddr = nullptr;
599 void* dstDeviceAddr = nullptr;
600 
601 aclTensor* self = nullptr;
602 aclTensor* mat2 = nullptr;
603 aclTensor* out = nullptr;
604 aclTensor* mat2NZ = nullptr;
605 
606 std::vector<uint16_t> selfHostData(m * k, 0x3F80); // bfloat16_t 用0x3F80表示uint_16的1
607 std::vector<uint16_t> mat2HostData(k * n, 0x3F80); // bfloat16_t 用0x3F80表示uint_16的1
608 std::vector<uint16_t> outHostData(m * n, 0);
609 // weightNz需要的空间大于等于原[k,n]矩阵, 需要对齐16
610 int64_t kAlign = (k + 16 - 1) / 16 * 16;
611 int64_t nAlign = (n + 16 - 1) / 16 * 16;
612 std::vector<uint16_t> dstTensorHostData(kAlign * nAlign, 0x3F80);
613 
614 aclDataType srcDtype = aclDataType::ACL_BF16;
615 aclDataType additionalDtype = aclDataType::ACL_BF16;
616 // 创建self aclTensor
617 ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, srcDtype, &self);
618 CHECK_RET(ret == ACL_SUCCESS, return ret);
619 // 创建mat2 aclTensor
620 ret = CreateAclTensor(mat2HostData, mat2Shape, &mat2DeviceAddr, srcDtype, &mat2);
621 CHECK_RET(ret == ACL_SUCCESS, return ret);
622 // 创建out aclTensor
623 ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, srcDtype, &out);
624 CHECK_RET(ret == ACL_SUCCESS, return ret);
625 
626 // 3. 调用CANN算子库API,需要修改为具体的Api名称
627 int8_t cubeMathType = 1;
628 aclOpExecutor* executor = nullptr;
629 
630 // weight tensor ND转NZ,调用npu_format_cast接口
631 int64_t* dstShape = nullptr;
632 uint64_t dstShapeSize = 0;
633 int actualFormat;
634 uint64_t workspaceSize = 0;
635 void* workspaceAddr = nullptr;
636 
637 uint64_t workspaceSizeMm = 0;
638 void* workspaceAddrMm = nullptr;
639 
640 // 计算目标tensor的shape和format
641 ret = aclnnNpuFormatCastCalculateSizeAndFormat(mat2, 29, additionalDtype, &dstShape, &dstShapeSize, &actualFormat);
642 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnNpuFormatCastCalculateSizeAndFormat failed. ERROR: %d\n", ret); return ret);
643 
644 ret = CreateAclTensorWithFormat(dstTensorHostData, mat2Shape, &dstShape, &dstShapeSize, &dstDeviceAddr, srcDtype, &mat2NZ, static_cast<aclFormat>(actualFormat));
645 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("CreateAclTensorWithFormat failed. ERROR: %d\n", ret); return ret);
646 
647 // 调用aclnnNpuFormatCastGetWorkspaceSize第一段接口
648 ret = aclnnNpuFormatCastGetWorkspaceSize(mat2, mat2NZ, &workspaceSize, &executor);
649 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnNpuFormatCastGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
650 
651 // 根据第一段接口计算出的workspaceSize申请device内存
652 if (workspaceSize > 0) {
653 ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
654 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
655 }
656 
657 // 调用aclnnNpuFormatCastGetWorkspaceSize第二段接口
658 ret = aclnnNpuFormatCast(workspaceAddr, workspaceSize, executor, stream);
659 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnNpuFormatCast failed. ERROR: %d\n", ret); return ret);
660 
661 // 4. 同步等待任务执行结束
662 ret = aclrtSynchronizeStream(stream);
663 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
664 
665 // 调用aclnnMatmulWeightNz第一段接口
666 ret = aclnnMatmulWeightNzGetWorkspaceSize(self, mat2NZ, out, cubeMathType, &workspaceSizeMm, &executor);
667 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnMatmulWeightNzGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
668 
669 // 根据第一段接口计算出的workspaceSize申请device内存
670 if (workspaceSizeMm > 0) {
671 ret = aclrtMalloc(&workspaceAddrMm, workspaceSizeMm, ACL_MEM_MALLOC_HUGE_FIRST);
672 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
673 }
674 // 调用aclnnMatmulWeightNz第二段接口
675 ret = aclnnMatmulWeightNz(workspaceAddrMm, workspaceSizeMm, executor, stream);
676 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnMatmulWeightNz failed. ERROR: %d\n", ret); return ret);
677 
678 // 4. 同步等待任务执行结束
679 ret = aclrtSynchronizeStream(stream);
680 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
681 
682 // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
683 auto size = GetShapeSize(outShape);
684 std::vector<uint16_t> resultData(size, 0);
685 ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]), outDeviceAddr,
686 size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
687 CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return ret);
688 for (int64_t i = 0; i < size; i++) {
689 float bf16Float = Bf16ToFloat(resultData[i]);
690 LOG_PRINT("result[%ld] is: %f\n", i, bf16Float);
691 }
692 
693 // 6. 释放aclTensor和aclScalar
694 aclDestroyTensor(self);
695 aclDestroyTensor(mat2);
696 aclDestroyTensor(out);
697 aclDestroyTensor(mat2NZ);
698 
699 // 7. 释放device资源
700 aclrtFree(selfDeviceAddr);
701 aclrtFree(mat2DeviceAddr);
702 aclrtFree(outDeviceAddr);
703 aclrtFree(dstDeviceAddr);
704 
705 if (workspaceSize > 0) {
706 aclrtFree(workspaceAddr);
707 }
708 
709 if (workspaceSizeMm > 0) {
710 aclrtFree(workspaceAddrMm);
711 }
712 aclrtDestroyStream(stream);
713 aclrtResetDevice(deviceId);
714 aclFinalize();
715 return 0;
716 }
717 ```
Mmatmul/quant_matmul_dequant/docs/aclnnQuantMatmulDequant.md+4-4
@@ -15,25 +15,25 @@
15 15 
16- 接口功能:对输入x进行量化,矩阵乘以及反量化。16- 接口功能:对输入x进行量化,矩阵乘以及反量化。
17- 计算公式: 17- 计算公式:
18 1.若输入smoothScaleOptional,则18 1. 若输入smoothScaleOptional,则
19 19
20 $$20 $$
21 x = x\cdot scale_{smooth}21 x = x\cdot scale_{smooth}
22 $$22 $$
23 23 
24 2.若不输入xScaleOptional,则为动态量化,需要计算x量化系数。24 2. 若不输入xScaleOptional,则为动态量化,需要计算x量化系数。
25 25
26 $$26 $$
27 scale_{x}=row\_max(abs(x))/max_{quantDataType}27 scale_{x}=row\_max(abs(x))/max_{quantDataType}
28 $$28 $$
29 29 
30 3.量化30 3. 量化
31 31
32 $$32 $$
33 x_{quantized}=round(x/scale_{x})33 x_{quantized}=round(x/scale_{x})
34 $$34 $$
35 35 
36 4.矩阵乘+反量化36 4. 矩阵乘+反量化
37 37
38 - 4.1若输入的$scale_{weight}$数据类型为FLOAT32,则:38 - 4.1若输入的$scale_{weight}$数据类型为FLOAT32,则:
39 39 
Mrnn/single_layer_lstm_grad/docs/aclnnLstmBackward.md+6-6
@@ -59,19 +59,19 @@
59 59 
60 - **循环 $t = T - 1$ 到 $0$**60 - **循环 $t = T - 1$ 到 $0$**
61 61 
62 1.**当前隐藏状态梯度**62 1. **当前隐藏状态梯度**
63 63 
64 $$64 $$
65 \delta\mathbf{h}_t = \frac{\partial L_t}{\partial \mathbf{h}_t} + \delta\mathbf{h}_{\text{next}}65 \delta\mathbf{h}_t = \frac{\partial L_t}{\partial \mathbf{h}_t} + \delta\mathbf{h}_{\text{next}}
66 $$66 $$
67 67 
68 2.**当前细胞状态梯度**68 2. **当前细胞状态梯度**
69 69 
70 $$70 $$
71 \delta\mathbf{c}_t = \delta\mathbf{h}_t \odot \mathbf{o}_t \odot (1 - \tanh^2(\mathbf{c}_t)) + \delta\mathbf{c}_{\text{next}} \odot \mathbf{f}_{\text{next}}71 \delta\mathbf{c}_t = \delta\mathbf{h}_t \odot \mathbf{o}_t \odot (1 - \tanh^2(\mathbf{c}_t)) + \delta\mathbf{c}_{\text{next}} \odot \mathbf{f}_{\text{next}}
72 $$72 $$
73 73 
74 3.**门控梯度计算**74 3. **门控梯度计算**
75 75 
76 $$76 $$
77 \delta\mathbf{o}_t = \delta\mathbf{h}_t \odot \tanh(\mathbf{c}_t) \odot \mathbf{o}_t \odot (1 - \mathbf{o}_t)77 \delta\mathbf{o}_t = \delta\mathbf{h}_t \odot \tanh(\mathbf{c}_t) \odot \mathbf{o}_t \odot (1 - \mathbf{o}_t)
@@ -89,7 +89,7 @@
89 \delta\mathbf{f}_t = \delta\mathbf{c}_t \odot \mathbf{c}_{t-1} \odot \mathbf{f}_t \odot (1 - \mathbf{f}_t)89 \delta\mathbf{f}_t = \delta\mathbf{c}_t \odot \mathbf{c}_{t-1} \odot \mathbf{f}_t \odot (1 - \mathbf{f}_t)
90 $$90 $$
91 91 
92 4.**参数梯度累加**92 4. **参数梯度累加**
93 93 
94 $$94 $$
95 \frac{\partial L}{\partial \mathbf{W}_f} \mathrel{+}= \delta\mathbf{f}_t \mathbf{z}_t^\top95 \frac{\partial L}{\partial \mathbf{W}_f} \mathrel{+}= \delta\mathbf{f}_t \mathbf{z}_t^\top
@@ -123,7 +123,7 @@
123 \frac{\partial L}{\partial \mathbf{b}_o} \mathrel{+}= \delta\mathbf{o}_t123 \frac{\partial L}{\partial \mathbf{b}_o} \mathrel{+}= \delta\mathbf{o}_t
124 $$124 $$
125 125 
126 5.**传播到前一时刻**126 5. **传播到前一时刻**
127 127 
128 $$128 $$
129 \delta\mathbf{z}_t = \mathbf{W}_f^\top \delta\mathbf{f}_t + \mathbf{W}_i^\top \delta\mathbf{i}_t + \mathbf{W}_g^\top \delta\mathbf{g}_t + \mathbf{W}_o^\top \delta\mathbf{o}_t129 \delta\mathbf{z}_t = \mathbf{W}_f^\top \delta\mathbf{f}_t + \mathbf{W}_i^\top \delta\mathbf{i}_t + \mathbf{W}_g^\top \delta\mathbf{g}_t + \mathbf{W}_o^\top \delta\mathbf{o}_t
@@ -137,7 +137,7 @@
137 \delta\mathbf{c}_{\text{prev}} = \delta\mathbf{c}_t \odot \mathbf{f}_t137 \delta\mathbf{c}_{\text{prev}} = \delta\mathbf{c}_t \odot \mathbf{f}_t
138 $$138 $$
139 139 
140 6.**更新传播变量**140 6. **更新传播变量**
141 141 
142 $$142 $$
143 \delta\mathbf{h}_{\text{next}} \leftarrow \delta\mathbf{h}_{\text{prev}}143 \delta\mathbf{h}_{\text{next}} \leftarrow \delta\mathbf{h}_{\text{prev}}