已合并
add bidirection_lstm,bidirection_lstmv2 example #1909
LSYlsy0214创建于 2月13日
add bidirection_lstm,bidirection_lstmv2 example #1909
已合并
LSYlsy0214创建于 2月13日
2 个文件变更+507-0
@@ -0,0 +1,252 @@
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+#include <iostream>
11+#include <vector>
12+#include "acl/acl.h"
13+#include "aclnnop/aclnn_bidirection_lstm.h"
14+ 
15+#define CHECK_RET(cond, return_expr) \
16+ do { \
17+ if (!(cond)) { \
18+ return_expr; \
19+ } \
20+ } while (0)
21+ 
22+#define LOG_PRINT(message, ...) \
23+ do { \
24+ printf(message, ##__VA_ARGS__); \
25+ } while (0)
26+ 
27+int64_t GetShapeSize(const std::vector<int64_t>& shape) {
28+ int64_t shapeSize = 1;
29+ for (auto i : shape) {
30+ shapeSize *= i;
31+ }
32+ return shapeSize;
33+}
34+ 
35+void PrintOutResult(std::vector<int64_t> &shape, void** deviceAddr) {
36+ auto size = GetShapeSize(shape);
37+ std::vector<float> resultData(size, 0);
38+ auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]),
39+ *deviceAddr, size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
40+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return);
41+ for (int64_t i = 0; i < size; i++) {
42+ LOG_PRINT("mean result[%ld] is: %f\n", i, resultData[i]);
43+ }
44+}
45+ 
46+int Init(int32_t deviceId, aclrtStream* stream) {
47+ // 固定写法,资源初始化
48+ auto ret = aclInit(nullptr);
49+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
50+ ret = aclrtSetDevice(deviceId);
51+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
52+ ret = aclrtCreateStream(stream);
53+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
54+ return 0;
55+}
56+ 
57+template <typename T>
58+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
59+ aclDataType dataType, aclTensor** tensor) {
60+ auto size = GetShapeSize(shape) * sizeof(T);
61+ // 调用aclrtMalloc申请device侧内存
62+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
63+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
64+ // 调用aclrtMemcpy将host侧数据复制到device侧内存上
65+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
66+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
67+ 
68+ // 计算连续tensor的strides
69+ std::vector<int64_t> strides(shape.size(), 1);
70+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
71+ strides[i] = shape[i + 1] * strides[i + 1];
72+ }
73+ 
74+ // 调用aclCreateTensor接口创建aclTensor
75+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
76+ shape.data(), shape.size(), *deviceAddr);
77+ return 0;
78+}
79+ 
80+int main() {
81+ // 1. (固定写法)device/stream初始化,参考acl API手册
82+ // 根据自己的实际device填写deviceId
83+ int32_t deviceId = 0;
84+ aclrtStream stream;
85+ auto ret = Init(deviceId, &stream);
86+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
87+ 
88+ // 2. 构造输入与输出,需要根据API的接口自定义构造
89+ int time_step = 2;
90+ int batch_size = 32;
91+ int input_size = 32;
92+ int hidden_size = 32;
93+ 
94+ int64_t numLayers = 1;
95+ bool isbias = true;
96+ bool batchFirst = false;
97+ bool bidirection = true;
98+ 
99+ std::vector<int64_t> selfShape = {time_step, batch_size, input_size};
100+ std::vector<int64_t> weightHIShape = {4 * hidden_size, input_size};
101+ std::vector<int64_t> weightHHShape = {4 * hidden_size, hidden_size};
102+ std::vector<int64_t> initHShape = {2, batch_size, hidden_size};
103+ std::vector<int64_t> initCShape = {2, batch_size, hidden_size};
104+ std::vector<int64_t> biasHIShape = {4 * hidden_size};
105+ std::vector<int64_t> biasHHShape = {4 * hidden_size};
106+ std::vector<int64_t> outShape = {time_step, batch_size, 2 * hidden_size};
107+ std::vector<int64_t> outHShape = {2, batch_size, hidden_size};
108+ std::vector<int64_t> outCShape = {2, batch_size, hidden_size};
109+ 
110+ void* selfDeviceAddr = nullptr;
111+ void* weightHIDeviceAddr = nullptr;
112+ void* weightHHDeviceAddr = nullptr;
113+ void* weightHIReverseDeviceAddr = nullptr;
114+ void* weightHHReverseDeviceAddr = nullptr;
115+ void* initHDeviceAddr = nullptr;
116+ void* initCDeviceAddr = nullptr;
117+ void* biasHIDeviceAddr = nullptr;
118+ void* biasHHDeviceAddr = nullptr;
119+ void* biasHIReverseDeviceAddr = nullptr;
120+ void* biasHHReverseDeviceAddr = nullptr;
121+ void* outDeviceAddr = nullptr;
122+ void* outHDeviceAddr = nullptr;
123+ void* outCDeviceAddr = nullptr;
124+ 
125+ aclTensor* self = nullptr;
126+ aclTensor* weightHI = nullptr;
127+ aclTensor* weightHH = nullptr;
128+ aclTensor* weightHIReverse = nullptr;
129+ aclTensor* weightHHReverse = nullptr;
130+ aclTensor* biasHI = nullptr;
131+ aclTensor* biasHH = nullptr;
132+ aclTensor* biasHIReverse = nullptr;
133+ aclTensor* biasHHReverse = nullptr;
134+ aclTensor* initH = nullptr;
135+ aclTensor* initC = nullptr;
136+ aclTensor* out = nullptr;
137+ aclTensor* outH = nullptr;
138+ aclTensor* outC = nullptr;
139+ 
140+ std::vector<uint16_t> selfHostData(GetShapeSize(selfShape));
141+ std::vector<uint16_t> weightHIHostData(GetShapeSize(weightHIShape));
142+ std::vector<uint16_t> weightHHHostData(GetShapeSize(weightHHShape));
143+ std::vector<uint16_t> biasHIHostData(GetShapeSize(biasHIShape));
144+ std::vector<uint16_t> biasHHHostData(GetShapeSize(biasHHShape));
145+ std::vector<uint16_t> initHHostData(GetShapeSize(initHShape));
146+ std::vector<uint16_t> initCHostData(GetShapeSize(initCShape));
147+ std::vector<uint16_t> outHostData(GetShapeSize(outShape));
148+ std::vector<uint16_t> outHHostData(GetShapeSize(outHShape));
149+ std::vector<uint16_t> outCHostData(GetShapeSize(outCShape));
150+ 
151+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT16, &self);
152+ CHECK_RET(ret == ACL_SUCCESS, return ret);
153+ ret = CreateAclTensor(weightHIHostData, weightHIShape, &weightHIDeviceAddr, aclDataType::ACL_FLOAT16, &weightHI);
154+ CHECK_RET(ret == ACL_SUCCESS, return ret);
155+ ret = CreateAclTensor(weightHHHostData, weightHHShape, &weightHHDeviceAddr, aclDataType::ACL_FLOAT16, &weightHH);
156+ CHECK_RET(ret == ACL_SUCCESS, return ret);
157+ ret = CreateAclTensor(initHHostData, initHShape, &initHDeviceAddr, aclDataType::ACL_FLOAT16, &initH);
158+ CHECK_RET(ret == ACL_SUCCESS, return ret);
159+ ret = CreateAclTensor(initCHostData, initCShape, &initCDeviceAddr, aclDataType::ACL_FLOAT16, &initC);
160+ CHECK_RET(ret == ACL_SUCCESS, return ret);
161+ ret = CreateAclTensor(biasHIHostData, biasHIShape, &biasHIDeviceAddr, aclDataType::ACL_FLOAT16, &biasHI);
162+ CHECK_RET(ret == ACL_SUCCESS, return ret);
163+ ret = CreateAclTensor(biasHHHostData, biasHHShape, &biasHHDeviceAddr, aclDataType::ACL_FLOAT16, &biasHH);
164+ CHECK_RET(ret == ACL_SUCCESS, return ret);
165+ ret = CreateAclTensor(weightHIHostData, weightHIShape, &weightHIReverseDeviceAddr, aclDataType::ACL_FLOAT16, &weightHIReverse);
166+ CHECK_RET(ret == ACL_SUCCESS, return ret);
167+ ret = CreateAclTensor(weightHHHostData, weightHHShape, &weightHHReverseDeviceAddr, aclDataType::ACL_FLOAT16, &weightHHReverse);
168+ CHECK_RET(ret == ACL_SUCCESS, return ret);
169+ ret = CreateAclTensor(biasHIHostData, biasHIShape, &biasHIReverseDeviceAddr, aclDataType::ACL_FLOAT16, &biasHIReverse);
170+ CHECK_RET(ret == ACL_SUCCESS, return ret);
171+ ret = CreateAclTensor(biasHHHostData, biasHHShape, &biasHHReverseDeviceAddr, aclDataType::ACL_FLOAT16, &biasHHReverse);
172+ CHECK_RET(ret == ACL_SUCCESS, return ret);
173+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT16, &out);
174+ CHECK_RET(ret == ACL_SUCCESS, return ret);
175+ ret = CreateAclTensor(outHHostData, outHShape, &outHDeviceAddr, aclDataType::ACL_FLOAT16, &outH);
176+ CHECK_RET(ret == ACL_SUCCESS, return ret);
177+ ret = CreateAclTensor(outCHostData, outCShape, &outCDeviceAddr, aclDataType::ACL_FLOAT16, &outC);
178+ CHECK_RET(ret == ACL_SUCCESS, return ret);
179+ 
180+ // 3. 调用CANN算子库API,需要修改为具体的Api名称
181+ uint64_t workspaceSize = 0;
182+ aclOpExecutor* executor;
183+ 
184+ // 调用aclnnBidirectionLSTM第一段接口
185+ ret = aclnnBidirectionLSTMGetWorkspaceSize(self, initH, initC, weightHI, weightHH,
186+ biasHI, biasHH, weightHIReverse, weightHHReverse, biasHIReverse, biasHHReverse,
187+ numLayers, isbias, batchFirst, bidirection,
188+ out, outH, outC,
189+ &workspaceSize, &executor);
190+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBidirectionLSTMGetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
191+ 
192+ // 根据第一段接口计算出的workspaceSize申请device内存
193+ void* workspaceAddr = nullptr;
194+ if (workspaceSize > 0) {
195+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
196+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
197+ }
198+ 
199+ // 调用aclnnBidirectionLSTM第二段接口
200+ ret = aclnnBidirectionLSTM(workspaceAddr, workspaceSize, executor, stream);
201+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBidirectionLSTM failed. ERROR: %d\n", ret); return ret);
202+ 
203+ // 4. (固定写法)同步等待任务执行结束
204+ ret = aclrtSynchronizeStream(stream);
205+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
206+ 
207+ // 5. 获取输出的值,将device侧内存上的结果复制至host侧,需要根据具体API的接口定义修改
208+ PrintOutResult(outShape, &outDeviceAddr);
209+ PrintOutResult(outHShape, &outHDeviceAddr);
210+ PrintOutResult(outCShape, &outCDeviceAddr);
211+ 
212+ // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改
213+ aclDestroyTensor(self);
214+ aclDestroyTensor(weightHI);
215+ aclDestroyTensor(weightHH);
216+ aclDestroyTensor(initH);
217+ aclDestroyTensor(initC);
218+ aclDestroyTensor(biasHI);
219+ aclDestroyTensor(biasHH);
220+ aclDestroyTensor(weightHIReverse);
221+ aclDestroyTensor(weightHHReverse);
222+ aclDestroyTensor(biasHIReverse);
223+ aclDestroyTensor(biasHHReverse);
224+ aclDestroyTensor(out);
225+ aclDestroyTensor(outH);
226+ aclDestroyTensor(outC);
227+ 
228+ // 7. 释放device资源
229+ aclrtFree(selfDeviceAddr);
230+ aclrtFree(weightHIDeviceAddr);
231+ aclrtFree(weightHHDeviceAddr);
232+ aclrtFree(initHDeviceAddr);
233+ aclrtFree(initCDeviceAddr);
234+ aclrtFree(biasHIDeviceAddr);
235+ aclrtFree(biasHHDeviceAddr);
236+ aclrtFree(weightHIReverseDeviceAddr);
237+ aclrtFree(weightHHReverseDeviceAddr);
238+ aclrtFree(biasHIReverseDeviceAddr);
239+ aclrtFree(biasHHReverseDeviceAddr);
240+ aclrtFree(outDeviceAddr);
241+ aclrtFree(outHDeviceAddr);
242+ aclrtFree(outCDeviceAddr);
243+ 
244+ if (workspaceSize > 0) {
245+ aclrtFree(workspaceAddr);
246+ }
247+ aclrtDestroyStream(stream);
248+ aclrtResetDevice(deviceId);
249+ aclFinalize();
250+ 
251+ return 0;
252+}
@@ -0,0 +1,255 @@
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+#include <iostream>
11+#include <vector>
12+#include "acl/acl.h"
13+#include "aclnnop/aclnn_bidirection_lstmv2.h"
14+ 
15+#define CHECK_RET(cond, return_expr) \
16+ do { \
17+ if (!(cond)) { \
18+ return_expr; \
19+ } \
20+ } while (0)
21+ 
22+#define LOG_PRINT(message, ...) \
23+ do { \
24+ printf(message, ##__VA_ARGS__); \
25+ } while (0)
26+ 
27+int64_t GetShapeSize(const std::vector<int64_t>& shape) {
28+ int64_t shapeSize = 1;
29+ for (auto i : shape) {
30+ shapeSize *= i;
31+ }
32+ return shapeSize;
33+}
34+ 
35+void PrintOutResult(std::vector<int64_t> &shape, void** deviceAddr) {
36+ auto size = GetShapeSize(shape);
37+ std::vector<float> resultData(size, 0);
38+ auto ret = aclrtMemcpy(resultData.data(), resultData.size() * sizeof(resultData[0]),
39+ *deviceAddr, size * sizeof(resultData[0]), ACL_MEMCPY_DEVICE_TO_HOST);
40+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("copy result from device to host failed. ERROR: %d\n", ret); return);
41+ for (int64_t i = 0; i < size; i++) {
42+ LOG_PRINT("mean result[%ld] is: %f\n", i, resultData[i]);
43+ }
44+}
45+ 
46+int Init(int32_t deviceId, aclrtStream* stream) {
47+ // 固定写法,资源初始化
48+ auto ret = aclInit(nullptr);
49+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclInit failed. ERROR: %d\n", ret); return ret);
50+ ret = aclrtSetDevice(deviceId);
51+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSetDevice failed. ERROR: %d\n", ret); return ret);
52+ ret = aclrtCreateStream(stream);
53+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtCreateStream failed. ERROR: %d\n", ret); return ret);
54+ return 0;
55+}
56+ 
57+template <typename T>
58+int CreateAclTensor(const std::vector<T>& hostData, const std::vector<int64_t>& shape, void** deviceAddr,
59+ aclDataType dataType, aclTensor** tensor) {
60+ auto size = GetShapeSize(shape) * sizeof(T);
61+ // 调用aclrtMalloc申请device侧内存
62+ auto ret = aclrtMalloc(deviceAddr, size, ACL_MEM_MALLOC_HUGE_FIRST);
63+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMalloc failed. ERROR: %d\n", ret); return ret);
64+ // 调用aclrtMemcpy将host侧数据复制到device侧内存上
65+ ret = aclrtMemcpy(*deviceAddr, size, hostData.data(), size, ACL_MEMCPY_HOST_TO_DEVICE);
66+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtMemcpy failed. ERROR: %d\n", ret); return ret);
67+ 
68+ // 计算连续tensor的strides
69+ std::vector<int64_t> strides(shape.size(), 1);
70+ for (int64_t i = shape.size() - 2; i >= 0; i--) {
71+ strides[i] = shape[i + 1] * strides[i + 1];
72+ }
73+ 
74+ // 调用aclCreateTensor接口创建aclTensor
75+ *tensor = aclCreateTensor(shape.data(), shape.size(), dataType, strides.data(), 0, aclFormat::ACL_FORMAT_ND,
76+ shape.data(), shape.size(), *deviceAddr);
77+ return 0;
78+}
79+ 
80+int main() {
81+ // 1. (固定写法)device/stream初始化,参考acl API手册
82+ // 根据自己的实际device填写deviceId
83+ int32_t deviceId = 0;
84+ aclrtStream stream;
85+ auto ret = Init(deviceId, &stream);
86+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("Init acl failed. ERROR: %d\n", ret); return ret);
87+ 
88+ // 2. 构造输入与输出,需要根据API的接口自定义构造
89+ int time_step = 2;
90+ int batch_size = 32;
91+ int input_size = 32;
92+ int hidden_size = 32;
93+ 
94+ int64_t numLayers = 1;
95+ bool isbias = true;
96+ bool batchFirst = false;
97+ bool bidirection = true;
98+ bool packed = false;
99+ 
100+ std::vector<int64_t> selfShape = {time_step, batch_size, input_size};
101+ std::vector<int64_t> weightHIShape = {4 * hidden_size, input_size};
102+ std::vector<int64_t> weightHHShape = {4 * hidden_size, hidden_size};
103+ std::vector<int64_t> initHShape = {2, batch_size, hidden_size};
104+ std::vector<int64_t> initCShape = {2, batch_size, hidden_size};
105+ std::vector<int64_t> biasHIShape = {4 * hidden_size};
106+ std::vector<int64_t> biasHHShape = {4 * hidden_size};
107+ std::vector<int64_t> outShape = {time_step, batch_size, 2 * hidden_size};
108+ std::vector<int64_t> outHShape = {2, batch_size, hidden_size};
109+ std::vector<int64_t> outCShape = {2, batch_size, hidden_size};
110+ 
111+ void* selfDeviceAddr = nullptr;
112+ void* weightHIDeviceAddr = nullptr;
113+ void* weightHHDeviceAddr = nullptr;
114+ void* weightHIReverseDeviceAddr = nullptr;
115+ void* weightHHReverseDeviceAddr = nullptr;
116+ void* initHDeviceAddr = nullptr;
117+ void* initCDeviceAddr = nullptr;
118+ void* biasHIDeviceAddr = nullptr;
119+ void* biasHHDeviceAddr = nullptr;
120+ void* biasHIReverseDeviceAddr = nullptr;
121+ void* biasHHReverseDeviceAddr = nullptr;
122+ void* outDeviceAddr = nullptr;
123+ void* outHDeviceAddr = nullptr;
124+ void* outCDeviceAddr = nullptr;
125+ 
126+ aclTensor* self = nullptr;
127+ aclTensor* weightHI = nullptr;
128+ aclTensor* weightHH = nullptr;
129+ aclTensor* weightHIReverse = nullptr;
130+ aclTensor* weightHHReverse = nullptr;
131+ aclTensor* biasHI = nullptr;
132+ aclTensor* biasHH = nullptr;
133+ aclTensor* biasHIReverse = nullptr;
134+ aclTensor* biasHHReverse = nullptr;
135+ aclTensor* batchSize = nullptr;
136+ aclTensor* initH = nullptr;
137+ aclTensor* initC = nullptr;
138+ aclTensor* out = nullptr;
139+ aclTensor* outH = nullptr;
140+ aclTensor* outC = nullptr;
141+ 
142+ std::vector<uint16_t> selfHostData(GetShapeSize(selfShape));
143+ std::vector<uint16_t> weightHIHostData(GetShapeSize(weightHIShape));
144+ std::vector<uint16_t> weightHHHostData(GetShapeSize(weightHHShape));
145+ std::vector<uint16_t> biasHIHostData(GetShapeSize(biasHIShape));
146+ std::vector<uint16_t> biasHHHostData(GetShapeSize(biasHHShape));
147+ std::vector<uint16_t> initHHostData(GetShapeSize(initHShape));
148+ std::vector<uint16_t> initCHostData(GetShapeSize(initCShape));
149+ std::vector<uint16_t> outHostData(GetShapeSize(outShape));
150+ std::vector<uint16_t> outHHostData(GetShapeSize(outHShape));
151+ std::vector<uint16_t> outCHostData(GetShapeSize(outCShape));
152+ 
153+ ret = CreateAclTensor(selfHostData, selfShape, &selfDeviceAddr, aclDataType::ACL_FLOAT16, &self);
154+ CHECK_RET(ret == ACL_SUCCESS, return ret);
155+ ret = CreateAclTensor(weightHIHostData, weightHIShape, &weightHIDeviceAddr, aclDataType::ACL_FLOAT16, &weightHI);
156+ CHECK_RET(ret == ACL_SUCCESS, return ret);
157+ ret = CreateAclTensor(weightHHHostData, weightHHShape, &weightHHDeviceAddr, aclDataType::ACL_FLOAT16, &weightHH);
158+ CHECK_RET(ret == ACL_SUCCESS, return ret);
159+ ret = CreateAclTensor(initHHostData, initHShape, &initHDeviceAddr, aclDataType::ACL_FLOAT16, &initH);
160+ CHECK_RET(ret == ACL_SUCCESS, return ret);
161+ ret = CreateAclTensor(initCHostData, initCShape, &initCDeviceAddr, aclDataType::ACL_FLOAT16, &initC);
162+ CHECK_RET(ret == ACL_SUCCESS, return ret);
163+ ret = CreateAclTensor(biasHIHostData, biasHIShape, &biasHIDeviceAddr, aclDataType::ACL_FLOAT16, &biasHI);
164+ CHECK_RET(ret == ACL_SUCCESS, return ret);
165+ ret = CreateAclTensor(biasHHHostData, biasHHShape, &biasHHDeviceAddr, aclDataType::ACL_FLOAT16, &biasHH);
166+ CHECK_RET(ret == ACL_SUCCESS, return ret);
167+ ret = CreateAclTensor(weightHIHostData, weightHIShape, &weightHIReverseDeviceAddr, aclDataType::ACL_FLOAT16, &weightHIReverse);
168+ CHECK_RET(ret == ACL_SUCCESS, return ret);
169+ ret = CreateAclTensor(weightHHHostData, weightHHShape, &weightHHReverseDeviceAddr, aclDataType::ACL_FLOAT16, &weightHHReverse);
170+ CHECK_RET(ret == ACL_SUCCESS, return ret);
171+ ret = CreateAclTensor(biasHIHostData, biasHIShape, &biasHIReverseDeviceAddr, aclDataType::ACL_FLOAT16, &biasHIReverse);
172+ CHECK_RET(ret == ACL_SUCCESS, return ret);
173+ ret = CreateAclTensor(biasHHHostData, biasHHShape, &biasHHReverseDeviceAddr, aclDataType::ACL_FLOAT16, &biasHHReverse);
174+ CHECK_RET(ret == ACL_SUCCESS, return ret);
175+ ret = CreateAclTensor(outHostData, outShape, &outDeviceAddr, aclDataType::ACL_FLOAT16, &out);
176+ CHECK_RET(ret == ACL_SUCCESS, return ret);
177+ ret = CreateAclTensor(outHHostData, outHShape, &outHDeviceAddr, aclDataType::ACL_FLOAT16, &outH);
178+ CHECK_RET(ret == ACL_SUCCESS, return ret);
179+ ret = CreateAclTensor(outCHostData, outCShape, &outCDeviceAddr, aclDataType::ACL_FLOAT16, &outC);
180+ CHECK_RET(ret == ACL_SUCCESS, return ret);
181+ 
182+ // 3. 调用CANN算子库API,需要修改为具体的Api名称
183+ uint64_t workspaceSize = 0;
184+ aclOpExecutor* executor;
185+ 
186+ // 调用aclnnBidirectionLSTMV2第一段接口
187+ ret = aclnnBidirectionLSTMV2GetWorkspaceSize(self, initH, initC, weightHI, weightHH,
188+ biasHI, biasHH, weightHIReverse, weightHHReverse, biasHIReverse, biasHHReverse,
189+ batchSize,
190+ numLayers, isbias, batchFirst, bidirection, packed,
191+ out, outH, outC,
192+ &workspaceSize, &executor);
193+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBidirectionLSTMV2GetWorkspaceSize failed. ERROR: %d\n", ret); return ret);
194+ 
195+ // 根据第一段接口计算出的workspaceSize申请device内存
196+ void* workspaceAddr = nullptr;
197+ if (workspaceSize > 0) {
198+ ret = aclrtMalloc(&workspaceAddr, workspaceSize, ACL_MEM_MALLOC_HUGE_FIRST);
199+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("allocate workspace failed. ERROR: %d\n", ret); return ret);
200+ }
201+ 
202+ // 调用aclnnBidirectionLSTMV2第二段接口
203+ ret = aclnnBidirectionLSTMV2(workspaceAddr, workspaceSize, executor, stream);
204+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclnnBidirectionLSTMV2 failed. ERROR: %d\n", ret); return ret);
205+ 
206+ // 4. (固定写法)同步等待任务执行结束
207+ ret = aclrtSynchronizeStream(stream);
208+ CHECK_RET(ret == ACL_SUCCESS, LOG_PRINT("aclrtSynchronizeStream failed. ERROR: %d\n", ret); return ret);
209+ 
210+ // 5. 获取输出的值,将device侧内存上的结果复制至host侧,需要根据具体API的接口定义修改
211+ PrintOutResult(outShape, &outDeviceAddr);
212+ PrintOutResult(outHShape, &outHDeviceAddr);
213+ PrintOutResult(outCShape, &outCDeviceAddr);
214+ 
215+ // 6. 释放aclTensor和aclScalar,需要根据具体API的接口定义修改
216+ aclDestroyTensor(self);
217+ aclDestroyTensor(weightHI);
218+ aclDestroyTensor(weightHH);
219+ aclDestroyTensor(initH);
220+ aclDestroyTensor(initC);
221+ aclDestroyTensor(biasHI);
222+ aclDestroyTensor(biasHH);
223+ aclDestroyTensor(weightHIReverse);
224+ aclDestroyTensor(weightHHReverse);
225+ aclDestroyTensor(biasHIReverse);
226+ aclDestroyTensor(biasHHReverse);
227+ aclDestroyTensor(out);
228+ aclDestroyTensor(outH);
229+ aclDestroyTensor(outC);
230+ 
231+ // 7. 释放device资源
232+ aclrtFree(selfDeviceAddr);
233+ aclrtFree(weightHIDeviceAddr);
234+ aclrtFree(weightHHDeviceAddr);
235+ aclrtFree(initHDeviceAddr);
236+ aclrtFree(initCDeviceAddr);
237+ aclrtFree(biasHIDeviceAddr);
238+ aclrtFree(biasHHDeviceAddr);
239+ aclrtFree(weightHIReverseDeviceAddr);
240+ aclrtFree(weightHHReverseDeviceAddr);
241+ aclrtFree(biasHIReverseDeviceAddr);
242+ aclrtFree(biasHHReverseDeviceAddr);
243+ aclrtFree(outDeviceAddr);
244+ aclrtFree(outHDeviceAddr);
245+ aclrtFree(outCDeviceAddr);
246+ 
247+ if (workspaceSize > 0) {
248+ aclrtFree(workspaceAddr);
249+ }
250+ aclrtDestroyStream(stream);
251+ aclrtResetDevice(deviceId);
252+ aclFinalize();
253+ 
254+ return 0;
255+}