blob: d391267e3e70e4e76e8ecc07cc81d579924817e1 [file] [log] [blame]
Michalis Spyrouba27e442019-05-28 10:04:57 +01001/*
Sheri Zhangcece42c2021-02-10 15:32:38 +00002 * Copyright (c) 2019-2021 Arm Limited.
Michalis Spyrouba27e442019-05-28 10:04:57 +01003 *
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 */
Michalis Spyrouba27e442019-05-28 10:04:57 +010024#include "arm_compute/runtime/NEON/functions/NELSTMLayerQuantized.h"
Manuel Bottini10c53f12019-07-17 16:11:53 +010025
Michalis Spyrouba27e442019-05-28 10:04:57 +010026#include "tests/NEON/Accessor.h"
27#include "tests/PaddingCalculator.h"
28#include "tests/Utils.h"
29#include "tests/datasets/LSTMLayerDataset.h"
30#include "tests/framework/Asserts.h"
31#include "tests/framework/Macros.h"
32#include "tests/framework/datasets/Datasets.h"
33#include "tests/validation/Validation.h"
34
35#include <vector>
36
37namespace arm_compute
38{
39namespace test
40{
41namespace validation
42{
43namespace
44{
45template <typename T>
46inline 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
60template <typename T>
61inline 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
giuros01b5e75db2019-07-24 16:29:53 +010066/** Tolerance for quantized asymmetric operations */
67#if defined(__aarch64__)
68constexpr AbsoluteTolerance<int16_t> tolerance_qsymm16(0);
69#else // defined(__aarch64__)
70constexpr AbsoluteTolerance<int16_t> tolerance_qsymm16(1);
71#endif // defined(__aarch64__)
72
Michalis Spyrouba27e442019-05-28 10:04:57 +010073} // namespace
74
75TEST_SUITE(NEON)
76TEST_SUITE(LSTMLayerQuantized)
77
78// *INDENT-OFF*
79// clang-format off
Manuel Bottini07263982019-10-17 18:37:26 +010080TEST_SUITE(IntegrationTestCase)
81TEST_SUITE(MultSmallerEq1)
82TEST_CASE(RunSmall, framework::DatasetMode::PRECOMMIT)
Michalis Spyrouba27e442019-05-28 10:04:57 +010083{
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);
104 auto recurrent_to_input_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
105 auto recurrent_to_forget_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
106 auto recurrent_to_cell_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
107 auto recurrent_to_output_weights = create_tensor<Tensor>(recurrent_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();
Michalis Spyrouba27e442019-05-28 10:04:57 +0100143
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();
giuros01b5e75db2019-07-24 16:29:53 +0100206 validate(Accessor(output_state), expected_output, tolerance_qsymm16);
Michalis Spyrouba27e442019-05-28 10:04:57 +0100207
208 // Second input
209 fill_tensor(expected_output, std::vector<uint8_t> { 128, 129, 12, 137,
210 128, 131, 10, 136 });
211 lstmq.run();
giuros01b5e75db2019-07-24 16:29:53 +0100212 validate(Accessor(output_state), expected_output, tolerance_qsymm16);
Michalis Spyrouba27e442019-05-28 10:04:57 +0100213
214 // Third input
215 fill_tensor(expected_output, std::vector<uint8_t> { 128, 129, 8, 140,
216 128, 130, 6, 138 });
217 lstmq.run();
giuros01b5e75db2019-07-24 16:29:53 +0100218 validate(Accessor(output_state), expected_output, tolerance_qsymm16);
Michalis Spyrouba27e442019-05-28 10:04:57 +0100219}
220
Manuel Bottini07263982019-10-17 18:37:26 +0100221TEST_CASE(RunLarge, framework::DatasetMode::PRECOMMIT)
Michalis Spyrouba27e442019-05-28 10:04:57 +0100222{
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();
giuros01b5e75db2019-07-24 16:29:53 +0100436 validate(Accessor(output_state), expected_output, tolerance_qsymm16);
Michalis Spyrouba27e442019-05-28 10:04:57 +0100437
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();
giuros01b5e75db2019-07-24 16:29:53 +0100456 validate(Accessor(output_state), expected_output, tolerance_qsymm16);
Michalis Spyrouba27e442019-05-28 10:04:57 +0100457}
Manuel Bottini07263982019-10-17 18:37:26 +0100458TEST_SUITE_END() // MultSmallerEq1
459
460TEST_SUITE(MultGreater1)
461TEST_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}
599TEST_SUITE_END() // MultGreater1
600TEST_SUITE_END() // IntegrationTestCase
Michalis Spyrouba27e442019-05-28 10:04:57 +0100601// clang-format on
602// *INDENT-ON*
603
604TEST_SUITE_END() // LSTMLayerQuantized
Sheri Zhangcece42c2021-02-10 15:32:38 +0000605TEST_SUITE_END() // Neon
Michalis Spyrouba27e442019-05-28 10:04:57 +0100606} // namespace validation
607} // namespace test
608} // namespace arm_compute