xref: /aosp_15_r20/external/android-nn-driver/test/1.3/QLstm.cpp (revision 3e777be0405cee09af5d5785ff37f7cfb5bee59a)
1 //
2 // Copyright © 2020 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "../DriverTestHelpers.hpp"
7 
8 #include <1.3/HalPolicy.hpp>
9 
10 #include <array>
11 
12 using ArmnnDriver   = armnn_driver::ArmnnDriver;
13 using DriverOptions = armnn_driver::DriverOptions;
14 
15 using namespace driverTestHelpers;
16 using namespace android::hardware;
17 
18 using HalPolicy = hal_1_3::HalPolicy;
19 
20 static const float TOLERANCE = 1.0f;
21 
22 namespace
23 {
24 
25 template<typename T>
CreateRequestArgument(const std::vector<T> & value,unsigned int poolIndex)26 RequestArgument CreateRequestArgument(const std::vector<T>& value, unsigned int poolIndex)
27 {
28     V1_0::DataLocation inputInloc = {};
29     inputInloc.poolIndex = poolIndex;
30     inputInloc.offset = 0;
31     inputInloc.length = value.size() * sizeof(T);
32     RequestArgument inputRequestArgument = {};
33     inputRequestArgument.location = inputInloc;
34     inputRequestArgument.dimensions = hidl_vec<uint32_t>{};
35     return inputRequestArgument;
36 }
37 
38 // Helper function to create an OperandLifeTime::NO_VALUE for testing.
39 // To be used on optional input operands that have no values - these are valid and should be tested.
CreateNoValueLifeTime(const hidl_vec<uint32_t> & dimensions)40 HalPolicy::OperandLifeTime CreateNoValueLifeTime(const hidl_vec<uint32_t>& dimensions)
41 {
42     // Only create a NO_VALUE for optional operands that have no elements
43     if (dimensions.size() == 0 || dimensions[0] == 0)
44     {
45         return HalPolicy::OperandLifeTime::NO_VALUE;
46     }
47     return HalPolicy::OperandLifeTime::CONSTANT_COPY;
48 }
49 
ExecuteModel(const armnn_driver::hal_1_3::HalPolicy::Model & model,armnn_driver::ArmnnDriver & driver,const V1_0::Request & request)50 void ExecuteModel(const armnn_driver::hal_1_3::HalPolicy::Model& model,
51                   armnn_driver::ArmnnDriver& driver,
52                   const V1_0::Request& request)
53 {
54     android::sp<V1_3::IPreparedModel> preparedModel = PrepareModel_1_3(model, driver);
55     if (preparedModel.get() != nullptr)
56     {
57         Execute(preparedModel, request);
58     }
59 }
60 
61 // Add our own tests here since we skip the qlstm tests which Google supplies (because of non-const weights)
QLstmTestImpl(const hidl_vec<uint32_t> & inputDimensions,const std::vector<int8_t> & inputValue,const hidl_vec<uint32_t> & inputToInputWeightsDimensions,const std::vector<int8_t> & inputToInputWeightsValue,const hidl_vec<uint32_t> & inputToForgetWeightsDimensions,const std::vector<int8_t> & inputToForgetWeightsValue,const hidl_vec<uint32_t> & inputToCellWeightsDimensions,const std::vector<int8_t> & inputToCellWeightsValue,const hidl_vec<uint32_t> & inputToOutputWeightsDimensions,const std::vector<int8_t> & inputToOutputWeightsValue,const hidl_vec<uint32_t> & recurrentToInputWeightsDimensions,const std::vector<int8_t> & recurrentToInputWeightsValue,const hidl_vec<uint32_t> & recurrentToForgetWeightsDimensions,const std::vector<int8_t> & recurrentToForgetWeightsValue,const hidl_vec<uint32_t> & recurrentToCellWeightsDimensions,const std::vector<int8_t> & recurrentToCellWeightsValue,const hidl_vec<uint32_t> & recurrentToOutputWeightsDimensions,const std::vector<int8_t> & recurrentToOutputWeightsValue,const hidl_vec<uint32_t> & cellToInputWeightsDimensions,const std::vector<int16_t> & cellToInputWeightsValue,const hidl_vec<uint32_t> & cellToForgetWeightsDimensions,const std::vector<int16_t> & cellToForgetWeightsValue,const hidl_vec<uint32_t> & cellToOutputWeightsDimensions,const std::vector<int16_t> & cellToOutputWeightsValue,const hidl_vec<uint32_t> & inputGateBiasDimensions,const std::vector<int32_t> & inputGateBiasValue,const hidl_vec<uint32_t> & forgetGateBiasDimensions,const std::vector<int32_t> & forgetGateBiasValue,const hidl_vec<uint32_t> & cellBiasDimensions,const std::vector<int32_t> & cellBiasValue,const hidl_vec<uint32_t> & outputGateBiasDimensions,const std::vector<int32_t> & outputGateBiasValue,const hidl_vec<uint32_t> & projectionWeightsDimensions,const std::vector<int8_t> & projectionWeightsValue,const hidl_vec<uint32_t> & projectionBiasDimensions,const std::vector<int32_t> & projectionBiasValue,const hidl_vec<uint32_t> & outputPreviousTimeStepInDimensions,const std::vector<int8_t> & outputPreviousTimeStepInValue,const hidl_vec<uint32_t> & cellStatePreviousTimeStepInDimensions,const std::vector<int16_t> & cellStatePreviousTimeStepInValue,const hidl_vec<uint32_t> & inputLayerNormWeightsDimensions,const std::vector<int16_t> & inputLayerNormWeightsValue,const hidl_vec<uint32_t> & forgetLayerNormWeightsDimensions,const std::vector<int16_t> & forgetLayerNormWeightsValue,const hidl_vec<uint32_t> & cellLayerNormWeightsDimensions,const std::vector<int16_t> & cellLayerNormWeightsValue,const hidl_vec<uint32_t> & outputLayerNormWeightsDimensions,const std::vector<int16_t> & outputLayerNormWeightsValue,const float & cellClipValue,const float & projectionClipValue,const float & matMulInputGateValue,const float & matMulForgetGateValue,const float & matMulCellGateValue,const float & matMulOutputGateValue,const int32_t & projInputZeroPointValue,const float & projInputScaleValue,const hidl_vec<uint32_t> & outputStateOutDimensions,const std::vector<int8_t> & outputStateOutValue,const hidl_vec<uint32_t> & cellStateOutDimensions,const std::vector<int16_t> & cellStateOutValue,const hidl_vec<uint32_t> & outputDimensions,const std::vector<int8_t> & outputValue,armnn::Compute compute)62 void QLstmTestImpl(const hidl_vec<uint32_t>&   inputDimensions,
63                    const std::vector<int8_t>&   inputValue,
64                    const hidl_vec<uint32_t>&    inputToInputWeightsDimensions,
65                    const std::vector<int8_t>&   inputToInputWeightsValue,
66                    const hidl_vec<uint32_t>&    inputToForgetWeightsDimensions,
67                    const std::vector<int8_t>&   inputToForgetWeightsValue,
68                    const hidl_vec<uint32_t>&    inputToCellWeightsDimensions,
69                    const std::vector<int8_t>&   inputToCellWeightsValue,
70                    const hidl_vec<uint32_t>&    inputToOutputWeightsDimensions,
71                    const std::vector<int8_t>&   inputToOutputWeightsValue,
72                    const hidl_vec<uint32_t>&    recurrentToInputWeightsDimensions,
73                    const std::vector<int8_t>&   recurrentToInputWeightsValue,
74                    const hidl_vec<uint32_t>&    recurrentToForgetWeightsDimensions,
75                    const std::vector<int8_t>&   recurrentToForgetWeightsValue,
76                    const hidl_vec<uint32_t>&    recurrentToCellWeightsDimensions,
77                    const std::vector<int8_t>&   recurrentToCellWeightsValue,
78                    const hidl_vec<uint32_t>&    recurrentToOutputWeightsDimensions,
79                    const std::vector<int8_t>&   recurrentToOutputWeightsValue,
80                    const hidl_vec<uint32_t>&    cellToInputWeightsDimensions,
81                    const std::vector<int16_t>&  cellToInputWeightsValue,
82                    const hidl_vec<uint32_t>&    cellToForgetWeightsDimensions,
83                    const std::vector<int16_t>&  cellToForgetWeightsValue,
84                    const hidl_vec<uint32_t>&    cellToOutputWeightsDimensions,
85                    const std::vector<int16_t>&  cellToOutputWeightsValue,
86                    const hidl_vec<uint32_t>&    inputGateBiasDimensions,
87                    const std::vector<int32_t>&  inputGateBiasValue,
88                    const hidl_vec<uint32_t>&    forgetGateBiasDimensions,
89                    const std::vector<int32_t>&  forgetGateBiasValue,
90                    const hidl_vec<uint32_t>&    cellBiasDimensions,
91                    const std::vector<int32_t>&  cellBiasValue,
92                    const hidl_vec<uint32_t>&    outputGateBiasDimensions,
93                    const std::vector<int32_t>&  outputGateBiasValue,
94                    const hidl_vec<uint32_t>&    projectionWeightsDimensions,
95                    const std::vector<int8_t>&   projectionWeightsValue,
96                    const hidl_vec<uint32_t>&    projectionBiasDimensions,
97                    const std::vector<int32_t>&  projectionBiasValue,
98                    const hidl_vec<uint32_t>&    outputPreviousTimeStepInDimensions,
99                    const std::vector<int8_t>&   outputPreviousTimeStepInValue,
100                    const hidl_vec<uint32_t>&    cellStatePreviousTimeStepInDimensions,
101                    const std::vector<int16_t>&  cellStatePreviousTimeStepInValue,
102                    const hidl_vec<uint32_t>&    inputLayerNormWeightsDimensions,
103                    const std::vector<int16_t>&  inputLayerNormWeightsValue,
104                    const hidl_vec<uint32_t>&    forgetLayerNormWeightsDimensions,
105                    const std::vector<int16_t>&  forgetLayerNormWeightsValue,
106                    const hidl_vec<uint32_t>&    cellLayerNormWeightsDimensions,
107                    const std::vector<int16_t>&  cellLayerNormWeightsValue,
108                    const hidl_vec<uint32_t>&    outputLayerNormWeightsDimensions,
109                    const std::vector<int16_t>&  outputLayerNormWeightsValue,
110                    const float&                 cellClipValue,
111                    const float&                 projectionClipValue,
112                    const float&                 matMulInputGateValue,
113                    const float&                 matMulForgetGateValue,
114                    const float&                 matMulCellGateValue,
115                    const float&                 matMulOutputGateValue,
116                    const int32_t&               projInputZeroPointValue,
117                    const float&                 projInputScaleValue,
118                    const hidl_vec<uint32_t>&    outputStateOutDimensions,
119                    const std::vector<int8_t>&   outputStateOutValue,
120                    const hidl_vec<uint32_t>&    cellStateOutDimensions,
121                    const std::vector<int16_t>&  cellStateOutValue,
122                    const hidl_vec<uint32_t>&    outputDimensions,
123                    const std::vector<int8_t>&   outputValue,
124                    armnn::Compute               compute)
125 {
126     auto driver = std::make_unique<ArmnnDriver>(DriverOptions(compute));
127     HalPolicy::Model model = {};
128 
129     // Scale/Offset quantization info
130     float inputScale    = 0.0078125f;
131     int32_t inputOffset = 0;
132 
133     int32_t hiddenStateZeroPoint = 0;
134     float hiddenStateScale       = 0.007f;
135 
136     float outputScale    = hiddenStateScale;
137     int32_t outputOffset = hiddenStateZeroPoint;
138 
139     float cellStateScale    = 3.05176e-05f;
140     float cellWeightsScale  = 1.0f;
141     int32_t cellStateOffset = 0;
142 
143     float weightsScale    = 0.00784314f;
144     int32_t weightsOffset = 0;
145 
146     float layerNormScale    = 3.05182e-05f;
147     int32_t layerNormOffset = 0;
148 
149     float biasScale    = layerNormScale / 1024;
150     int32_t biasOffset = 0;
151 
152     // Inputs:
153     // 00: The input to the LSTM cell. Type: ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED Shape: [batchSize, inputSize]
154     AddInputOperand<HalPolicy>(model,
155                                inputDimensions,
156                                HalPolicy::OperandType::TENSOR_QUANT8_ASYMM_SIGNED,
157                                inputScale,
158                                inputOffset);
159 
160     // 01: The input-to-input weights. Optional. Type: ANEURALNETWORKS_TENSOR_QUANT8_SYMM Shape: [numUnits, inputSize]
161     AddTensorOperand<HalPolicy>(model,
162                                 inputToInputWeightsDimensions,
163                                 inputToInputWeightsValue,
164                                 HalPolicy::OperandType::TENSOR_QUANT8_SYMM,
165                                 CreateNoValueLifeTime(inputToInputWeightsDimensions),
166                                 weightsScale,
167                                 weightsOffset);
168 
169     // 02: The input-to-forget weights. Type: ANEURALNETWORKS_TENSOR_QUANT8_SYMM Shape: [numUnits, inputSize]
170     AddTensorOperand<HalPolicy>(model,
171                                 inputToForgetWeightsDimensions,
172                                 inputToForgetWeightsValue,
173                                 HalPolicy::OperandType::TENSOR_QUANT8_SYMM,
174                                 CreateNoValueLifeTime(inputToForgetWeightsDimensions),
175                                 weightsScale,
176                                 weightsOffset);
177 
178     // 03: The input-to-cell weights. Type: ANEURALNETWORKS_TENSOR_QUANT8_SYMM Shape: [numUnits, inputSize]
179     AddTensorOperand<HalPolicy>(model,
180                                 inputToCellWeightsDimensions,
181                                 inputToCellWeightsValue,
182                                 HalPolicy::OperandType::TENSOR_QUANT8_SYMM,
183                                 CreateNoValueLifeTime(inputToCellWeightsDimensions),
184                                 weightsScale,
185                                 weightsOffset);
186 
187     // 04: The input-to-output weights. Type: ANEURALNETWORKS_TENSOR_QUANT8_SYMM Shape: [numUnits, inputSize]
188     AddTensorOperand<HalPolicy>(model,
189                                 inputToOutputWeightsDimensions,
190                                 inputToOutputWeightsValue,
191                                 HalPolicy::OperandType::TENSOR_QUANT8_SYMM,
192                                 CreateNoValueLifeTime(inputToOutputWeightsDimensions),
193                                 weightsScale,
194                                 weightsOffset);
195 
196     // 05: The recurrent-to-input weights. Optional. Type: ANEURALNETWORKS_TENSOR_QUANT8_SYMM
197     //     Shape: [numUnits, outputSize]
198     AddTensorOperand<HalPolicy>(model,
199                                 recurrentToInputWeightsDimensions,
200                                 recurrentToInputWeightsValue,
201                                 HalPolicy::OperandType::TENSOR_QUANT8_SYMM,
202                                 CreateNoValueLifeTime(recurrentToInputWeightsDimensions),
203                                 weightsScale,
204                                 weightsOffset);
205 
206     // 06: The recurrent-to-forget weights. Type: ANEURALNETWORKS_TENSOR_QUANT8_SYMM Shape: [numUnits, outputSize]
207     AddTensorOperand<HalPolicy>(model,
208                                 recurrentToForgetWeightsDimensions,
209                                 recurrentToForgetWeightsValue,
210                                 HalPolicy::OperandType::TENSOR_QUANT8_SYMM,
211                                 CreateNoValueLifeTime(recurrentToForgetWeightsDimensions),
212                                 weightsScale,
213                                 weightsOffset);
214 
215     // 07: The recurrent-to-cell weights. Type: ANEURALNETWORKS_TENSOR_QUANT8_SYMM Shape: [numUnits, outputSize]
216     AddTensorOperand<HalPolicy>(model,
217                                 recurrentToCellWeightsDimensions,
218                                 recurrentToCellWeightsValue,
219                                 HalPolicy::OperandType::TENSOR_QUANT8_SYMM,
220                                 CreateNoValueLifeTime(recurrentToCellWeightsDimensions),
221                                 weightsScale,
222                                 weightsOffset);
223 
224     // 08: The recurrent-to-output weights. Type: ANEURALNETWORKS_TENSOR_QUANT8_SYMM Shape: [numUnits, outputSize]
225     AddTensorOperand<HalPolicy>(model,
226                                 recurrentToOutputWeightsDimensions,
227                                 recurrentToOutputWeightsValue,
228                                 HalPolicy::OperandType::TENSOR_QUANT8_SYMM,
229                                 CreateNoValueLifeTime(recurrentToOutputWeightsDimensions),
230                                 weightsScale,
231                                 weightsOffset);
232 
233     // 09: The cell-to-input weights (for peephole). Optional. Type: ANEURALNETWORKS_TENSOR_QUANT16_SYMM
234     //     Shape: [numUnits]
235     AddTensorOperand<HalPolicy>(model,
236                                 cellToInputWeightsDimensions,
237                                 cellToInputWeightsValue,
238                                 HalPolicy::OperandType::TENSOR_QUANT16_SYMM ,
239                                 CreateNoValueLifeTime(cellToInputWeightsDimensions),
240                                 cellWeightsScale,
241                                 weightsOffset);
242 
243     // 10: The cell-to-forget weights (for peephole). Optional. Type: ANEURALNETWORKS_TENSOR_QUANT16_SYMM
244     //     Shape: [numUnits].
245     AddTensorOperand<HalPolicy>(model,
246                                 cellToForgetWeightsDimensions,
247                                 cellToForgetWeightsValue,
248                                 HalPolicy::OperandType::TENSOR_QUANT16_SYMM,
249                                 CreateNoValueLifeTime(cellToForgetWeightsDimensions),
250                                 cellWeightsScale,
251                                 weightsOffset);
252 
253     // 11: The cell-to-output weights (for peephole). Optional. Type: ANEURALNETWORKS_TENSOR_QUANT16_SYMM
254     //     Shape: [numUnits]
255     AddTensorOperand<HalPolicy>(model,
256                                 cellToOutputWeightsDimensions,
257                                 cellToOutputWeightsValue,
258                                 HalPolicy::OperandType::TENSOR_QUANT16_SYMM,
259                                 CreateNoValueLifeTime(cellToOutputWeightsDimensions),
260                                 cellWeightsScale,
261                                 weightsOffset);
262 
263     // 12: The input gate bias. Quantized with scale being the product of input and weights scales
264     //     and zeroPoint equal to 0. Optional. Type: ANEURALNETWORKS_TENSOR_INT32 Shape: [numUnits]
265     AddTensorOperand<HalPolicy>(model,
266                                 inputGateBiasDimensions,
267                                 inputGateBiasValue,
268                                 HalPolicy::OperandType::TENSOR_INT32,
269                                 CreateNoValueLifeTime(inputGateBiasDimensions),
270                                 biasScale,
271                                 biasOffset);
272 
273     // 13: The forget gate bias. Quantized with scale being the product of input and weights scales
274     //     and zeroPoint equal to 0. Type: ANEURALNETWORKS_TENSOR_INT32 Shape: [numUnits]
275     AddTensorOperand<HalPolicy>(model,
276                                 forgetGateBiasDimensions,
277                                 forgetGateBiasValue,
278                                 HalPolicy::OperandType::TENSOR_INT32,
279                                 CreateNoValueLifeTime(forgetGateBiasDimensions),
280                                 biasScale,
281                                 biasOffset);
282 
283     // 14: The cell bias. Quantized with scale being the product of input and weights scales and zeroPoint equal to 0.
284     //     Type: ANEURALNETWORKS_TENSOR_INT32 Shape: [numUnits]
285     AddTensorOperand<HalPolicy>(model,
286                                 cellBiasDimensions,
287                                 cellBiasValue,
288                                 HalPolicy::OperandType::TENSOR_INT32,
289                                 CreateNoValueLifeTime(cellBiasDimensions),
290                                 biasScale,
291                                 biasOffset);
292 
293     // 15: The output gate bias. Quantized with scale being the product of input and weights scales
294     //     and zeroPoint equal to 0. Type: ANEURALNETWORKS_TENSOR_INT32 Shape: [numUnits]
295     AddTensorOperand<HalPolicy>(model,
296                                 outputGateBiasDimensions,
297                                 outputGateBiasValue,
298                                 HalPolicy::OperandType::TENSOR_INT32,
299                                 CreateNoValueLifeTime(outputGateBiasDimensions),
300                                 biasScale,
301                                 biasOffset);
302 
303     // 16: The projection weights. Optional. Type: ANEURALNETWORKS_TENSOR_QUANT8_SYMM Shape: [outputSize, numUnits]
304     AddTensorOperand<HalPolicy>(model,
305                                 projectionWeightsDimensions,
306                                 projectionWeightsValue,
307                                 HalPolicy::OperandType::TENSOR_QUANT8_SYMM,
308                                 CreateNoValueLifeTime(projectionWeightsDimensions),
309                                 0.00392157f,
310                                 weightsOffset);
311 
312     // 17: The projection bias. Quantized with scale being the product of input and weights scales
313     //     and zeroPoint equal to 0. Optional. Type: ANEURALNETWORKS_TENSOR_INT32 Shape: [outputSize]
314     AddTensorOperand<HalPolicy>(model,
315                                 projectionBiasDimensions,
316                                 projectionBiasValue,
317                                 HalPolicy::OperandType::TENSOR_INT32,
318                                 CreateNoValueLifeTime(projectionBiasDimensions),
319                                 0.0f,
320                                 biasOffset);
321 
322     // 18: The output from the previous time step. Type: ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED
323     //     Shape: [batchSize, outputSize]
324     AddInputOperand<HalPolicy>(model,
325                                outputPreviousTimeStepInDimensions,
326                                HalPolicy::OperandType::TENSOR_QUANT8_ASYMM_SIGNED,
327                                cellStateScale,
328                                inputOffset);
329 
330     // 19: The cell state from the previous time step. Type: ANEURALNETWORKS_TENSOR_QUANT16_SYMM
331     //     Shape: [batchSize, numUnits]
332     AddInputOperand<HalPolicy>(model,
333                                cellStatePreviousTimeStepInDimensions,
334                                HalPolicy::OperandType::TENSOR_QUANT16_SYMM,
335                                cellStateScale,
336                                cellStateOffset);
337 
338     // If any of the tensors have a value all normalization tensors are set
339     if (!inputLayerNormWeightsValue.empty()  ||
340         !forgetLayerNormWeightsValue.empty() ||
341         !cellLayerNormWeightsValue.empty()   ||
342         !outputLayerNormWeightsValue.empty())
343     {
344         // Normalization:
345         // 20: The input layer normalization weights. Used to rescale normalized inputs to activation at input gate.
346         //      Optional. Type: ANEURALNETWORKS_TENSOR_QUANT16_SYMM Shape: [numUnits]
347         AddTensorOperand<HalPolicy>(model,
348                                     inputLayerNormWeightsDimensions,
349                                     inputLayerNormWeightsValue,
350                                     HalPolicy::OperandType::TENSOR_QUANT16_SYMM,
351                                     CreateNoValueLifeTime(inputLayerNormWeightsDimensions),
352                                     layerNormScale,
353                                     layerNormOffset);
354 
355         // 21: The forget layer normalization weights. Used to rescale normalized inputs to activation at forget gate.
356         //     Optional. Type: ANEURALNETWORKS_TENSOR_QUANT16_SYMM Shape: [numUnits]
357         AddTensorOperand<HalPolicy>(model,
358                                     forgetLayerNormWeightsDimensions,
359                                     forgetLayerNormWeightsValue,
360                                     HalPolicy::OperandType::TENSOR_QUANT16_SYMM,
361                                     CreateNoValueLifeTime(forgetLayerNormWeightsDimensions),
362                                     layerNormScale,
363                                     layerNormOffset);
364 
365         // 22: The cell layer normalization weights. Used to rescale normalized inputs to activation at cell gate.
366         //     Optional. Type: ANEURALNETWORKS_TENSOR_QUANT16_SYMM Shape: [numUnits]
367         AddTensorOperand<HalPolicy>(model,
368                                     cellLayerNormWeightsDimensions,
369                                     cellLayerNormWeightsValue,
370                                     HalPolicy::OperandType::TENSOR_QUANT16_SYMM,
371                                     CreateNoValueLifeTime(cellLayerNormWeightsDimensions),
372                                     layerNormScale,
373                                     layerNormOffset);
374 
375         // 23: The output layer normalization weights. Used to rescale normalized inputs to activation at output gate.
376         //     Optional. Type: ANEURALNETWORKS_TENSOR_QUANT16_SYMM Shape: [numUnits]
377         AddTensorOperand<HalPolicy>(model,
378                                     outputLayerNormWeightsDimensions,
379                                     outputLayerNormWeightsValue,
380                                     HalPolicy::OperandType::TENSOR_QUANT16_SYMM,
381                                     CreateNoValueLifeTime(outputLayerNormWeightsDimensions),
382                                     layerNormScale,
383                                     layerNormOffset);
384     }
385 
386     // Constant scalar values
387     // 24: The cell clip. If provided the cell state is clipped by this value prior to the cell output activation.
388     //     Optional. Type: ANEURALNETWORKS_FLOAT32.
389     AddFloatOperand<HalPolicy>(model, cellClipValue);
390 
391     // Constant scalar values
392     // 25: The projection clip. If provided and projection is enabled, this is used for clipping the projected values.
393     //     Optional. Type: ANEURALNETWORKS_FLOAT32.
394     AddFloatOperand<HalPolicy>(model, projectionClipValue);
395 
396     // Constant scalar values
397     // 26: The scale of the intermediate result of matmul, i.e. input to layer normalization, at input gate.
398     //     Type: ANEURALNETWORKS_FLOAT32.
399     AddFloatOperand<HalPolicy>(model, matMulInputGateValue);
400 
401     // Constant scalar values
402     // 27: The scale of the intermediate result of matmul, i.e. input to layer normalization, at forget gate.
403     //     Type: ANEURALNETWORKS_FLOAT32.
404     AddFloatOperand<HalPolicy>(model, matMulForgetGateValue);
405 
406     // Constant scalar values
407     // 28: The scale of the intermediate result of matmul, i.e. input to layer normalization, at cell gate.
408     //     Type: ANEURALNETWORKS_FLOAT32.
409     AddFloatOperand<HalPolicy>(model, matMulCellGateValue);
410 
411     // Constant scalar values
412     // 29: The scale of the intermediate result of matmul, i.e. input to layer normalization, at output gate.
413     //     Type: ANEURALNETWORKS_FLOAT32.
414     AddFloatOperand<HalPolicy>(model, matMulOutputGateValue);
415 
416     // Constant scalar values
417     // 30: The zero point of the hidden state, i.e. input to projection. Type: ANEURALNETWORKS_INT32.
418     AddIntOperand<HalPolicy>(model, projInputZeroPointValue);
419 
420     // Constant scalar values
421     // 31: The scale of the hidden state, i.e. input to projection. Type: ANEURALNETWORKS_FLOAT32.
422     AddFloatOperand<HalPolicy>(model, projInputScaleValue);
423 
424     // Outputs:
425     //  0: The output state (out). Type: ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED Shape: [batchSize, outputSize]
426     AddOutputOperand<HalPolicy>(model,
427                                 outputStateOutDimensions,
428                                 HalPolicy::OperandType::TENSOR_QUANT8_ASYMM_SIGNED,
429                                 cellStateScale,
430                                 cellStateScale);
431 
432     //  1: The cell state (out). Type: ANEURALNETWORKS_TENSOR_QUANT16_SYMM Shape: [batchSize, numUnits].
433     AddOutputOperand<HalPolicy>(model,
434                                 cellStateOutDimensions,
435                                 HalPolicy::OperandType::TENSOR_QUANT16_SYMM,
436                                 cellStateScale,
437                                 cellStateOffset);
438 
439     //  2: The output. This is effectively the same as the current "output state (out)" value.
440     //     Type: ANEURALNETWORKS_TENSOR_QUANT8_ASYMM_SIGNED Shape: [batchSize, outputSize]
441     AddOutputOperand<HalPolicy>(model,
442                                 outputDimensions,
443                                 HalPolicy::OperandType::TENSOR_QUANT8_ASYMM_SIGNED,
444                                 cellStateScale,
445                                 cellStateScale);
446 
447     // make the QUANTIZED_LSTM operation
448     model.main.operations.resize(1);
449     model.main.operations[0].type = HalPolicy::OperationType::QUANTIZED_LSTM;
450 
451     model.main.operations[0].inputs = hidl_vec<uint32_t> { 0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11,
452                                                           12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23,
453                                                           24, 25, 26, 27, 28, 29, 30, 31};
454     model.main.operations[0].outputs = hidl_vec<uint32_t> {32, 33, 34};
455 
456     // define the input values
457     hidl_vec<RequestArgument> inputArguments;
458     inputArguments.resize(3);
459 
460     inputArguments[0] = CreateRequestArgument<int8_t>(inputValue, 0);
461     inputArguments[1] = CreateRequestArgument<int8_t>(outputPreviousTimeStepInValue, 1);
462     inputArguments[2] = CreateRequestArgument<int16_t>(cellStatePreviousTimeStepInValue, 2);
463 
464     // define the expected output values
465     hidl_vec<RequestArgument> outputArguments;
466     outputArguments.resize(3);
467 
468     outputArguments[0] = CreateRequestArgument<int8_t>(outputStateOutValue, 3);
469     outputArguments[1] = CreateRequestArgument<int16_t>(cellStateOutValue, 4);
470     outputArguments[2] = CreateRequestArgument<int8_t>(outputValue, 5);
471 
472     android::hardware::neuralnetworks::V1_0::Request request = {};
473     request.inputs  = inputArguments;
474     request.outputs = outputArguments;
475 
476     // set the input data
477     AddPoolAndSetData(inputValue.size(), request, inputValue.data());
478     AddPoolAndSetData(outputPreviousTimeStepInValue.size(), request, outputPreviousTimeStepInValue.data());
479     AddPoolAndSetData(cellStatePreviousTimeStepInValue.size(), request, cellStatePreviousTimeStepInValue.data());
480 
481     // add memory for the outputs
482     android::sp<IMemory> outputStateOutMemory = AddPoolAndGetData<int8_t>(outputStateOutValue.size(), request);
483     int8_t* outputStateOutData = static_cast<int8_t*>(static_cast<void*>(outputStateOutMemory->getPointer()));
484 
485     android::sp<IMemory> cellStateOutMemory = AddPoolAndGetData<int16_t>(cellStateOutValue.size(), request);
486     int16_t* cellStateOutData = static_cast<int16_t*>(static_cast<void*>(cellStateOutMemory->getPointer()));
487 
488     android::sp<IMemory> outputMemory = AddPoolAndGetData<int8_t>(outputValue.size(), request);
489     int8_t* outputData = static_cast<int8_t*>(static_cast<void*>(outputMemory->getPointer()));
490 
491     // make the prepared model and run the execution
492     ExecuteModel(model, *driver, request);
493 
494     // check the results
495     for (size_t i = 0; i < outputStateOutValue.size(); ++i)
496     {
497         DOCTEST_CHECK_MESSAGE(outputStateOutValue[i] == doctest::Approx( outputStateOutData[i] ).epsilon(TOLERANCE),
498                               "outputStateOut[" << i << "]: " << outputStateOutValue[i] << " != "
499                               << outputStateOutData[i]);
500     }
501 
502     // CELL STATE OUTPUT Does not match currently: IVGCVSW-4860 Verify remaining VTS tests (2) for QLSTM
503     // Comment out for now
504     // for (size_t i = 0; i < cellStateOutValue.size(); ++i)
505     // {
506     //    BOOST_TEST(TolerantCompareEqual(cellStateOutValue[i], cellStateOutData[i]),
507     //               "cellStateOut[" << i << "]: " << cellStateOutValue[i] << " != " << cellStateOutData[i]);
508     //}
509 
510     for (size_t i = 0; i < outputValue.size(); ++i)
511     {
512         DOCTEST_CHECK_MESSAGE(outputValue[i] == doctest::Approx( outputData[i] ).epsilon(TOLERANCE),
513                               "output[" << i << "]: " << outputValue[i] << " != " << outputData[i]);
514     }
515 }
516 
QLstmWithProjection(armnn::Compute compute)517 void QLstmWithProjection(armnn::Compute compute)
518 {
519     // This replicates android/frameworks/ml/nn/runtime/test/specs/V1_3/qlstm_projection.mod.py
520     // with values from android/frameworks/ml/nn/runtime/test/generated/spec_V1_3/qlstm_projection.example.cpp
521     // and weights, biases and scalars passed as CONSTANT_COPY tensors (instead of SUBGRAPH_INPUT tensors).
522 
523     uint32_t batchSize  = 2;
524     uint32_t inputSize  = 5;
525     uint32_t outputSize = 3;
526     uint32_t numUnits   = 4;
527 
528     // Inputs:
529     hidl_vec<uint32_t> inputDimensions{batchSize, inputSize};
530     std::vector<int8_t> inputValue{ 90, 102, 13, 26, 38, 102, 13, 26, 51, 64};
531 
532     hidl_vec<uint32_t> inputToInputWeightsDimensions{numUnits, inputSize};
533     std::vector<int8_t> inputToInputWeightsValue{   64,  77,   89, -102,
534                                                   -115,  13,   25,   38,
535                                                    -51,  64, -102,   89,
536                                                    -77,  64,  -51,  -64,
537                                                    -51, -38,  -25,  -13 };
538 
539     hidl_vec<uint32_t> inputToForgetWeightsDimensions{numUnits, inputSize};
540     std::vector<int8_t> inputToForgetWeightsValue{ -77,  -13,  38,  25,
541                                                    115,  -64, -25, -51,
542                                                     38, -102, -51,  38,
543                                                    -64,  -51, -77,  38,
544                                                    -51,  -77, -64, -64 };
545 
546     hidl_vec<uint32_t> inputToCellWeightsDimensions{numUnits, inputSize};
547     std::vector<int8_t> inputToCellWeightsValue{  -51, -38, -25, -13,
548                                                   -64,  64, -25, -38,
549                                                   -25, -77,  77, -13,
550                                                   -51, -38, -89,  89,
551                                                  -115, -64, 102,  77 };
552 
553     hidl_vec<uint32_t> inputToOutputWeightsDimensions{numUnits, inputSize};
554     std::vector<int8_t> inputToOutputWeightsValue{ -102, -51, -25, -115,
555                                                     -13, -89,  38,  -38,
556                                                    -102, -25,  77,  -25,
557                                                      51, -89, -38,  -64,
558                                                      13,  64, -77,  -51 };
559 
560     hidl_vec<uint32_t> recurrentToInputWeightsDimensions{numUnits, outputSize};
561     std::vector<int8_t> recurrentToInputWeightsValue{ -25, -38, 51, 13, -64, 115, -25, -38, -89, 6, -25, -77 };
562 
563     hidl_vec<uint32_t> recurrentToForgetWeightsDimensions{numUnits, outputSize};
564     std::vector<int8_t> recurrentToForgetWeightsValue{ -64, -38, -64, -25, 77, 51, 115, 38, -13, 25, 64, 25 };
565 
566     hidl_vec<uint32_t> recurrentToCellWeightsDimensions{numUnits, outputSize};
567     std::vector<int8_t> recurrentToCellWeightsValue{ -38, 25, 13, -38, 102, -10, -25, 38, 102, -77, -13, 25 };
568 
569     hidl_vec<uint32_t> recurrentToOutputWeightsDimensions{numUnits, outputSize};
570     std::vector<int8_t> recurrentToOutputWeightsValue{ 38, -13, 13, -25, -64, -89, -25, -77, -13, -51, -89, -25 };
571 
572     hidl_vec<uint32_t> cellToInputWeightsDimensions{0};
573     std::vector<int16_t> cellToInputWeightsValue;
574 
575     hidl_vec<uint32_t> cellToForgetWeightsDimensions{0};
576     std::vector<int16_t> cellToForgetWeightsValue;
577 
578     hidl_vec<uint32_t> cellToOutputWeightsDimensions{0};
579     std::vector<int16_t> cellToOutputWeightsValue;
580 
581     hidl_vec<uint32_t> inputGateBiasDimensions{numUnits};
582     std::vector<int32_t> inputGateBiasValue{ 644245, 3221226, 4724464, 8160438 };
583 
584     hidl_vec<uint32_t> forgetGateBiasDimensions{numUnits};
585     std::vector<int32_t> forgetGateBiasValue{ 2147484, -6442451, -4294968, 2147484 };
586 
587     hidl_vec<uint32_t> cellBiasDimensions{numUnits};
588     std::vector<int32_t> cellBiasValue{-1073742, 15461883, 5368709, 1717987 };
589 
590     hidl_vec<uint32_t> outputGateBiasDimensions{numUnits};
591     std::vector<int32_t> outputGateBiasValue{ 1073742, -214748, 4294968, 2147484 };
592 
593     hidl_vec<uint32_t> projectionWeightsDimensions{outputSize, numUnits};
594     std::vector<int8_t> projectionWeightsValue{ -25, 51, 3, -51, 25, 127, 77, 20, 18, 51, -102, 51 };
595 
596     hidl_vec<uint32_t> projectionBiasDimensions{outputSize};
597     std::vector<int32_t> projectionBiasValue{ 0, 0, 0 };
598 
599     hidl_vec<uint32_t> outputStateInDimensions{batchSize, outputSize};
600     std::vector<int8_t> outputStateInValue{ 0, 0, 0, 0, 0, 0 };
601 
602     hidl_vec<uint32_t> cellStateInDimensions{batchSize, numUnits};
603     std::vector<int16_t> cellStateInValue{ 0, 0, 0, 0, 0, 0, 0, 0 };
604 
605     // Normalization:
606     hidl_vec<uint32_t> inputLayerNormWeightsDimensions{numUnits};
607     std::vector<int16_t> inputLayerNormWeightsValue{ 3277, 6553, 9830, 16384 };
608 
609     hidl_vec<uint32_t> forgetLayerNormWeightsDimensions{numUnits};
610     std::vector<int16_t> forgetLayerNormWeightsValue{ 6553, 6553, 13107, 9830 };
611 
612     hidl_vec<uint32_t> cellLayerNormWeightsDimensions{numUnits};
613     std::vector<int16_t> cellLayerNormWeightsValue{ 22937, 6553, 9830, 26214 };
614 
615     hidl_vec<uint32_t> outputLayerNormWeightsDimensions{numUnits};
616     std::vector<int16_t> outputLayerNormWeightsValue{ 19660, 6553, 6553, 16384 };
617 
618     float cellClipValue           = 0.0f;
619     float projectionClipValue     = 0.0f;
620     float inputIntermediateScale  = 0.007059f;
621     float forgetIntermediateScale = 0.007812f;
622     float cellIntermediateScale   = 0.007059f;
623     float outputIntermediateScale = 0.007812f;
624     int32_t hiddenStateZeroPoint  = 0;
625     float hiddenStateScale        = 0.007f;
626 
627     // Outputs:
628     hidl_vec<uint32_t> outputStateOutDimensions{batchSize, outputSize};
629     std::vector<int8_t> outputStateOutValue{ 127, 127, -108, -67, 127, 127 };
630 
631     hidl_vec<uint32_t> cellStateOutDimensions{batchSize, numUnits};
632     std::vector<int16_t> cellStateOutValue { -14650, 8939, 5771, 6715, -11843, 7847, 1508, 12939 };
633 
634     hidl_vec<uint32_t> outputDimensions{batchSize, outputSize};
635     std::vector<int8_t> outputValue { 127, 127, -108, -67, 127, 127 };
636 
637     QLstmTestImpl(inputDimensions,                       inputValue,
638                   inputToInputWeightsDimensions,         inputToInputWeightsValue,
639                   inputToForgetWeightsDimensions,        inputToForgetWeightsValue,
640                   inputToCellWeightsDimensions,          inputToCellWeightsValue,
641                   inputToOutputWeightsDimensions,        inputToOutputWeightsValue,
642                   recurrentToInputWeightsDimensions,     recurrentToInputWeightsValue,
643                   recurrentToForgetWeightsDimensions,    recurrentToForgetWeightsValue,
644                   recurrentToCellWeightsDimensions,      recurrentToCellWeightsValue,
645                   recurrentToOutputWeightsDimensions,    recurrentToOutputWeightsValue,
646                   cellToInputWeightsDimensions,          cellToInputWeightsValue,
647                   cellToForgetWeightsDimensions,         cellToForgetWeightsValue,
648                   cellToOutputWeightsDimensions,         cellToOutputWeightsValue,
649                   inputGateBiasDimensions,               inputGateBiasValue,
650                   forgetGateBiasDimensions,              forgetGateBiasValue,
651                   cellBiasDimensions,                    cellBiasValue,
652                   outputGateBiasDimensions,              outputGateBiasValue,
653                   projectionWeightsDimensions,           projectionWeightsValue,
654                   projectionBiasDimensions,              projectionBiasValue,
655                   outputStateInDimensions,               outputStateInValue,
656                   cellStateInDimensions,                 cellStateInValue,
657                   inputLayerNormWeightsDimensions,       inputLayerNormWeightsValue,
658                   forgetLayerNormWeightsDimensions,      forgetLayerNormWeightsValue,
659                   cellLayerNormWeightsDimensions,        cellLayerNormWeightsValue,
660                   outputLayerNormWeightsDimensions,      outputLayerNormWeightsValue,
661                   cellClipValue,
662                   projectionClipValue,
663                   inputIntermediateScale,
664                   forgetIntermediateScale,
665                   cellIntermediateScale,
666                   outputIntermediateScale,
667                   hiddenStateZeroPoint,
668                   hiddenStateScale,
669                   outputStateOutDimensions,              outputStateOutValue,
670                   cellStateOutDimensions,                cellStateOutValue,
671                   outputDimensions,                      outputValue,
672                   compute);
673 }
674 
QLstmWithNoProjection(armnn::Compute compute)675 void QLstmWithNoProjection(armnn::Compute compute)
676 {
677     // This replicates android/frameworks/ml/nn/runtime/test/specs/V1_3/qlstm_noprojection.mod.py
678     // with values from android/frameworks/ml/nn/runtime/test/generated/spec_V1_3/qlstm_noprojection.example.cpp
679     // and weights, biases and scalars passed as CONSTANT_COPY tensors (instead of SUBGRAPH_INPUT tensors).
680 
681     uint32_t batchSize  = 2;
682     uint32_t inputSize  = 5;
683     uint32_t outputSize = 4;
684     uint32_t numUnits   = 4;
685 
686     // Inputs:
687     hidl_vec<uint32_t> inputDimensions{batchSize, inputSize};
688     std::vector<int8_t> inputValue { 90, 102, 13, 26, 38, 102, 13, 26, 51, 64 };
689 
690     hidl_vec<uint32_t> inputToInputWeightsDimensions{0, 0};
691     std::vector<int8_t> inputToInputWeightsValue;
692 
693     hidl_vec<uint32_t> inputToForgetWeightsDimensions{numUnits, inputSize};
694     std::vector<int8_t> inputToForgetWeightsValue { -77, -13,  38,  25,  115,
695                                                     -64, -25, -51,  38, -102,
696                                                     -51,  38, -64, -51,  -77,
697                                                      38, -51, -77, -64,  -64 };
698 
699     hidl_vec<uint32_t> inputToCellWeightsDimensions{numUnits, inputSize};
700     std::vector<int8_t> inputToCellWeightsValue { -51,  -38, -25, -13, -64,
701                                                    64,  -25, -38, -25, -77,
702                                                    77,  -13, -51, -38, -89,
703                                                    89, -115, -64, 102,  77 };
704 
705     hidl_vec<uint32_t> inputToOutputWeightsDimensions{numUnits, inputSize};
706     std::vector<int8_t> inputToOutputWeightsValue { -102, -51, -25, -115, -13,
707                                                      -89,  38, -38, -102, -25,
708                                                       77, -25,  51,  -89, -38,
709                                                      -64,  13,  64,  -77, -51 };
710 
711     hidl_vec<uint32_t> recurrentToInputWeightsDimensions{0, 0};
712     std::vector<int8_t> recurrentToInputWeightsValue;
713 
714     hidl_vec<uint32_t> recurrentToForgetWeightsDimensions{numUnits, outputSize};
715     std::vector<int8_t> recurrentToForgetWeightsValue { -64, -38, -64, -25,
716                                                          77,  51, 115,  38,
717                                                         -13,  25,  64,  25,
718                                                          25,  38, -13,  51 };
719 
720     hidl_vec<uint32_t> recurrentToCellWeightsDimensions{numUnits, outputSize};
721     std::vector<int8_t> recurrentToCellWeightsValue { -38,  25,  13, -38,
722                                                       102, -10, -25,  38,
723                                                       102, -77, -13,  25,
724                                                        38, -13,  25,  64 };
725 
726     hidl_vec<uint32_t> recurrentToOutputWeightsDimensions{numUnits, outputSize};
727     std::vector<int8_t> recurrentToOutputWeightsValue {  38, -13,  13, -25,
728                                                         -64, -89, -25, -77,
729                                                         -13, -51, -89, -25,
730                                                          13,  64,  25, -38 };
731 
732     hidl_vec<uint32_t> cellToInputWeightsDimensions{0};
733     std::vector<int16_t> cellToInputWeightsValue;
734 
735     hidl_vec<uint32_t> cellToForgetWeightsDimensions{0};
736     std::vector<int16_t> cellToForgetWeightsValue;
737 
738     hidl_vec<uint32_t> cellToOutputWeightsDimensions{0};
739     std::vector<int16_t> cellToOutputWeightsValue;
740 
741     hidl_vec<uint32_t> inputGateBiasDimensions{0};
742     std::vector<int32_t> inputGateBiasValue;
743 
744     hidl_vec<uint32_t> forgetGateBiasDimensions{numUnits};
745     std::vector<int32_t> forgetGateBiasValue { 2147484, -6442451, -4294968, 2147484 };
746 
747     hidl_vec<uint32_t> cellBiasDimensions{numUnits};
748     std::vector<int32_t> cellBiasValue { -1073742, 15461883, 5368709, 1717987 };
749 
750     hidl_vec<uint32_t> outputGateBiasDimensions{numUnits};
751     std::vector<int32_t> outputGateBiasValue { 1073742, -214748, 4294968, 2147484 };
752 
753     hidl_vec<uint32_t> projectionWeightsDimensions{0, 0};
754     std::vector<int8_t> projectionWeightsValue;
755 
756     hidl_vec<uint32_t> projectionBiasDimensions{0};
757     std::vector<int32_t> projectionBiasValue;
758 
759     hidl_vec<uint32_t> outputStateInDimensions{batchSize, outputSize};
760     std::vector<int8_t> outputStateInValue { 0, 0, 0, 0, 0, 0, 0, 0 };
761 
762     hidl_vec<uint32_t> cellStateInDimensions{batchSize, numUnits};
763     std::vector<int16_t> cellStateInValue { 0, 0, 0, 0, 0, 0, 0, 0 };
764 
765     // Normalization:
766     hidl_vec<uint32_t> inputLayerNormWeightsDimensions{0};
767     std::vector<int16_t> inputLayerNormWeightsValue;
768 
769     hidl_vec<uint32_t> forgetLayerNormWeightsDimensions{numUnits};
770     std::vector<int16_t> forgetLayerNormWeightsValue { 6553, 6553, 13107, 9830 };
771 
772     hidl_vec<uint32_t> cellLayerNormWeightsDimensions{numUnits};
773     std::vector<int16_t> cellLayerNormWeightsValue { 22937, 6553, 9830, 26214 };
774 
775     hidl_vec<uint32_t> outputLayerNormWeightsDimensions{numUnits};
776     std::vector<int16_t> outputLayerNormWeightsValue { 19660, 6553, 6553, 16384 };
777 
778     float cellClipValue           = 0.0f;
779     float projectionClipValue     = 0.0f;
780     float inputIntermediateScale  = 0.007059f;
781     float forgetIntermediateScale = 0.007812f;
782     float cellIntermediateScale   = 0.007059f;
783     float outputIntermediateScale = 0.007812f;
784     int32_t hiddenStateZeroPoint  = 0;
785     float hiddenStateScale        = 0.007f;
786 
787     // Outputs:
788     hidl_vec<uint32_t> outputStateOutDimensions{batchSize, outputSize};
789     std::vector<int8_t> outputStateOutValue { -15, 21, 14, 20, -15, 15, 5, 27 };
790 
791     hidl_vec<uint32_t> cellStateOutDimensions{batchSize, numUnits};
792     std::vector<int16_t> cellStateOutValue { -11692, 9960, 5491, 8861, -9422, 7726, 2056, 13149 };
793 
794     hidl_vec<uint32_t> outputDimensions{batchSize, outputSize};
795     std::vector<int8_t> outputValue { -15, 21, 14, 20, -15, 15, 5, 27 };
796 
797     QLstmTestImpl(inputDimensions,                       inputValue,
798                   inputToInputWeightsDimensions,         inputToInputWeightsValue,
799                   inputToForgetWeightsDimensions,        inputToForgetWeightsValue,
800                   inputToCellWeightsDimensions,          inputToCellWeightsValue,
801                   inputToOutputWeightsDimensions,        inputToOutputWeightsValue,
802                   recurrentToInputWeightsDimensions,     recurrentToInputWeightsValue,
803                   recurrentToForgetWeightsDimensions,    recurrentToForgetWeightsValue,
804                   recurrentToCellWeightsDimensions,      recurrentToCellWeightsValue,
805                   recurrentToOutputWeightsDimensions,    recurrentToOutputWeightsValue,
806                   cellToInputWeightsDimensions,          cellToInputWeightsValue,
807                   cellToForgetWeightsDimensions,         cellToForgetWeightsValue,
808                   cellToOutputWeightsDimensions,         cellToOutputWeightsValue,
809                   inputGateBiasDimensions,               inputGateBiasValue,
810                   forgetGateBiasDimensions,              forgetGateBiasValue,
811                   cellBiasDimensions,                    cellBiasValue,
812                   outputGateBiasDimensions,              outputGateBiasValue,
813                   projectionWeightsDimensions,           projectionWeightsValue,
814                   projectionBiasDimensions,              projectionBiasValue,
815                   outputStateInDimensions,               outputStateInValue,
816                   cellStateInDimensions,                 cellStateInValue,
817                   inputLayerNormWeightsDimensions,       inputLayerNormWeightsValue,
818                   forgetLayerNormWeightsDimensions,      forgetLayerNormWeightsValue,
819                   cellLayerNormWeightsDimensions,        cellLayerNormWeightsValue,
820                   outputLayerNormWeightsDimensions,      outputLayerNormWeightsValue,
821                   cellClipValue,
822                   projectionClipValue,
823                   inputIntermediateScale,
824                   forgetIntermediateScale,
825                   cellIntermediateScale,
826                   outputIntermediateScale,
827                   hiddenStateZeroPoint,
828                   hiddenStateScale,
829                   outputStateOutDimensions,              outputStateOutValue,
830                   cellStateOutDimensions,                cellStateOutValue,
831                   outputDimensions,                      outputValue,
832                   compute);
833 }
834 
DynamicOutputQLstmWithNoProjection(armnn::Compute compute)835 void DynamicOutputQLstmWithNoProjection(armnn::Compute compute)
836 {
837     // This replicates android/frameworks/ml/nn/runtime/test/specs/V1_3/qlstm_noprojection.mod.py
838     // with values from android/frameworks/ml/nn/runtime/test/generated/spec_V1_3/qlstm_noprojection.example.cpp
839     // and weights, biases and scalars passed as CONSTANT_COPY tensors (instead of SUBGRAPH_INPUT tensors)
840     // and made cellStateOutput dynamic.
841 
842     uint32_t batchSize  = 2;
843     uint32_t inputSize  = 5;
844     uint32_t outputSize = 4;
845     uint32_t numUnits   = 4;
846 
847     // Inputs:
848     hidl_vec<uint32_t> inputDimensions{batchSize, inputSize};
849     std::vector<int8_t> inputValue { 90, 102, 13, 26, 38, 102, 13, 26, 51, 64 };
850 
851     hidl_vec<uint32_t> inputToInputWeightsDimensions{0, 0};
852     std::vector<int8_t> inputToInputWeightsValue;
853 
854     hidl_vec<uint32_t> inputToForgetWeightsDimensions{numUnits, inputSize};
855     std::vector<int8_t> inputToForgetWeightsValue { -77, -13,  38,  25,  115,
856                                                     -64, -25, -51,  38, -102,
857                                                     -51,  38, -64, -51,  -77,
858                                                     38, -51, -77, -64,  -64 };
859 
860     hidl_vec<uint32_t> inputToCellWeightsDimensions{numUnits, inputSize};
861     std::vector<int8_t> inputToCellWeightsValue { -51,  -38, -25, -13, -64,
862                                                   64,  -25, -38, -25, -77,
863                                                   77,  -13, -51, -38, -89,
864                                                   89, -115, -64, 102,  77 };
865 
866     hidl_vec<uint32_t> inputToOutputWeightsDimensions{numUnits, inputSize};
867     std::vector<int8_t> inputToOutputWeightsValue { -102, -51, -25, -115, -13,
868                                                     -89,  38, -38, -102, -25,
869                                                     77, -25,  51,  -89, -38,
870                                                     -64,  13,  64,  -77, -51 };
871 
872     hidl_vec<uint32_t> recurrentToInputWeightsDimensions{0, 0};
873     std::vector<int8_t> recurrentToInputWeightsValue;
874 
875     hidl_vec<uint32_t> recurrentToForgetWeightsDimensions{numUnits, outputSize};
876     std::vector<int8_t> recurrentToForgetWeightsValue { -64, -38, -64, -25,
877                                                         77,  51, 115,  38,
878                                                         -13,  25,  64,  25,
879                                                         25,  38, -13,  51 };
880 
881     hidl_vec<uint32_t> recurrentToCellWeightsDimensions{numUnits, outputSize};
882     std::vector<int8_t> recurrentToCellWeightsValue { -38,  25,  13, -38,
883                                                       102, -10, -25,  38,
884                                                       102, -77, -13,  25,
885                                                       38, -13,  25,  64 };
886 
887     hidl_vec<uint32_t> recurrentToOutputWeightsDimensions{numUnits, outputSize};
888     std::vector<int8_t> recurrentToOutputWeightsValue {  38, -13,  13, -25,
889                                                          -64, -89, -25, -77,
890                                                          -13, -51, -89, -25,
891                                                          13,  64,  25, -38 };
892 
893     hidl_vec<uint32_t> cellToInputWeightsDimensions{0};
894     std::vector<int16_t> cellToInputWeightsValue;
895 
896     hidl_vec<uint32_t> cellToForgetWeightsDimensions{0};
897     std::vector<int16_t> cellToForgetWeightsValue;
898 
899     hidl_vec<uint32_t> cellToOutputWeightsDimensions{0};
900     std::vector<int16_t> cellToOutputWeightsValue;
901 
902     hidl_vec<uint32_t> inputGateBiasDimensions{0};
903     std::vector<int32_t> inputGateBiasValue;
904 
905     hidl_vec<uint32_t> forgetGateBiasDimensions{numUnits};
906     std::vector<int32_t> forgetGateBiasValue { 2147484, -6442451, -4294968, 2147484 };
907 
908     hidl_vec<uint32_t> cellBiasDimensions{numUnits};
909     std::vector<int32_t> cellBiasValue { -1073742, 15461883, 5368709, 1717987 };
910 
911     hidl_vec<uint32_t> outputGateBiasDimensions{numUnits};
912     std::vector<int32_t> outputGateBiasValue { 1073742, -214748, 4294968, 2147484 };
913 
914     hidl_vec<uint32_t> projectionWeightsDimensions{0, 0};
915     std::vector<int8_t> projectionWeightsValue;
916 
917     hidl_vec<uint32_t> projectionBiasDimensions{0};
918     std::vector<int32_t> projectionBiasValue;
919 
920     hidl_vec<uint32_t> outputStateInDimensions{batchSize, outputSize};
921     std::vector<int8_t> outputStateInValue { 0, 0, 0, 0, 0, 0, 0, 0 };
922 
923     hidl_vec<uint32_t> cellStateInDimensions{batchSize, numUnits};
924     std::vector<int16_t> cellStateInValue { 0, 0, 0, 0, 0, 0, 0, 0 };
925 
926     // Normalization:
927     hidl_vec<uint32_t> inputLayerNormWeightsDimensions{0};
928     std::vector<int16_t> inputLayerNormWeightsValue;
929 
930     hidl_vec<uint32_t> forgetLayerNormWeightsDimensions{numUnits};
931     std::vector<int16_t> forgetLayerNormWeightsValue { 6553, 6553, 13107, 9830 };
932 
933     hidl_vec<uint32_t> cellLayerNormWeightsDimensions{numUnits};
934     std::vector<int16_t> cellLayerNormWeightsValue { 22937, 6553, 9830, 26214 };
935 
936     hidl_vec<uint32_t> outputLayerNormWeightsDimensions{numUnits};
937     std::vector<int16_t> outputLayerNormWeightsValue { 19660, 6553, 6553, 16384 };
938 
939     float cellClipValue           = 0.0f;
940     float projectionClipValue     = 0.0f;
941     float inputIntermediateScale  = 0.007059f;
942     float forgetIntermediateScale = 0.007812f;
943     float cellIntermediateScale   = 0.007059f;
944     float outputIntermediateScale = 0.007812f;
945     int32_t hiddenStateZeroPoint  = 0;
946     float hiddenStateScale        = 0.007f;
947 
948     // Outputs:
949     hidl_vec<uint32_t> outputStateOutDimensions{batchSize, outputSize};
950     std::vector<int8_t> outputStateOutValue { -15, 21, 14, 20, -15, 15, 5, 27 };
951 
952     hidl_vec<uint32_t> cellStateOutDimensions{};
953     std::vector<int16_t> cellStateOutValue { -11692, 9960, 5491, 8861, -9422, 7726, 2056, 13149 };
954 
955     hidl_vec<uint32_t> outputDimensions{batchSize, outputSize};
956     std::vector<int8_t> outputValue { -15, 21, 14, 20, -15, 15, 5, 27 };
957 
958     QLstmTestImpl(inputDimensions,                       inputValue,
959                   inputToInputWeightsDimensions,         inputToInputWeightsValue,
960                   inputToForgetWeightsDimensions,        inputToForgetWeightsValue,
961                   inputToCellWeightsDimensions,          inputToCellWeightsValue,
962                   inputToOutputWeightsDimensions,        inputToOutputWeightsValue,
963                   recurrentToInputWeightsDimensions,     recurrentToInputWeightsValue,
964                   recurrentToForgetWeightsDimensions,    recurrentToForgetWeightsValue,
965                   recurrentToCellWeightsDimensions,      recurrentToCellWeightsValue,
966                   recurrentToOutputWeightsDimensions,    recurrentToOutputWeightsValue,
967                   cellToInputWeightsDimensions,          cellToInputWeightsValue,
968                   cellToForgetWeightsDimensions,         cellToForgetWeightsValue,
969                   cellToOutputWeightsDimensions,         cellToOutputWeightsValue,
970                   inputGateBiasDimensions,               inputGateBiasValue,
971                   forgetGateBiasDimensions,              forgetGateBiasValue,
972                   cellBiasDimensions,                    cellBiasValue,
973                   outputGateBiasDimensions,              outputGateBiasValue,
974                   projectionWeightsDimensions,           projectionWeightsValue,
975                   projectionBiasDimensions,              projectionBiasValue,
976                   outputStateInDimensions,               outputStateInValue,
977                   cellStateInDimensions,                 cellStateInValue,
978                   inputLayerNormWeightsDimensions,       inputLayerNormWeightsValue,
979                   forgetLayerNormWeightsDimensions,      forgetLayerNormWeightsValue,
980                   cellLayerNormWeightsDimensions,        cellLayerNormWeightsValue,
981                   outputLayerNormWeightsDimensions,      outputLayerNormWeightsValue,
982                   cellClipValue,
983                   projectionClipValue,
984                   inputIntermediateScale,
985                   forgetIntermediateScale,
986                   cellIntermediateScale,
987                   outputIntermediateScale,
988                   hiddenStateZeroPoint,
989                   hiddenStateScale,
990                   outputStateOutDimensions,              outputStateOutValue,
991                   cellStateOutDimensions,                cellStateOutValue,
992                   outputDimensions,                      outputValue,
993                   compute);
994 }
995 
996 } // anonymous namespace
997 
998 // Support is not added yet
999 //TEST_CASE(QLSTMWithProjectionTest, COMPUTE_DEVICES)
1000 //{
1001 //     QLstmWithProjection(sample);
1002 //}
1003 
1004 DOCTEST_TEST_SUITE("QLSTMTests_CpuRef")
1005 {
1006 
1007     DOCTEST_TEST_CASE("QLSTMWithNoProjectionTest_CpuRef")
1008     {
1009         QLstmWithNoProjection(armnn::Compute::CpuRef);
1010     }
1011 
1012     DOCTEST_TEST_CASE("DynamicOutputQLstmWithNoProjection_CpuRef")
1013     {
1014         DynamicOutputQLstmWithNoProjection(armnn::Compute::CpuRef);
1015     }
1016 
1017 }
1018 #ifdef ARMCOMPUTECL_ENABLED
1019 DOCTEST_TEST_SUITE("QLSTMTests_CpuAcc")
1020 {
1021 
1022     DOCTEST_TEST_CASE("QLSTMWithNoProjectionTest_CpuAcc")
1023     {
1024         QLstmWithNoProjection(armnn::Compute::CpuAcc);
1025     }
1026 
1027     DOCTEST_TEST_CASE("DynamicOutputQLstmWithNoProjection_CpuAcc")
1028     {
1029         DynamicOutputQLstmWithNoProjection(armnn::Compute::CpuAcc);
1030     }
1031 
1032 }
1033 #endif
1034