已合并
修改算子readme文档 #3615
xiu_ling_wang创建于 4月8日
修改算子readme文档 #3615
已合并
xiu_ling_wang创建于 4月8日
6 个文件变更+178-16
@@ -1,6 +1,6 @@
1# EmbeddingBag1# EmbeddingBag
2 2 
3-## 产品支持情况3+## 产品支持情况
4 4 
5| 产品 | 是否支持 |5| 产品 | 是否支持 |
6| ---- | :----:|6| ---- | :----:|
@@ -19,7 +19,7 @@
19 - shape推导方式如下:19 - shape推导方式如下:
20 假设:20 假设:
21 21 
22- ```22+ ```cpp
23 weight的shape为(numWeight, embeddingDim)23 weight的shape为(numWeight, embeddingDim)
24 indices的shape为(indices)24 indices的shape为(indices)
25 offsets的shape为(offsets)25 offsets的shape为(offsets)
@@ -27,7 +27,7 @@
27 27 
28 - 当mode为sum模式:28 - 当mode为sum模式:
29 29 
30- ```30+ ```cpp
31 y的shape 为 include_last_offset ? (offsets - 1, embeddingDim) : (offsets, embeddingDim)31 y的shape 为 include_last_offset ? (offsets - 1, embeddingDim) : (offsets, embeddingDim)
32 offset2bag的shape 为 (indices,)32 offset2bag的shape 为 (indices,)
33 bag_size的shape 为 include_last_offset ? (offsets - 1) : (offsets,)33 bag_size的shape 为 include_last_offset ? (offsets - 1) : (offsets,)
@@ -36,7 +36,7 @@
36 36 
37 - 当mode为mean模式:37 - 当mode为mean模式:
38 38 
39- ```39+ ```cpp
40 y的shape 为 include_last_offset? (offsets - 1, embeddingDim) : (offsets, embeddingDim)40 y的shape 为 include_last_offset? (offsets - 1, embeddingDim) : (offsets, embeddingDim)
41 offset2bag的shape 为 (indices,)41 offset2bag的shape 为 (indices,)
42 bag_size的shape 为 include_last_offset ? (offsets - 1) : (offsets,)42 bag_size的shape 为 include_last_offset ? (offsets - 1) : (offsets,)
@@ -44,7 +44,8 @@
44 ```44 ```
45 45 
46 - 当mode为max模式:46 - 当mode为max模式:
47- ```47+ 
48+ ```cpp
48 y的shape 为 include_last_offset ? (offsets - 1, embeddingDim) : (offsets, embeddingDim)49 y的shape 为 include_last_offset ? (offsets - 1, embeddingDim) : (offsets, embeddingDim)
49 offset2bag的shape 为 (indices,)50 offset2bag的shape 为 (indices,)
50 bag_size的shape 为 include_last_offset ? (offsets - 1) : (offsets,)51 bag_size的shape 为 include_last_offset ? (offsets - 1) : (offsets,)
@@ -101,7 +102,7 @@
101 <td>y</td>102 <td>y</td>
102 <td>输出</td>103 <td>输出</td>
103 <td>词嵌入矩阵聚合后的结果。</td>104 <td>词嵌入矩阵聚合后的结果。</td>
104- <td>INT32INT64</td>105+ <td>FLOATFLOAT16、BFLOAT16</td>
105 <td>ND</td>106 <td>ND</td>
106 </tr>107 </tr>
107 <tr>108 <tr>
@@ -13,4 +13,4 @@
13set(SUPPORT_COMPUTE_UNIT "ascend950")13set(SUPPORT_COMPUTE_UNIT "ascend950")
14# 设置每种芯片类型对应的tiling文件目录,即采用op_host目录下哪个文件夹下的tiling文件编译14# 设置每种芯片类型对应的tiling文件目录,即采用op_host目录下哪个文件夹下的tiling文件编译
15set(SUPPORT_TILING_DIR "arch35")15set(SUPPORT_TILING_DIR "arch35")
16-add_modules_sources(HOSTNAME ${OPHOST_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR} OPTYPE embedding_dense_grad ACLNNTYPE aclnn_exclude COMPUTE_UNIT ${SUPPORT_COMPUTE_UNIT} TILING_DIR ${SUPPORT_TILING_DIR} DISABLE_IN_OPP TRUE)16+add_modules_sources(HOSTNAME ${OPHOST_NAME} MODE PRIVATE DIR ${CMAKE_CURRENT_SOURCE_DIR} OPTYPE embedding_dense_grad ACLNNTYPE aclnn_exclude COMPUTE_UNIT ${SUPPORT_COMPUTE_UNIT} TILING_DIR ${SUPPORT_TILING_DIR} DISABLE_IN_OPP TRUE DEPENDENCIES embedding_dense_grad_v2)
@@ -80,6 +80,7 @@
80 - <term>Atlas 训练系列产品</term>:grad和out参数数据类型不支持BFLOAT16。80 - <term>Atlas 训练系列产品</term>:grad和out参数数据类型不支持BFLOAT16。
81 81 
82## 约束说明82## 约束说明
83+ 
83- <term>Atlas 训练系列产品</term>84- <term>Atlas 训练系列产品</term>
84 - 对于scale为true的场景,设定grad最后一维为embeddingDim,其大小超出指定范围时会被拦截报错。其合理范围如下:85 - 对于scale为true的场景,设定grad最后一维为embeddingDim,其大小超出指定范围时会被拦截报错。其合理范围如下:
85 - indices为int32时,需满足86 - indices为int32时,需满足
@@ -98,4 +99,10 @@
98 - 在参数shape超过以下限制时,输出无法保证高精度,若开启了确定性计算,也无法保证高性能99 - 在参数shape超过以下限制时,输出无法保证高精度,若开启了确定性计算,也无法保证高性能
99 - grad合轴成二维shape后,第一个维度超过INT32_MAX(2147483647)100 - grad合轴成二维shape后,第一个维度超过INT32_MAX(2147483647)
100 - numWeights超过INT32_MAX(2147483647)101 - numWeights超过INT32_MAX(2147483647)
101- - indices合轴后维度超过INT32_INF(2139095040)时,无法保证高性能102+ - indices合轴后维度超过INT32_INF(2139095040)时,无法保证高性能
103+ 
104+ ## 调用说明
105+
106+ | 调用方式 | 调用样例 | 说明 |
107+ |--------------|------------------------------------------------------------------------|--------------------------------------------------------------|
108+ | aclnn调用 | [test_aclnn_embedding_dense_grad](./examples/test_aclnn_embedding_dense_grad.cpp) | 通过[aclnnEmbeddingDenseBackward](./docs/aclnnEmbeddingDenseBackward.md)接口方式调用EmbeddingDenseGrad算子。 |
@@ -0,0 +1,155 @@
1+/**
2+ * Copyright (c) 2025 Huawei Technologies Co., Ltd.
3+ * This program is free software, you can redistribute it and/or modify it under the terms and conditions of
4+ * CANN Open Software License Agreement Version 2.0 (the "License").
5+ * Please refer to the License for details. You may not use this file except in compliance with the License.
6+ * THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND, EITHER EXPRESS OR IMPLIED,
7+ * INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT, MERCHANTABILITY, OR FITNESS FOR A PARTICULAR PURPOSE.
8+ * See LICENSE in the root of the software repository for the full text of the License.
9+ */
10+ 
11+#include <iostream>
12+#include <vector>
13+#include "acl/acl.h"
14+#include "aclnnop/aclnn_embedding_dense_backward.h"
15+ 
16+#define CHECK_RET(cond, return_expr) \
17+ do { \
18+ if (!(cond)) { \
19+ return_expr; \
20+ } \
21+ } while (0)
22+ 
23+#define LOG_PRINT(message, ...) \
24+ do { \
25+ printf(message, ##__VA_ARGS__); \
26+ } while (0)
27+ 
28+int64_t GetShapeSize(const std::vector<int64_t>& shape) {
29+ int64_t shapeSize = 1;
30+ for (auto i : shape) {
31+ shapeSize *= i;
32+ }
33+ return shapeSize;
34+}
35+ 
36+int Init(int32_t deviceId, aclrtStream* stream) {
37+ // 固定写法,资源初始化
38+ auto ret = aclInit(nullptr);
39+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
40+ ret = aclrtSetDevice(deviceId);
41+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
42+ ret = aclrtCreateStream(stream);
43+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
44+ return 0;
45+}
46+ 
47+template <typename T>
48+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
49+ aclDataType dataType, aclTensor** tensor) {
50+ auto size = GetShapeSize(shape) * sizeof(T);
51+ // 调用aclrtMalloc申请device侧内存
52+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
53+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
54+ // 调用aclrtMemcpy将host侧数据拷贝到device侧内存上
55+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
56+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
57+ 
58+ // 计算连续tensor的strides
59+ std::vector<int64_t> strides(shape.size(), 1);
60+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
61+ strides[i] = shape[i + 1] * strides[i + 1];
62+ }
63+ 
64+ // 调用aclCreateTensor接口创建aclTensor
65+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
66+ shape.data(), shape.size(), *deviceAddr);
67+ return 0;
68+}
69+ 
70+int main() {
71+ // 1. (固定写法)device/stream初始化,参考acl API
72+ // 根据自己的实际device填写deviceId
73+ int32_t deviceId = 0;
74+ aclrtStream stream;
75+ auto ret = Init(deviceId, &stream);
76+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
77+ 
78+ // 2. 构造输入与输出,需要根据API的接口自定义构造
79+ uint64_t numWeights = 4;
80+ uint64_t paddingIdx = 0;
81+ bool scaleGradByFreq = false;
82+ std::vector<int64_t> gradOutputShape = {2, 3};
83+ std::vector<int64_t> indicesShape = {2};
84+ std::vector<int64_t> outShape = {4, 3};
85+ void* gradOutputDeviceAddr = nullptr;
86+ void* indicesDeviceAddr = nullptr;
87+ void* outDeviceAddr = nullptr;
88+ aclTensor* gradOutput = nullptr;
89+ aclTensor* indices = nullptr;
90+ aclTensor* out = nullptr;
91+ 
92+ std::vector<float> gradOutputHostData = {1, 2, 3, 4, 5, 6};
93+ std::vector<int64_t> indicesHostData = {1, 2};
94+ std::vector<float> outHostData = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
95+ 
96+ // 创建gradOutput aclTensor
97+ ret = CreateAclTensor(gradOutputHostData, gradOutputShape, &gradOutputDeviceAddr, aclDataType::ACL_FLOAT, &gradOutput);
98+ CHECK_RET(ret == ACL_SUCCESS, return ret);
99+ // 创建indices aclTensor
100+ ret = CreateAclTensor(indicesHostData, indicesShape, &indicesDeviceAddr, aclDataType::ACL_INT64, &indices);
101+ CHECK_RET(ret == ACL_SUCCESS, return ret);
102+ // 创建out aclTensor
103+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT, &out);
104+ CHECK_RET(ret == ACL_SUCCESS, return ret);
105+ 
106+ // 3. 调用CANN算子库API,需要修改为具体的API名称
107+ uint64_t workspaceSize = 0;
108+ aclOpExecutor* executor;
109+ // 调用aclnnEmbeddingDenseBackward第一段接口
110+ ret = aclnnEmbeddingDenseBackwardGetWorkspaceSize(gradOutput, indices, numWeights, paddingIdx, scaleGradByFreq, out,
111+ &workspaceSize, &executor);
112+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnEmbeddingDenseBackwardGetWorkspaceSize failed. ERROR: %d\n", ret);
113+ return ret);
114+ // 根据第一段接口计算出的workspaceSize申请device内存
115+ void* workspaceAddr = nullptr;
116+ if (workspaceSize > 0) {
117+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
118+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
119+ }
120+ // 调用aclnnEmbeddingDenseBackward第二段接口
121+ ret = aclnnEmbeddingDenseBackward(workspaceAddr, workspaceSize, executor, stream);
122+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnEmbeddingDenseBackward failed. ERROR: %d\n", ret); return ret);
123+ 
124+ // 4. (固定写法)同步等待任务执行结束
125+ ret = aclrtSynchronizeStream(stream);
126+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
127+ 
128+ // 5. 获取输出的值,将device侧内存上的结果拷贝至host侧,需要根据具体API的接口定义修改
129+ auto size = GetShapeSize(outShape);
130+ std::vector<float> resultData(size, 0);
131+ ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]),
132+ outDeviceAddr, size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
133+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy resultData from device to host failed. ERROR: %d\n", ret);
134+ return ret);
135+ for (int64_t i = 0; i < size; i++) {
136+ LOG_PRINT("resultData[%ld] is: %f\n", i, resultData[i]);
137+ }
138+ 
139+ // 6. 释放aclTensor,需要根据具体API的接口定义修改
140+ aclDestroyTensor(gradOutput);
141+ aclDestroyTensor(indices);
142+ aclDestroyTensor(out);
143+ 
144+ // 7. 释放device资源,需要根据具体API的接口定义修改
145+ aclrtFree(gradOutputDeviceAddr);
146+ aclrtFree(indicesDeviceAddr);
147+ aclrtFree(outDeviceAddr);
148+ if (workspaceSize > 0) {
149+ aclrtFree(workspaceAddr);
150+ }
151+ aclrtDestroyStream(stream);
152+ aclrtResetDevice(deviceId);
153+ aclFinalize();
154+ return 0;
155+}
@@ -40,7 +40,7 @@
40 <thead>40 <thead>
41 <tr>41 <tr>
42 <th>参数名</th>42 <th>参数名</th>
43- <th>输入/输出</th>43+ <th>输入/输出/属性</th>
44 <th>描述</th>44 <th>描述</th>
45 <th>数据类型</th>45 <th>数据类型</th>
46 <th>数据格式</th>46 <th>数据格式</th>
@@ -77,7 +77,7 @@
77 <tr>77 <tr>
78 <td>batch_dims</td>78 <td>batch_dims</td>
79 <td>可选属性</td>79 <td>可选属性</td>
80- <td><ul><li>用于指定批处理的维度。</li><li>默认值为0.0。</li></ul></td>80+ <td><ul><li>用于指定批处理的维度。</li><li>默认值为0。</li></ul></td>
81 <td>INT64</td>81 <td>INT64</td>
82 <td>ND</td>82 <td>ND</td>
83 </tr>83 </tr>
@@ -99,4 +99,4 @@
99| 调用方式 | 调用样例 | 说明 |99| 调用方式 | 调用样例 | 说明 |
100|--------------|------------------------------------------------------------------------|--------------------------------------------------------------|100|--------------|------------------------------------------------------------------------|--------------------------------------------------------------|
101| aclnn调用 | [test_aclnn_gather_v2](./examples/test_aclnn_gather_v2.cpp) | 通过[aclnnGatherV2](./docs/aclnnGatherV2.md)接口方式调用GatherV2算子。 |101| aclnn调用 | [test_aclnn_gather_v2](./examples/test_aclnn_gather_v2.cpp) | 通过[aclnnGatherV2](./docs/aclnnGatherV2.md)接口方式调用GatherV2算子。 |
102-| aclnn调用 | [test_aclnn_embedding_renorm](./examples/test_aclnn_embedding_renorm.cpp) | 通过[aclnnEmbeddingRenorm](./docs/aclnnEmbeddingRenorm.md)接口方式调用EmbeddingRenorm算子。 |102+| aclnn调用 | [test_aclnn_embedding_renorm](./examples/test_aclnn_embedding_renorm.cpp) | 通过[aclnnEmbeddingRenorm](./docs/aclnnEmbeddingRenorm.md)接口方式调用Renorm算子。 |
@@ -11,7 +11,6 @@
11| <term>Atlas 推理系列产品</term> | × |11| <term>Atlas 推理系列产品</term> | × |
12| <term>Atlas 训练系列产品</term> | √ |12| <term>Atlas 训练系列产品</term> | √ |
13 13 
14- 
15## 功能说明14## 功能说明
16 15 
17- 接口功能:根据索引 indices 将输入 self 对应坐标的数据与输入 values 进行替换或累加。16- 接口功能:根据索引 indices 将输入 self 对应坐标的数据与输入 values 进行替换或累加。
@@ -29,10 +28,8 @@
29 self[indices] = self[indices] + values28 self[indices] = self[indices] + values
30 $$29 $$
31 30 
32- 
33## 参数说明31## 参数说明
34 32 
35- 
36<table style="undefined;table-layout: fixed; width: 980px"><colgroup>33<table style="undefined;table-layout: fixed; width: 980px"><colgroup>
37 <col style="width: 100px">34 <col style="width: 100px">
38 <col style="width: 150px">35 <col style="width: 150px">
@@ -43,7 +40,7 @@
43 <thead>40 <thead>
44 <tr>41 <tr>
45 <th>参数名</th>42 <th>参数名</th>
46- <th>输入/输出</th>43+ <th>输入/输出/属性</th>
47 <th>描述</th>44 <th>描述</th>
48 <th>数据类型</th>45 <th>数据类型</th>
49 <th>数据格式</th>46 <th>数据格式</th>
@@ -87,11 +84,13 @@
87 </tbody></table>84 </tbody></table>
88 85 
89 - <term>Atlas 200I/500 A2 推理产品</term><term>Atlas 推理系列产品</term><term>Atlas 训练系列产品</term>:数据类型不支持BFLOAT16。86 - <term>Atlas 200I/500 A2 推理产品</term><term>Atlas 推理系列产品</term><term>Atlas 训练系列产品</term>:数据类型不支持BFLOAT16。
87+ 
90## 约束说明88## 约束说明
91 89 
9290
91+ 
93## 调用说明92## 调用说明
94 93 
95| 调用方式 | 调用样例 | 说明 |94| 调用方式 | 调用样例 | 说明 |
96|--------------|------------------------------------------------------------------------|--------------------------------------------------------------|95|--------------|------------------------------------------------------------------------|--------------------------------------------------------------|
97-| aclnn调用 | [test_aclnn_index_put_v2](examples/arch35/test_aclnn_index_put_v2.cpp) | 通过[aclnnAbs](./docs/aclnnIndexPutImpl.md)接口方式调用IndexPutImpl算子。 |96+| aclnn调用 | [test_aclnn_index_put_v2](examples/arch35/test_aclnn_index_put_v2.cpp) | 通过[aclnnIndexPutImpl](./docs/aclnnIndexPutImpl.md)接口方式调用IndexPutImpl算子。 |