blob: 6b98ee2b67d70a18e6a9206928bab45f432ffaf4 [file] [log] [blame]
Michalis Spyrouba27e442019-05-28 10:04:57 +01001/*
Mohammed Suhail Munshi0a48c4c2024-01-30 18:25:51 +00002 * Copyright (c) 2019-2021, 2024 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 */
giuros01b5e75db2019-07-24 16:29:53 +010067constexpr AbsoluteTolerance<int16_t> tolerance_qsymm16(1);
giuros01b5e75db2019-07-24 16:29:53 +010068
Michalis Spyrouba27e442019-05-28 10:04:57 +010069} // namespace
70
71TEST_SUITE(NEON)
72TEST_SUITE(LSTMLayerQuantized)
73
74// *INDENT-OFF*
75// clang-format off
Manuel Bottini07263982019-10-17 18:37:26 +010076TEST_SUITE(IntegrationTestCase)
77TEST_SUITE(MultSmallerEq1)
78TEST_CASE(RunSmall, framework::DatasetMode::PRECOMMIT)
Michalis Spyrouba27e442019-05-28 10:04:57 +010079{
80 const int batch_size = 2;
81 const int input_size = 2;
82 const int output_size = 4;
83
84
85 QuantizationInfo qasymm(1.f / 128.f, 128);
86 QuantizationInfo qweights(1.f / 128.f, 128);
87 QuantizationInfo qsymm_3(8.f / 32768.f, 0);
88 QuantizationInfo qsymm_4(16.f / 32768.f, 0);
89
90 TensorShape input_shape{ input_size, batch_size };
91 TensorShape input_weights_shape{ input_size, output_size };
92 TensorShape recurrent_weights_shape{ output_size, output_size };
93 TensorShape output_shape{ output_size, batch_size};
94 TensorShape bias_shape{ output_size };
95
96 auto input_to_input_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
97 auto input_to_forget_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
98 auto input_to_cell_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
99 auto input_to_output_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
100 auto recurrent_to_input_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
101 auto recurrent_to_forget_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
102 auto recurrent_to_cell_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
103 auto recurrent_to_output_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
104 auto input_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
105 auto forget_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
106 auto cell_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
107 auto output_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
108
109 // LSTM input
110 auto input = create_tensor<Tensor>(input_shape, DataType::QASYMM8, 1, qasymm);
111
112 // LSTM output state
113 auto output_state = create_tensor<Tensor>(output_shape, DataType::QASYMM8, 1, qasymm);
114
115 // LSTM cell state
116 auto cell_state = create_tensor<Tensor>(output_shape, DataType::QSYMM16, 1, qsymm_4);
117
118 NELSTMLayerQuantized lstmq;
119
120 lstmq.configure(&input, &input_to_input_weights, &input_to_forget_weights, &input_to_cell_weights, &input_to_output_weights,
121 &recurrent_to_input_weights, &recurrent_to_forget_weights, &recurrent_to_cell_weights, &recurrent_to_output_weights,
122 &input_gate_bias, &forget_gate_bias, &cell_gate_bias, &output_gate_bias, &cell_state, &output_state, &cell_state, &output_state);
123
124 input.allocator()->allocate();
125 input_to_input_weights.allocator()->allocate();
126 input_to_forget_weights.allocator()->allocate();
127 input_to_cell_weights.allocator()->allocate();
128 input_to_output_weights.allocator()->allocate();
129 recurrent_to_input_weights.allocator()->allocate();
130 recurrent_to_forget_weights.allocator()->allocate();
131 recurrent_to_cell_weights.allocator()->allocate();
132 recurrent_to_output_weights.allocator()->allocate();
133 input_gate_bias.allocator()->allocate();
134 forget_gate_bias.allocator()->allocate();
135 cell_gate_bias.allocator()->allocate();
136 output_gate_bias.allocator()->allocate();
137 cell_state.allocator()->allocate();
138 output_state.allocator()->allocate();
Michalis Spyrouba27e442019-05-28 10:04:57 +0100139
140 // Fill weights and biases
141 fill_tensor(input_to_input_weights, std::vector<uint8_t>{ 47, 168,
142 66, 239,
143 6, 42,
144 237, 236 });
145
146 fill_tensor(input_to_forget_weights, std::vector<uint8_t> { 204, 193,
147 148, 59,
148 113, 17,
149 66, 197 });
150
151 fill_tensor(input_to_cell_weights, std::vector<uint8_t> { 172, 101,
152 184, 209,
153 165, 82,
154 108, 209 });
155
156 fill_tensor(input_to_output_weights, std::vector<uint8_t> { 203, 244,
157 219, 114,
158 130, 16,
159 163, 222 });
160
161 fill_tensor(recurrent_to_input_weights, std::vector<uint8_t> { 162, 168, 7, 95,
162 91, 155, 108, 216,
163 255, 100, 48, 188,
164 58, 37, 186, 147 });
165
166 fill_tensor(recurrent_to_forget_weights, std::vector<uint8_t> { 46, 58, 47, 170,
167 246, 96, 12, 99,
168 68, 23, 186, 161,
169 237, 164, 89, 6 });
170
171 fill_tensor(recurrent_to_cell_weights, std::vector<uint8_t> { 234, 99, 71, 206,
172 205, 159, 64, 253,
173 191, 148, 116, 8,
174 209, 136, 59, 138 });
175
176 fill_tensor(recurrent_to_output_weights, std::vector<uint8_t> { 23, 241, 137, 36,
177 206, 5, 227, 56,
178 254, 176, 231, 47,
179 18, 201, 161, 11 });
180
181 fill_tensor(input_gate_bias, std::vector<int> {-103038, 30525, 115255, -38154 });
182 fill_tensor(forget_gate_bias, std::vector<int> { -23428, 126970, 116806, 46307 });
183 fill_tensor(cell_gate_bias, std::vector<int> { 128006, 69949, -42808, 42568 });
184 fill_tensor(output_gate_bias, std::vector<int> { -67066, -53607, 47233, 7300 });
185
186 SimpleTensor<uint8_t> expected_output(output_shape, DataType::QASYMM8, 1, qasymm);
187
188 // Initialize state
189 fill_tensor(output_state, std::vector<uint8_t> { 128, 128, 128, 128,
190 128, 128, 128, 128 });
191 fill_tensor(cell_state, std::vector<int16_t> { 0, 0, 0, 0,
192 0, 0, 0, 0 });
193
194 // First input
195 fill_tensor(input, std::vector<uint8_t> { 106, 193,
196 155, 150 });
197
198 fill_tensor(expected_output, std::vector<uint8_t> { 128, 130, 36, 134,
199 128, 131, 35, 133 });
200
201 lstmq.run();
giuros01b5e75db2019-07-24 16:29:53 +0100202 validate(Accessor(output_state), expected_output, tolerance_qsymm16);
Michalis Spyrouba27e442019-05-28 10:04:57 +0100203
204 // Second input
205 fill_tensor(expected_output, std::vector<uint8_t> { 128, 129, 12, 137,
206 128, 131, 10, 136 });
207 lstmq.run();
giuros01b5e75db2019-07-24 16:29:53 +0100208 validate(Accessor(output_state), expected_output, tolerance_qsymm16);
Michalis Spyrouba27e442019-05-28 10:04:57 +0100209
210 // Third input
211 fill_tensor(expected_output, std::vector<uint8_t> { 128, 129, 8, 140,
212 128, 130, 6, 138 });
213 lstmq.run();
giuros01b5e75db2019-07-24 16:29:53 +0100214 validate(Accessor(output_state), expected_output, tolerance_qsymm16);
Michalis Spyrouba27e442019-05-28 10:04:57 +0100215}
216
Manuel Bottini07263982019-10-17 18:37:26 +0100217TEST_CASE(RunLarge, framework::DatasetMode::PRECOMMIT)
Michalis Spyrouba27e442019-05-28 10:04:57 +0100218{
219 const int batch_size = 16;
220 const int input_size = 8;
221 const int output_size = 8;
222
223
224 QuantizationInfo qasymm(1.f / 128.f, 128);
225 QuantizationInfo qweights(1.f / 128.f, 128);
226 QuantizationInfo qsymm_3(8.f / 32768.f, 0);
227 QuantizationInfo qsymm_4(16.f / 32768.f, 0);
228
229 TensorShape input_shape{ input_size, batch_size };
230 TensorShape input_weights_shape{ input_size, output_size };
231 TensorShape recurrent_weights_shape{ output_size, output_size };
232 TensorShape output_shape{ output_size, batch_size};
233 TensorShape bias_shape{ output_size };
234
235 auto input_to_input_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
236 auto input_to_forget_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
237 auto input_to_cell_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
238 auto input_to_output_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
239 auto recurrent_to_input_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
240 auto recurrent_to_forget_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
241 auto recurrent_to_cell_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
242 auto recurrent_to_output_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
243 auto input_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
244 auto forget_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
245 auto cell_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
246 auto output_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
247
248 // LSTM input
249 auto input = create_tensor<Tensor>(input_shape, DataType::QASYMM8, 1, qasymm);
250
251 // LSTM output state
252 auto output_state = create_tensor<Tensor>(output_shape, DataType::QASYMM8, 1, qasymm);
253
254 // LSTM cell state
255 auto cell_state = create_tensor<Tensor>(output_shape, DataType::QSYMM16, 1, qsymm_4);
256
257 NELSTMLayerQuantized lstmq;
258
259 lstmq.configure(&input, &input_to_input_weights, &input_to_forget_weights, &input_to_cell_weights, &input_to_output_weights,
260 &recurrent_to_input_weights, &recurrent_to_forget_weights, &recurrent_to_cell_weights, &recurrent_to_output_weights,
261 &input_gate_bias, &forget_gate_bias, &cell_gate_bias, &output_gate_bias, &cell_state, &output_state, &cell_state, &output_state);
262
263 input.allocator()->allocate();
264 input_to_input_weights.allocator()->allocate();
265 input_to_forget_weights.allocator()->allocate();
266 input_to_cell_weights.allocator()->allocate();
267 input_to_output_weights.allocator()->allocate();
268 recurrent_to_input_weights.allocator()->allocate();
269 recurrent_to_forget_weights.allocator()->allocate();
270 recurrent_to_cell_weights.allocator()->allocate();
271 recurrent_to_output_weights.allocator()->allocate();
272 input_gate_bias.allocator()->allocate();
273 forget_gate_bias.allocator()->allocate();
274 cell_gate_bias.allocator()->allocate();
275 output_gate_bias.allocator()->allocate();
276 cell_state.allocator()->allocate();
277 output_state.allocator()->allocate();
278
279 // Fill weights and biases
280 fill_tensor(input_to_input_weights, std::vector<uint8_t>{ 141, 89, 200, 180, 46, 50, 87, 128,
281 149, 227, 177, 187, 212, 229, 54, 111,
282 131, 116, 3, 58, 196, 26, 131, 255,
283 22, 106, 216, 69, 239, 12, 232, 207,
284 184, 56, 236, 172, 28, 143, 161, 124,
285 255, 33, 197, 122, 47, 197, 26, 229,
286 91, 79, 11, 160, 26, 80, 100, 36,
287 248, 186, 97, 61, 125, 46, 14, 100, });
288
289 fill_tensor(input_to_forget_weights, std::vector<uint8_t> { 237, 165, 141, 249, 72, 116, 36 , 115,
290 234, 213, 85, 84, 59, 62, 150, 246,
291 182, 102, 158, 214, 182, 183, 94, 11,
292 158, 192, 92, 189, 160, 219, 206, 249,
293 88, 213, 193, 244, 151, 72, 129, 49,
294 239, 83, 106, 9, 169, 187, 125, 171,
295 32, 141, 126, 92, 13, 36, 224, 150,
296 187, 250, 178, 169, 89, 214, 91, 173 });
297
298 fill_tensor(input_to_cell_weights, std::vector<uint8_t> { 93, 103, 226, 139, 185, 252, 129, 171,
299 159, 32, 25, 175, 224, 183, 165, 35,
300 207, 69, 238, 228, 149, 214, 79, 6,
301 5, 66, 102, 14, 19, 111, 36, 143,
302 22, 85, 13, 78, 236, 121, 122, 77,
303 249, 39, 88, 12, 205, 143, 93, 240,
304 167, 89, 188, 50, 73, 69, 201, 251,
305 59, 32, 203, 184, 139, 191, 199, 74});
306
307 fill_tensor(input_to_output_weights, std::vector<uint8_t> { 205, 7, 95, 104, 252, 143, 226, 73,
308 229, 114, 152, 171, 221, 153, 73, 229,
309 153, 165, 223, 239, 100, 38, 172, 211,
310 226, 133, 239, 207, 116, 230, 170, 100,
311 241, 95, 171, 124, 63, 115, 32, 127,
312 141, 239, 53, 193, 201, 53, 104, 178,
313 186, 212, 167, 107, 226, 230, 71, 213,
314 148, 217, 19, 248, 233, 195, 183, 156 });
315
316 fill_tensor(recurrent_to_input_weights, std::vector<uint8_t> { 147, 112, 140, 103, 3, 255, 17, 49,
317 84, 112, 144, 213, 138, 142, 112, 66,
318 117, 30, 101, 35, 25, 132, 211, 229,
319 183, 208, 102, 16, 38, 85, 101, 152,
320 226, 83, 132, 22, 161, 110, 157, 129,
321 184, 63, 168, 42, 220, 126, 209, 157,
322 5, 88, 243, 83, 249, 19, 226, 209,
323 173, 96, 185, 77, 146, 227, 238, 136 });
324
325
326 fill_tensor(recurrent_to_forget_weights, std::vector<uint8_t> { 52, 132, 92, 200, 213, 32, 213, 37,
327 116, 142, 116, 180, 4, 172, 158, 143,
328 110, 40, 99, 28, 221, 153, 133, 2,
329 247, 144, 198, 100, 20, 15, 221, 196,
330 159, 178, 188, 151, 171, 15, 25, 217,
331 178, 109, 110, 118, 128, 39, 232, 234,
332 184, 214, 177, 13, 56, 6, 28, 252,
333 89, 187, 242, 59, 146, 111, 132, 129});
334
335 fill_tensor(recurrent_to_cell_weights, std::vector<uint8_t> { 70, 44, 137, 29, 36, 127, 1, 241,
336 26, 241, 142, 114, 67, 181, 49, 57,
337 131, 152, 175, 77, 23, 63, 37, 124,
338 150, 113, 95, 103, 110, 201, 69, 97,
339 196, 242, 62, 214, 66, 19, 45, 135,
340 22, 168, 149, 104, 77, 101, 36, 68,
341 170, 116, 222, 100, 109, 1, 154, 18,
342 133, 215, 105, 93, 31, 57, 231, 112 });
343
344
345 fill_tensor(recurrent_to_output_weights, std::vector<uint8_t> { 45 , 181 , 220 , 219 , 49 , 63 , 49 , 129,
346 7 , 166 , 104 , 114 , 83 , 40 , 1 , 195,
347 245 , 142 , 82 , 232 , 104 , 245 , 82 , 196,
348 111 , 56 , 156 , 9 , 141 , 240 , 180 , 148,
349 247 , 198 , 234 , 137 , 13 , 210 , 161 , 192,
350 196 , 59 , 233 , 184 , 142 , 187 , 140 , 166,
351 2 , 95 , 152 , 46 , 71 , 46 , 113 , 32,
352 175 , 229 , 86 , 87 , 62 , 93 , 74 , 130});
353
354 fill_tensor(input_gate_bias, std::vector<int> { -40040, -106916, -92315, -79123, 45160, -17954, 50962, -63758 });
355 fill_tensor(forget_gate_bias, std::vector<int> { -128514, 8463, -57831, 116977, 106547, -28132, -124557, 44941 });
356 fill_tensor(cell_gate_bias, std::vector<int> { 88388 , 123601, -116148, -13022, 21619, 48926, 57523, 39332 });
357 fill_tensor(output_gate_bias, std::vector<int> { 59485 , -33070, 21386, -100633, -115959, 125768, -56407, 24897 });
358
359 SimpleTensor<uint8_t> expected_output(output_shape, DataType::QASYMM8, 1, qasymm);
360
361 // Initialize state
362 fill_tensor(output_state, std::vector<uint8_t> { 128, 128, 128, 128, 128, 128, 128, 128,
363 128, 128, 128, 128, 128, 128, 128, 128,
364 128, 128, 128, 128, 128, 128, 128, 128,
365 128, 128, 128, 128, 128, 128, 128, 128,
366 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
379 fill_tensor(cell_state, std::vector<int16_t> { 0, 0, 0, 0, 0, 0, 0, 0,
380 0, 0, 0, 0, 0, 0, 0, 0,
381 0, 0, 0, 0, 0, 0, 0, 0,
382 0, 0, 0, 0, 0, 0, 0, 0,
383 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
396 // First input
397 fill_tensor(input, std::vector<uint8_t> { 247, 203, 159, 131, 182, 114, 207, 195,
398 48 , 61 , 154, 16, 80, 101, 116, 255,
399 50 , 115 , 45, 186, 75, 212, 98, 48,
400 88 , 146 , 24, 143, 218, 174, 203, 200,
401 239 , 16 , 66, 136, 234, 54, 94, 51,
402 101 , 128 , 220, 213, 164, 82, 137, 255,
403 70 , 165 , 234, 220, 66, 35, 183, 206,
404 39 , 57 , 180, 202, 23, 172, 224, 109,
405 102 , 215 , 186, 82, 215, 147, 85, 187,
406 96 , 249 , 59, 116, 150, 44, 167, 128,
407 34 , 217 , 148, 193, 243, 38, 250, 208,
408 112 , 130 , 208, 29, 16, 122, 20, 92,
409 24 , 72 , 104, 29, 150, 233, 151, 19,
410 158 , 192 , 254, 70, 73, 142, 106, 152,
411 3 , 61 , 24, 135, 212, 9, 80, 234,
412 147 , 246 , 83, 249, 49, 14, 68, 50});
413
414 fill_tensor(expected_output, std::vector<uint8_t> {131, 128, 128, 128, 128, 180, 129, 133,
415 136, 128, 126, 128, 128, 173, 135, 130,
416 160, 128, 128, 128, 128, 138, 132, 129,
417 131, 128, 127, 128, 128, 169, 129, 131,
418 133, 128, 128, 128, 128, 182, 130, 129,
419 131, 128, 128, 128, 128, 163, 129, 130,
420 131, 128, 128, 128, 128, 149, 132, 129,
421 143, 128, 127, 128, 128, 150, 134, 131,
422 134, 128, 128, 128, 128, 167, 130, 130,
423 131, 128, 128, 128, 128, 152, 132, 129,
424 128, 128, 128, 128, 128, 169, 130, 130,
425 173, 128, 128, 128, 128, 148, 139, 130,
426 152, 128, 128, 128, 128, 168, 139, 132,
427 147, 128, 128, 128, 128, 161, 131, 132,
428 130, 128, 128, 128, 128, 159, 134, 128,
429 140, 128, 128, 128, 128, 133, 132, 128 });
430
431 lstmq.run();
giuros01b5e75db2019-07-24 16:29:53 +0100432 validate(Accessor(output_state), expected_output, tolerance_qsymm16);
Michalis Spyrouba27e442019-05-28 10:04:57 +0100433
434 // Second input
435 fill_tensor(expected_output, std::vector<uint8_t> { 130, 128, 128, 128, 128, 205, 129, 137,
436 135, 128, 127, 128, 128, 190, 137, 132,
437 160, 128, 128, 128, 128, 142, 133, 131,
438 130, 128, 128, 128, 128, 185, 129, 133,
439 132, 128, 128, 128, 128, 198, 131, 130,
440 130, 128, 128, 128, 128, 178, 130, 131,
441 131, 128, 128, 128, 128, 158, 132, 131,
442 142, 128, 127, 128, 128, 158, 135, 134,
443 133, 128, 128, 128, 128, 178, 131, 132,
444 131, 128, 128, 128, 128, 160, 132, 130,
445 128, 128, 128, 128, 128, 190, 131, 131,
446 170, 128, 128, 128, 128, 157, 142, 131,
447 149, 128, 128, 128, 128, 178, 142, 135,
448 145, 128, 128, 128, 129, 173, 132, 135,
449 129, 128, 128, 128, 128, 171, 134, 129,
450 140, 128, 128, 128, 128, 135, 132, 129});
451 lstmq.run();
giuros01b5e75db2019-07-24 16:29:53 +0100452 validate(Accessor(output_state), expected_output, tolerance_qsymm16);
Michalis Spyrouba27e442019-05-28 10:04:57 +0100453}
Manuel Bottini07263982019-10-17 18:37:26 +0100454TEST_SUITE_END() // MultSmallerEq1
455
456TEST_SUITE(MultGreater1)
457TEST_CASE(RunSmall, framework::DatasetMode::PRECOMMIT)
458{
459 //Input sequence length is 1
460 const int batch_size = 2;
461 const int input_size = 2;
462 const int output_size = 4;
463
464 QuantizationInfo qasymm(1.f / 128.f, 128);
465 QuantizationInfo qweights(1.f / 16.f, 16);
466 QuantizationInfo qsymm_3(8.f / 32768.f, 0);
467 QuantizationInfo qsymm_4(16.f / 32768.f, 0);
468
469 TensorShape input_shape{ input_size, batch_size };
470 TensorShape input_weights_shape{ input_size, output_size };
471 TensorShape recurrent_weights_shape{ output_size, output_size };
472 TensorShape output_shape{ output_size, batch_size};
473 TensorShape bias_shape{ output_size };
474
475 auto input_to_input_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
476 auto input_to_forget_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
477 auto input_to_cell_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
478 auto input_to_output_weights = create_tensor<Tensor>(input_weights_shape, DataType::QASYMM8, 1, qweights);
479 auto recurrent_to_input_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
480 auto recurrent_to_forget_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
481 auto recurrent_to_cell_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
482 auto recurrent_to_output_weights = create_tensor<Tensor>(recurrent_weights_shape, DataType::QASYMM8, 1, qweights);
483 auto input_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
484 auto forget_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
485 auto cell_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
486 auto output_gate_bias = create_tensor<Tensor>(bias_shape, DataType::S32);
487
488 // LSTM input
489 auto input = create_tensor<Tensor>(input_shape, DataType::QASYMM8, 1, qasymm);
490
491 // LSTM output state
492 auto output_state = create_tensor<Tensor>(output_shape, DataType::QASYMM8, 1, qasymm);
493
494 // LSTM cell state
495 auto cell_state = create_tensor<Tensor>(output_shape, DataType::QSYMM16, 1, qsymm_4);
496
497 NELSTMLayerQuantized lstmq;
498
499 lstmq.configure(&input, &input_to_input_weights, &input_to_forget_weights, &input_to_cell_weights, &input_to_output_weights,
500 &recurrent_to_input_weights, &recurrent_to_forget_weights, &recurrent_to_cell_weights, &recurrent_to_output_weights,
501 &input_gate_bias, &forget_gate_bias, &cell_gate_bias, &output_gate_bias, &cell_state, &output_state, &cell_state, &output_state);
502
503 input.allocator()->allocate();
504 input_to_input_weights.allocator()->allocate();
505 input_to_forget_weights.allocator()->allocate();
506 input_to_cell_weights.allocator()->allocate();
507 input_to_output_weights.allocator()->allocate();
508 recurrent_to_input_weights.allocator()->allocate();
509 recurrent_to_forget_weights.allocator()->allocate();
510 recurrent_to_cell_weights.allocator()->allocate();
511 recurrent_to_output_weights.allocator()->allocate();
512 input_gate_bias.allocator()->allocate();
513 forget_gate_bias.allocator()->allocate();
514 cell_gate_bias.allocator()->allocate();
515 output_gate_bias.allocator()->allocate();
516 cell_state.allocator()->allocate();
517 output_state.allocator()->allocate();
518
519 // Fill weights and biases
520 fill_tensor(input_to_input_weights, std::vector<uint8_t>{ 122, 130,
521 124, 134,
522 120, 122,
523 134, 134 });
524
525 fill_tensor(input_to_forget_weights, std::vector<uint8_t> { 204, 193,
526 148, 59,
527 113, 17,
528 66, 197 });
529
530 fill_tensor(input_to_cell_weights, std::vector<uint8_t> { 172, 101,
531 184, 209,
532 165, 82,
533 108, 209 });
534
535 fill_tensor(input_to_output_weights, std::vector<uint8_t> { 203, 244,
536 219, 114,
537 130, 16,
538 163, 222 });
539
540 fill_tensor(recurrent_to_input_weights, std::vector<uint8_t> { 162, 168, 7, 95,
541 91, 155, 108, 216,
542 255, 100, 48, 188,
543 58, 37, 186, 147 });
544
545 fill_tensor(recurrent_to_forget_weights, std::vector<uint8_t> { 46, 58, 47, 170,
546 246, 96, 12, 99,
547 68, 23, 186, 161,
548 237, 164, 89, 6 });
549
550 fill_tensor(recurrent_to_cell_weights, std::vector<uint8_t> { 234, 99, 71, 206,
551 205, 159, 64, 253,
552 191, 148, 116, 8,
553 209, 136, 59, 138 });
554
555 fill_tensor(recurrent_to_output_weights, std::vector<uint8_t> { 23, 241, 137, 36,
556 206, 5, 227, 56,
557 254, 176, 231, 47,
558 18, 201, 161, 11 });
559
560 fill_tensor(input_gate_bias, std::vector<int> {-103038, 30525, 115255, -38154 });
561 fill_tensor(forget_gate_bias, std::vector<int> { -23428, 126970, 116806, 46307 });
562 fill_tensor(cell_gate_bias, std::vector<int> { 128006, 69949, -42808, 42568 });
563 fill_tensor(output_gate_bias, std::vector<int> { -67066, -53607, 47233, 7300 });
564
565 SimpleTensor<uint8_t> expected_output(output_shape, DataType::QASYMM8, 1, qasymm);
566
567 // Initialize state
568 fill_tensor(output_state, std::vector<uint8_t> { 128, 128, 128, 128,
569 128, 128, 128, 128 });
570 fill_tensor(cell_state, std::vector<int16_t> { 0, 0, 0, 0,
571 0, 0, 0, 0 });
572
573 // First input
574 fill_tensor(input, std::vector<uint8_t> { 106, 193,
575 155, 150 });
576
577 fill_tensor(expected_output, std::vector<uint8_t> { 128, 128, 31, 128,
578 128, 128, 31, 128 });
579
580 lstmq.run();
581 validate(Accessor(output_state), expected_output);
582
583 // Second input
584 fill_tensor(expected_output, std::vector<uint8_t> { 128, 128, 5, 128,
585 128, 128, 5, 128 });
586 lstmq.run();
587 validate(Accessor(output_state), expected_output);
588
589 // Third input
590 fill_tensor(expected_output, std::vector<uint8_t> { 128, 128, 1, 128,
591 128, 128, 1, 128, });
592 lstmq.run();
593 validate(Accessor(output_state), expected_output);
594}
595TEST_SUITE_END() // MultGreater1
596TEST_SUITE_END() // IntegrationTestCase
Michalis Spyrouba27e442019-05-28 10:04:57 +0100597// clang-format on
598// *INDENT-ON*
599
600TEST_SUITE_END() // LSTMLayerQuantized
Sheri Zhangac6499a2021-02-10 15:32:38 +0000601TEST_SUITE_END() // Neon
Michalis Spyrouba27e442019-05-28 10:04:57 +0100602} // namespace validation
603} // namespace test
604} // namespace arm_compute