1 /*
2 * Copyright (c) 2019-2020 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 */
24 #include "arm_compute/core/Types.h"
25 #include "arm_compute/runtime/CPP/functions/CPPTopKV.h"
26 #include "arm_compute/runtime/Tensor.h"
27 #include "arm_compute/runtime/TensorAllocator.h"
28 #include "tests/NEON/Accessor.h"
29 #include "tests/PaddingCalculator.h"
30 #include "tests/datasets/ShapeDatasets.h"
31 #include "tests/framework/Asserts.h"
32 #include "tests/framework/Macros.h"
33 #include "tests/framework/datasets/Datasets.h"
34 #include "tests/validation/Validation.h"
35 #include "tests/validation/fixtures/PermuteFixture.h"
36
37 namespace arm_compute
38 {
39 namespace test
40 {
41 namespace validation
42 {
43 namespace
44 {
45 template <typename U, typename T>
fill_tensor(U && tensor,const std::vector<T> & v)46 inline void fill_tensor(U &&tensor, const std::vector<T> &v)
47 {
48 std::memcpy(tensor.data(), v.data(), sizeof(T) * v.size());
49 }
50 } // namespace
51
52 TEST_SUITE(CPP)
TEST_SUITE(TopKV)53 TEST_SUITE(TopKV)
54
55 // *INDENT-OFF*
56 // clang-format off
57 DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip(zip(
58 framework::dataset::make("PredictionsInfo", { TensorInfo(TensorShape(20, 10), 1, DataType::F32),
59 TensorInfo(TensorShape(10, 20), 1, DataType::F16), // Mismatching batch_size
60 TensorInfo(TensorShape(20, 10), 1, DataType::S8), // Unsupported data type
61 TensorInfo(TensorShape(10, 10, 10), 1, DataType::F32), // Wrong predictions dimensions
62 TensorInfo(TensorShape(20, 10), 1, DataType::F32)}), // Wrong output dimension
63 framework::dataset::make("TargetsInfo",{ TensorInfo(TensorShape(10), 1, DataType::U32),
64 TensorInfo(TensorShape(10), 1, DataType::U32),
65 TensorInfo(TensorShape(10), 1, DataType::U32),
66 TensorInfo(TensorShape(10), 1, DataType::U32),
67 TensorInfo(TensorShape(10), 1, DataType::U32)})),
68 framework::dataset::make("OutputInfo",{ TensorInfo(TensorShape(10), 1, DataType::U8),
69 TensorInfo(TensorShape(10), 1, DataType::U8),
70 TensorInfo(TensorShape(10), 1, DataType::U8),
71 TensorInfo(TensorShape(10), 1, DataType::U8),
72 TensorInfo(TensorShape(1), 1, DataType::U8)})),
73
74 framework::dataset::make("k",{ 0, 1, 2, 3, 4 })),
75 framework::dataset::make("Expected", {true, false, false, false, false })),
76 prediction_info, targets_info, output_info, k, expected)
77 {
78 const Status status = CPPTopKV::validate(&prediction_info.clone()->set_is_resizable(false),&targets_info.clone()->set_is_resizable(false), &output_info.clone()->set_is_resizable(false), k);
79 ARM_COMPUTE_EXPECT(bool(status) == expected, framework::LogLevel::ERRORS);
80 }
81 // clang-format on
82 // *INDENT-ON*
83
TEST_CASE(Float,framework::DatasetMode::ALL)84 TEST_CASE(Float, framework::DatasetMode::ALL)
85 {
86 const unsigned int k = 5;
87
88 Tensor predictions = create_tensor<Tensor>(TensorShape(10, 20), DataType::F32);
89 Tensor targets = create_tensor<Tensor>(TensorShape(20), DataType::U32);
90
91 predictions.allocator()->allocate();
92 targets.allocator()->allocate();
93
94 // Fill the tensors with random pre-generated values
95 fill_tensor(Accessor(predictions), std::vector<float>
96 {
97 0.8147, 0.6557, 0.4387, 0.7513, 0.3517, 0.1622, 0.1067, 0.8530, 0.7803, 0.5470,
98 0.9058, 0.0357, 0.3816, 0.2551, 0.8308, 0.7943, 0.9619, 0.6221, 0.3897, 0.2963,
99 0.1270, 0.8491, 0.7655, 0.5060, 0.5853, 0.3112, 0.0046, 0.3510, 0.2417, 0.7447,
100 0.9134, 0.9340, 0.7952, 0.6991, 0.5497, 0.5285, 0.7749, 0.5132, 0.4039, 0.1890,
101 0.6324, 0.6787, 0.1869, 0.8909, 0.9172, 0.1656, 0.8173, 0.4018, 0.0965, 0.6868,
102 0.0975, 0.7577, 0.4898, 0.9593, 0.2858, 0.6020, 0.8687, 0.0760, 0.1320, 0.1835,
103 0.2785, 0.7431, 0.4456, 0.5472, 0.7572, 0.2630, 0.0844, 0.2399, 0.9421, 0.3685,
104 0.5469, 0.3922, 0.6463, 0.1386, 0.7537, 0.6541, 0.3998, 0.1233, 0.9561, 0.6256,
105 0.9575, 0.6555, 0.7094, 0.1493, 0.3804, 0.6892, 0.2599, 0.1839, 0.5752, 0.7802,
106 0.9649, 0.1712, 0.7547, 0.2575, 0.5678, 0.7482, 0.8001, 0.2400, 0.0598, 0.0811,
107 0.1576, 0.7060, 0.2760, 0.8407, 0.0759, 0.4505, 0.4314, 0.4173, 0.2348, 0.9294,
108 0.9706, 0.0318, 0.6797, 0.2543, 0.0540, 0.0838, 0.9106, 0.0497, 0.3532, 0.7757,
109 0.9572, 0.2769, 0.6551, 0.8143, 0.5308, 0.2290, 0.1818, 0.9027, 0.8212, 0.4868,
110 0.4854, 0.0462, 0.1626, 0.2435, 0.7792, 0.9133, 0.2638, 0.9448, 0.0154, 0.4359,
111 0.8003, 0.0971, 0.1190, 0.9293, 0.9340, 0.1524, 0.1455, 0.4909, 0.0430, 0.4468,
112 0.1419, 0.8235, 0.4984, 0.3500, 0.1299, 0.8258, 0.1361, 0.4893, 0.1690, 0.3063,
113 0.4218, 0.6948, 0.9597, 0.1966, 0.5688, 0.5383, 0.8693, 0.3377, 0.6491, 0.5085,
114 0.9157, 0.3171, 0.3404, 0.2511, 0.4694, 0.9961, 0.5797, 0.9001, 0.7317, 0.5108,
115 0.7922, 0.9502, 0.5853, 0.6160, 0.0119, 0.0782, 0.5499, 0.3692, 0.6477, 0.8176,
116 0.9595, 0.0344, 0.2238, 0.4733, 0.3371, 0.4427, 0.1450, 0.1112, 0.4509, 0.7948
117 });
118
119 fill_tensor(Accessor(targets), std::vector<int> { 1, 5, 7, 2, 8, 1, 2, 1, 2, 4, 3, 9, 4, 1, 9, 9, 4, 1, 2, 4 });
120
121 // Determine the output through the CPP kernel
122 Tensor output;
123 CPPTopKV topkv;
124 topkv.configure(&predictions, &targets, &output, k);
125
126 output.allocator()->allocate();
127
128 // Run the kernel
129 topkv.run();
130
131 // Validate against the expected values
132 SimpleTensor<uint8_t> expected_output(TensorShape(20), DataType::U8);
133 fill_tensor(expected_output, std::vector<uint8_t> { 1, 1, 0, 1, 0, 1, 1, 0, 1, 1, 1, 1, 0, 0, 1, 0, 1, 0, 0, 0 });
134 validate(Accessor(output), expected_output);
135 }
136
TEST_CASE(QASYMM8,framework::DatasetMode::ALL)137 TEST_CASE(QASYMM8, framework::DatasetMode::ALL)
138 {
139 const unsigned int k = 5;
140
141 Tensor predictions = create_tensor<Tensor>(TensorShape(10, 20), DataType::QASYMM8, 1, QuantizationInfo());
142 Tensor targets = create_tensor<Tensor>(TensorShape(20), DataType::U32);
143
144 predictions.allocator()->allocate();
145 targets.allocator()->allocate();
146
147 // Fill the tensors with random pre-generated values
148 fill_tensor(Accessor(predictions), std::vector<uint8_t>
149 {
150 133, 235, 69, 118, 140, 179, 189, 203, 137, 157,
151 242, 1, 196, 170, 166, 25, 102, 244, 24, 254,
152 164, 119, 49, 198, 140, 135, 175, 84, 29, 136,
153 246, 109, 74, 90, 185, 136, 181, 172, 35, 123,
154 62, 118, 24, 170, 134, 221, 114, 113, 174, 206,
155 174, 198, 148, 107, 255, 125, 6, 214, 127, 59,
156 75, 83, 175, 216, 56, 101, 85, 197, 49, 128,
157 172, 201, 140, 214, 28, 172, 109, 43, 127, 231,
158 178, 121, 109, 66, 29, 190, 70, 221, 38, 148,
159 18, 10, 165, 158, 17, 134, 51, 254, 15, 217,
160 66, 46, 166, 150, 104, 90, 211, 132, 218, 190,
161 58, 185, 174, 139, 115, 39, 111, 227, 144, 151,
162 171, 122, 163, 223, 94, 151, 228, 151, 238, 64,
163 217, 40, 242, 68, 196, 68, 101, 40, 179, 171,
164 89, 88, 54, 82, 161, 12, 197, 52, 150, 22,
165 200, 156, 182, 31, 198, 194, 102, 105, 209, 161,
166 173, 50, 61, 241, 239, 63, 207, 192, 226, 170,
167 2, 190, 31, 166, 250, 114, 194, 212, 254, 187,
168 155, 63, 156, 123, 50, 177, 97, 203, 1, 229,
169 100, 235, 116, 164, 36, 92, 56, 82, 222, 252
170 });
171
172 fill_tensor(Accessor(targets), std::vector<int> { 1, 5, 7, 2, 8, 1, 2, 1, 2, 4, 3, 9, 4, 1, 9, 9, 4, 1, 2, 4 });
173
174 // Determine the output through the CPP kernel
175 Tensor output;
176 CPPTopKV topkv;
177 topkv.configure(&predictions, &targets, &output, k);
178
179 output.allocator()->allocate();
180
181 // Run the kernel
182 topkv.run();
183
184 // Validate against the expected values
185 SimpleTensor<uint8_t> expected_output(TensorShape(20), DataType::U8);
186 fill_tensor(expected_output, std::vector<uint8_t> { 1, 0, 0, 0, 1, 1, 1, 1, 0, 0, 1, 1, 0, 0, 0, 0, 1, 1, 1, 0 });
187 validate(Accessor(output), expected_output);
188 }
189
TEST_CASE(QASYMM8_SIGNED,framework::DatasetMode::ALL)190 TEST_CASE(QASYMM8_SIGNED, framework::DatasetMode::ALL)
191 {
192 const unsigned int k = 5;
193
194 Tensor predictions = create_tensor<Tensor>(TensorShape(10, 20), DataType::QASYMM8_SIGNED, 1, QuantizationInfo());
195 Tensor targets = create_tensor<Tensor>(TensorShape(20), DataType::U32);
196
197 predictions.allocator()->allocate();
198 targets.allocator()->allocate();
199
200 // Fill the tensors with random pre-generated values
201 fill_tensor(Accessor(predictions), std::vector<int8_t>
202 {
203 123, -34, 69, 118, 20, -45, 99, -98, 127, 117, //-34
204 -99, 1, -128, 90, 60, 25, 102, 76, 24, -110, //25
205 99, 119, 49, 43, -40, 60, 43, 84, 29, 67, //84
206 33, 109, 74, 90, 90, 44, 98, 90, 35, 123, //74
207 62, 118, 24, -32, 34, 21, 114, 113, 124, 20, //124
208 74, 98, 48, 107, 127, 125, 6, -98, 127, 59, //98
209 75, 83, 75, -118, 56, 101, 85, 97, 49, 127, //75
210 72, -20, 40, 14, 28, -30, 109, 43, 127, -31, //-20
211 78, 121, 109, 66, 29, 90, 70, 21, 38, 48, //109
212 18, 10, 115, 124, 17, 123, 51, 54, 15, 17, //17
213 66, 46, -66, 125, 104, 90, 123, 113, -54, -126, //125
214 58, -85, 74, 39, 115, 39, 111, -27, 44, 51, //51
215 71, 122, -34, -123, 94, 113, 125, 111, 38, 64, //94
216 -17, 40, 42, 68, 96, 68, 101, 40, 79, 71, //40
217 89, 88, 54, 82, 127, 12, 112, 52, 125, 22, //22
218 -128, 56, 82, 31, 98, 94, 102, 105, 127, 123, //123
219 112, 50, 61, 41, 39, 63, -77, 92, 26, 70, //39
220 2, 90, 31, 99, -34, 114, 112, 126, 127, 87, //90
221 125, 63, 56, 123, 50, -77, 97, -93, 1, 29, //56
222 100, -35, 116, 64, 36, 92, 56, 82, -22, -118 //36
223 });
224
225 fill_tensor(Accessor(targets), std::vector<int> { 1, 5, 7, 2, 8, 1, 2, 1, 2, 4, 3, 9, 4, 1, 9, 9, 4, 1, 2, 4 });
226
227 // Determine the output through the CPP kernel
228 Tensor output;
229 CPPTopKV topkv;
230 topkv.configure(&predictions, &targets, &output, k);
231
232 output.allocator()->allocate();
233
234 // Run the kernel
235 topkv.run();
236
237 // Validate against the expected values
238 SimpleTensor<int8_t> expected_output(TensorShape(20), DataType::U8);
239 fill_tensor(expected_output, std::vector<int8_t> { 0, 1, 1, 0, 1, 1, 0, 0, 1, 0, 1, 1, 1, 0, 0, 1, 0, 0, 1, 0 });
240 validate(Accessor(output), expected_output);
241 }
242
243 TEST_SUITE_END() // TopKV
244 TEST_SUITE_END() // CPP
245 } // namespace validation
246 } // namespace test
247 } // namespace arm_compute
248