Compute Library
 22.05
LSTMLayerQuantized.cpp
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2019-2021 Arm Limited.
3  *
4  * SPDX-License-Identifier: MIT
5  *
6  * Permission is hereby granted, free of charge, to any person obtaining a copy
7  * of this software and associated documentation files (the "Software"), to
8  * deal in the Software without restriction, including without limitation the
9  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10  * sell copies of the Software, and to permit persons to whom the Software is
11  * furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all
14  * copies or substantial portions of the Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22  * SOFTWARE.
23  */
25 
26 #include "tests/NEON/Accessor.h"
28 #include "tests/Utils.h"
29 #include "tests/datasets/LSTMLayerDataset.h"
31 #include "tests/framework/Macros.h"
34 
35 #include <vector>
36 
37 namespace arm_compute
38 {
39 namespace test
40 {
41 namespace validation
42 {
43 namespace
44 {
45 template <typename T>
46 inline void fill_tensor(Tensor &tensor, const std::vector<T> &v)
47 {
48  // Import memory accounting for padding
49  TensorShape t_shape = tensor.info()->tensor_shape();
50  Window window;
51  window.use_tensor_dimensions(t_shape);
52  Iterator out(&tensor, window);
53  execute_window_loop(window, [&](const Coordinates & id)
54  {
55  *reinterpret_cast<T *>(out.ptr()) = v[coord2index(t_shape, id)];
56  },
57  out);
58 }
59 
60 template <typename T>
61 inline void fill_tensor(SimpleTensor<T> &tensor, const std::vector<T> &v)
62 {
63  std::memcpy(tensor.data(), v.data(), sizeof(T) * v.size());
64 }
65 
66 /** Tolerance for quantized asymmetric operations */
67 #if defined(__aarch64__)
68 constexpr AbsoluteTolerance<int16_t> tolerance_qsymm16(0);
69 #else // defined(__aarch64__)
70 constexpr AbsoluteTolerance<int16_t> tolerance_qsymm16(1);
71 #endif // defined(__aarch64__)
72 
73 } // namespace
74 
75 TEST_SUITE(NEON)
76 TEST_SUITE(LSTMLayerQuantized)
77 
78 // *INDENT-OFF*
79 // clang-format off
80 TEST_SUITE(IntegrationTestCase)
81 TEST_SUITE(MultSmallerEq1)
83 {
84  const int batch_size = 2;
85  const int input_size = 2;
86  const int output_size = 4;
87 
88 
89  QuantizationInfo qasymm(1.f / 128.f, 128);
90  QuantizationInfo qweights(1.f / 128.f, 128);
91  QuantizationInfo qsymm_3(8.f / 32768.f, 0);
92  QuantizationInfo qsymm_4(16.f / 32768.f, 0);
93 
94  TensorShape input_shape{ input_size, batch_size };
95  TensorShape input_weights_shape{ input_size, output_size };
96  TensorShape recurrent_weights_shape{ output_size, output_size };
97  TensorShape output_shape{ output_size, batch_size};
98  TensorShape bias_shape{ output_size };
99 
100  auto input_to_input_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
101  auto input_to_forget_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
102  auto input_to_cell_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
103  auto input_to_output_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
108  auto input_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
109  auto forget_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
110  auto cell_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
111  auto output_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
112 
113  // LSTM input
114  auto input = create_tensor<Tensor>(input_shape, DataType::QASYMM8, 1, qasymm);
115 
116  // LSTM output state
117  auto output_state = create_tensor<Tensor>(output_shape, DataType::QASYMM8, 1, qasymm);
118 
119  // LSTM cell state
120  auto cell_state = create_tensor<Tensor>(output_shape, DataType::QSYMM16, 1, qsymm_4);
121 
122  NELSTMLayerQuantized lstmq;
123 
124  lstmq.configure(&input, &input_to_input_weights, &input_to_forget_weights, &input_to_cell_weights, &input_to_output_weights,
125  &recurrent_to_input_weights, &recurrent_to_forget_weights, &recurrent_to_cell_weights, &recurrent_to_output_weights,
126  &input_gate_bias, &forget_gate_bias, &cell_gate_bias, &output_gate_bias, &cell_state, &output_state, &cell_state, &output_state);
127 
128  input.allocator()->allocate();
129  input_to_input_weights.allocator()->allocate();
130  input_to_forget_weights.allocator()->allocate();
131  input_to_cell_weights.allocator()->allocate();
132  input_to_output_weights.allocator()->allocate();
133  recurrent_to_input_weights.allocator()->allocate();
134  recurrent_to_forget_weights.allocator()->allocate();
135  recurrent_to_cell_weights.allocator()->allocate();
136  recurrent_to_output_weights.allocator()->allocate();
137  input_gate_bias.allocator()->allocate();
138  forget_gate_bias.allocator()->allocate();
139  cell_gate_bias.allocator()->allocate();
140  output_gate_bias.allocator()->allocate();
141  cell_state.allocator()->allocate();
142  output_state.allocator()->allocate();
143 
144  // Fill weights and biases
145  fill_tensor(input_to_input_weights, std::vector<uint8_t>{ 47, 168,
146  66, 239,
147  6, 42,
148  237, 236 });
149 
150  fill_tensor(input_to_forget_weights, std::vector<uint8_t> { 204, 193,
151  148, 59,
152  113, 17,
153  66, 197 });
154 
155  fill_tensor(input_to_cell_weights, std::vector<uint8_t> { 172, 101,
156  184, 209,
157  165, 82,
158  108, 209 });
159 
160  fill_tensor(input_to_output_weights, std::vector<uint8_t> { 203, 244,
161  219, 114,
162  130, 16,
163  163, 222 });
164 
165  fill_tensor(recurrent_to_input_weights, std::vector<uint8_t> { 162, 168, 7, 95,
166  91, 155, 108, 216,
167  255, 100, 48, 188,
168  58, 37, 186, 147 });
169 
170  fill_tensor(recurrent_to_forget_weights, std::vector<uint8_t> { 46, 58, 47, 170,
171  246, 96, 12, 99,
172  68, 23, 186, 161,
173  237, 164, 89, 6 });
174 
175  fill_tensor(recurrent_to_cell_weights, std::vector<uint8_t> { 234, 99, 71, 206,
176  205, 159, 64, 253,
177  191, 148, 116, 8,
178  209, 136, 59, 138 });
179 
180  fill_tensor(recurrent_to_output_weights, std::vector<uint8_t> { 23, 241, 137, 36,
181  206, 5, 227, 56,
182  254, 176, 231, 47,
183  18, 201, 161, 11 });
184 
185  fill_tensor(input_gate_bias, std::vector<int> {-103038, 30525, 115255, -38154 });
186  fill_tensor(forget_gate_bias, std::vector<int> { -23428, 126970, 116806, 46307 });
187  fill_tensor(cell_gate_bias, std::vector<int> { 128006, 69949, -42808, 42568 });
188  fill_tensor(output_gate_bias, std::vector<int> { -67066, -53607, 47233, 7300 });
189 
190  SimpleTensor<uint8_t> expected_output(output_shape, DataType::QASYMM8, 1, qasymm);
191 
192  // Initialize state
193  fill_tensor(output_state, std::vector<uint8_t> { 128, 128, 128, 128,
194  128, 128, 128, 128 });
195  fill_tensor(cell_state, std::vector<int16_t> { 0, 0, 0, 0,
196  0, 0, 0, 0 });
197 
198  // First input
199  fill_tensor(input, std::vector<uint8_t> { 106, 193,
200  155, 150 });
201 
202  fill_tensor(expected_output, std::vector<uint8_t> { 128, 130, 36, 134,
203  128, 131, 35, 133 });
204 
205  lstmq.run();
206  validate(Accessor(output_state), expected_output, tolerance_qsymm16);
207 
208  // Second input
209  fill_tensor(expected_output, std::vector<uint8_t> { 128, 129, 12, 137,
210  128, 131, 10, 136 });
211  lstmq.run();
212  validate(Accessor(output_state), expected_output, tolerance_qsymm16);
213 
214  // Third input
215  fill_tensor(expected_output, std::vector<uint8_t> { 128, 129, 8, 140,
216  128, 130, 6, 138 });
217  lstmq.run();
218  validate(Accessor(output_state), expected_output, tolerance_qsymm16);
219 }
220 
222 {
223  const int batch_size = 16;
224  const int input_size = 8;
225  const int output_size = 8;
226 
227 
228  QuantizationInfo qasymm(1.f / 128.f, 128);
229  QuantizationInfo qweights(1.f / 128.f, 128);
230  QuantizationInfo qsymm_3(8.f / 32768.f, 0);
231  QuantizationInfo qsymm_4(16.f / 32768.f, 0);
232 
233  TensorShape input_shape{ input_size, batch_size };
234  TensorShape input_weights_shape{ input_size, output_size };
235  TensorShape recurrent_weights_shape{ output_size, output_size };
236  TensorShape output_shape{ output_size, batch_size};
237  TensorShape bias_shape{ output_size };
238 
239  auto input_to_input_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
240  auto input_to_forget_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
241  auto input_to_cell_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
242  auto input_to_output_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
243  auto recurrent_to_input_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
244  auto recurrent_to_forget_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
245  auto recurrent_to_cell_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
246  auto recurrent_to_output_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
247  auto input_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
248  auto forget_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
249  auto cell_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
250  auto output_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
251 
252  // LSTM input
253  auto input = create_tensor<Tensor>(input_shape, DataType::QASYMM8, 1, qasymm);
254 
255  // LSTM output state
256  auto output_state = create_tensor<Tensor>(output_shape, DataType::QASYMM8, 1, qasymm);
257 
258  // LSTM cell state
259  auto cell_state = create_tensor<Tensor>(output_shape, DataType::QSYMM16, 1, qsymm_4);
260 
261  NELSTMLayerQuantized lstmq;
262 
263  lstmq.configure(&input, &input_to_input_weights, &input_to_forget_weights, &input_to_cell_weights, &input_to_output_weights,
264  &recurrent_to_input_weights, &recurrent_to_forget_weights, &recurrent_to_cell_weights, &recurrent_to_output_weights,
265  &input_gate_bias, &forget_gate_bias, &cell_gate_bias, &output_gate_bias, &cell_state, &output_state, &cell_state, &output_state);
266 
267  input.allocator()->allocate();
268  input_to_input_weights.allocator()->allocate();
269  input_to_forget_weights.allocator()->allocate();
270  input_to_cell_weights.allocator()->allocate();
271  input_to_output_weights.allocator()->allocate();
272  recurrent_to_input_weights.allocator()->allocate();
273  recurrent_to_forget_weights.allocator()->allocate();
274  recurrent_to_cell_weights.allocator()->allocate();
275  recurrent_to_output_weights.allocator()->allocate();
276  input_gate_bias.allocator()->allocate();
277  forget_gate_bias.allocator()->allocate();
278  cell_gate_bias.allocator()->allocate();
279  output_gate_bias.allocator()->allocate();
280  cell_state.allocator()->allocate();
281  output_state.allocator()->allocate();
282 
283  // Fill weights and biases
284  fill_tensor(input_to_input_weights, std::vector<uint8_t>{ 141, 89, 200, 180, 46, 50, 87, 128,
285  149, 227, 177, 187, 212, 229, 54, 111,
286  131, 116, 3, 58, 196, 26, 131, 255,
287  22, 106, 216, 69, 239, 12, 232, 207,
288  184, 56, 236, 172, 28, 143, 161, 124,
289  255, 33, 197, 122, 47, 197, 26, 229,
290  91, 79, 11, 160, 26, 80, 100, 36,
291  248, 186, 97, 61, 125, 46, 14, 100, });
292 
293  fill_tensor(input_to_forget_weights, std::vector<uint8_t> { 237, 165, 141, 249, 72, 116, 36 , 115,
294  234, 213, 85, 84, 59, 62, 150, 246,
295  182, 102, 158, 214, 182, 183, 94, 11,
296  158, 192, 92, 189, 160, 219, 206, 249,
297  88, 213, 193, 244, 151, 72, 129, 49,
298  239, 83, 106, 9, 169, 187, 125, 171,
299  32, 141, 126, 92, 13, 36, 224, 150,
300  187, 250, 178, 169, 89, 214, 91, 173 });
301 
302  fill_tensor(input_to_cell_weights, std::vector<uint8_t> { 93, 103, 226, 139, 185, 252, 129, 171,
303  159, 32, 25, 175, 224, 183, 165, 35,
304  207, 69, 238, 228, 149, 214, 79, 6,
305  5, 66, 102, 14, 19, 111, 36, 143,
306  22, 85, 13, 78, 236, 121, 122, 77,
307  249, 39, 88, 12, 205, 143, 93, 240,
308  167, 89, 188, 50, 73, 69, 201, 251,
309  59, 32, 203, 184, 139, 191, 199, 74});
310 
311  fill_tensor(input_to_output_weights, std::vector<uint8_t> { 205, 7, 95, 104, 252, 143, 226, 73,
312  229, 114, 152, 171, 221, 153, 73, 229,
313  153, 165, 223, 239, 100, 38, 172, 211,
314  226, 133, 239, 207, 116, 230, 170, 100,
315  241, 95, 171, 124, 63, 115, 32, 127,
316  141, 239, 53, 193, 201, 53, 104, 178,
317  186, 212, 167, 107, 226, 230, 71, 213,
318  148, 217, 19, 248, 233, 195, 183, 156 });
319 
320  fill_tensor(recurrent_to_input_weights, std::vector<uint8_t> { 147, 112, 140, 103, 3, 255, 17, 49,
321  84, 112, 144, 213, 138, 142, 112, 66,
322  117, 30, 101, 35, 25, 132, 211, 229,
323  183, 208, 102, 16, 38, 85, 101, 152,
324  226, 83, 132, 22, 161, 110, 157, 129,
325  184, 63, 168, 42, 220, 126, 209, 157,
326  5, 88, 243, 83, 249, 19, 226, 209,
327  173, 96, 185, 77, 146, 227, 238, 136 });
328 
329 
330  fill_tensor(recurrent_to_forget_weights, std::vector<uint8_t> { 52, 132, 92, 200, 213, 32, 213, 37,
331  116, 142, 116, 180, 4, 172, 158, 143,
332  110, 40, 99, 28, 221, 153, 133, 2,
333  247, 144, 198, 100, 20, 15, 221, 196,
334  159, 178, 188, 151, 171, 15, 25, 217,
335  178, 109, 110, 118, 128, 39, 232, 234,
336  184, 214, 177, 13, 56, 6, 28, 252,
337  89, 187, 242, 59, 146, 111, 132, 129});
338 
339  fill_tensor(recurrent_to_cell_weights, std::vector<uint8_t> { 70, 44, 137, 29, 36, 127, 1, 241,
340  26, 241, 142, 114, 67, 181, 49, 57,
341  131, 152, 175, 77, 23, 63, 37, 124,
342  150, 113, 95, 103, 110, 201, 69, 97,
343  196, 242, 62, 214, 66, 19, 45, 135,
344  22, 168, 149, 104, 77, 101, 36, 68,
345  170, 116, 222, 100, 109, 1, 154, 18,
346  133, 215, 105, 93, 31, 57, 231, 112 });
347 
348 
349  fill_tensor(recurrent_to_output_weights, std::vector<uint8_t> { 45 , 181 , 220 , 219 , 49 , 63 , 49 , 129,
350  7 , 166 , 104 , 114 , 83 , 40 , 1 , 195,
351  245 , 142 , 82 , 232 , 104 , 245 , 82 , 196,
352  111 , 56 , 156 , 9 , 141 , 240 , 180 , 148,
353  247 , 198 , 234 , 137 , 13 , 210 , 161 , 192,
354  196 , 59 , 233 , 184 , 142 , 187 , 140 , 166,
355  2 , 95 , 152 , 46 , 71 , 46 , 113 , 32,
356  175 , 229 , 86 , 87 , 62 , 93 , 74 , 130});
357 
358  fill_tensor(input_gate_bias, std::vector<int> { -40040, -106916, -92315, -79123, 45160, -17954, 50962, -63758 });
359  fill_tensor(forget_gate_bias, std::vector<int> { -128514, 8463, -57831, 116977, 106547, -28132, -124557, 44941 });
360  fill_tensor(cell_gate_bias, std::vector<int> { 88388 , 123601, -116148, -13022, 21619, 48926, 57523, 39332 });
361  fill_tensor(output_gate_bias, std::vector<int> { 59485 , -33070, 21386, -100633, -115959, 125768, -56407, 24897 });
362 
363  SimpleTensor<uint8_t> expected_output(output_shape, DataType::QASYMM8, 1, qasymm);
364 
365  // Initialize state
366  fill_tensor(output_state, std::vector<uint8_t> { 128, 128, 128, 128, 128, 128, 128, 128,
367  128, 128, 128, 128, 128, 128, 128, 128,
368  128, 128, 128, 128, 128, 128, 128, 128,
369  128, 128, 128, 128, 128, 128, 128, 128,
370  128, 128, 128, 128, 128, 128, 128, 128,
371  128, 128, 128, 128, 128, 128, 128, 128,
372  128, 128, 128, 128, 128, 128, 128, 128,
373  128, 128, 128, 128, 128, 128, 128, 128,
374  128, 128, 128, 128, 128, 128, 128, 128,
375  128, 128, 128, 128, 128, 128, 128, 128,
376  128, 128, 128, 128, 128, 128, 128, 128,
377  128, 128, 128, 128, 128, 128, 128, 128,
378  128, 128, 128, 128, 128, 128, 128, 128,
379  128, 128, 128, 128, 128, 128, 128, 128,
380  128, 128, 128, 128, 128, 128, 128, 128,
381  128, 128, 128, 128, 128, 128, 128, 128 });
382 
383  fill_tensor(cell_state, std::vector<int16_t> { 0, 0, 0, 0, 0, 0, 0, 0,
384  0, 0, 0, 0, 0, 0, 0, 0,
385  0, 0, 0, 0, 0, 0, 0, 0,
386  0, 0, 0, 0, 0, 0, 0, 0,
387  0, 0, 0, 0, 0, 0, 0, 0,
388  0, 0, 0, 0, 0, 0, 0, 0,
389  0, 0, 0, 0, 0, 0, 0, 0,
390  0, 0, 0, 0, 0, 0, 0, 0,
391  0, 0, 0, 0, 0, 0, 0, 0,
392  0, 0, 0, 0, 0, 0, 0, 0,
393  0, 0, 0, 0, 0, 0, 0, 0,
394  0, 0, 0, 0, 0, 0, 0, 0,
395  0, 0, 0, 0, 0, 0, 0, 0,
396  0, 0, 0, 0, 0, 0, 0, 0,
397  0, 0, 0, 0, 0, 0, 0, 0,
398  0, 0, 0, 0, 0, 0, 0, 0});
399 
400  // First input
401  fill_tensor(input, std::vector<uint8_t> { 247, 203, 159, 131, 182, 114, 207, 195,
402  48 , 61 , 154, 16, 80, 101, 116, 255,
403  50 , 115 , 45, 186, 75, 212, 98, 48,
404  88 , 146 , 24, 143, 218, 174, 203, 200,
405  239 , 16 , 66, 136, 234, 54, 94, 51,
406  101 , 128 , 220, 213, 164, 82, 137, 255,
407  70 , 165 , 234, 220, 66, 35, 183, 206,
408  39 , 57 , 180, 202, 23, 172, 224, 109,
409  102 , 215 , 186, 82, 215, 147, 85, 187,
410  96 , 249 , 59, 116, 150, 44, 167, 128,
411  34 , 217 , 148, 193, 243, 38, 250, 208,
412  112 , 130 , 208, 29, 16, 122, 20, 92,
413  24 , 72 , 104, 29, 150, 233, 151, 19,
414  158 , 192 , 254, 70, 73, 142, 106, 152,
415  3 , 61 , 24, 135, 212, 9, 80, 234,
416  147 , 246 , 83, 249, 49, 14, 68, 50});
417 
418  fill_tensor(expected_output, std::vector<uint8_t> {131, 128, 128, 128, 128, 180, 129, 133,
419  136, 128, 126, 128, 128, 173, 135, 130,
420  160, 128, 128, 128, 128, 138, 132, 129,
421  131, 128, 127, 128, 128, 169, 129, 131,
422  133, 128, 128, 128, 128, 182, 130, 129,
423  131, 128, 128, 128, 128, 163, 129, 130,
424  131, 128, 128, 128, 128, 149, 132, 129,
425  143, 128, 127, 128, 128, 150, 134, 131,
426  134, 128, 128, 128, 128, 167, 130, 130,
427  131, 128, 128, 128, 128, 152, 132, 129,
428  128, 128, 128, 128, 128, 169, 130, 130,
429  173, 128, 128, 128, 128, 148, 139, 130,
430  152, 128, 128, 128, 128, 168, 139, 132,
431  147, 128, 128, 128, 128, 161, 131, 132,
432  130, 128, 128, 128, 128, 159, 134, 128,
433  140, 128, 128, 128, 128, 133, 132, 128 });
434 
435  lstmq.run();
436  validate(Accessor(output_state), expected_output, tolerance_qsymm16);
437 
438  // Second input
439  fill_tensor(expected_output, std::vector<uint8_t> { 130, 128, 128, 128, 128, 205, 129, 137,
440  135, 128, 127, 128, 128, 190, 137, 132,
441  160, 128, 128, 128, 128, 142, 133, 131,
442  130, 128, 128, 128, 128, 185, 129, 133,
443  132, 128, 128, 128, 128, 198, 131, 130,
444  130, 128, 128, 128, 128, 178, 130, 131,
445  131, 128, 128, 128, 128, 158, 132, 131,
446  142, 128, 127, 128, 128, 158, 135, 134,
447  133, 128, 128, 128, 128, 178, 131, 132,
448  131, 128, 128, 128, 128, 160, 132, 130,
449  128, 128, 128, 128, 128, 190, 131, 131,
450  170, 128, 128, 128, 128, 157, 142, 131,
451  149, 128, 128, 128, 128, 178, 142, 135,
452  145, 128, 128, 128, 129, 173, 132, 135,
453  129, 128, 128, 128, 128, 171, 134, 129,
454  140, 128, 128, 128, 128, 135, 132, 129});
455  lstmq.run();
456  validate(Accessor(output_state), expected_output, tolerance_qsymm16);
457 }
458 TEST_SUITE_END() // MultSmallerEq1
459 
460 TEST_SUITE(MultGreater1)
461 TEST_CASE(RunSmall, framework::DatasetMode::PRECOMMIT)
462 {
463  //Input sequence length is 1
464  const int batch_size = 2;
465  const int input_size = 2;
466  const int output_size = 4;
467 
468  QuantizationInfo qasymm(1.f / 128.f, 128);
469  QuantizationInfo qweights(1.f / 16.f, 16);
470  QuantizationInfo qsymm_3(8.f / 32768.f, 0);
471  QuantizationInfo qsymm_4(16.f / 32768.f, 0);
472 
473  TensorShape input_shape{ input_size, batch_size };
474  TensorShape input_weights_shape{ input_size, output_size };
475  TensorShape recurrent_weights_shape{ output_size, output_size };
476  TensorShape output_shape{ output_size, batch_size};
477  TensorShape bias_shape{ output_size };
478 
479  auto input_to_input_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
480  auto input_to_forget_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
481  auto input_to_cell_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
482  auto input_to_output_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
483  auto recurrent_to_input_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
484  auto recurrent_to_forget_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
485  auto recurrent_to_cell_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
486  auto recurrent_to_output_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
487  auto input_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
488  auto forget_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
489  auto cell_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
490  auto output_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
491 
492  // LSTM input
493  auto input = create_tensor<Tensor>(input_shape, DataType::QASYMM8, 1, qasymm);
494 
495  // LSTM output state
496  auto output_state = create_tensor<Tensor>(output_shape, DataType::QASYMM8, 1, qasymm);
497 
498  // LSTM cell state
499  auto cell_state = create_tensor<Tensor>(output_shape, DataType::QSYMM16, 1, qsymm_4);
500 
501  NELSTMLayerQuantized lstmq;
502 
503  lstmq.configure(&input, &input_to_input_weights, &input_to_forget_weights, &input_to_cell_weights, &input_to_output_weights,
504  &recurrent_to_input_weights, &recurrent_to_forget_weights, &recurrent_to_cell_weights, &recurrent_to_output_weights,
505  &input_gate_bias, &forget_gate_bias, &cell_gate_bias, &output_gate_bias, &cell_state, &output_state, &cell_state, &output_state);
506 
507  input.allocator()->allocate();
508  input_to_input_weights.allocator()->allocate();
509  input_to_forget_weights.allocator()->allocate();
510  input_to_cell_weights.allocator()->allocate();
511  input_to_output_weights.allocator()->allocate();
512  recurrent_to_input_weights.allocator()->allocate();
513  recurrent_to_forget_weights.allocator()->allocate();
514  recurrent_to_cell_weights.allocator()->allocate();
515  recurrent_to_output_weights.allocator()->allocate();
516  input_gate_bias.allocator()->allocate();
517  forget_gate_bias.allocator()->allocate();
518  cell_gate_bias.allocator()->allocate();
519  output_gate_bias.allocator()->allocate();
520  cell_state.allocator()->allocate();
521  output_state.allocator()->allocate();
522 
523  // Fill weights and biases
524  fill_tensor(input_to_input_weights, std::vector<uint8_t>{ 122, 130,
525  124, 134,
526  120, 122,
527  134, 134 });
528 
529  fill_tensor(input_to_forget_weights, std::vector<uint8_t> { 204, 193,
530  148, 59,
531  113, 17,
532  66, 197 });
533 
534  fill_tensor(input_to_cell_weights, std::vector<uint8_t> { 172, 101,
535  184, 209,
536  165, 82,
537  108, 209 });
538 
539  fill_tensor(input_to_output_weights, std::vector<uint8_t> { 203, 244,
540  219, 114,
541  130, 16,
542  163, 222 });
543 
544  fill_tensor(recurrent_to_input_weights, std::vector<uint8_t> { 162, 168, 7, 95,
545  91, 155, 108, 216,
546  255, 100, 48, 188,
547  58, 37, 186, 147 });
548 
549  fill_tensor(recurrent_to_forget_weights, std::vector<uint8_t> { 46, 58, 47, 170,
550  246, 96, 12, 99,
551  68, 23, 186, 161,
552  237, 164, 89, 6 });
553 
554  fill_tensor(recurrent_to_cell_weights, std::vector<uint8_t> { 234, 99, 71, 206,
555  205, 159, 64, 253,
556  191, 148, 116, 8,
557  209, 136, 59, 138 });
558 
559  fill_tensor(recurrent_to_output_weights, std::vector<uint8_t> { 23, 241, 137, 36,
560  206, 5, 227, 56,
561  254, 176, 231, 47,
562  18, 201, 161, 11 });
563 
564  fill_tensor(input_gate_bias, std::vector<int> {-103038, 30525, 115255, -38154 });
565  fill_tensor(forget_gate_bias, std::vector<int> { -23428, 126970, 116806, 46307 });
566  fill_tensor(cell_gate_bias, std::vector<int> { 128006, 69949, -42808, 42568 });
567  fill_tensor(output_gate_bias, std::vector<int> { -67066, -53607, 47233, 7300 });
568 
569  SimpleTensor<uint8_t> expected_output(output_shape, DataType::QASYMM8, 1, qasymm);
570 
571  // Initialize state
572  fill_tensor(output_state, std::vector<uint8_t> { 128, 128, 128, 128,
573  128, 128, 128, 128 });
574  fill_tensor(cell_state, std::vector<int16_t> { 0, 0, 0, 0,
575  0, 0, 0, 0 });
576 
577  // First input
578  fill_tensor(input, std::vector<uint8_t> { 106, 193,
579  155, 150 });
580 
581  fill_tensor(expected_output, std::vector<uint8_t> { 128, 128, 31, 128,
582  128, 128, 31, 128 });
583 
584  lstmq.run();
585  validate(Accessor(output_state), expected_output);
586 
587  // Second input
588  fill_tensor(expected_output, std::vector<uint8_t> { 128, 128, 5, 128,
589  128, 128, 5, 128 });
590  lstmq.run();
591  validate(Accessor(output_state), expected_output);
592 
593  // Third input
594  fill_tensor(expected_output, std::vector<uint8_t> { 128, 128, 1, 128,
595  128, 128, 1, 128, });
596  lstmq.run();
597  validate(Accessor(output_state), expected_output);
598 }
599 TEST_SUITE_END() // MultGreater1
600 TEST_SUITE_END() // IntegrationTestCase
601 // clang-format on
602 // *INDENT-ON*
603 
604 TEST_SUITE_END() // LSTMLayerQuantized
605 TEST_SUITE_END() // Neon
606 } // namespace validation
607 } // namespace test
608 } // namespace arm_compute
quantized, symmetric fixed-point 16-bit number
QuantizationInfo qweights(1.f/16.f, 16)
SimpleTensor< uint8_t > expected_output(output_shape, DataType::QASYMM8, 1, qasymm)
Copyright (c) 2017-2022 Arm Limited.
int coord2index(const TensorShape &shape, const Coordinates &coord)
Linearise the given coordinate.
Definition: Utils.h:387
void configure(const ICLTensor *input, const ICLTensor *input_to_input_weights, const ICLTensor *input_to_forget_weights, const ICLTensor *input_to_cell_weights, const ICLTensor *input_to_output_weights, const ICLTensor *recurrent_to_input_weights, const ICLTensor *recurrent_to_forget_weights, const ICLTensor *recurrent_to_cell_weights, const ICLTensor *recurrent_to_output_weights, const ICLTensor *input_gate_bias, const ICLTensor *forget_gate_bias, const ICLTensor *cell_bias, const ICLTensor *output_gate_bias, ICLTensor *cell_state_in, const ICLTensor *output_state_in, ICLTensor *cell_state_out, ICLTensor *output_state_out)
Initialize function&#39;s tensors.
QuantizationInfo qsymm_3(8.f/32768.f, 0)
1 channel, 1 S32 per channel
const auto input_shape
Validate test suite is to test ARM_COMPUTE_RETURN_ON_* macros we use to check the validity of given a...
DatasetMode
Possible dataset modes.
Definition: DatasetModes.h:40
fill_tensor(input_to_input_weights, std::vector< uint8_t >{ 122, 130, 124, 134, 120, 122, 134, 134 })
TEST_SUITE_END() FIXTURE_DATA_TEST_CASE(RunSmall
[CLActivationLayer Test snippet]
quantized, asymmetric fixed-point 8-bit number unsigned
validate(CLAccessor(output_state), expected_output)
QuantizationInfo qasymm(1.f/128.f, 128)
void execute_window_loop(const Window &w, L &&lambda_function, Ts &&... iterators)
Iterate through the passed window, automatically adjusting the iterators and calling the lambda_funct...
Definition: Helpers.inl:77
TEST_CASE(FusedActivation, framework::DatasetMode::ALL)
Validate fused activation expecting the following behaviours:
QuantizationInfo qsymm_4(16.f/32768.f, 0)
TEST_SUITE(QASYMM8_to_F32) FIXTURE_DATA_TEST_CASE(RunSmall