• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 //
2 // Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 #include "QLstmLayer.hpp"
6 
7 #include "LayerCloneBase.hpp"
8 
9 #include <armnn/LstmParams.hpp>
10 #include <armnn/TypesUtils.hpp>
11 #include <backendsCommon/CpuTensorHandle.hpp>
12 #include <backendsCommon/WorkloadFactory.hpp>
13 
14 namespace armnn
15 {
16 
QLstmLayer(const QLstmDescriptor & param,const char * name)17 QLstmLayer::QLstmLayer(const QLstmDescriptor& param, const char* name)
18         : LayerWithParameters(3, 3, LayerType::QLstm, param, name)
19 {
20 }
21 
CreateWorkload(const IWorkloadFactory & factory) const22 std::unique_ptr<IWorkload> QLstmLayer::CreateWorkload(const IWorkloadFactory& factory) const
23 {
24     QLstmQueueDescriptor descriptor;
25 
26     // Basic parameters
27     descriptor.m_InputToForgetWeights = m_BasicParameters.m_InputToForgetWeights.get();
28     descriptor.m_InputToCellWeights = m_BasicParameters.m_InputToCellWeights.get();
29     descriptor.m_InputToOutputWeights = m_BasicParameters.m_InputToOutputWeights.get();
30     descriptor.m_RecurrentToForgetWeights = m_BasicParameters.m_RecurrentToForgetWeights.get();
31     descriptor.m_RecurrentToCellWeights = m_BasicParameters.m_RecurrentToCellWeights.get();
32     descriptor.m_RecurrentToOutputWeights = m_BasicParameters.m_RecurrentToOutputWeights.get();
33     descriptor.m_ForgetGateBias = m_BasicParameters.m_ForgetGateBias.get();
34     descriptor.m_CellBias = m_BasicParameters.m_CellBias.get();
35     descriptor.m_OutputGateBias = m_BasicParameters.m_OutputGateBias.get();
36 
37     // CIFG parameters
38     if (!m_Param.m_CifgEnabled)
39     {
40         descriptor.m_InputToInputWeights     = m_CifgParameters.m_InputToInputWeights.get();
41         descriptor.m_RecurrentToInputWeights = m_CifgParameters.m_RecurrentToInputWeights.get();
42         descriptor.m_InputGateBias           = m_CifgParameters.m_InputGateBias.get();
43     }
44 
45     // Projection parameters
46     if (m_Param.m_ProjectionEnabled)
47     {
48         descriptor.m_ProjectionWeights = m_ProjectionParameters.m_ProjectionWeights.get();
49         descriptor.m_ProjectionBias    = m_ProjectionParameters.m_ProjectionBias.get();
50     }
51 
52     // Peephole parameters
53     if (m_Param.m_PeepholeEnabled)
54     {
55         if (!m_Param.m_CifgEnabled)
56         {
57             descriptor.m_CellToInputWeights = m_PeepholeParameters.m_CellToInputWeights.get();
58         }
59 
60         descriptor.m_CellToForgetWeights = m_PeepholeParameters.m_CellToForgetWeights.get();
61         descriptor.m_CellToOutputWeights = m_PeepholeParameters.m_CellToOutputWeights.get();
62     }
63 
64     // Layer normalisation parameters
65     if(m_Param.m_LayerNormEnabled)
66     {
67         if (!m_Param.m_CifgEnabled)
68         {
69             descriptor.m_InputLayerNormWeights = m_LayerNormParameters.m_InputLayerNormWeights.get();
70         }
71         descriptor.m_ForgetLayerNormWeights = m_LayerNormParameters.m_ForgetLayerNormWeights.get();
72         descriptor.m_CellLayerNormWeights   = m_LayerNormParameters.m_CellLayerNormWeights.get();
73         descriptor.m_OutputLayerNormWeights = m_LayerNormParameters.m_OutputLayerNormWeights.get();
74     }
75 
76     SetAdditionalInfo(descriptor);
77 
78     return factory.CreateQLstm(descriptor, PrepInfoAndDesc(descriptor));
79 }
80 
Clone(Graph & graph) const81 QLstmLayer* QLstmLayer::Clone(Graph& graph) const
82 {
83     auto layer = CloneBase<QLstmLayer>(graph, m_Param, GetName());
84 
85     layer->m_BasicParameters.m_InputToForgetWeights = m_BasicParameters.m_InputToForgetWeights ?
86             std::make_unique<ScopedCpuTensorHandle>(*m_BasicParameters.m_InputToForgetWeights) : nullptr;
87     layer->m_BasicParameters.m_InputToCellWeights = m_BasicParameters.m_InputToCellWeights ?
88             std::make_unique<ScopedCpuTensorHandle>(*m_BasicParameters.m_InputToCellWeights) : nullptr;
89     layer->m_BasicParameters.m_InputToOutputWeights = m_BasicParameters.m_InputToOutputWeights ?
90             std::make_unique<ScopedCpuTensorHandle>(*m_BasicParameters.m_InputToOutputWeights) : nullptr;
91     layer->m_BasicParameters.m_RecurrentToForgetWeights = m_BasicParameters.m_RecurrentToForgetWeights ?
92             std::make_unique<ScopedCpuTensorHandle>(*m_BasicParameters.m_RecurrentToForgetWeights) : nullptr;
93     layer->m_BasicParameters.m_RecurrentToCellWeights = m_BasicParameters.m_RecurrentToCellWeights ?
94             std::make_unique<ScopedCpuTensorHandle>(*m_BasicParameters.m_RecurrentToCellWeights) : nullptr;
95     layer->m_BasicParameters.m_RecurrentToOutputWeights = m_BasicParameters.m_RecurrentToOutputWeights ?
96             std::make_unique<ScopedCpuTensorHandle>(*m_BasicParameters.m_RecurrentToOutputWeights) : nullptr;
97     layer->m_BasicParameters.m_ForgetGateBias = m_BasicParameters.m_ForgetGateBias ?
98             std::make_unique<ScopedCpuTensorHandle>(*m_BasicParameters.m_ForgetGateBias) : nullptr;
99     layer->m_BasicParameters.m_CellBias = m_BasicParameters.m_CellBias ?
100             std::make_unique<ScopedCpuTensorHandle>(*m_BasicParameters.m_CellBias) : nullptr;
101     layer->m_BasicParameters.m_OutputGateBias = m_BasicParameters.m_OutputGateBias ?
102             std::make_unique<ScopedCpuTensorHandle>(*m_BasicParameters.m_OutputGateBias) : nullptr;
103 
104     if (!m_Param.m_CifgEnabled)
105     {
106         layer->m_CifgParameters.m_InputToInputWeights = m_CifgParameters.m_InputToInputWeights ?
107                 std::make_unique<ScopedCpuTensorHandle>(*m_CifgParameters.m_InputToInputWeights) : nullptr;
108         layer->m_CifgParameters.m_RecurrentToInputWeights = m_CifgParameters.m_RecurrentToInputWeights ?
109                 std::make_unique<ScopedCpuTensorHandle>(*m_CifgParameters.m_RecurrentToInputWeights) : nullptr;
110         layer->m_CifgParameters.m_InputGateBias = m_CifgParameters.m_InputGateBias ?
111                 std::make_unique<ScopedCpuTensorHandle>(*m_CifgParameters.m_InputGateBias) : nullptr;
112     }
113 
114     if (m_Param.m_ProjectionEnabled)
115     {
116         layer->m_ProjectionParameters.m_ProjectionWeights = m_ProjectionParameters.m_ProjectionWeights ?
117                 std::make_unique<ScopedCpuTensorHandle>(*m_ProjectionParameters.m_ProjectionWeights) : nullptr;
118         layer->m_ProjectionParameters.m_ProjectionBias = m_ProjectionParameters.m_ProjectionBias ?
119                 std::make_unique<ScopedCpuTensorHandle>(*m_ProjectionParameters.m_ProjectionBias) : nullptr;
120     }
121 
122     if (m_Param.m_PeepholeEnabled)
123     {
124         if (!m_Param.m_CifgEnabled) {
125             layer->m_PeepholeParameters.m_CellToInputWeights = m_PeepholeParameters.m_CellToInputWeights ?
126                     std::make_unique<ScopedCpuTensorHandle>(*m_PeepholeParameters.m_CellToInputWeights) : nullptr;
127         }
128 
129         layer->m_PeepholeParameters.m_CellToForgetWeights = m_PeepholeParameters.m_CellToForgetWeights ?
130                 std::make_unique<ScopedCpuTensorHandle>(*m_PeepholeParameters.m_CellToForgetWeights) : nullptr;
131         layer->m_PeepholeParameters.m_CellToOutputWeights = m_PeepholeParameters.m_CellToOutputWeights ?
132                 std::make_unique<ScopedCpuTensorHandle>(*m_PeepholeParameters.m_CellToOutputWeights) : nullptr;
133     }
134 
135     if (m_Param.m_LayerNormEnabled)
136     {
137         if (!m_Param.m_CifgEnabled) {
138             layer->m_LayerNormParameters.m_InputLayerNormWeights = m_LayerNormParameters.m_InputLayerNormWeights ?
139                     std::make_unique<ScopedCpuTensorHandle>(*m_LayerNormParameters.m_InputLayerNormWeights) : nullptr;
140         }
141 
142         layer->m_LayerNormParameters.m_ForgetLayerNormWeights = m_LayerNormParameters.m_ForgetLayerNormWeights ?
143                 std::make_unique<ScopedCpuTensorHandle>(*m_LayerNormParameters.m_ForgetLayerNormWeights) : nullptr;
144         layer->m_LayerNormParameters.m_CellLayerNormWeights = m_LayerNormParameters.m_CellLayerNormWeights ?
145                 std::make_unique<ScopedCpuTensorHandle>(*m_LayerNormParameters.m_CellLayerNormWeights) : nullptr;
146         layer->m_LayerNormParameters.m_OutputLayerNormWeights = m_LayerNormParameters.m_OutputLayerNormWeights ?
147                 std::make_unique<ScopedCpuTensorHandle>(*m_LayerNormParameters.m_OutputLayerNormWeights) : nullptr;
148     }
149 
150     return std::move(layer);
151 }
152 
InferOutputShapes(const std::vector<TensorShape> & inputShapes) const153 std::vector<TensorShape> QLstmLayer::InferOutputShapes(const std::vector<TensorShape>& inputShapes) const
154 {
155     ARMNN_ASSERT(inputShapes.size() == 3);
156 
157     // Get input values for validation
158     unsigned int batchSize = inputShapes[0][0];
159     unsigned int outputSize = inputShapes[1][1];
160     unsigned int numUnits = inputShapes[2][1];
161 
162     std::vector<TensorShape> outShapes;
163     outShapes.push_back(TensorShape({ batchSize, outputSize })); // outputStateOut
164     outShapes.push_back(TensorShape({ batchSize, numUnits })); // cellStateOut
165     outShapes.push_back(TensorShape({ batchSize, outputSize })); // output
166 
167     return outShapes;
168 }
169 
ValidateTensorShapesFromInputs()170 void QLstmLayer::ValidateTensorShapesFromInputs()
171 {
172     VerifyLayerConnections(3, CHECK_LOCATION());
173 
174     const TensorShape& outputShape = GetOutputSlot(0).GetTensorInfo().GetShape();
175 
176     VerifyShapeInferenceType(outputShape, m_ShapeInferenceMethod);
177 
178     auto inferredShapes = InferOutputShapes(
179     {
180         GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape(), // input
181         GetInputSlot(1).GetConnection()->GetTensorInfo().GetShape(), // previousOutputIn
182         GetInputSlot(2).GetConnection()->GetTensorInfo().GetShape()  // previousCellStateIn
183     });
184 
185     ARMNN_ASSERT(inferredShapes.size() == 3);
186 
187     // Check if the weights are nullptr for basic params
188     ARMNN_ASSERT_MSG(m_BasicParameters.m_InputToForgetWeights != nullptr,
189             "QLstmLayer: m_BasicParameters.m_InputToForgetWeights should not be null.");
190     ARMNN_ASSERT_MSG(m_BasicParameters.m_InputToCellWeights != nullptr,
191             "QLstmLayer: m_BasicParameters.m_InputToCellWeights should not be null.");
192     ARMNN_ASSERT_MSG(m_BasicParameters.m_InputToOutputWeights != nullptr,
193             "QLstmLayer: m_BasicParameters.m_InputToOutputWeights should not be null.");
194     ARMNN_ASSERT_MSG(m_BasicParameters.m_RecurrentToForgetWeights != nullptr,
195             "QLstmLayer: m_BasicParameters.m_RecurrentToForgetWeights should not be null.");
196     ARMNN_ASSERT_MSG(m_BasicParameters.m_RecurrentToCellWeights != nullptr,
197             "QLstmLayer: m_BasicParameters.m_RecurrentToCellWeights should not be null.");
198     ARMNN_ASSERT_MSG(m_BasicParameters.m_RecurrentToOutputWeights != nullptr,
199             "QLstmLayer: m_BasicParameters.m_RecurrentToOutputWeights should not be null.");
200     ARMNN_ASSERT_MSG(m_BasicParameters.m_ForgetGateBias != nullptr,
201             "QLstmLayer: m_BasicParameters.m_ForgetGateBias should not be null.");
202     ARMNN_ASSERT_MSG(m_BasicParameters.m_CellBias != nullptr,
203             "QLstmLayer: m_BasicParameters.m_CellBias should not be null.");
204     ARMNN_ASSERT_MSG(m_BasicParameters.m_OutputGateBias != nullptr,
205             "QLstmLayer: m_BasicParameters.m_OutputGateBias should not be null.");
206 
207     if (!m_Param.m_CifgEnabled)
208     {
209         ARMNN_ASSERT_MSG(m_CifgParameters.m_InputToInputWeights != nullptr,
210                 "QLstmLayer: m_CifgParameters.m_InputToInputWeights should not be null.");
211         ARMNN_ASSERT_MSG(m_CifgParameters.m_RecurrentToInputWeights != nullptr,
212                 "QLstmLayer: m_CifgParameters.m_RecurrentToInputWeights should not be null.");
213         ARMNN_ASSERT_MSG(m_CifgParameters.m_InputGateBias != nullptr,
214                 "QLstmLayer: m_CifgParameters.m_InputGateBias should not be null.");
215 
216         ValidateAndCopyShape(outputShape, inferredShapes[0], m_ShapeInferenceMethod, "QLstmLayer");
217     }
218     else
219     {
220         ARMNN_ASSERT_MSG(m_CifgParameters.m_InputToInputWeights == nullptr,
221                 "QLstmLayer: m_CifgParameters.m_InputToInputWeights should not have a value when CIFG is enabled.");
222         ARMNN_ASSERT_MSG(m_CifgParameters.m_RecurrentToInputWeights == nullptr,
223                 "QLstmLayer: m_CifgParameters.m_RecurrentToInputWeights should "
224                              "not have a value when CIFG is enabled.");
225         ARMNN_ASSERT_MSG(m_CifgParameters.m_InputGateBias == nullptr,
226                 "QLstmLayer: m_CifgParameters.m_InputGateBias should not have a value when CIFG is enabled.");
227 
228         ValidateAndCopyShape(outputShape, inferredShapes[0], m_ShapeInferenceMethod, "QLstmLayer");
229     }
230 
231     if (m_Param.m_ProjectionEnabled)
232     {
233         ARMNN_ASSERT_MSG(m_ProjectionParameters.m_ProjectionWeights != nullptr,
234                          "QLstmLayer: m_ProjectionParameters.m_ProjectionWeights should not be null.");
235     }
236 
237     if (m_Param.m_PeepholeEnabled)
238     {
239         if (!m_Param.m_CifgEnabled) {
240             ARMNN_ASSERT_MSG(m_PeepholeParameters.m_CellToInputWeights != nullptr,
241                     "QLstmLayer: m_PeepholeParameters.m_CellToInputWeights should not be null "
242                     "when Peephole is enabled and CIFG is disabled.");
243         }
244 
245         ARMNN_ASSERT_MSG(m_PeepholeParameters.m_CellToForgetWeights != nullptr,
246                          "QLstmLayer: m_PeepholeParameters.m_CellToForgetWeights should not be null.");
247         ARMNN_ASSERT_MSG(m_PeepholeParameters.m_CellToOutputWeights != nullptr,
248                          "QLstmLayer: m_PeepholeParameters.m_CellToOutputWeights should not be null.");
249     }
250 
251     ValidateAndCopyShape(
252             GetOutputSlot(1).GetTensorInfo().GetShape(), inferredShapes[1], m_ShapeInferenceMethod, "QLstmLayer", 1);
253     ValidateAndCopyShape(
254             GetOutputSlot(2).GetTensorInfo().GetShape(), inferredShapes[2], m_ShapeInferenceMethod, "QLstmLayer", 2);
255 
256     if (m_Param.m_LayerNormEnabled)
257     {
258         if(!m_Param.m_CifgEnabled)
259         {
260             ARMNN_ASSERT_MSG(m_LayerNormParameters.m_InputLayerNormWeights != nullptr,
261                              "QLstmLayer: m_LayerNormParameters.m_InputLayerNormWeights should not be null.");
262         }
263         ARMNN_ASSERT_MSG(m_LayerNormParameters.m_ForgetLayerNormWeights != nullptr,
264                          "QLstmLayer: m_LayerNormParameters.m_ForgetLayerNormWeights should not be null.");
265         ARMNN_ASSERT_MSG(m_LayerNormParameters.m_CellLayerNormWeights != nullptr,
266                          "QLstmLayer: m_LayerNormParameters.m_CellLayerNormWeights should not be null.");
267         ARMNN_ASSERT_MSG(m_LayerNormParameters.m_OutputLayerNormWeights != nullptr,
268                          "QLstmLayer: m_LayerNormParameters.m_UutputLayerNormWeights should not be null.");
269     }
270 }
271 
GetConstantTensorsByRef()272 Layer::ConstantTensors QLstmLayer::GetConstantTensorsByRef()
273 {
274     return {m_BasicParameters.m_InputToForgetWeights,
275             m_BasicParameters.m_InputToCellWeights,
276             m_BasicParameters.m_InputToOutputWeights,
277             m_BasicParameters.m_RecurrentToForgetWeights,
278             m_BasicParameters.m_RecurrentToCellWeights,
279             m_BasicParameters.m_RecurrentToOutputWeights,
280             m_BasicParameters.m_ForgetGateBias,
281             m_BasicParameters.m_CellBias,
282             m_BasicParameters.m_OutputGateBias,
283 
284             // Cifg parameters
285             m_CifgParameters.m_InputToInputWeights,
286             m_CifgParameters.m_RecurrentToInputWeights,
287             m_CifgParameters.m_InputGateBias,
288 
289             // Projection parameters
290             m_ProjectionParameters.m_ProjectionWeights,
291             m_ProjectionParameters.m_ProjectionBias,
292 
293             // Peephole parameters
294             m_PeepholeParameters.m_CellToInputWeights,
295             m_PeepholeParameters.m_CellToForgetWeights,
296             m_PeepholeParameters.m_CellToOutputWeights,
297 
298             // Layer normalisation parameters
299             m_LayerNormParameters.m_InputLayerNormWeights,
300             m_LayerNormParameters.m_ForgetLayerNormWeights,
301             m_LayerNormParameters.m_CellLayerNormWeights,
302             m_LayerNormParameters.m_OutputLayerNormWeights};
303 }
304 
Accept(ILayerVisitor & visitor) const305 void QLstmLayer::Accept(ILayerVisitor& visitor) const
306 {
307     LstmInputParams inputParams;
308 
309     ConstTensor inputToInputWeightsTensor;
310     if (m_CifgParameters.m_InputToInputWeights != nullptr)
311     {
312         ConstTensor inputToInputWeightsTensorCopy(m_CifgParameters.m_InputToInputWeights->GetTensorInfo(),
313                                                   m_CifgParameters.m_InputToInputWeights->Map(true));
314         inputToInputWeightsTensor = inputToInputWeightsTensorCopy;
315         inputParams.m_InputToInputWeights = &inputToInputWeightsTensor;
316     }
317 
318     ConstTensor inputToForgetWeightsTensor;
319     if (m_BasicParameters.m_InputToForgetWeights != nullptr)
320     {
321         ConstTensor inputToForgetWeightsTensorCopy(m_BasicParameters.m_InputToForgetWeights->GetTensorInfo(),
322                                                    m_BasicParameters.m_InputToForgetWeights->Map(true));
323         inputToForgetWeightsTensor = inputToForgetWeightsTensorCopy;
324         inputParams.m_InputToForgetWeights = &inputToForgetWeightsTensor;
325     }
326 
327     ConstTensor inputToCellWeightsTensor;
328     if (m_BasicParameters.m_InputToCellWeights != nullptr)
329     {
330         ConstTensor inputToCellWeightsTensorCopy(m_BasicParameters.m_InputToCellWeights->GetTensorInfo(),
331                                                  m_BasicParameters.m_InputToCellWeights->Map(true));
332         inputToCellWeightsTensor = inputToCellWeightsTensorCopy;
333         inputParams.m_InputToCellWeights = &inputToCellWeightsTensor;
334     }
335 
336     ConstTensor inputToOutputWeightsTensor;
337     if (m_BasicParameters.m_InputToOutputWeights != nullptr)
338     {
339         ConstTensor inputToOutputWeightsTensorCopy(m_BasicParameters.m_InputToOutputWeights->GetTensorInfo(),
340                                                    m_BasicParameters.m_InputToOutputWeights->Map(true));
341         inputToOutputWeightsTensor = inputToOutputWeightsTensorCopy;
342         inputParams.m_InputToOutputWeights = &inputToOutputWeightsTensor;
343     }
344 
345     ConstTensor recurrentToInputWeightsTensor;
346     if (m_CifgParameters.m_RecurrentToInputWeights != nullptr)
347     {
348         ConstTensor recurrentToInputWeightsTensorCopy(
349                 m_CifgParameters.m_RecurrentToInputWeights->GetTensorInfo(),
350                 m_CifgParameters.m_RecurrentToInputWeights->Map(true));
351         recurrentToInputWeightsTensor = recurrentToInputWeightsTensorCopy;
352         inputParams.m_RecurrentToInputWeights = &recurrentToInputWeightsTensor;
353     }
354 
355     ConstTensor recurrentToForgetWeightsTensor;
356     if (m_BasicParameters.m_RecurrentToForgetWeights != nullptr)
357     {
358         ConstTensor recurrentToForgetWeightsTensorCopy(
359                 m_BasicParameters.m_RecurrentToForgetWeights->GetTensorInfo(),
360                 m_BasicParameters.m_RecurrentToForgetWeights->Map(true));
361         recurrentToForgetWeightsTensor = recurrentToForgetWeightsTensorCopy;
362         inputParams.m_RecurrentToForgetWeights = &recurrentToForgetWeightsTensor;
363     }
364 
365     ConstTensor recurrentToCellWeightsTensor;
366     if (m_BasicParameters.m_RecurrentToCellWeights != nullptr)
367     {
368         ConstTensor recurrentToCellWeightsTensorCopy(
369                 m_BasicParameters.m_RecurrentToCellWeights->GetTensorInfo(),
370                 m_BasicParameters.m_RecurrentToCellWeights->Map(true));
371         recurrentToCellWeightsTensor = recurrentToCellWeightsTensorCopy;
372         inputParams.m_RecurrentToCellWeights = &recurrentToCellWeightsTensor;
373     }
374 
375     ConstTensor recurrentToOutputWeightsTensor;
376     if (m_BasicParameters.m_RecurrentToOutputWeights != nullptr)
377     {
378         ConstTensor recurrentToOutputWeightsTensorCopy(
379                 m_BasicParameters.m_RecurrentToOutputWeights->GetTensorInfo(),
380                 m_BasicParameters.m_RecurrentToOutputWeights->Map(true));
381         recurrentToOutputWeightsTensor = recurrentToOutputWeightsTensorCopy;
382         inputParams.m_RecurrentToOutputWeights = &recurrentToOutputWeightsTensor;
383     }
384 
385     ConstTensor cellToInputWeightsTensor;
386     if (m_PeepholeParameters.m_CellToInputWeights != nullptr)
387     {
388         ConstTensor cellToInputWeightsTensorCopy(m_PeepholeParameters.m_CellToInputWeights->GetTensorInfo(),
389                                                  m_PeepholeParameters.m_CellToInputWeights->Map(true));
390         cellToInputWeightsTensor = cellToInputWeightsTensorCopy;
391         inputParams.m_CellToInputWeights = &cellToInputWeightsTensor;
392     }
393 
394     ConstTensor cellToForgetWeightsTensor;
395     if (m_PeepholeParameters.m_CellToForgetWeights != nullptr)
396     {
397         ConstTensor cellToForgetWeightsTensorCopy(m_PeepholeParameters.m_CellToForgetWeights->GetTensorInfo(),
398                                                   m_PeepholeParameters.m_CellToForgetWeights->Map(true));
399         cellToForgetWeightsTensor = cellToForgetWeightsTensorCopy;
400         inputParams.m_CellToForgetWeights = &cellToForgetWeightsTensor;
401     }
402 
403     ConstTensor cellToOutputWeightsTensor;
404     if (m_PeepholeParameters.m_CellToOutputWeights != nullptr)
405     {
406         ConstTensor cellToOutputWeightsTensorCopy(m_PeepholeParameters.m_CellToOutputWeights->GetTensorInfo(),
407                                                   m_PeepholeParameters.m_CellToOutputWeights->Map(true));
408         cellToOutputWeightsTensor = cellToOutputWeightsTensorCopy;
409         inputParams.m_CellToOutputWeights = &cellToOutputWeightsTensor;
410     }
411 
412     ConstTensor inputGateBiasTensor;
413     if (m_CifgParameters.m_InputGateBias != nullptr)
414     {
415         ConstTensor inputGateBiasTensorCopy(m_CifgParameters.m_InputGateBias->GetTensorInfo(),
416                                             m_CifgParameters.m_InputGateBias->Map(true));
417         inputGateBiasTensor = inputGateBiasTensorCopy;
418         inputParams.m_InputGateBias = &inputGateBiasTensor;
419     }
420 
421     ConstTensor forgetGateBiasTensor;
422     if (m_BasicParameters.m_ForgetGateBias != nullptr)
423     {
424         ConstTensor forgetGateBiasTensorCopy(m_BasicParameters.m_ForgetGateBias->GetTensorInfo(),
425                                              m_BasicParameters.m_ForgetGateBias->Map(true));
426         forgetGateBiasTensor = forgetGateBiasTensorCopy;
427         inputParams.m_ForgetGateBias = &forgetGateBiasTensor;
428     }
429 
430     ConstTensor cellBiasTensor;
431     if (m_BasicParameters.m_CellBias != nullptr)
432     {
433         ConstTensor cellBiasTensorCopy(m_BasicParameters.m_CellBias->GetTensorInfo(),
434                                        m_BasicParameters.m_CellBias->Map(true));
435         cellBiasTensor = cellBiasTensorCopy;
436         inputParams.m_CellBias = &cellBiasTensor;
437     }
438 
439     ConstTensor outputGateBias;
440     if (m_BasicParameters.m_OutputGateBias != nullptr)
441     {
442         ConstTensor outputGateBiasCopy(m_BasicParameters.m_OutputGateBias->GetTensorInfo(),
443                                        m_BasicParameters.m_OutputGateBias->Map(true));
444         outputGateBias = outputGateBiasCopy;
445         inputParams.m_OutputGateBias = &outputGateBias;
446     }
447 
448     ConstTensor projectionWeightsTensor;
449     if (m_ProjectionParameters.m_ProjectionWeights != nullptr)
450     {
451         ConstTensor projectionWeightsTensorCopy(m_ProjectionParameters.m_ProjectionWeights->GetTensorInfo(),
452                                                 m_ProjectionParameters.m_ProjectionWeights->Map(true));
453         projectionWeightsTensor = projectionWeightsTensorCopy;
454         inputParams.m_ProjectionWeights = &projectionWeightsTensor;
455     }
456 
457     ConstTensor projectionBiasTensor;
458     if (m_ProjectionParameters.m_ProjectionBias != nullptr)
459     {
460         ConstTensor projectionBiasTensorCopy(m_ProjectionParameters.m_ProjectionBias->GetTensorInfo(),
461                                              m_ProjectionParameters.m_ProjectionBias->Map(true));
462         projectionBiasTensor = projectionBiasTensorCopy;
463         inputParams.m_ProjectionBias = &projectionBiasTensor;
464     }
465 
466     ConstTensor inputLayerNormTensor;
467     if (m_LayerNormParameters.m_InputLayerNormWeights != nullptr)
468     {
469         ConstTensor inputLayerNormTensorCopy(m_LayerNormParameters.m_InputLayerNormWeights->GetTensorInfo(),
470                                              m_LayerNormParameters.m_InputLayerNormWeights->Map(true));
471         inputLayerNormTensor = inputLayerNormTensorCopy;
472         inputParams.m_InputLayerNormWeights = &inputLayerNormTensor;
473     }
474 
475     ConstTensor forgetLayerNormTensor;
476     if (m_LayerNormParameters.m_ForgetLayerNormWeights != nullptr)
477     {
478         ConstTensor forgetLayerNormTensorCopy(m_LayerNormParameters.m_ForgetLayerNormWeights->GetTensorInfo(),
479                                               m_LayerNormParameters.m_ForgetLayerNormWeights->Map(true));
480         forgetLayerNormTensor = forgetLayerNormTensorCopy;
481         inputParams.m_ForgetLayerNormWeights = &forgetLayerNormTensor;
482     }
483 
484     ConstTensor cellLayerNormTensor;
485     if (m_LayerNormParameters.m_CellLayerNormWeights != nullptr)
486     {
487         ConstTensor cellLayerNormTensorCopy(m_LayerNormParameters.m_CellLayerNormWeights->GetTensorInfo(),
488                                             m_LayerNormParameters.m_CellLayerNormWeights->Map(true));
489         cellLayerNormTensor = cellLayerNormTensorCopy;
490         inputParams.m_CellLayerNormWeights = &cellLayerNormTensor;
491     }
492 
493     ConstTensor outputLayerNormTensor;
494     if (m_LayerNormParameters.m_OutputLayerNormWeights != nullptr)
495     {
496         ConstTensor outputLayerNormTensorCopy(m_LayerNormParameters.m_OutputLayerNormWeights->GetTensorInfo(),
497                                               m_LayerNormParameters.m_OutputLayerNormWeights->Map(true));
498         outputLayerNormTensor = outputLayerNormTensorCopy;
499         inputParams.m_OutputLayerNormWeights = &outputLayerNormTensor;
500     }
501 
502 
503     visitor.VisitQLstmLayer(this, GetParameters(), inputParams, GetName());
504 }
505 
506 } // namespace armnn
507