Line data Source code
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 : * \file aclnn_lstm_backward.cpp
13 : * \brief
14 : */
15 : #include "aclnn_lstm_backward.h"
16 : #include "single_layer_lstm_grad.h"
17 : #include "aclnn_kernels/cast.h"
18 : #include "aclnn_kernels/contiguous.h"
19 : #include "aclnn/aclnn_base.h"
20 : #include "opdev/common_types.h"
21 : #include "opdev/data_type_utils.h"
22 : #include "opdev/shape_utils.h"
23 : #include "opdev/format_utils.h"
24 : #include "opdev/op_dfx.h"
25 : #include "opdev/op_executor.h"
26 : #include "opdev/op_log.h"
27 : #include "opdev/tensor_view_utils.h"
28 : #include "opdev/platform.h"
29 : #include "aclnn_kernels/common/op_error_check.h"
30 : #include "level0/greater.h"
31 : #include "aclnn_kernels/cast.h"
32 : #include "level0/concat.h"
33 : #include "level0/arange.h"
34 : #include "aclnn_kernels/reshape.h"
35 : #include "level0/broadcast_to.h"
36 : #include "aclnn_kernels/slice.h"
37 : #include "level0/unsqueeze.h"
38 : #include "level0/squeeze.h"
39 : #include "aclnn_kernels/transpose.h"
40 : #include "level0/add.h"
41 : #include "level0/zero_op.h"
42 : using namespace op;
43 : #ifdef __cplusplus
44 : extern "C" {
45 : #endif
46 :
47 : namespace {
48 : // 通用维度常量
49 : constexpr int64_t DIM_ZERO = 0;
50 : constexpr int64_t DIM_ONE = 1;
51 : constexpr int64_t DIM_TWO = 2;
52 : constexpr int64_t DIM_THREE = 3;
53 :
54 : // LSTM特定常量
55 : constexpr int64_t GATE_COUNT = 4; // i, j, f, o 四个门
56 : constexpr int64_t SINGLE_DIRECTION = 1;
57 : constexpr int64_t BI_DIRECTION = 2;
58 : constexpr int64_t HC_TENSOR_COUNT = 2; // h和c两个张量
59 : constexpr int64_t REDUCE_DIM = 1;
60 : constexpr int64_t CONCAT_DIM_HIDDEN = 2;
61 : constexpr int64_t CONCAT_DIM_LAYER = 0;
62 : constexpr int64_t WEIGHT_INPUT_INDEX = 0;
63 : constexpr int64_t WEIGHT_HIDDEN_INDEX = 1;
64 : constexpr int64_t BIAS_INPUT_INDEX = 2;
65 : constexpr int64_t BIAS_HIDDEN_INDEX = 3;
66 : constexpr int64_t LSTM_CONFIG_NO_BIAS_NO_BIDIR = 0;
67 : constexpr int64_t LSTM_CONFIG_BIDIR_ONLY = 1;
68 : constexpr int64_t LSTM_CONFIG_BIAS_ONLY = 2;
69 : constexpr int64_t LSTM_CONFIG_BIAS_BIDIR = 3;
70 : constexpr int64_t SEQUENCE_DIM = 0;
71 : constexpr int64_t BATCH_DIM = 1;
72 : constexpr int64_t HIDDEN_DIM = 2;
73 : constexpr int64_t OUT_NUM = 5;
74 :
75 : // 函数返回结果索引
76 : constexpr int64_t RESULT_WEIGHT_GRAD_INDEX = 0;
77 : constexpr int64_t RESULT_BIAS_GRAD_INDEX = 1;
78 : constexpr int64_t RESULT_INPUT_GRAD_INDEX = 2;
79 : constexpr int64_t RESULT_HIDDEN_GRAD_INDEX = 3;
80 : constexpr int64_t RESULT_CELL_GRAD_INDEX = 4;
81 :
82 : // 切片张量数组索引
83 : constexpr int64_t SLICE_INIT_H_INDEX = 0;
84 : constexpr int64_t SLICE_INIT_C_INDEX = 1;
85 : constexpr int64_t SLICE_DH_INDEX = 2;
86 : constexpr int64_t SLICE_DC_INDEX = 3;
87 :
88 : // 双向张量数组索引
89 : constexpr int64_t BIDIR_INIT_H_INDEX = 0;
90 : constexpr int64_t BIDIR_INIT_C_INDEX = 1;
91 : constexpr int64_t BIDIR_DH_INDEX = 2;
92 : constexpr int64_t BIDIR_DC_INDEX = 3;
93 : constexpr int64_t BIDIR_DY_INDEX = 4;
94 :
95 : // 参数索引计算
96 : constexpr int64_t NUM_NO_B_NO_BIDIR = 2;
97 : constexpr int64_t NUM_WITH_B_OR_BID = 4;
98 : constexpr int64_t NUM_WITH_B_AND_BID = 8;
99 :
100 : // 门索引
101 : constexpr int64_t GATE_I_INDEX = 0;
102 : constexpr int64_t GATE_J_INDEX = 1;
103 : constexpr int64_t GATE_F_INDEX = 2;
104 : constexpr int64_t GATE_O_INDEX = 3;
105 :
106 : // 函数返回索引
107 : constexpr int64_t INDEX_ZERO = 0;
108 : constexpr int64_t INDEX_ONE = 1;
109 : constexpr int64_t INDEX_TWO = 2;
110 : constexpr int64_t INDEX_THREE = 3;
111 : constexpr int64_t INDEX_FOUR = 4;
112 :
113 : // 拼接最大数量
114 : constexpr size_t CONCAT_MAX_NUM = 32;
115 :
116 : static const std::initializer_list<op::DataType> DTYPE_SUPPORT_LIST = {op::DataType::DT_FLOAT,
117 : op::DataType::DT_FLOAT16};
118 : } // namespace
119 :
120 : static const std::initializer_list<op::DataType> BATCH_SIZES_DTYPE_SUPPORT_LIST = {op::DataType::DT_INT64};
121 :
122 : struct LSTMContinuousTensors {
123 : const aclTensor* inputContiguous = nullptr;
124 : const aclTensorList* hxContiguous = nullptr;
125 : const aclTensorList* paramsContiguous = nullptr;
126 : const aclTensor* dyContiguous = nullptr;
127 : const aclTensor* dhContiguous = nullptr;
128 : const aclTensor* dcContiguous = nullptr;
129 : const aclTensorList* iContiguous = nullptr;
130 : const aclTensorList* gContiguous = nullptr;
131 : const aclTensorList* fContiguous = nullptr;
132 : const aclTensorList* oContiguous = nullptr;
133 : const aclTensorList* hContiguous = nullptr;
134 : const aclTensorList* cContiguous = nullptr;
135 : const aclTensorList* tanhcContiguous = nullptr;
136 : const aclTensor* batchSizesContiguous = nullptr;
137 : };
138 :
139 : struct SingleTensorItem {
140 : const char* name;
141 : const aclTensor* tensor;
142 : };
143 :
144 : struct TensorListItem {
145 : const char* name;
146 : const aclTensorList* list;
147 : };
148 :
149 4 : static const aclTensor* SplitToConcat(std::vector<const aclTensor*> tensorListA, int64_t dim, aclOpExecutor* executor)
150 : {
151 4 : if (tensorListA.size() == 1) {
152 2 : return tensorListA[0];
153 : }
154 :
155 4 : while (tensorListA.size() > 1) {
156 : std::vector<const aclTensor*> tensorListOnce;
157 : std::vector<const aclTensor*> tensorListB;
158 10 : for (auto tensor : tensorListA) {
159 8 : tensorListOnce.emplace_back(tensor);
160 8 : if (tensorListOnce.size() == CONCAT_MAX_NUM) {
161 0 : auto tensorList = executor->AllocTensorList(tensorListOnce.data(), tensorListOnce.size());
162 0 : auto concatTensor = l0op::ConcatD(tensorList, dim, executor);
163 0 : CHECK_RET(concatTensor != nullptr, nullptr);
164 0 : tensorListB.emplace_back(concatTensor);
165 : tensorListOnce.clear();
166 : }
167 : }
168 2 : if (!tensorListOnce.empty()) {
169 2 : if (tensorListOnce.size() == 1) {
170 0 : tensorListB.emplace_back(tensorListOnce.front());
171 : } else {
172 2 : auto aclTensorListTail = executor->AllocTensorList(tensorListOnce.data(), tensorListOnce.size());
173 2 : auto concatTensorTail = l0op::ConcatD(aclTensorListTail, dim, executor);
174 2 : CHECK_RET(concatTensorTail != nullptr, nullptr);
175 2 : tensorListB.emplace_back(concatTensorTail);
176 : }
177 : tensorListOnce.clear();
178 : }
179 2 : tensorListA = tensorListB;
180 : }
181 :
182 2 : CHECK_RET(!tensorListA.empty(), nullptr);
183 2 : return tensorListA.front();
184 : }
185 :
186 0 : static const aclTensor* GetMask(const aclTensor* input, const aclTensor* batchSizes, const aclTensor* h,
187 : aclOpExecutor* executor)
188 : {
189 0 : auto inputShape = input->GetViewShape();
190 0 : auto hShape = h->GetViewShape();
191 0 : auto inputDtype = input->GetDataType();
192 0 : auto batchSize = inputShape[BATCH_DIM];
193 0 : auto timeStep = inputShape[SEQUENCE_DIM];
194 0 : auto start = executor->AllocScalar(0);
195 0 : auto end = executor->AllocScalar(batchSize);
196 0 : auto step = executor->AllocScalar(1);
197 0 : gert::Shape arrangeShape;
198 : arrangeShape.AppendDim(batchSize);
199 0 : auto arrangeSizeTensor = executor->AllocTensor(arrangeShape, op::DataType::DT_INT64, Format::FORMAT_ND);
200 0 : CHECK_RET(arrangeSizeTensor != nullptr, nullptr);
201 0 : auto arrangeTensor = l0op::Arange(start, end, step, arrangeSizeTensor, false, executor);
202 0 : CHECK_RET(arrangeTensor != nullptr, nullptr);
203 0 : FVector<int64_t> broadTVector{timeStep, batchSize};
204 0 : aclIntArray* broadTArray = executor->AllocIntArray(broadTVector.data(), DIM_TWO);
205 0 : CHECK_RET(broadTArray != nullptr, nullptr);
206 0 : auto arrangeReshapeTensor = l0op::UnsqueezeNd(arrangeTensor, DIM_ZERO, executor);
207 0 : CHECK_RET(arrangeReshapeTensor != nullptr, nullptr);
208 0 : auto arrangeBroadTTensor = l0op::BroadcastTo(arrangeReshapeTensor, broadTArray, executor);
209 0 : CHECK_RET(arrangeBroadTTensor != nullptr, nullptr);
210 :
211 0 : auto batchSizesReshapeTensor = l0op::UnsqueezeNd(batchSizes, DIM_ONE, executor);
212 0 : CHECK_RET(batchSizesReshapeTensor != nullptr, nullptr);
213 0 : auto batchSizesBroadTTensor = l0op::BroadcastTo(batchSizesReshapeTensor, broadTArray, executor);
214 0 : CHECK_RET(batchSizesBroadTTensor != nullptr, nullptr);
215 :
216 0 : const aclTensor* mask = l0op::Greater(batchSizesBroadTTensor, arrangeBroadTTensor, executor);
217 0 : CHECK_RET(mask != nullptr, nullptr);
218 0 : auto seqLengthWithoutHidden = l0op::Cast(mask, inputDtype, executor);
219 0 : CHECK_RET(seqLengthWithoutHidden != nullptr, nullptr);
220 :
221 0 : FVector<int64_t> broadVector{timeStep, batchSize, hShape[HIDDEN_DIM]};
222 0 : aclIntArray* broadArray = executor->AllocIntArray(broadVector.data(), DIM_THREE);
223 0 : CHECK_RET(broadArray != nullptr, nullptr);
224 0 : auto seqLengthReshape = l0op::UnsqueezeNd(seqLengthWithoutHidden, DIM_TWO, executor);
225 0 : CHECK_RET(seqLengthReshape != nullptr, nullptr);
226 0 : auto seqlength = l0op::BroadcastTo(seqLengthReshape, broadArray, executor);
227 0 : CHECK_RET(seqlength != nullptr, nullptr);
228 : return seqlength;
229 : }
230 :
231 5 : static std::array<const aclTensor*, OUT_NUM> ExecLstmBackward(
232 : const aclTensor* input, const aclTensor* initH, const aclTensor* initC, const aclTensor* weight,
233 : const aclTensor* bias, const aclTensor* dy, const aclTensor* dh, const aclTensor* dc, const aclTensor* seqLength,
234 : const aclTensor* i, const aclTensor* j, const aclTensor* f, const aclTensor* o, const aclTensor* h,
235 : const aclTensor* c, const aclTensor* tanhc, aclOpExecutor* executor, bool flagDirection = false)
236 : {
237 5 : const char* direction = flagDirection ? "REDIRECTIONAL" : "UNIDIRECTIONAL";
238 : const char* gateOrder = "ifjo";
239 : std::array<const aclTensor*, OUT_NUM> nullptrRes{nullptr, nullptr, nullptr, nullptr, nullptr};
240 5 : auto result = l0op::SingleLayerLstmGrad(input, weight, bias, nullptr, initH, initC, h, c, dy, dh, dc, i, j, f, o,
241 : tanhc, seqLength, direction, gateOrder, executor);
242 5 : CHECK_RET(result[RESULT_WEIGHT_GRAD_INDEX] != nullptr && result[RESULT_BIAS_GRAD_INDEX] != nullptr &&
243 : result[RESULT_INPUT_GRAD_INDEX] != nullptr && result[RESULT_HIDDEN_GRAD_INDEX] != nullptr &&
244 : result[RESULT_CELL_GRAD_INDEX] != nullptr,
245 : nullptrRes);
246 5 : return result;
247 : }
248 :
249 3 : static FVector<const aclTensor*> GetWeightBiasFromParams(const aclTensorList* params, bool hasBias, bool bidirectional,
250 : int64_t paramNumPerLayer, int64_t layerIdx,
251 : aclOpExecutor* executor)
252 : {
253 : FVector<const aclTensor*> result{};
254 : FVector<const aclTensor*> nullptrRes{};
255 3 : int64_t layerOffset = (layerIdx - 1) * paramNumPerLayer;
256 :
257 : // 前向权重
258 3 : FVector<const aclTensor*> weightForwardVector = {(*params)[layerOffset + WEIGHT_INPUT_INDEX],
259 3 : (*params)[layerOffset + WEIGHT_HIDDEN_INDEX]};
260 3 : const aclTensorList* weightForwardList = executor->AllocTensorList(weightForwardVector.data(),
261 : weightForwardVector.size());
262 3 : CHECK_RET(weightForwardList != nullptr, nullptrRes);
263 3 : auto weightForward = l0op::ConcatD(weightForwardList, 1, executor);
264 3 : CHECK_RET(weightForward != nullptr, nullptrRes);
265 3 : result.emplace_back(weightForward);
266 :
267 3 : if (hasBias && bidirectional) {
268 2 : auto biasForward = l0op::Add((*params)[layerOffset + BIAS_INPUT_INDEX],
269 2 : (*params)[layerOffset + BIAS_HIDDEN_INDEX], executor);
270 2 : result.emplace_back(biasForward);
271 : // 后向权重
272 : FVector<const aclTensor*> weightBackwardVector = {
273 2 : (*params)[layerOffset + NUM_WITH_B_AND_BID / BI_DIRECTION + WEIGHT_INPUT_INDEX],
274 2 : (*params)[layerOffset + NUM_WITH_B_AND_BID / BI_DIRECTION + WEIGHT_HIDDEN_INDEX]};
275 2 : const aclTensorList* weightBackwardList = executor->AllocTensorList(weightBackwardVector.data(),
276 : weightBackwardVector.size());
277 2 : CHECK_RET(weightBackwardList != nullptr, nullptrRes);
278 2 : auto weightBackward = l0op::ConcatD(weightBackwardList, REDUCE_DIM, executor);
279 2 : CHECK_RET(weightBackward != nullptr, nullptrRes);
280 2 : result.emplace_back(weightBackward);
281 :
282 2 : auto biasBackward = l0op::Add((*params)[layerOffset + NUM_WITH_B_AND_BID / BI_DIRECTION + BIAS_INPUT_INDEX],
283 2 : (*params)[layerOffset + NUM_WITH_B_AND_BID / BI_DIRECTION + BIAS_HIDDEN_INDEX],
284 2 : executor);
285 2 : CHECK_RET(biasBackward != nullptr, nullptrRes);
286 2 : result.emplace_back(biasBackward);
287 1 : } else if (!hasBias && bidirectional) {
288 : FVector<const aclTensor*> weightBackwardVector = {
289 0 : (*params)[layerOffset + NUM_WITH_B_OR_BID / BI_DIRECTION + WEIGHT_INPUT_INDEX],
290 0 : (*params)[layerOffset + NUM_WITH_B_OR_BID / BI_DIRECTION + WEIGHT_HIDDEN_INDEX]};
291 0 : const aclTensorList* weightBackwardList = executor->AllocTensorList(weightBackwardVector.data(),
292 : weightBackwardVector.size());
293 0 : CHECK_RET(weightBackwardList != nullptr, nullptrRes);
294 0 : auto weightBackward = l0op::ConcatD(weightBackwardList, REDUCE_DIM, executor);
295 0 : CHECK_RET(weightBackward != nullptr, nullptrRes);
296 0 : const aclTensor* emptyTensor = nullptr;
297 0 : result.emplace_back(emptyTensor);
298 0 : result.emplace_back(weightBackward);
299 0 : result.emplace_back(emptyTensor);
300 1 : } else if (hasBias && !bidirectional) {
301 1 : auto biasForward = l0op::Add((*params)[layerOffset + BIAS_INPUT_INDEX],
302 1 : (*params)[layerOffset + BIAS_HIDDEN_INDEX], executor);
303 1 : CHECK_RET(biasForward != nullptr, nullptrRes);
304 1 : result.emplace_back(biasForward);
305 : } else {
306 0 : const aclTensor* biasForward = nullptr;
307 0 : result.emplace_back(biasForward);
308 : }
309 : return result;
310 : }
311 :
312 0 : static std::array<const aclTensor*, HC_TENSOR_COUNT * 2> CreateSliceTensors(int64_t layerIndex,
313 : const aclTensor* initHMultiLayer,
314 : const aclTensor* initCMultiLayer,
315 : const aclTensor* dh, const aclTensor* dc,
316 : aclOpExecutor* executor)
317 : {
318 0 : std::array<const aclTensor*, HC_TENSOR_COUNT * 2> result{nullptr, nullptr, nullptr, nullptr};
319 0 : auto hShape = initHMultiLayer->GetViewShape();
320 : // 创建偏移量数组
321 0 : FVector<int64_t> offsetVector{layerIndex, 0, 0};
322 0 : aclIntArray* offsetArray = executor->AllocIntArray(offsetVector.data(), offsetVector.size());
323 0 : CHECK_RET(offsetArray != nullptr, result);
324 :
325 : // 创建大小数组
326 0 : FVector<int64_t> sizeVector{1, hShape[BATCH_DIM], hShape[HIDDEN_DIM]};
327 0 : aclIntArray* sizeArray = executor->AllocIntArray(sizeVector.data(), sizeVector.size());
328 0 : CHECK_RET(sizeArray != nullptr, result);
329 :
330 : // 创建四个切片张量
331 0 : result[SLICE_INIT_H_INDEX] = l0op::Slice(initHMultiLayer, offsetArray, sizeArray, executor);
332 0 : result[SLICE_INIT_C_INDEX] = l0op::Slice(initCMultiLayer, offsetArray, sizeArray, executor);
333 0 : result[SLICE_DH_INDEX] = l0op::Slice(dh, offsetArray, sizeArray, executor);
334 0 : result[SLICE_DC_INDEX] = l0op::Slice(dc, offsetArray, sizeArray, executor);
335 0 : return result;
336 : }
337 :
338 : static std::tuple<const aclTensor*, std::vector<const aclTensor*>, std::vector<const aclTensor*>,
339 : std::vector<const aclTensor*>, std::vector<const aclTensor*>>
340 1 : LstmBackwardSingleLayerDirec(const aclTensor* input, const aclTensor* initHMultiLayer, const aclTensor* initCMultiLayer,
341 : const aclTensorList* params, const aclTensor* dy, const aclTensor* dh, const aclTensor* dc,
342 : const aclTensor* seqLength, const aclTensorList* i, const aclTensorList* j,
343 : const aclTensorList* f, const aclTensorList* o, const aclTensorList* h,
344 : const aclTensorList* c, const aclTensorList* tanhc, int64_t layersTemp, int64_t numLayers,
345 : bool hasBias, int64_t paramNumPerLayer, aclOpExecutor* executor)
346 : {
347 1 : auto inputCur = layersTemp == 1 ? input : (*h)[layersTemp - BI_DIRECTION];
348 1 : auto nullptrRes = std::make_tuple(nullptr, std::vector<const aclTensor*>(), std::vector<const aclTensor*>(),
349 1 : std::vector<const aclTensor*>(), std::vector<const aclTensor*>());
350 : const aclTensor* initHCur = initHMultiLayer;
351 : const aclTensor* initCCur = initCMultiLayer;
352 : const aclTensor* dhCur = dh;
353 : const aclTensor* dcCur = dc;
354 1 : auto weightBias = GetWeightBiasFromParams(params, hasBias, false, paramNumPerLayer, layersTemp, executor);
355 1 : const aclTensor* weightCur = weightBias[0];
356 1 : const aclTensor* biasCur = weightBias[1];
357 1 : CHECK_RET(weightCur != nullptr, nullptrRes);
358 1 : if (hasBias) {
359 1 : CHECK_RET(biasCur != nullptr, nullptrRes);
360 : }
361 :
362 1 : if (numLayers > 1) {
363 0 : auto sliceTensors = CreateSliceTensors(layersTemp - 1, initHMultiLayer, initCMultiLayer, dh, dc, executor);
364 0 : CHECK_RET(sliceTensors[SLICE_INIT_H_INDEX] != nullptr && sliceTensors[SLICE_INIT_C_INDEX] != nullptr &&
365 : sliceTensors[SLICE_DH_INDEX] != nullptr && sliceTensors[SLICE_DC_INDEX] != nullptr,
366 : nullptrRes);
367 : initHCur = sliceTensors[SLICE_INIT_H_INDEX];
368 : initCCur = sliceTensors[SLICE_INIT_C_INDEX];
369 : dhCur = sliceTensors[SLICE_DH_INDEX];
370 : dcCur = sliceTensors[SLICE_DC_INDEX];
371 : }
372 1 : auto result = ExecLstmBackward(inputCur, initHCur, initCCur, weightCur, biasCur, dy, dhCur, dcCur, seqLength,
373 : (*i)[layersTemp - 1], (*j)[layersTemp - 1], (*f)[layersTemp - 1],
374 : (*o)[layersTemp - 1], (*h)[layersTemp - 1], (*c)[layersTemp - 1],
375 1 : (*tanhc)[layersTemp - 1], executor, false);
376 1 : std::vector<const aclTensor*> dwVector = {result[RESULT_WEIGHT_GRAD_INDEX]};
377 1 : std::vector<const aclTensor*> dbVector = {result[RESULT_BIAS_GRAD_INDEX]};
378 1 : std::vector<const aclTensor*> dhPrevVector = {result[RESULT_HIDDEN_GRAD_INDEX]};
379 1 : std::vector<const aclTensor*> dcPrevVector = {result[RESULT_CELL_GRAD_INDEX]};
380 1 : return std::tie(result[RESULT_INPUT_GRAD_INDEX], dhPrevVector, dcPrevVector, dwVector, dbVector);
381 : }
382 :
383 3 : static bool CheckTupleNotNull(
384 : const std::tuple<const aclTensor*, std::vector<const aclTensor*>, std::vector<const aclTensor*>,
385 : std::vector<const aclTensor*>, std::vector<const aclTensor*>>& tuple)
386 : {
387 3 : if (!std::get<0>(tuple)) {
388 : return false;
389 : }
390 : const auto& dhVec = std::get<INDEX_ONE>(tuple);
391 : const auto& dcVec = std::get<INDEX_TWO>(tuple);
392 : const auto& dwVec = std::get<INDEX_THREE>(tuple);
393 : const auto& dbVec = std::get<INDEX_FOUR>(tuple);
394 6 : return std::all_of(dwVec.begin(), dwVec.end(), [](auto* ptr) { return ptr != nullptr; }) &&
395 3 : std::all_of(dbVec.begin(), dbVec.end(), [](auto* ptr) { return ptr != nullptr; }) &&
396 6 : std::all_of(dhVec.begin(), dhVec.end(), [](auto* ptr) { return ptr != nullptr; }) &&
397 3 : std::all_of(dcVec.begin(), dcVec.end(), [](auto* ptr) { return ptr != nullptr; });
398 : }
399 :
400 : static std::tuple<const aclTensor*, std::vector<const aclTensor*>, std::vector<const aclTensor*>,
401 : std::vector<const aclTensor*>, std::vector<const aclTensor*>>
402 1 : LstmBackwardMultiLayerDirec(const aclTensor* input, const aclTensor* initHMultiLayer, const aclTensor* initCMultiLayer,
403 : const aclTensorList* params, const aclTensor* dy, const aclTensor* dh, const aclTensor* dc,
404 : const aclTensor* seqLength, const aclTensorList* i, const aclTensorList* j,
405 : const aclTensorList* f, const aclTensorList* o, const aclTensorList* h,
406 : const aclTensorList* c, const aclTensorList* tanhc, int64_t numLayers, int64_t layersTemp,
407 : bool hasBias, int64_t paramNumPerLayer, aclOpExecutor* executor)
408 : {
409 1 : const aclTensor* lastLayerDy = nullptr;
410 : std::vector<const aclTensor*> lastLayerDhPrevVector{};
411 : std::vector<const aclTensor*> lastLayerDcPrevVector{};
412 : std::vector<const aclTensor*> lastLayerDwVector{};
413 : std::vector<const aclTensor*> lastLayerDbVector{};
414 1 : auto nullptrRes = std::make_tuple(nullptr, std::vector<const aclTensor*>(), std::vector<const aclTensor*>(),
415 1 : std::vector<const aclTensor*>(), std::vector<const aclTensor*>());
416 1 : auto hShape = initHMultiLayer->GetViewShape();
417 1 : CHECK_RET(hShape.GetDimNum() == DIM_THREE, nullptrRes);
418 :
419 1 : if (layersTemp == numLayers) {
420 : auto lastLayerOutput = LstmBackwardSingleLayerDirec(input, initHMultiLayer, initCMultiLayer, params, dy, dh, dc,
421 : seqLength, i, j, f, o, h, c, tanhc, layersTemp, numLayers,
422 1 : hasBias, paramNumPerLayer, executor);
423 1 : CHECK_RET(CheckTupleNotNull(lastLayerOutput), nullptrRes);
424 : return lastLayerOutput;
425 : } else {
426 0 : std::tie(lastLayerDy, lastLayerDhPrevVector, lastLayerDcPrevVector, lastLayerDwVector,
427 0 : lastLayerDbVector) = LstmBackwardMultiLayerDirec(input, initHMultiLayer, initCMultiLayer, params, dy,
428 : dh, dc, seqLength, i, j, f, o, h, c, tanhc, numLayers,
429 : layersTemp + 1, hasBias, paramNumPerLayer, executor);
430 0 : CHECK_RET(CheckTupleNotNull(std::tie(lastLayerDy, lastLayerDhPrevVector, lastLayerDcPrevVector,
431 : lastLayerDwVector, lastLayerDbVector)),
432 : nullptrRes);
433 : }
434 0 : auto weightBias = GetWeightBiasFromParams(params, hasBias, false, paramNumPerLayer, layersTemp, executor);
435 0 : const aclTensor* weightCur = weightBias[0];
436 0 : const aclTensor* biasCur = weightBias[1];
437 0 : CHECK_RET(weightCur != nullptr, nullptrRes);
438 0 : if (hasBias) {
439 0 : CHECK_RET(biasCur != nullptr, nullptrRes);
440 : }
441 :
442 0 : auto sliceTensors = CreateSliceTensors(layersTemp - 1, initHMultiLayer, initCMultiLayer, dh, dc, executor);
443 :
444 0 : CHECK_RET(sliceTensors[SLICE_INIT_H_INDEX] != nullptr && sliceTensors[SLICE_INIT_C_INDEX] != nullptr &&
445 : sliceTensors[SLICE_DH_INDEX] != nullptr && sliceTensors[SLICE_DC_INDEX] != nullptr,
446 : nullptrRes);
447 :
448 0 : auto inputCur = layersTemp == 1 ? input : (*h)[layersTemp - BI_DIRECTION];
449 0 : auto result = ExecLstmBackward(inputCur, sliceTensors[SLICE_INIT_H_INDEX], sliceTensors[SLICE_INIT_C_INDEX],
450 : weightCur, biasCur, lastLayerDy, sliceTensors[SLICE_DH_INDEX],
451 : sliceTensors[SLICE_DC_INDEX], seqLength, (*i)[layersTemp - 1], (*j)[layersTemp - 1],
452 : (*f)[layersTemp - 1], (*o)[layersTemp - 1], (*h)[layersTemp - 1],
453 : (*c)[layersTemp - 1], (*tanhc)[layersTemp - 1], executor, false);
454 :
455 0 : lastLayerDwVector.emplace_back(result[RESULT_WEIGHT_GRAD_INDEX]);
456 0 : lastLayerDbVector.emplace_back(result[RESULT_BIAS_GRAD_INDEX]);
457 0 : lastLayerDhPrevVector.emplace_back(result[RESULT_HIDDEN_GRAD_INDEX]);
458 0 : lastLayerDcPrevVector.emplace_back(result[RESULT_CELL_GRAD_INDEX]);
459 0 : return std::tie(result[RESULT_INPUT_GRAD_INDEX], lastLayerDhPrevVector, lastLayerDcPrevVector, lastLayerDwVector,
460 : lastLayerDbVector);
461 : }
462 :
463 4 : static std::array<const aclTensor*, 5> CreateBidDirectionTensors(const aclTensor* initHMultiLayer,
464 : const aclTensor* initCMultiLayer, const aclTensor* dh,
465 : const aclTensor* dc, const aclTensor* dy,
466 : int64_t layersTemp, aclOpExecutor* executor,
467 : bool isBackward)
468 : {
469 : // 定义统一的错误返回值
470 : const std::array<const aclTensor*, 5> nullptrRes = {nullptr, nullptr, nullptr, nullptr, nullptr};
471 4 : auto hShape = initHMultiLayer->GetViewShape();
472 4 : CHECK_RET(hShape.GetDimNum() == DIM_THREE, nullptrRes);
473 4 : auto dyShape = dy->GetViewShape();
474 4 : CHECK_RET(dyShape.GetDimNum() == DIM_THREE, nullptrRes);
475 :
476 : // 根据方向计算偏移量
477 4 : int64_t initOffset = isBackward ? (BI_DIRECTION * layersTemp - 1) : (BI_DIRECTION * layersTemp - BI_DIRECTION);
478 4 : int64_t dyStart = isBackward ? (dyShape[HIDDEN_DIM] / BI_DIRECTION) : 0;
479 :
480 : // 创建初始隐藏状态和细胞状态
481 4 : FVector<int64_t> offsetVectorInit{initOffset, DIM_ZERO, DIM_ZERO};
482 4 : aclIntArray* offsetArrayInit = executor->AllocIntArray(offsetVectorInit.data(), offsetVectorInit.size());
483 4 : CHECK_RET(offsetArrayInit != nullptr, nullptrRes);
484 :
485 4 : FVector<int64_t> sizeVectorInit{1, hShape[BATCH_DIM], hShape[HIDDEN_DIM]};
486 4 : aclIntArray* sizeArrayInit = executor->AllocIntArray(sizeVectorInit.data(), sizeVectorInit.size());
487 4 : CHECK_RET(sizeArrayInit != nullptr, nullptrRes);
488 :
489 4 : auto initH = l0op::Slice(initHMultiLayer, offsetArrayInit, sizeArrayInit, executor);
490 4 : CHECK_RET(initH != nullptr, nullptrRes);
491 :
492 4 : auto initC = l0op::Slice(initCMultiLayer, offsetArrayInit, sizeArrayInit, executor);
493 4 : CHECK_RET(initC != nullptr, nullptrRes);
494 :
495 4 : auto dhDir = l0op::Slice(dh, offsetArrayInit, sizeArrayInit, executor);
496 4 : CHECK_RET(dhDir != nullptr, nullptrRes);
497 :
498 4 : auto dcDir = l0op::Slice(dc, offsetArrayInit, sizeArrayInit, executor);
499 4 : CHECK_RET(dcDir != nullptr, nullptrRes);
500 :
501 : // 创建输出梯度
502 4 : FVector<int64_t> offsetVectorDy{DIM_ZERO, DIM_ZERO, dyStart};
503 4 : aclIntArray* offsetArrayDy = executor->AllocIntArray(offsetVectorDy.data(), offsetVectorDy.size());
504 4 : CHECK_RET(offsetArrayDy != nullptr, nullptrRes);
505 :
506 4 : FVector<int64_t> sizeVectorDy{dyShape[SEQUENCE_DIM], dyShape[BATCH_DIM], dyShape[HIDDEN_DIM] / BI_DIRECTION};
507 4 : aclIntArray* sizeArrayDy = executor->AllocIntArray(sizeVectorDy.data(), sizeVectorDy.size());
508 4 : CHECK_RET(sizeArrayDy != nullptr, nullptrRes);
509 :
510 4 : auto dyDir = l0op::Slice(dy, offsetArrayDy, sizeArrayDy, executor);
511 4 : CHECK_RET(dyDir != nullptr, nullptrRes);
512 :
513 4 : return {initH, initC, dhDir, dcDir, dyDir};
514 : }
515 :
516 2 : static const aclTensor* CreateInputTensor(const aclTensor* input, const aclTensorList* h, int64_t layersTemp,
517 : aclOpExecutor* executor)
518 : {
519 2 : if (layersTemp == 1) {
520 : return input;
521 : } else {
522 1 : auto inputCurForward = (*h)[BI_DIRECTION * (layersTemp - BI_DIRECTION)];
523 1 : CHECK_RET(inputCurForward != nullptr, nullptr);
524 :
525 1 : auto inputCurBackward = (*h)[BI_DIRECTION * (layersTemp - BI_DIRECTION) + 1];
526 1 : CHECK_RET(inputCurBackward != nullptr, nullptr);
527 :
528 1 : op::FVector<const aclTensor*> inputCurVector = {inputCurForward, inputCurBackward};
529 1 : const aclTensorList* inputCurList = executor->AllocTensorList(inputCurVector.data(), inputCurVector.size());
530 1 : CHECK_RET(inputCurList != nullptr, nullptr);
531 :
532 1 : auto result = l0op::ConcatD(inputCurList, CONCAT_DIM_HIDDEN, executor);
533 1 : CHECK_RET(result != nullptr, nullptr);
534 :
535 : return result;
536 : }
537 : }
538 :
539 : static std::tuple<const aclTensor*, std::vector<const aclTensor*>, std::vector<const aclTensor*>,
540 : std::vector<const aclTensor*>, std::vector<const aclTensor*>>
541 2 : MergeResults(std::array<const aclTensor*, 5> resultForward, std::array<const aclTensor*, 5> resultBackward,
542 : std::vector<const aclTensor*>& dhVector, std::vector<const aclTensor*>& dcVector,
543 : std::vector<const aclTensor*>& dwVector, std::vector<const aclTensor*>& dbVector, aclOpExecutor* executor)
544 : {
545 2 : auto nullptrRes = std::make_tuple(nullptr, std::vector<const aclTensor*>(), std::vector<const aclTensor*>(),
546 2 : std::vector<const aclTensor*>(), std::vector<const aclTensor*>());
547 : std::vector<const aclTensor*> catDhPrevVector = {resultForward[RESULT_HIDDEN_GRAD_INDEX],
548 2 : resultBackward[RESULT_HIDDEN_GRAD_INDEX]};
549 : std::vector<const aclTensor*> catDcPrevVector = {resultForward[RESULT_CELL_GRAD_INDEX],
550 2 : resultBackward[RESULT_CELL_GRAD_INDEX]};
551 2 : dwVector.emplace_back(resultForward[RESULT_WEIGHT_GRAD_INDEX]);
552 2 : dwVector.emplace_back(resultBackward[RESULT_WEIGHT_GRAD_INDEX]);
553 2 : dbVector.emplace_back(resultForward[RESULT_BIAS_GRAD_INDEX]);
554 2 : dbVector.emplace_back(resultBackward[RESULT_BIAS_GRAD_INDEX]);
555 2 : dhVector.emplace_back(resultForward[RESULT_HIDDEN_GRAD_INDEX]);
556 2 : dhVector.emplace_back(resultBackward[RESULT_HIDDEN_GRAD_INDEX]);
557 2 : dcVector.emplace_back(resultForward[RESULT_CELL_GRAD_INDEX]);
558 2 : dcVector.emplace_back(resultBackward[RESULT_CELL_GRAD_INDEX]);
559 :
560 2 : auto dx = l0op::Add(resultForward[RESULT_INPUT_GRAD_INDEX], resultBackward[RESULT_INPUT_GRAD_INDEX], executor);
561 2 : CHECK_RET(dx != nullptr, nullptrRes);
562 : return std::make_tuple(dx, dhVector, dcVector, dwVector, dbVector);
563 : }
564 :
565 : static std::tuple<const aclTensor*, std::vector<const aclTensor*>, std::vector<const aclTensor*>,
566 : std::vector<const aclTensor*>, std::vector<const aclTensor*>>
567 1 : LstmBackwardSingleLayerBidirec(const aclTensor* input, const aclTensor* initHMultiLayer,
568 : const aclTensor* initCMultiLayer, const aclTensorList* params, const aclTensor* dy,
569 : const aclTensor* dh, const aclTensor* dc, const aclTensor* seqLength,
570 : const aclTensorList* i, const aclTensorList* j, const aclTensorList* f,
571 : const aclTensorList* o, const aclTensorList* h, const aclTensorList* c,
572 : const aclTensorList* tanhc, int64_t layersTemp, bool hasBias, int64_t paramNumPerLayer,
573 : aclOpExecutor* executor)
574 : {
575 1 : auto nullptrRes = std::make_tuple(nullptr, std::vector<const aclTensor*>(), std::vector<const aclTensor*>(),
576 1 : std::vector<const aclTensor*>(), std::vector<const aclTensor*>());
577 :
578 : const aclTensor* inputCur = nullptr;
579 1 : auto weightBias = GetWeightBiasFromParams(params, hasBias, true, paramNumPerLayer, layersTemp, executor);
580 1 : const aclTensor* weightForwardCur = weightBias[0];
581 1 : CHECK_RET(weightForwardCur != nullptr, nullptrRes);
582 1 : const aclTensor* weightBackwardCur = weightBias[INDEX_TWO];
583 1 : CHECK_RET(weightBackwardCur != nullptr, nullptrRes);
584 1 : const aclTensor* biasForwardCur = weightBias[1];
585 1 : const aclTensor* biasBackwardCur = weightBias[INDEX_THREE];
586 1 : if (hasBias) {
587 1 : CHECK_RET(biasForwardCur != nullptr, nullptrRes);
588 1 : CHECK_RET(biasBackwardCur != nullptr, nullptrRes);
589 : }
590 :
591 1 : auto forwardTensors = CreateBidDirectionTensors(initHMultiLayer, initCMultiLayer, dh, dc, dy, layersTemp, executor,
592 : false);
593 1 : CHECK_RET(forwardTensors[BIDIR_INIT_H_INDEX] != nullptr, nullptrRes); // initHForward
594 1 : CHECK_RET(forwardTensors[BIDIR_INIT_C_INDEX] != nullptr, nullptrRes); // initCForward
595 1 : CHECK_RET(forwardTensors[BIDIR_DH_INDEX] != nullptr, nullptrRes); // dhForward
596 1 : CHECK_RET(forwardTensors[BIDIR_DC_INDEX] != nullptr, nullptrRes); // dcForward
597 1 : CHECK_RET(forwardTensors[BIDIR_DY_INDEX] != nullptr, nullptrRes); // dyForward
598 :
599 : // 创建输入
600 1 : inputCur = CreateInputTensor(input, h, layersTemp, executor);
601 1 : CHECK_RET(inputCur != nullptr, nullptrRes);
602 : // 前向LSTM计算
603 1 : auto resultForward = ExecLstmBackward(
604 : inputCur, forwardTensors[BIDIR_INIT_H_INDEX], forwardTensors[BIDIR_INIT_C_INDEX], weightForwardCur,
605 : biasForwardCur, forwardTensors[BIDIR_DY_INDEX], forwardTensors[BIDIR_DH_INDEX], forwardTensors[BIDIR_DC_INDEX],
606 : seqLength, (*i)[layersTemp * BI_DIRECTION - BI_DIRECTION], (*j)[layersTemp * BI_DIRECTION - BI_DIRECTION],
607 : (*f)[layersTemp * BI_DIRECTION - BI_DIRECTION], (*o)[layersTemp * BI_DIRECTION - BI_DIRECTION],
608 : (*h)[layersTemp * BI_DIRECTION - BI_DIRECTION], (*c)[layersTemp * BI_DIRECTION - BI_DIRECTION],
609 1 : (*tanhc)[layersTemp * BI_DIRECTION - BI_DIRECTION], executor, false);
610 :
611 1 : auto backwardTensors = CreateBidDirectionTensors(initHMultiLayer, initCMultiLayer, dh, dc, dy, layersTemp, executor,
612 : true);
613 1 : CHECK_RET(backwardTensors[BIDIR_INIT_H_INDEX] != nullptr, nullptrRes); // initHBackward
614 1 : CHECK_RET(backwardTensors[BIDIR_INIT_C_INDEX] != nullptr, nullptrRes); // initCBackward
615 1 : CHECK_RET(backwardTensors[BIDIR_DH_INDEX] != nullptr, nullptrRes); // dhBackward
616 1 : CHECK_RET(backwardTensors[BIDIR_DC_INDEX] != nullptr, nullptrRes); // dcBackward
617 1 : CHECK_RET(backwardTensors[BIDIR_DY_INDEX] != nullptr, nullptrRes); // dyBackward
618 :
619 : // 后向LSTM计算
620 1 : auto resultBackward = ExecLstmBackward(
621 : inputCur, backwardTensors[BIDIR_INIT_H_INDEX], backwardTensors[BIDIR_INIT_C_INDEX], weightBackwardCur,
622 : biasBackwardCur, backwardTensors[BIDIR_DY_INDEX], backwardTensors[BIDIR_DH_INDEX],
623 : backwardTensors[BIDIR_DC_INDEX], seqLength, (*i)[layersTemp * BI_DIRECTION - 1],
624 : (*j)[layersTemp * BI_DIRECTION - 1], (*f)[layersTemp * BI_DIRECTION - 1], (*o)[layersTemp * BI_DIRECTION - 1],
625 : (*h)[layersTemp * BI_DIRECTION - 1], (*c)[layersTemp * BI_DIRECTION - 1],
626 1 : (*tanhc)[layersTemp * BI_DIRECTION - 1], executor, true);
627 :
628 : // 合并结果
629 : std::vector<const aclTensor*> dwVector{};
630 : std::vector<const aclTensor*> dbVector{};
631 : std::vector<const aclTensor*> dhPrevVector{};
632 : std::vector<const aclTensor*> dcPrevVector{};
633 : auto mergedResult = MergeResults(resultForward, resultBackward, dhPrevVector, dcPrevVector, dwVector, dbVector,
634 1 : executor);
635 : return mergedResult;
636 : }
637 :
638 : static std::tuple<const aclTensor*, std::vector<const aclTensor*>, std::vector<const aclTensor*>,
639 : std::vector<const aclTensor*>, std::vector<const aclTensor*>>
640 2 : LstmBackwardMultiLayerBidirec(const aclTensor* input, const aclTensor* initHMultiLayer,
641 : const aclTensor* initCMultiLayer, const aclTensorList* params, const aclTensor* dy,
642 : const aclTensor* dh, const aclTensor* dc, const aclTensor* seqLength,
643 : const aclTensorList* i, const aclTensorList* j, const aclTensorList* f,
644 : const aclTensorList* o, const aclTensorList* h, const aclTensorList* c,
645 : const aclTensorList* tanhc, int64_t numLayers, int64_t layersTemp, bool hasBias,
646 : int64_t paramNumPerLayer, aclOpExecutor* executor)
647 : {
648 2 : const aclTensor* lastLayerDy = nullptr;
649 : std::vector<const aclTensor*> lastLayerDhPrevVector{};
650 : std::vector<const aclTensor*> lastLayerDcPrevVector{};
651 : std::vector<const aclTensor*> lastLayerDwVector{};
652 : std::vector<const aclTensor*> lastLayerDbVector{};
653 :
654 2 : auto nullptrRes = std::make_tuple(nullptr, std::vector<const aclTensor*>(), std::vector<const aclTensor*>(),
655 2 : std::vector<const aclTensor*>(), std::vector<const aclTensor*>());
656 :
657 : const aclTensor* inputCur = nullptr;
658 :
659 : // 递归终止条件:处理最后一层
660 2 : if (layersTemp == numLayers) {
661 : auto lastLayerOutput = LstmBackwardSingleLayerBidirec(input, initHMultiLayer, initCMultiLayer, params, dy, dh,
662 : dc, seqLength, i, j, f, o, h, c, tanhc, layersTemp,
663 1 : hasBias, paramNumPerLayer, executor);
664 1 : CHECK_RET(CheckTupleNotNull(lastLayerOutput), nullptrRes);
665 : return lastLayerOutput;
666 : } else {
667 : // 递归调用处理下一层
668 1 : std::tie(lastLayerDy, lastLayerDhPrevVector, lastLayerDcPrevVector, lastLayerDwVector,
669 2 : lastLayerDbVector) = LstmBackwardMultiLayerBidirec(input, initHMultiLayer, initCMultiLayer, params, dy,
670 : dh, dc, seqLength, i, j, f, o, h, c, tanhc,
671 : numLayers, layersTemp + 1, hasBias,
672 : paramNumPerLayer, executor);
673 2 : CHECK_RET(CheckTupleNotNull(std::tie(lastLayerDy, lastLayerDhPrevVector, lastLayerDcPrevVector,
674 : lastLayerDwVector, lastLayerDbVector)),
675 : nullptrRes);
676 : }
677 : // 获取当前层权重和偏置
678 1 : auto weightBias = GetWeightBiasFromParams(params, hasBias, true, paramNumPerLayer, layersTemp, executor);
679 1 : const aclTensor* weightForwardCur = weightBias[0];
680 1 : CHECK_RET(weightForwardCur != nullptr, nullptrRes);
681 1 : const aclTensor* weightBackwardCur = weightBias[INDEX_TWO];
682 1 : CHECK_RET(weightBackwardCur != nullptr, nullptrRes);
683 1 : const aclTensor* biasForwardCur = weightBias[1];
684 1 : const aclTensor* biasBackwardCur = weightBias[INDEX_THREE];
685 1 : if (hasBias) {
686 1 : CHECK_RET(biasForwardCur != nullptr, nullptrRes);
687 1 : CHECK_RET(biasBackwardCur != nullptr, nullptrRes);
688 : }
689 :
690 : // 创建输入张量
691 1 : inputCur = CreateInputTensor(input, h, layersTemp, executor);
692 1 : CHECK_RET(inputCur != nullptr, nullptrRes);
693 :
694 : // 使用 std::array 接收前向张量
695 1 : auto forwardTensors = CreateBidDirectionTensors(initHMultiLayer, initCMultiLayer, dh, dc, lastLayerDy, layersTemp,
696 : executor, false);
697 1 : CHECK_RET(forwardTensors[BIDIR_INIT_H_INDEX] != nullptr, nullptrRes); // initHForward
698 1 : CHECK_RET(forwardTensors[BIDIR_INIT_C_INDEX] != nullptr, nullptrRes); // initCForward
699 1 : CHECK_RET(forwardTensors[BIDIR_DH_INDEX] != nullptr, nullptrRes); // dhForward
700 1 : CHECK_RET(forwardTensors[BIDIR_DC_INDEX] != nullptr, nullptrRes); // dcForward
701 1 : CHECK_RET(forwardTensors[BIDIR_DY_INDEX] != nullptr, nullptrRes); // dyForward
702 :
703 : // 前向LSTM计算
704 1 : auto resultForward = ExecLstmBackward(
705 : inputCur, forwardTensors[BIDIR_INIT_H_INDEX], forwardTensors[BIDIR_INIT_C_INDEX], weightForwardCur,
706 : biasForwardCur, forwardTensors[BIDIR_DY_INDEX], forwardTensors[BIDIR_DH_INDEX], forwardTensors[BIDIR_DC_INDEX],
707 : seqLength, (*i)[layersTemp * BI_DIRECTION - BI_DIRECTION], (*j)[layersTemp * BI_DIRECTION - BI_DIRECTION],
708 : (*f)[layersTemp * BI_DIRECTION - BI_DIRECTION], (*o)[layersTemp * BI_DIRECTION - BI_DIRECTION],
709 : (*h)[layersTemp * BI_DIRECTION - BI_DIRECTION], (*c)[layersTemp * BI_DIRECTION - BI_DIRECTION],
710 1 : (*tanhc)[layersTemp * BI_DIRECTION - BI_DIRECTION], executor, false);
711 :
712 1 : auto backwardTensors = CreateBidDirectionTensors(initHMultiLayer, initCMultiLayer, dh, dc, lastLayerDy, layersTemp,
713 : executor, true);
714 1 : CHECK_RET(backwardTensors[BIDIR_INIT_H_INDEX] != nullptr, nullptrRes); // initHBackward
715 1 : CHECK_RET(backwardTensors[BIDIR_INIT_C_INDEX] != nullptr, nullptrRes); // initCBackward
716 1 : CHECK_RET(backwardTensors[BIDIR_DH_INDEX] != nullptr, nullptrRes); // dhBackward
717 1 : CHECK_RET(backwardTensors[BIDIR_DC_INDEX] != nullptr, nullptrRes); // dcBackward
718 1 : CHECK_RET(backwardTensors[BIDIR_DY_INDEX] != nullptr, nullptrRes); // dyBackward
719 :
720 : // 后向LSTM计算
721 1 : auto resultBackward = ExecLstmBackward(
722 : inputCur, backwardTensors[BIDIR_INIT_H_INDEX], backwardTensors[BIDIR_INIT_C_INDEX], weightBackwardCur,
723 : biasBackwardCur, backwardTensors[BIDIR_DY_INDEX], backwardTensors[BIDIR_DH_INDEX],
724 : backwardTensors[BIDIR_DC_INDEX], seqLength, (*i)[layersTemp * BI_DIRECTION - 1],
725 : (*j)[layersTemp * BI_DIRECTION - 1], (*f)[layersTemp * BI_DIRECTION - 1], (*o)[layersTemp * BI_DIRECTION - 1],
726 : (*h)[layersTemp * BI_DIRECTION - 1], (*c)[layersTemp * BI_DIRECTION - 1],
727 1 : (*tanhc)[layersTemp * BI_DIRECTION - 1], executor, true);
728 :
729 : // 合并结果并更新权重向量
730 : auto mergedResult = MergeResults(resultForward, resultBackward, lastLayerDhPrevVector, lastLayerDcPrevVector,
731 1 : lastLayerDwVector, lastLayerDbVector, executor);
732 : return mergedResult;
733 : }
734 :
735 18 : static bool CheckTensorListNotNull(const aclTensorList* tensorList)
736 : {
737 77 : for (uint64_t index = 0; index < tensorList->Size(); index++) {
738 59 : OP_CHECK_NULL((*tensorList)[index], return false);
739 : }
740 : return true;
741 : }
742 :
743 2 : static bool CheckNotNull(const aclTensor* input, const aclTensorList* hc, const aclTensorList* params,
744 : const aclTensorList* i, const aclTensorList* j, const aclTensorList* f, const aclTensorList* o,
745 : const aclTensorList* h, const aclTensorList* c, const aclTensorList* tanhc,
746 : const aclTensor* dx, const aclTensor* dhPrev, const aclTensor* dcPrev,
747 : const aclTensorList* dparams, bool hasBias, int64_t numLayers, bool bidirectional)
748 : {
749 2 : OP_CHECK_NULL(input, return false);
750 2 : OP_CHECK_NULL(hc, return false);
751 2 : OP_CHECK_NULL(params, return false);
752 2 : OP_CHECK_NULL(i, return false);
753 2 : OP_CHECK_NULL(j, return false);
754 2 : OP_CHECK_NULL(f, return false);
755 2 : OP_CHECK_NULL(o, return false);
756 2 : OP_CHECK_NULL(h, return false);
757 2 : OP_CHECK_NULL(c, return false);
758 2 : OP_CHECK_NULL(tanhc, return false);
759 2 : OP_CHECK_NULL(dx, return false);
760 2 : OP_CHECK_NULL(dhPrev, return false);
761 2 : OP_CHECK_NULL(dcPrev, return false);
762 2 : OP_CHECK_NULL(dparams, return false);
763 2 : uint64_t gateLength = bidirectional ? numLayers * BI_DIRECTION : numLayers;
764 6 : bool tensorLengthCheck = gateLength == i->Size() && gateLength == j->Size() && gateLength == f->Size() &&
765 8 : gateLength == o->Size() && gateLength == h->Size() && gateLength == c->Size() &&
766 2 : gateLength == tanhc->Size();
767 2 : if (hc->Size() != HC_TENSOR_COUNT) {
768 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "For inithc tensorlist, the tensor quantities %ld should be %d.", hc->Size(),
769 : HC_TENSOR_COUNT);
770 0 : return false;
771 : }
772 2 : if (!tensorLengthCheck) {
773 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID,
774 : "For tensor lists such as the 4 gates, the tensor quantities should follow consistent patterns.");
775 0 : return false;
776 : }
777 2 : uint64_t paramsLength = hasBias && bidirectional ? NUM_WITH_B_AND_BID * numLayers :
778 1 : (hasBias || bidirectional) ? NUM_WITH_B_OR_BID * numLayers :
779 0 : NUM_NO_B_NO_BIDIR * numLayers;
780 2 : bool paramsLengthCheck = paramsLength == params->Size() && paramsLength == dparams->Size();
781 : if (!paramsLengthCheck) {
782 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "For tensor lists include params and dparams, the tensor quantities should "
783 : "follow the pattern related to the weigths.");
784 0 : return false;
785 : }
786 :
787 6 : return CheckTensorListNotNull(hc) && CheckTensorListNotNull(i) && CheckTensorListNotNull(j) &&
788 6 : CheckTensorListNotNull(f) && CheckTensorListNotNull(o) && CheckTensorListNotNull(h) &&
789 6 : CheckTensorListNotNull(c) && CheckTensorListNotNull(tanhc) && CheckTensorListNotNull(dparams);
790 : }
791 :
792 20 : static bool CheckTensorListFormat(const aclTensorList* tensors, const char* listName, const ge::Format format)
793 : {
794 99 : for (uint64_t idx = 0; idx < tensors->Size(); idx++) {
795 79 : if ((*tensors)[idx]->GetStorageFormat() != format) {
796 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "%s tensor %lu format only support ND", listName, idx);
797 0 : return false;
798 : }
799 : }
800 20 : return true;
801 : }
802 :
803 2 : static bool CheckTensorListsFormat(const aclTensorList* hc, const aclTensorList* params, const aclTensorList* i,
804 : const aclTensorList* j, const aclTensorList* f, const aclTensorList* o,
805 : const aclTensorList* h, const aclTensorList* c, const aclTensorList* tanhc,
806 : const aclTensorList* dparams)
807 : {
808 2 : if (!CheckTensorListFormat(hc, "hc", Format::FORMAT_NCL))
809 : return false;
810 2 : if (!CheckTensorListFormat(params, "params", Format::FORMAT_ND))
811 : return false;
812 2 : if (!CheckTensorListFormat(i, "i", Format::FORMAT_NCL))
813 : return false;
814 2 : if (!CheckTensorListFormat(j, "j", Format::FORMAT_NCL))
815 : return false;
816 2 : if (!CheckTensorListFormat(f, "f", Format::FORMAT_NCL))
817 : return false;
818 2 : if (!CheckTensorListFormat(o, "o", Format::FORMAT_NCL))
819 : return false;
820 2 : if (!CheckTensorListFormat(h, "h", Format::FORMAT_NCL))
821 : return false;
822 2 : if (!CheckTensorListFormat(c, "c", Format::FORMAT_NCL))
823 : return false;
824 2 : if (!CheckTensorListFormat(tanhc, "tanhc", Format::FORMAT_NCL))
825 : return false;
826 2 : if (!CheckTensorListFormat(dparams, "dparams", Format::FORMAT_ND))
827 : return false;
828 : return true;
829 : }
830 :
831 2 : static bool CheckFormatValid(const aclTensor* input, const aclTensorList* hc, const aclTensorList* params,
832 : const aclTensor* dy, const aclTensor* dh, const aclTensor* dc, const aclTensorList* i,
833 : const aclTensorList* j, const aclTensorList* f, const aclTensorList* o,
834 : const aclTensorList* h, const aclTensorList* c, const aclTensorList* tanhc,
835 : const aclTensor* dx, const aclTensor* dhPrev, const aclTensor* dcPrev,
836 : const aclTensorList* dparams, const aclTensor* batchSizes = nullptr)
837 : {
838 2 : auto inputFormat = batchSizes == nullptr ? Format::FORMAT_NCL : Format::FORMAT_ND;
839 2 : if (input->GetStorageFormat() != inputFormat) {
840 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "input format only support ND/NCL");
841 0 : return false;
842 : }
843 2 : if (dy != nullptr && dy->GetStorageFormat() != inputFormat) {
844 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "dy format only support ND/NCL");
845 0 : return false;
846 : }
847 2 : if (dh != nullptr && dh->GetStorageFormat() != Format::FORMAT_NCL) {
848 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "dh format only support NCL");
849 0 : return false;
850 : }
851 2 : if (dc != nullptr && dc->GetStorageFormat() != Format::FORMAT_NCL) {
852 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "dc format only support NCL");
853 0 : return false;
854 : }
855 2 : if (dx->GetStorageFormat() != inputFormat) {
856 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "dx format only support ND/NCL");
857 0 : return false;
858 : }
859 2 : if (dhPrev->GetStorageFormat() != Format::FORMAT_NCL) {
860 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "dhPrev format only support NCL");
861 0 : return false;
862 : }
863 2 : if (dcPrev->GetStorageFormat() != Format::FORMAT_NCL) {
864 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "dcPrev format only support NCL");
865 0 : return false;
866 : }
867 2 : if (batchSizes != nullptr && batchSizes->GetStorageFormat() != Format::FORMAT_ND) {
868 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "batchSizes only support ND");
869 0 : return false;
870 : }
871 2 : if (!CheckTensorListsFormat(hc, params, i, j, f, o, h, c, tanhc, dparams)) {
872 : return false;
873 : }
874 : return true;
875 : }
876 :
877 : // 检查单个张量的数据类型支持和一致性
878 12 : static bool CheckSingleTensorDtype(const aclTensor* tensor, const char* tensorName, ge::DataType baseDtype)
879 : {
880 : // 检查是否在支持的数据类型列表中
881 12 : OP_CHECK_DTYPE_NOT_SUPPORT(tensor, DTYPE_SUPPORT_LIST, return false);
882 :
883 : // 检查数据类型一致性
884 12 : if (tensor->GetDataType() != baseDtype) {
885 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "%s tensor dtype inconsistent, expected: %s, actual: %s.", tensorName,
886 : op::ToString(baseDtype).GetString(), op::ToString(tensor->GetDataType()).GetString());
887 0 : return false;
888 : }
889 :
890 : return true;
891 : }
892 :
893 : // 检查张量列表的数据类型支持和一致性
894 20 : static bool CheckTensorListDtype(const aclTensorList* tensors, const char* listName, ge::DataType baseDtype)
895 : {
896 99 : for (uint64_t idx = 0; idx < tensors->Size(); idx++) {
897 79 : const aclTensor* tensor = (*tensors)[idx];
898 : // 检查是否在支持的数据类型列表中
899 79 : OP_CHECK_DTYPE_NOT_SUPPORT(tensor, DTYPE_SUPPORT_LIST, return false);
900 :
901 : // 检查数据类型一致性
902 79 : if (tensor->GetDataType() != baseDtype) {
903 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "%s tensor %lu dtype inconsistent, expected: %s, actual: %s.", listName,
904 : idx, op::ToString(baseDtype).GetString(), op::ToString(tensor->GetDataType()).GetString());
905 0 : return false;
906 : }
907 : }
908 20 : return true;
909 : }
910 :
911 2 : static bool CheckDtypeValid(const aclTensor* input, const aclTensorList* hc, const aclTensorList* params,
912 : const aclTensor* dy, const aclTensor* dh, const aclTensor* dc, const aclTensorList* i,
913 : const aclTensorList* j, const aclTensorList* f, const aclTensorList* o,
914 : const aclTensorList* h, const aclTensorList* c, const aclTensorList* tanhc,
915 : const aclTensor* dx, const aclTensor* dhPrev, const aclTensor* dcPrev,
916 : const aclTensorList* dparams, const aclTensor* batchSizes = nullptr)
917 : {
918 2 : ge::DataType baseDtype = input->GetDataType();
919 2 : const SingleTensorItem singleTensors[] = {{"dy", dy}, {"dh", dh}, {"dc", dc},
920 2 : {"dx", dx}, {"dhPrev", dhPrev}, {"dcPrev", dcPrev}};
921 2 : const TensorListItem listTensors[] = {
922 : {"hc", hc}, {"params", params}, {"i", i}, {"j", j}, {"f", f},
923 2 : {"o", o}, {"h", h}, {"c", c}, {"tanhc", tanhc}, {"dparams", dparams}};
924 14 : for (const auto& item : singleTensors) {
925 12 : if (item.tensor != nullptr && !CheckSingleTensorDtype(item.tensor, item.name, baseDtype)) {
926 : return false;
927 : }
928 : }
929 2 : if (batchSizes != nullptr && batchSizes->GetDataType() != op::DataType::DT_INT64) {
930 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "batchSizes tensor dtype inconsistent, expected: %s, actual: %s.",
931 : op::ToString(op::DataType::DT_INT64).GetString(), op::ToString(batchSizes->GetDataType()).GetString());
932 0 : return false;
933 : }
934 22 : for (const auto& item : listTensors) {
935 20 : if (!CheckTensorListDtype(item.list, item.name, baseDtype)) {
936 : return false;
937 : }
938 : }
939 : return true;
940 : }
941 :
942 93 : static bool ValidateInputShape(const aclTensor* input, const std::vector<int64_t>& expected_dims,
943 : const char* tensorName)
944 : {
945 93 : auto shape = input->GetViewShape();
946 93 : if (shape.GetDimNum() != expected_dims.size()) {
947 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Input tensor %s has wrong dimension count", tensorName);
948 0 : return false;
949 : }
950 :
951 312 : for (size_t i = 0; i < expected_dims.size(); ++i) {
952 438 : if (expected_dims[i] != shape.GetDim(i)) {
953 0 : OP_LOGE(ACLNN_ERR_PARAM_INVALID, "Input tensor %s dim %zu mismatch", tensorName, i);
954 0 : return false;
955 : }
956 : }
957 93 : return true;
958 : };
959 :
960 2 : static bool ValidateLayerWithBiasAndBidir(const aclTensorList* params, const aclTensorList* dparams, int64_t layerIdx,
961 : const std::vector<int64_t>& weightInputDim,
962 : const std::vector<int64_t>& weightHiddenDim,
963 : const std::vector<int64_t>& biasDim)
964 : {
965 : const int64_t stride = NUM_WITH_B_AND_BID; // 每层张量数(含bias和双向)
966 : const int64_t half = stride / BI_DIRECTION; // 每个方向的张量数
967 : // 前向方向 (索引 0~half-1)
968 4 : bool ok = ValidateInputShape((*params)[stride * layerIdx + WEIGHT_INPUT_INDEX], weightInputDim, "wi") &&
969 4 : ValidateInputShape((*params)[stride * layerIdx + WEIGHT_HIDDEN_INDEX], weightHiddenDim, "wh") &&
970 4 : ValidateInputShape((*params)[stride * layerIdx + BIAS_INPUT_INDEX], biasDim, "bi") &&
971 4 : ValidateInputShape((*params)[stride * layerIdx + BIAS_HIDDEN_INDEX], biasDim, "bh") &&
972 4 : ValidateInputShape((*dparams)[stride * layerIdx + WEIGHT_INPUT_INDEX], weightInputDim, "dwi") &&
973 4 : ValidateInputShape((*dparams)[stride * layerIdx + WEIGHT_HIDDEN_INDEX], weightHiddenDim, "dwh") &&
974 6 : ValidateInputShape((*dparams)[stride * layerIdx + BIAS_INPUT_INDEX], biasDim, "dbi") &&
975 2 : ValidateInputShape((*dparams)[stride * layerIdx + BIAS_HIDDEN_INDEX], biasDim, "dbh");
976 : // 反向方向 (索引 half~stride-1)
977 4 : ok = ok && ValidateInputShape((*params)[stride * layerIdx + half + WEIGHT_INPUT_INDEX], weightInputDim, "wi") &&
978 4 : ValidateInputShape((*params)[stride * layerIdx + half + WEIGHT_HIDDEN_INDEX], weightHiddenDim, "wh") &&
979 4 : ValidateInputShape((*params)[stride * layerIdx + half + BIAS_INPUT_INDEX], biasDim, "bi") &&
980 4 : ValidateInputShape((*params)[stride * layerIdx + half + BIAS_HIDDEN_INDEX], biasDim, "bh") &&
981 4 : ValidateInputShape((*dparams)[stride * layerIdx + half + WEIGHT_INPUT_INDEX], weightInputDim, "dwi") &&
982 4 : ValidateInputShape((*dparams)[stride * layerIdx + half + WEIGHT_HIDDEN_INDEX], weightHiddenDim, "dwh") &&
983 4 : ValidateInputShape((*dparams)[stride * layerIdx + half + BIAS_INPUT_INDEX], biasDim, "dbi") &&
984 2 : ValidateInputShape((*dparams)[stride * layerIdx + half + BIAS_HIDDEN_INDEX], biasDim, "dbh");
985 2 : return ok;
986 : }
987 :
988 1 : static bool ValidateLayerWithBiasOnly(const aclTensorList* params, const aclTensorList* dparams, int64_t layerIdx,
989 : const std::vector<int64_t>& weightInputDim,
990 : const std::vector<int64_t>& weightHiddenDim, const std::vector<int64_t>& biasDim)
991 : {
992 : const int64_t stride = NUM_WITH_B_OR_BID; // 每层张量数(含bias,单向)
993 2 : return ValidateInputShape((*params)[stride * layerIdx + WEIGHT_INPUT_INDEX], weightInputDim, "wi") &&
994 2 : ValidateInputShape((*params)[stride * layerIdx + WEIGHT_HIDDEN_INDEX], weightHiddenDim, "wh") &&
995 2 : ValidateInputShape((*params)[stride * layerIdx + BIAS_INPUT_INDEX], biasDim, "bi") &&
996 2 : ValidateInputShape((*params)[stride * layerIdx + BIAS_HIDDEN_INDEX], biasDim, "bh") &&
997 2 : ValidateInputShape((*dparams)[stride * layerIdx + WEIGHT_INPUT_INDEX], weightInputDim, "dwi") &&
998 2 : ValidateInputShape((*dparams)[stride * layerIdx + WEIGHT_HIDDEN_INDEX], weightHiddenDim, "dwh") &&
999 3 : ValidateInputShape((*dparams)[stride * layerIdx + BIAS_INPUT_INDEX], biasDim, "dbi") &&
1000 1 : ValidateInputShape((*dparams)[stride * layerIdx + BIAS_HIDDEN_INDEX], biasDim, "dbh");
1001 : }
1002 :
1003 0 : static bool ValidateLayerWithBidirOnly(const aclTensorList* params, const aclTensorList* dparams, int64_t layerIdx,
1004 : const std::vector<int64_t>& weightInputDim,
1005 : const std::vector<int64_t>& weightHiddenDim)
1006 : {
1007 : const int64_t stride = NUM_WITH_B_OR_BID; // 无bias时每层张量数(两个方向)
1008 : const int64_t half = stride / BI_DIRECTION;
1009 0 : bool ok = ValidateInputShape((*params)[stride * layerIdx + WEIGHT_INPUT_INDEX], weightInputDim, "wi") &&
1010 0 : ValidateInputShape((*params)[stride * layerIdx + WEIGHT_HIDDEN_INDEX], weightHiddenDim, "wh") &&
1011 0 : ValidateInputShape((*dparams)[stride * layerIdx + WEIGHT_INPUT_INDEX], weightInputDim, "dwi") &&
1012 0 : ValidateInputShape((*dparams)[stride * layerIdx + WEIGHT_HIDDEN_INDEX], weightHiddenDim, "dwh");
1013 0 : ok = ok && ValidateInputShape((*params)[stride * layerIdx + half + WEIGHT_INPUT_INDEX], weightInputDim, "wi") &&
1014 0 : ValidateInputShape((*params)[stride * layerIdx + half + WEIGHT_HIDDEN_INDEX], weightHiddenDim, "wh") &&
1015 0 : ValidateInputShape((*dparams)[stride * layerIdx + half + WEIGHT_INPUT_INDEX], weightInputDim, "dwi") &&
1016 0 : ValidateInputShape((*dparams)[stride * layerIdx + half + WEIGHT_HIDDEN_INDEX], weightHiddenDim, "dwh");
1017 0 : return ok;
1018 : }
1019 :
1020 0 : static bool ValidateLayerNoBiasNoBidir(const aclTensorList* params, const aclTensorList* dparams, int64_t layerIdx,
1021 : const std::vector<int64_t>& weightInputDim,
1022 : const std::vector<int64_t>& weightHiddenDim)
1023 : {
1024 : const int64_t stride = NUM_NO_B_NO_BIDIR; // 每层张量数(无bias,单向)
1025 0 : return ValidateInputShape((*params)[stride * layerIdx + WEIGHT_INPUT_INDEX], weightInputDim, "wi") &&
1026 0 : ValidateInputShape((*params)[stride * layerIdx + WEIGHT_HIDDEN_INDEX], weightHiddenDim, "wh") &&
1027 0 : ValidateInputShape((*dparams)[stride * layerIdx + WEIGHT_INPUT_INDEX], weightInputDim, "dwi") &&
1028 0 : ValidateInputShape((*dparams)[stride * layerIdx + WEIGHT_HIDDEN_INDEX], weightHiddenDim, "dwh");
1029 : }
1030 :
1031 5 : static bool CheckGateTensorsForIndex(const aclTensorList* i, const aclTensorList* j, const aclTensorList* f,
1032 : const aclTensorList* o, const aclTensorList* h, const aclTensorList* c,
1033 : const aclTensorList* tanhc, int64_t idx, const std::vector<int64_t>& hiddenDim)
1034 : {
1035 5 : if (!ValidateInputShape((*i)[idx], hiddenDim, "i"))
1036 : return false;
1037 5 : if (!ValidateInputShape((*j)[idx], hiddenDim, "j"))
1038 : return false;
1039 5 : if (!ValidateInputShape((*f)[idx], hiddenDim, "f"))
1040 : return false;
1041 5 : if (!ValidateInputShape((*o)[idx], hiddenDim, "o"))
1042 : return false;
1043 5 : if (!ValidateInputShape((*h)[idx], hiddenDim, "h"))
1044 : return false;
1045 5 : if (!ValidateInputShape((*c)[idx], hiddenDim, "c"))
1046 : return false;
1047 5 : if (!ValidateInputShape((*tanhc)[idx], hiddenDim, "tanhc"))
1048 : return false;
1049 : return true;
1050 : }
1051 :
1052 2 : static bool ValidateCoreShapes(int64_t numLayers, const aclTensor* input, const std::vector<int64_t>& inputDim,
1053 : const aclTensorList* hc, const std::vector<int64_t>& inithDim, const aclTensor* dx,
1054 : const aclTensor* dhPrev, const aclTensor* dcPrev, const aclTensor* dy,
1055 : const std::vector<int64_t>& outHiddenDim, const aclTensor* dh, const aclTensor* dc)
1056 : {
1057 2 : if (numLayers <= 0)
1058 : return false;
1059 6 : if (!ValidateInputShape(input, inputDim, "input") || !ValidateInputShape((*hc)[0], inithDim, "inith") ||
1060 6 : !ValidateInputShape((*hc)[1], inithDim, "initc") || !ValidateInputShape(dx, inputDim, "dx") ||
1061 6 : !ValidateInputShape(dhPrev, inithDim, "dhPrev") || !ValidateInputShape(dcPrev, inithDim, "dcPrev")) {
1062 0 : return false;
1063 : }
1064 2 : if (dy && !ValidateInputShape(dy, outHiddenDim, "dy"))
1065 : return false;
1066 2 : if (dh && !ValidateInputShape(dh, inithDim, "dh"))
1067 : return false;
1068 2 : if (dc && !ValidateInputShape(dc, inithDim, "dc"))
1069 : return false;
1070 :
1071 : return true;
1072 : }
1073 :
1074 2 : static bool CheckShapeValid(const aclTensor* input, const aclTensorList* hc, const aclTensorList* params,
1075 : const aclTensor* dy, const aclTensor* dh, const aclTensor* dc, const aclTensorList* i,
1076 : const aclTensorList* j, const aclTensorList* f, const aclTensorList* o,
1077 : const aclTensorList* h, const aclTensorList* c, const aclTensorList* tanhc,
1078 : const aclTensor* dx, const aclTensor* dhPrev, const aclTensor* dcPrev,
1079 : const aclTensorList* dparams, bool hasBias, int64_t numLayers, bool bidirectional,
1080 : bool batchFirst, const aclTensor* batchSizes = nullptr)
1081 : {
1082 2 : OP_CHECK_WRONG_DIMENSION((*i)[0], DIM_THREE, return false);
1083 : bool hasSeqlength = batchSizes != nullptr;
1084 2 : size_t inputDimsNum = hasSeqlength ? DIM_TWO : DIM_THREE;
1085 2 : OP_CHECK_WRONG_DIMENSION(input, inputDimsNum, return false);
1086 2 : if (hasSeqlength) {
1087 0 : OP_CHECK_WRONG_DIMENSION(batchSizes, DIM_ONE, return false);
1088 : }
1089 2 : auto iShape = (*i)[0]->GetViewShape();
1090 2 : auto inputShape = input->GetViewShape();
1091 2 : int64_t inputSize = inputShape[inputDimsNum - 1];
1092 2 : int64_t hiddenSize = iShape[HIDDEN_DIM];
1093 2 : int64_t batch = iShape[BATCH_DIM];
1094 :
1095 4 : int64_t timeStep = hasSeqlength ? batchSizes->GetViewShape()[SEQUENCE_DIM] :
1096 2 : batchFirst ? inputShape[BATCH_DIM] :
1097 : inputShape[SEQUENCE_DIM];
1098 2 : int64_t bid = bidirectional ? BI_DIRECTION : SINGLE_DIRECTION;
1099 :
1100 2 : const std::vector<int64_t> biasDim = {GATE_COUNT * hiddenSize};
1101 2 : const std::vector<int64_t> inithDim = {numLayers * bid, batch, hiddenSize};
1102 2 : const std::vector<int64_t> hiddenDim = {timeStep, batch, hiddenSize};
1103 2 : const std::vector<int64_t> outHiddenDim = hasSeqlength ? std::vector<int64_t>{timeStep * batch, hiddenSize * bid} :
1104 2 : batchFirst ? std::vector<int64_t>{batch, timeStep, hiddenSize * bid} :
1105 2 : std::vector<int64_t>{timeStep, batch, hiddenSize * bid};
1106 2 : const std::vector<int64_t> weightHiddenDim = {GATE_COUNT * hiddenSize, hiddenSize};
1107 2 : std::vector<int64_t> inputDim = hasSeqlength ? std::vector<int64_t>{timeStep * batch, inputSize} :
1108 2 : batchFirst ? std::vector<int64_t>{batch, timeStep, inputSize} :
1109 2 : std::vector<int64_t>{timeStep, batch, inputSize};
1110 2 : if (!ValidateCoreShapes(numLayers, input, inputDim, hc, inithDim, dx, dhPrev, dcPrev, dy, outHiddenDim, dh, dc))
1111 : return false;
1112 2 : int typeIdx = (hasBias ? 2 : 0) + (bidirectional ? 1 : 0);
1113 5 : for (int64_t layerIdx = 0; layerIdx < numLayers; ++layerIdx) {
1114 3 : int64_t curInputSize = (layerIdx == 0) ? inputSize : bid * hiddenSize;
1115 3 : const std::vector<int64_t> weightInputDim = {GATE_COUNT * hiddenSize, curInputSize};
1116 : bool ok = true;
1117 3 : switch (typeIdx) {
1118 0 : case LSTM_CONFIG_NO_BIAS_NO_BIDIR:
1119 0 : ok = ValidateLayerNoBiasNoBidir(params, dparams, layerIdx, weightInputDim, weightHiddenDim);
1120 : break;
1121 0 : case LSTM_CONFIG_BIDIR_ONLY:
1122 0 : ok = ValidateLayerWithBidirOnly(params, dparams, layerIdx, weightInputDim, weightHiddenDim);
1123 : break;
1124 1 : case LSTM_CONFIG_BIAS_ONLY:
1125 1 : ok = ValidateLayerWithBiasOnly(params, dparams, layerIdx, weightInputDim, weightHiddenDim, biasDim);
1126 : break;
1127 2 : case LSTM_CONFIG_BIAS_BIDIR:
1128 2 : ok = ValidateLayerWithBiasAndBidir(params, dparams, layerIdx, weightInputDim, weightHiddenDim, biasDim);
1129 : break;
1130 : }
1131 3 : if (!ok)
1132 : return false;
1133 : }
1134 :
1135 7 : for (int64_t gateIdx = 0; gateIdx < numLayers * bid; gateIdx++) {
1136 5 : if (!CheckGateTensorsForIndex(i, j, f, o, h, c, tanhc, gateIdx, hiddenDim))
1137 : return false;
1138 : }
1139 : return true;
1140 : }
1141 :
1142 2 : static aclnnStatus CheckParams(const aclTensor* input, const aclTensorList* hc, const aclTensorList* params,
1143 : const aclTensor* dy, const aclTensor* dh, const aclTensor* dc, const aclTensorList* i,
1144 : const aclTensorList* j, const aclTensorList* f, const aclTensorList* o,
1145 : const aclTensorList* h, const aclTensorList* c, const aclTensorList* tanhc,
1146 : const aclTensor* dx, const aclTensor* dhPrev, const aclTensor* dcPrev,
1147 : const aclTensorList* dparams, bool hasBias, int64_t numLayers, bool bidirectional,
1148 : bool batchFirst, const aclTensor* batchSizes = nullptr)
1149 : {
1150 : // 1. 检查参数是否为空指针
1151 2 : CHECK_RET(CheckNotNull(input, hc, params, i, j, f, o, h, c, tanhc, dx, dhPrev, dcPrev, dparams, hasBias, numLayers,
1152 : bidirectional),
1153 : ACLNN_ERR_PARAM_NULLPTR);
1154 : // 2. 检查输入的数据类型是否在API支持的数据类型范围之内,需要根据api定义校验
1155 2 : CHECK_RET(CheckDtypeValid(input, hc, params, dy, dh, dc, i, j, f, o, h, c, tanhc, dx, dhPrev, dcPrev, dparams,
1156 : batchSizes),
1157 : ACLNN_ERR_PARAM_INVALID);
1158 : // 3. 检查shape是否满足约束
1159 2 : CHECK_RET(CheckShapeValid(input, hc, params, dy, dh, dc, i, j, f, o, h, c, tanhc, dx, dhPrev, dcPrev, dparams,
1160 : hasBias, numLayers, bidirectional, batchFirst, batchSizes),
1161 : ACLNN_ERR_PARAM_INVALID);
1162 : // 4. 检查format是否满足约束
1163 2 : CHECK_RET(CheckFormatValid(input, hc, params, dy, dh, dc, i, j, f, o, h, c, tanhc, dx, dhPrev, dcPrev, dparams,
1164 : batchSizes),
1165 : ACLNN_ERR_PARAM_INVALID);
1166 :
1167 : return ACLNN_SUCCESS;
1168 : }
1169 :
1170 2 : static bool EmptyCheck(const aclTensor* input, const aclTensorList* hc, const aclTensorList* params,
1171 : const aclTensor* dy, const aclTensor* dh, const aclTensor* dc, const aclTensorList* i,
1172 : const aclTensorList* j, // 修正参数名:j -> g
1173 : const aclTensorList* f, const aclTensorList* o, const aclTensorList* h, const aclTensorList* c,
1174 : const aclTensorList* tanhc, const aclTensor* batchSizes = nullptr)
1175 : {
1176 2 : if (input->IsEmpty() || dy->IsEmpty() || dh->IsEmpty() || dc->IsEmpty()) {
1177 0 : return false;
1178 : }
1179 :
1180 2 : if (batchSizes != nullptr && batchSizes->IsEmpty()) {
1181 : return false;
1182 : }
1183 18 : auto checkTensorList = [](const aclTensorList* tensorList) {
1184 77 : for (uint64_t idx = 0; idx < tensorList->Size(); idx++) {
1185 59 : if ((*tensorList)[idx]->IsEmpty()) {
1186 : return false;
1187 : }
1188 : }
1189 : return true;
1190 : };
1191 6 : if (!checkTensorList(hc) || !checkTensorList(params) || !checkTensorList(i) || !checkTensorList(j) ||
1192 8 : !checkTensorList(f) || !checkTensorList(o) || !checkTensorList(h) || !checkTensorList(c) ||
1193 2 : !checkTensorList(tanhc)) {
1194 0 : return false;
1195 : }
1196 : return true;
1197 : }
1198 :
1199 10 : static const aclTensor* GetSliceTensor(const FVector<int64_t> offsetVector, const FVector<int64_t> sizeVector,
1200 : const aclTensor* input, aclOpExecutor* executor)
1201 : {
1202 10 : aclIntArray* offsetArray = executor->AllocIntArray(offsetVector.data(), offsetVector.size());
1203 10 : CHECK_RET(offsetArray != nullptr, nullptr);
1204 10 : aclIntArray* sizeArray = executor->AllocIntArray(sizeVector.data(), sizeVector.size());
1205 10 : CHECK_RET(sizeArray != nullptr, nullptr);
1206 10 : auto res = l0op::Slice(input, offsetArray, sizeArray, executor);
1207 10 : CHECK_RET(res != nullptr, nullptr);
1208 : return res;
1209 : }
1210 :
1211 : // 抽取处理LSTM梯度输出的函数
1212 2 : static std::tuple<const aclTensor*, const aclTensor*, std::vector<const aclTensor*>> GetLstmGradExceptDx(
1213 : std::tuple<const aclTensor*, std::vector<const aclTensor*>, std::vector<const aclTensor*>,
1214 : std::vector<const aclTensor*>, std::vector<const aclTensor*>>& output,
1215 : const aclTensor* input, const aclTensor* dhPrevOut, bool bidirectional, bool hasBias, int64_t numLayers,
1216 : aclOpExecutor* executor)
1217 : {
1218 2 : auto nullptrRes = std::make_tuple(nullptr, nullptr, std::vector<const aclTensor*>());
1219 2 : std::vector<const aclTensor*> dhPrevVectorReverse = std::get<INDEX_ONE>(output);
1220 2 : std::vector<const aclTensor*> dcPrevVectorReverse = std::get<INDEX_TWO>(output);
1221 2 : std::vector<const aclTensor*> dwVectorReverse = std::get<INDEX_THREE>(output);
1222 2 : std::vector<const aclTensor*> dbVectorReverse = std::get<INDEX_FOUR>(output);
1223 : std::vector<const aclTensor*> dhPrevVector{};
1224 : std::vector<const aclTensor*> dcPrevVector{};
1225 : std::vector<const aclTensor*> dparamsVector{};
1226 :
1227 2 : int64_t inputSize = input->GetViewShape()[DIM_TWO];
1228 2 : int64_t hiddenSize = dhPrevOut->GetViewShape()[HIDDEN_DIM];
1229 2 : int64_t bid = bidirectional ? BI_DIRECTION : SINGLE_DIRECTION;
1230 :
1231 : // 处理每一层的梯度
1232 5 : for (int64_t layerIdx = 0; layerIdx < numLayers; layerIdx++) {
1233 3 : auto dwFCur = dwVectorReverse[(numLayers - layerIdx - 1) * bid + 0];
1234 3 : auto inputSizeCur = layerIdx == 0 ? inputSize : hiddenSize * bid;
1235 :
1236 : // 前向层的输入权重梯度
1237 3 : FVector<int64_t> offsetVectorF{DIM_ZERO, DIM_ZERO};
1238 3 : FVector<int64_t> sizeVectorF{GATE_COUNT * hiddenSize, inputSizeCur};
1239 3 : auto dwFInputCur = GetSliceTensor(offsetVectorF, sizeVectorF, dwFCur, executor);
1240 :
1241 : // 前向层的隐藏状态权重梯度
1242 3 : FVector<int64_t> offsetVectorB{DIM_ZERO, inputSizeCur};
1243 3 : FVector<int64_t> sizeVectorB{GATE_COUNT * hiddenSize, hiddenSize};
1244 3 : auto dwFHiddenCur = GetSliceTensor(offsetVectorB, sizeVectorB, dwFCur, executor);
1245 3 : dparamsVector.emplace_back(dwFInputCur);
1246 3 : dparamsVector.emplace_back(dwFHiddenCur);
1247 :
1248 : // 处理偏置和双向情况
1249 3 : if (hasBias && bidirectional) {
1250 2 : auto dwBCur = dwVectorReverse[(numLayers - layerIdx - 1) * bid + 1];
1251 2 : auto dwBInputCur = GetSliceTensor(offsetVectorF, sizeVectorF, dwBCur, executor);
1252 2 : auto dwBHiddenCur = GetSliceTensor(offsetVectorB, sizeVectorB, dwBCur, executor);
1253 2 : auto dbFCur = dbVectorReverse[(numLayers - layerIdx - 1) * bid + 0];
1254 2 : auto dbBCur = dbVectorReverse[(numLayers - layerIdx - 1) * bid + 1];
1255 2 : dparamsVector.emplace_back(dbFCur);
1256 2 : dparamsVector.emplace_back(dbFCur);
1257 2 : dparamsVector.emplace_back(dwBInputCur);
1258 2 : dparamsVector.emplace_back(dwBHiddenCur);
1259 2 : dparamsVector.emplace_back(dbBCur);
1260 2 : dparamsVector.emplace_back(dbBCur);
1261 1 : } else if (hasBias && !bidirectional) {
1262 1 : auto dbFCur = dbVectorReverse[(numLayers - layerIdx - 1) * bid + 0];
1263 1 : dparamsVector.emplace_back(dbFCur);
1264 1 : dparamsVector.emplace_back(dbFCur);
1265 0 : } else if (!hasBias && bidirectional) {
1266 0 : auto dwBCur = dwVectorReverse[(numLayers - layerIdx - 1) * bid + 1];
1267 0 : auto dwBInputCur = GetSliceTensor(offsetVectorF, sizeVectorF, dwBCur, executor);
1268 0 : auto dwBHiddenCur = GetSliceTensor(offsetVectorB, sizeVectorB, dwBCur, executor);
1269 0 : dparamsVector.emplace_back(dwBInputCur);
1270 0 : dparamsVector.emplace_back(dwBHiddenCur);
1271 : }
1272 :
1273 : // 处理隐藏状态和细胞状态的梯度
1274 3 : dhPrevVector.emplace_back(dhPrevVectorReverse[(numLayers - layerIdx - 1) * bid + 0]);
1275 3 : dcPrevVector.emplace_back(dcPrevVectorReverse[(numLayers - layerIdx - 1) * bid + 0]);
1276 3 : if (bidirectional) {
1277 2 : dhPrevVector.emplace_back(dhPrevVectorReverse[(numLayers - layerIdx - 1) * bid + 1]);
1278 2 : dcPrevVector.emplace_back(dcPrevVectorReverse[(numLayers - layerIdx - 1) * bid + 1]);
1279 : }
1280 : }
1281 :
1282 : // 拼接隐藏状态梯度
1283 2 : auto dhPrev = SplitToConcat(dhPrevVector, CONCAT_DIM_LAYER, executor);
1284 :
1285 : // 拼接细胞状态梯度
1286 4 : auto dcPrev = SplitToConcat(dcPrevVector, CONCAT_DIM_LAYER, executor);
1287 2 : return std::make_tuple(dhPrev, dcPrev, dparamsVector);
1288 : }
1289 :
1290 18 : static const aclTensorList* MakeContiguousList(const aclTensorList* tensor_list, aclOpExecutor* executor)
1291 : {
1292 : std::vector<const aclTensor*> tensors_vec;
1293 77 : for (size_t i = 0; i < tensor_list->Size(); ++i) {
1294 59 : auto contiguous = l0op::Contiguous((*tensor_list)[i], executor);
1295 59 : if (contiguous == nullptr) {
1296 0 : return nullptr;
1297 : }
1298 59 : tensors_vec.push_back(contiguous);
1299 : }
1300 18 : return executor->AllocTensorList(tensors_vec.data(), tensors_vec.size());
1301 : }
1302 :
1303 2 : static aclnnStatus CreateContiguousTensors(const aclTensor* input, const aclTensorList* hx, const aclTensorList* params,
1304 : const aclTensor* dy, const aclTensor* dh, const aclTensor* dc,
1305 : const aclTensorList* i, const aclTensorList* g, const aclTensorList* f,
1306 : const aclTensorList* o, const aclTensorList* h, const aclTensorList* c,
1307 : const aclTensorList* tanhc, aclOpExecutor* executor,
1308 : LSTMContinuousTensors* output, const aclTensor* batchSizes = nullptr)
1309 : {
1310 2 : output->inputContiguous = l0op::Contiguous(input, executor);
1311 2 : CHECK_RET(output->inputContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
1312 :
1313 2 : output->hxContiguous = MakeContiguousList(hx, executor);
1314 2 : CHECK_RET(output->hxContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
1315 :
1316 2 : output->paramsContiguous = MakeContiguousList(params, executor);
1317 2 : CHECK_RET(output->paramsContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
1318 :
1319 2 : output->dyContiguous = l0op::Contiguous(dy, executor);
1320 2 : CHECK_RET(output->dyContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
1321 :
1322 2 : output->dhContiguous = l0op::Contiguous(dh, executor);
1323 2 : CHECK_RET(output->dhContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
1324 :
1325 2 : output->dcContiguous = l0op::Contiguous(dc, executor);
1326 2 : CHECK_RET(output->dcContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
1327 :
1328 2 : output->iContiguous = MakeContiguousList(i, executor);
1329 2 : CHECK_RET(output->iContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
1330 :
1331 2 : output->gContiguous = MakeContiguousList(g, executor);
1332 2 : CHECK_RET(output->gContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
1333 :
1334 2 : output->fContiguous = MakeContiguousList(f, executor);
1335 2 : CHECK_RET(output->fContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
1336 :
1337 2 : output->oContiguous = MakeContiguousList(o, executor);
1338 2 : CHECK_RET(output->oContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
1339 :
1340 2 : output->hContiguous = MakeContiguousList(h, executor);
1341 2 : CHECK_RET(output->hContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
1342 :
1343 2 : output->cContiguous = MakeContiguousList(c, executor);
1344 2 : CHECK_RET(output->cContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
1345 :
1346 2 : output->tanhcContiguous = MakeContiguousList(tanhc, executor);
1347 2 : CHECK_RET(output->tanhcContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
1348 :
1349 2 : output->batchSizesContiguous = batchSizes == nullptr ? nullptr : l0op::Contiguous(batchSizes, executor);
1350 : if (batchSizes != nullptr) {
1351 0 : CHECK_RET(output->batchSizesContiguous != nullptr, ACLNN_ERR_INNER_NULLPTR);
1352 : }
1353 : return ACL_SUCCESS;
1354 : }
1355 :
1356 : // 校验LSTM反向传播输出结果
1357 2 : static aclnnStatus ValidateLstmBackwardOutput(
1358 : const std::tuple<const aclTensor*, std::vector<const aclTensor*>, std::vector<const aclTensor*>,
1359 : std::vector<const aclTensor*>, std::vector<const aclTensor*>>& output)
1360 : {
1361 2 : CHECK_RET(std::get<0>(output) != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
1362 :
1363 7 : for (uint64_t idx = 0; idx < std::get<INDEX_THREE>(output).size(); idx++) {
1364 5 : CHECK_RET(std::get<INDEX_ONE>(output)[idx] != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
1365 5 : CHECK_RET(std::get<INDEX_TWO>(output)[idx] != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
1366 5 : CHECK_RET(std::get<INDEX_THREE>(output)[idx] != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
1367 : }
1368 :
1369 7 : for (uint64_t idx = 0; idx < std::get<INDEX_FOUR>(output).size(); idx++) {
1370 5 : CHECK_RET(std::get<INDEX_FOUR>(output)[idx] != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
1371 : }
1372 :
1373 : return ACLNN_SUCCESS;
1374 : }
1375 :
1376 : // 搬出LSTM反向传播结果
1377 2 : static aclnnStatus CopyLstmBackwardResults(const aclTensor* dx, const aclTensor* dhPrev, const aclTensor* dcPrev,
1378 : const std::vector<const aclTensor*>& dparamsVector, aclTensor* dxOut,
1379 : aclTensor* dhPrevOut, aclTensor* dcPrevOut, aclTensorList* dparamsOut,
1380 : int64_t numLayers, int64_t paramNumPerLayer, aclOpExecutor* executor)
1381 : {
1382 2 : auto dxCopyResult = l0op::ViewCopy(dx, dxOut, executor);
1383 2 : CHECK_RET(dxCopyResult != nullptr, ACLNN_ERR_INNER_NULLPTR);
1384 :
1385 2 : auto dhPrevCopyResult = l0op::ViewCopy(dhPrev, dhPrevOut, executor);
1386 2 : CHECK_RET(dhPrevCopyResult != nullptr, ACLNN_ERR_INNER_NULLPTR);
1387 :
1388 2 : auto dcPrevCopyResult = l0op::ViewCopy(dcPrev, dcPrevOut, executor);
1389 2 : CHECK_RET(dcPrevCopyResult != nullptr, ACLNN_ERR_INNER_NULLPTR);
1390 :
1391 22 : for (int64_t idx = 0; idx < numLayers * paramNumPerLayer; idx++) {
1392 20 : auto dparamsCopyResult = l0op::ViewCopy(dparamsVector[idx], (*dparamsOut)[idx], executor);
1393 20 : CHECK_RET(dparamsCopyResult != nullptr, ACLNN_ERR_INNER_NULLPTR);
1394 : }
1395 :
1396 : return ACLNN_SUCCESS;
1397 : }
1398 :
1399 2 : static aclnnStatus ExecLstmInputBackward(const LSTMContinuousTensors* allInput, aclTensor* dxOut, aclTensor* dhPrevOut,
1400 : aclTensor* dcPrevOut, aclTensorList* dparamsOut, bool batchFirst,
1401 : bool bidirectional, bool hasBias, int64_t numLayers, aclOpExecutor* executor)
1402 : {
1403 : std::tuple<const aclTensor*, std::vector<const aclTensor*>, std::vector<const aclTensor*>,
1404 : std::vector<const aclTensor*>, std::vector<const aclTensor*>>
1405 : output;
1406 : // T转到第1维
1407 2 : FVector<int64_t> newShapeDims = {1, 0, 2};
1408 2 : auto perm = executor->AllocIntArray(newShapeDims.data(), newShapeDims.size());
1409 2 : CHECK_RET(perm != nullptr, ACLNN_ERR_PARAM_NULLPTR);
1410 2 : auto inputTranspose = batchFirst ? l0op::Transpose(allInput->inputContiguous, perm, executor) :
1411 : allInput->inputContiguous;
1412 2 : CHECK_RET(inputTranspose != nullptr, ACLNN_ERR_PARAM_NULLPTR);
1413 2 : auto dyTranspose = batchFirst ? l0op::Transpose(allInput->dyContiguous, perm, executor) : allInput->dyContiguous;
1414 2 : CHECK_RET(dyTranspose != nullptr, ACLNN_ERR_PARAM_NULLPTR);
1415 :
1416 2 : int64_t paramNumPerLayer = (hasBias && bidirectional) ? NUM_WITH_B_AND_BID :
1417 1 : (hasBias || bidirectional) ? NUM_WITH_B_OR_BID :
1418 : NUM_NO_B_NO_BIDIR;
1419 1 : if (!bidirectional) {
1420 2 : output = LstmBackwardMultiLayerDirec(
1421 1 : inputTranspose, (*(allInput->hxContiguous))[0], (*(allInput->hxContiguous))[1], allInput->paramsContiguous,
1422 1 : dyTranspose, allInput->dhContiguous, allInput->dcContiguous, nullptr, allInput->iContiguous,
1423 1 : allInput->gContiguous, allInput->fContiguous, allInput->oContiguous, allInput->hContiguous,
1424 1 : allInput->cContiguous, allInput->tanhcContiguous, numLayers, 1, hasBias, paramNumPerLayer, executor);
1425 : } else {
1426 2 : output = LstmBackwardMultiLayerBidirec(
1427 1 : inputTranspose, (*allInput->hxContiguous)[0], (*allInput->hxContiguous)[1], allInput->paramsContiguous,
1428 1 : dyTranspose, allInput->dhContiguous, allInput->dcContiguous, nullptr, allInput->iContiguous,
1429 1 : allInput->gContiguous, allInput->fContiguous, allInput->oContiguous, allInput->hContiguous,
1430 1 : allInput->cContiguous, allInput->tanhcContiguous, numLayers, 1, hasBias, paramNumPerLayer, executor);
1431 : }
1432 2 : CHECK_RET(ValidateLstmBackwardOutput(output) == ACLNN_SUCCESS, ACLNN_ERR_PARAM_NULLPTR);
1433 2 : const aclTensor* dhPrev = nullptr;
1434 2 : const aclTensor* dcPrev = nullptr;
1435 : std::vector<const aclTensor*> dparamsVector{};
1436 : // 输出梯度处理
1437 4 : std::tie(dhPrev, dcPrev, dparamsVector) = GetLstmGradExceptDx(output, allInput->inputContiguous, dhPrevOut,
1438 : bidirectional, hasBias, numLayers, executor);
1439 2 : auto dx = batchFirst ? l0op::Transpose(std::get<0>(output), perm, executor) : std::get<0>(output);
1440 2 : CHECK_RET(dx != nullptr, ACLNN_ERR_PARAM_NULLPTR);
1441 2 : return CopyLstmBackwardResults(dx, dhPrev, dcPrev, dparamsVector, dxOut, dhPrevOut, dcPrevOut, dparamsOut,
1442 : numLayers, paramNumPerLayer, executor);
1443 : }
1444 :
1445 0 : static aclnnStatus ExecLstmDataBackward(const LSTMContinuousTensors* allInput, aclTensor* dxOut, aclTensor* dhPrevOut,
1446 : aclTensor* dcPrevOut, aclTensorList* dparamsOut, bool bidirectional,
1447 : bool hasBias, int64_t numLayers, aclOpExecutor* executor)
1448 : {
1449 : std::tuple<const aclTensor*, std::vector<const aclTensor*>, std::vector<const aclTensor*>,
1450 : std::vector<const aclTensor*>, std::vector<const aclTensor*>>
1451 : output;
1452 0 : auto batchSizeShape = allInput->batchSizesContiguous->GetViewShape();
1453 0 : auto dataShape = allInput->inputContiguous->GetViewShape();
1454 :
1455 : // 输入reshape为[T, N, D]
1456 0 : FVector<int64_t> reshapeInputVector{batchSizeShape[SEQUENCE_DIM], dataShape[0] / batchSizeShape[SEQUENCE_DIM],
1457 0 : dataShape[1]};
1458 0 : aclIntArray* reshapeInputArray = executor->AllocIntArray(reshapeInputVector.data(), DIM_THREE);
1459 0 : CHECK_RET(reshapeInputArray != nullptr, ACLNN_ERR_PARAM_NULLPTR);
1460 0 : auto input = l0op::Reshape(allInput->inputContiguous, reshapeInputArray, executor);
1461 0 : CHECK_RET(input != nullptr, ACLNN_ERR_PARAM_NULLPTR);
1462 0 : FVector<int64_t> reshapeDyVector{batchSizeShape[SEQUENCE_DIM], dataShape[0] / batchSizeShape[SEQUENCE_DIM],
1463 0 : allInput->dyContiguous->GetViewShape()[1]};
1464 0 : aclIntArray* reshapeDyArray = executor->AllocIntArray(reshapeDyVector.data(), DIM_THREE);
1465 0 : CHECK_RET(reshapeDyArray != nullptr, ACLNN_ERR_PARAM_NULLPTR);
1466 0 : auto dyReshape = l0op::Reshape(allInput->dyContiguous, reshapeDyArray, executor);
1467 0 : CHECK_RET(dyReshape != nullptr, ACLNN_ERR_PARAM_NULLPTR);
1468 : // batchSizes转Mask
1469 0 : const aclTensor* seqLength = GetMask(input, allInput->batchSizesContiguous, allInput->dhContiguous, executor);
1470 0 : CHECK_RET(seqLength != nullptr, ACLNN_ERR_PARAM_NULLPTR);
1471 0 : int64_t paramNumPerLayer = (hasBias && bidirectional) ? NUM_WITH_B_AND_BID :
1472 0 : (hasBias || bidirectional) ? NUM_WITH_B_OR_BID :
1473 : NUM_NO_B_NO_BIDIR;
1474 :
1475 0 : if (!bidirectional) {
1476 0 : output = LstmBackwardMultiLayerDirec(
1477 0 : input, (*(allInput->hxContiguous))[0], (*(allInput->hxContiguous))[1], allInput->paramsContiguous,
1478 0 : dyReshape, allInput->dhContiguous, allInput->dcContiguous, seqLength, allInput->iContiguous,
1479 0 : allInput->gContiguous, allInput->fContiguous, allInput->oContiguous, allInput->hContiguous,
1480 0 : allInput->cContiguous, allInput->tanhcContiguous, numLayers, 1, hasBias, paramNumPerLayer, executor);
1481 : } else {
1482 0 : output = LstmBackwardMultiLayerBidirec(
1483 0 : input, (*(allInput->hxContiguous))[0], (*(allInput->hxContiguous))[1], allInput->paramsContiguous,
1484 0 : dyReshape, allInput->dhContiguous, allInput->dcContiguous, seqLength, allInput->iContiguous,
1485 0 : allInput->gContiguous, allInput->fContiguous, allInput->oContiguous, allInput->hContiguous,
1486 0 : allInput->cContiguous, allInput->tanhcContiguous, numLayers, 1, hasBias, paramNumPerLayer, executor);
1487 : }
1488 0 : CHECK_RET(ValidateLstmBackwardOutput(output) == ACLNN_SUCCESS, ACLNN_ERR_PARAM_NULLPTR);
1489 0 : const aclTensor* dhPrev = nullptr;
1490 0 : const aclTensor* dcPrev = nullptr;
1491 : std::vector<const aclTensor*> dparamsVector{};
1492 0 : std::tie(dhPrev, dcPrev, dparamsVector) = GetLstmGradExceptDx(output, input, dhPrevOut, bidirectional, hasBias,
1493 : numLayers, executor);
1494 :
1495 0 : FVector<int64_t> reshapeVector{dataShape[0], dataShape[1]};
1496 0 : aclIntArray* reshapeArray = executor->AllocIntArray(reshapeVector.data(), DIM_TWO);
1497 0 : CHECK_RET(reshapeArray != nullptr, ACLNN_ERR_PARAM_NULLPTR);
1498 0 : auto dx = l0op::Reshape(std::get<0>(output), reshapeArray, executor);
1499 0 : CHECK_RET(dx != nullptr, ACLNN_ERR_PARAM_NULLPTR);
1500 0 : return CopyLstmBackwardResults(dx, dhPrev, dcPrev, dparamsVector, dxOut, dhPrevOut, dcPrevOut, dparamsOut,
1501 : numLayers, paramNumPerLayer, executor);
1502 : ;
1503 : }
1504 :
1505 0 : const aclTensor* ResetAndReshapeTensor(const aclTensor* srcTensor, const FVector<int64_t>& shape,
1506 : aclOpExecutor* executor)
1507 : {
1508 0 : const aclTensor* zeroTensor = l0op::ZerosLike(srcTensor, executor);
1509 0 : OP_CHECK_NULL(zeroTensor, return nullptr);
1510 0 : aclIntArray* reshapeArray = executor->AllocIntArray(shape.data(), shape.size());
1511 0 : OP_CHECK_NULL(reshapeArray, return nullptr);
1512 0 : const aclTensor* reshapedTensor = l0op::Reshape(zeroTensor, reshapeArray, executor);
1513 0 : OP_CHECK_NULL(reshapedTensor, return nullptr);
1514 : return reshapedTensor;
1515 : }
1516 :
1517 2 : aclnnStatus PrepareLSTMBackwardNoneInputs(const aclTensor* input, const aclTensorList* hx, const aclTensor* dh,
1518 : const aclTensor* dc, const aclTensor* dy, bool bidirectional,
1519 : aclOpExecutor* executor, const aclTensor*& dhOut, const aclTensor*& dcOut,
1520 : const aclTensor*& dyOut)
1521 : {
1522 2 : dhOut = dh;
1523 2 : dcOut = dc;
1524 2 : dyOut = dy;
1525 :
1526 2 : auto dhShape = (*hx)[0]->GetViewShape();
1527 2 : if (dh == nullptr) {
1528 0 : FVector<int64_t> dhReshapeVec{dhShape[0], dhShape[1], dhShape[2]};
1529 0 : dhOut = ResetAndReshapeTensor((*hx)[0], dhReshapeVec, executor);
1530 0 : CHECK_RET(dhOut != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
1531 : }
1532 2 : if (dc == nullptr) {
1533 0 : FVector<int64_t> dcReshapeVec{dhShape[0], dhShape[1], dhShape[2]};
1534 0 : dcOut = ResetAndReshapeTensor((*hx)[0], dcReshapeVec, executor);
1535 0 : CHECK_RET(dcOut != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
1536 : }
1537 : static const int64_t HIDDEN_DIM_INDEX = 2;
1538 2 : if (dy == nullptr) {
1539 0 : auto dyShape = input->GetViewShape();
1540 0 : auto dyType = input->GetDataType();
1541 0 : dyShape[HIDDEN_DIM_INDEX] = bidirectional ? dhShape[HIDDEN_DIM_INDEX] * BI_DIRECTION :
1542 : dhShape[HIDDEN_DIM_INDEX];
1543 0 : const aclTensor* dyAlloc = executor->AllocTensor(dyShape, dyType, Format::FORMAT_ND);
1544 0 : CHECK_RET(dyAlloc != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
1545 0 : FVector<int64_t> dyReshapeVec{dyShape[0], dyShape[1], dyShape[2]};
1546 0 : dyOut = ResetAndReshapeTensor(dyAlloc, dyReshapeVec, executor);
1547 0 : CHECK_RET(dyOut != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
1548 : }
1549 :
1550 : return ACLNN_SUCCESS;
1551 : }
1552 :
1553 2 : aclnnStatus aclnnLstmBackwardGetWorkspaceSize(const aclTensor* input, const aclTensorList* hx,
1554 : const aclTensorList* params, const aclTensor* dy, const aclTensor* dh,
1555 : const aclTensor* dc, const aclTensorList* i, const aclTensorList* g,
1556 : const aclTensorList* f, const aclTensorList* o, const aclTensorList* h,
1557 : const aclTensorList* c, const aclTensorList* tanhc,
1558 : const aclTensor* batchSizesOptional, bool hasBias, int64_t numLayers,
1559 : double dropout, bool train, bool bidirectional, bool batchFirst,
1560 : [[maybe_unused]] const aclBoolArray* outputMask, aclTensor* dxOut,
1561 : aclTensor* dhPrevOut, aclTensor* dcPrevOut, aclTensorList* dparamsOut,
1562 : uint64_t* workspaceSize, aclOpExecutor** executor)
1563 : {
1564 2 : L2_DFX_PHASE_1(aclnnLstmBackward,
1565 : DFX_IN(input, hx, params, dy, dh, dc, i, g, f, o, h, c, tanhc, batchSizesOptional, hasBias,
1566 : numLayers, dropout, train, bidirectional, batchFirst),
1567 : DFX_OUT(dxOut, dhPrevOut, dcPrevOut, dparamsOut));
1568 2 : auto uniqueExecutor = CREATE_EXECUTOR();
1569 2 : CHECK_RET(uniqueExecutor.get() != nullptr, ACLNN_ERR_INNER_CREATE_EXECUTOR);
1570 2 : auto ret = CheckParams(input, hx, params, dy, dh, dc, i, g, f, o, h, c, tanhc, dxOut, dhPrevOut, dcPrevOut,
1571 : dparamsOut, hasBias, numLayers, bidirectional, batchFirst, batchSizesOptional);
1572 2 : CHECK_RET(ret == ACLNN_SUCCESS, ret);
1573 : const aclTensor* dhInput = nullptr;
1574 : const aclTensor* dcInput = nullptr;
1575 : const aclTensor* dyInput = nullptr;
1576 2 : ret = PrepareLSTMBackwardNoneInputs(input, hx, dh, dc, dy, bidirectional, uniqueExecutor.get(), dhInput, dcInput,
1577 : dyInput);
1578 2 : CHECK_RET(ret == ACLNN_SUCCESS, ret);
1579 2 : if (!EmptyCheck(input, hx, params, dyInput, dhInput, dcInput, i, g, f, o, h, c, tanhc)) {
1580 0 : *workspaceSize = 0;
1581 0 : uniqueExecutor.ReleaseTo(executor);
1582 : return ACLNN_SUCCESS;
1583 : }
1584 :
1585 2 : LSTMContinuousTensors allInputContiguous;
1586 2 : CHECK_RET(CreateContiguousTensors(input, hx, params, dyInput, dhInput, dcInput, i, g, f, o, h, c, tanhc,
1587 : uniqueExecutor.get(), &allInputContiguous, batchSizesOptional) == ACLNN_SUCCESS,
1588 : ACLNN_ERR_PARAM_NULLPTR);
1589 :
1590 2 : if (batchSizesOptional == nullptr) {
1591 2 : ret = ExecLstmInputBackward(&allInputContiguous, dxOut, dhPrevOut, dcPrevOut, dparamsOut, batchFirst,
1592 : bidirectional, hasBias, numLayers, uniqueExecutor.get());
1593 : } else {
1594 0 : ret = ExecLstmDataBackward(&allInputContiguous, dxOut, dhPrevOut, dcPrevOut, dparamsOut, bidirectional, hasBias,
1595 : numLayers, uniqueExecutor.get());
1596 : }
1597 2 : CHECK_RET(ret == ACLNN_SUCCESS, ACLNN_ERR_INNER_NULLPTR);
1598 2 : *workspaceSize = uniqueExecutor->GetWorkspaceSize();
1599 2 : uniqueExecutor.ReleaseTo(executor);
1600 : return ACLNN_SUCCESS;
1601 2 : }
1602 :
1603 0 : aclnnStatus aclnnLstmBackward(void* workspace, uint64_t workspaceSize, aclOpExecutor* executor, aclrtStream stream)
1604 : {
1605 0 : L2_DFX_PHASE_2(aclnnLstmBackward);
1606 : // 固定写法,调用框架能力,完成计算
1607 0 : return CommonOpExecutorRun(workspace, workspaceSize, executor, stream);
1608 0 : }
1609 :
1610 : #ifdef __cplusplus
1611 : }
1612 : #endif
|