已合并
add bidirection_lstm,bidirection_lstmv2 example #1909
LSYlsy0214创建于 2月13日
add bidirection_lstm,bidirection_lstmv2 example #1909
已合并
共 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 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + do { \ | ||
| 17 | + if (!(cond)) { \ | ||
| 18 | + return_expr; \ | ||
| 19 | + } \ | ||
| 20 | + } while (0) | ||
| 21 | + | ||
| 22 | + | ||
| 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 | + | ||
| 11 | + | ||
| 12 | + | ||
| 13 | + | ||
| 14 | + | ||
| 15 | + | ||
| 16 | + do { \ | ||
| 17 | + if (!(cond)) { \ | ||
| 18 | + return_expr; \ | ||
| 19 | + } \ | ||
| 20 | + } while (0) | ||
| 21 | + | ||
| 22 | + | ||
| 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 | +} | ||