blob: 561c455a001c1b15f52d3b282c86dedadd442e7f [file] [log] [blame]
Gunes Bayire87fa662023-09-07 12:20:33 +01001/*
2 * Copyright (c) 2023 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
25#include "arm_compute/runtime/CL/CLTensor.h"
26
27#include "src/gpu/cl/kernels/ClMatMulLowpNativeMMULKernel.h"
28
Gunes Bayira116cd32023-09-13 11:59:34 +010029#include "tests/datasets/MatMulLowpMMULDataset.h"
Gunes Bayire87fa662023-09-07 12:20:33 +010030#include "tests/framework/Macros.h"
31#include "tests/framework/datasets/Datasets.h"
32#include "tests/validation/Validation.h"
33#include "tests/validation/fixtures/MatMulKernelFixture.h"
34#include "tests/validation/reference/Permute.h"
35
36#include <tuple>
37
38namespace arm_compute
39{
40namespace test
41{
42namespace validation
43{
44namespace
45{
Gunes Bayira116cd32023-09-13 11:59:34 +010046constexpr AbsoluteTolerance<float> tolerance_quant(1); /**< Tolerance value for comparing reference's output against implementation's output for quantized data types */
Gunes Bayire87fa662023-09-07 12:20:33 +010047}
Gunes Bayira116cd32023-09-13 11:59:34 +010048using framework::dataset::make;
Gunes Bayire87fa662023-09-07 12:20:33 +010049
50template <typename T>
Gunes Bayira116cd32023-09-13 11:59:34 +010051using CLMatMulLowpNativeMMULKernelFixture = MatMulKernelValidationFixture<T, ClMatMulLowpNativeMMULKernel, true /* use_mmul */>;
52
53template <typename T>
54using CLMatMulLowpNativeMMULKernelWithBiasFixture = MatMulKernelWithBiasValidation<T, ClMatMulLowpNativeMMULKernel, true /* use_mmul */>;
55
56/** M0 values to test --precommit*/
57const auto m0_values_precommit = framework::dataset::make("M0", { 1, 3 });
58
59/** N0 values to test --precommit*/
60const auto n0_values_precommit = framework::dataset::make("N0", { 2, 4 });
61
62/** M0 values to test --nightly*/
63const auto m0_values_nightly_lhs_nt = framework::dataset::make("M0", { 2, 4, 5, 8 });
64
65/** N0 values to test --nightly*/
66const auto n0_values_nightly_rhs_nt = framework::dataset::make("N0", { 1, 3, 8, 16 });
Gunes Bayire87fa662023-09-07 12:20:33 +010067
68TEST_SUITE(CL)
69TEST_SUITE(MatMulLowpNativeMMULKernel)
70TEST_SUITE(Validate)
71
72TEST_CASE(SupportedKernelConfigurations, framework::DatasetMode::ALL)
73{
74 using MatMulConfigurationPair = std::pair<MatMulKernelInfo, bool>;
75
76 const std::vector<MatMulConfigurationPair> supported_block_sizes =
77 {
78 // MatMulKernelInfo(adj_lhs, adj_rhs, M0, N0, K0, export_rhs_to_cl_image = false)
Gunes Bayir2ad0a6b2023-09-19 15:37:38 +010079 { MatMulKernelInfo(false, false, 0, 1, 4), false }, // M0 should be > 0
80 { MatMulKernelInfo(false, true, 3, 5, 4), false }, // N0 not in {1, 2, 3, 4, 8, 16}
81 { MatMulKernelInfo(false, false, 3, 6, 4), false }, // N0 not in {1, 2, 3, 4, 8, 16}
82 { MatMulKernelInfo(false, false, 3, 3, 8), false }, // K0 not in 4
83 { MatMulKernelInfo(false, false, 9, 1, 4), true },
84 { MatMulKernelInfo(false, true, 3, 16, 4), true },
85 { MatMulKernelInfo(false, false, 7, 3, 4), true },
86 { MatMulKernelInfo(false, false, 7, 3, 4, true), false }, // export to CLImage is unsupported for quantized types
Gunes Bayire87fa662023-09-07 12:20:33 +010087 };
88
89 // Set big enough shapes so that block sizes are not truncated. Also, set all dimensions equal
90 // so that it doesn't fail for different NT/T configurations. We aim to test the block sizes here,
91 // not the shapes themselves.
Gunes Bayir2ad0a6b2023-09-19 15:37:38 +010092 const TensorInfo lhs_info = TensorInfo(TensorShape(64U, 64U), 1, DataType::QASYMM8_SIGNED);
93 const TensorInfo rhs_info = TensorInfo(TensorShape(64U, 64U), 1, DataType::QASYMM8_SIGNED);
Gunes Bayire87fa662023-09-07 12:20:33 +010094
95 for(auto &pair : supported_block_sizes)
96 {
97 TensorInfo output_info;
Gunes Bayira116cd32023-09-13 11:59:34 +010098 Status status = ClMatMulLowpNativeMMULKernel::validate(&lhs_info, &rhs_info, nullptr, &output_info, pair.first);
99 const bool expected = (pair.second && arm_matrix_multiply_supported(CLKernelLibrary::get().get_device()));
Gunes Bayire87fa662023-09-07 12:20:33 +0100100
Gunes Bayira116cd32023-09-13 11:59:34 +0100101 ARM_COMPUTE_EXPECT(bool(status) == expected, framework::LogLevel::ERRORS);
Gunes Bayire87fa662023-09-07 12:20:33 +0100102 }
103}
104
105TEST_CASE(ValidateInputShapes, framework::DatasetMode::ALL)
106{
107 // Configurations are assumed to be Nt/Nt, but will be transposed inside the test to test other configurations
108 using ShapeConfigurationTuple = std::tuple<TensorShape, TensorShape, TensorShape, bool>;
109 const std::vector<ShapeConfigurationTuple> shape_configurations =
110 {
Gunes Bayira116cd32023-09-13 11:59:34 +0100111 { TensorShape(32U, 1U), TensorShape(3U, 32U), TensorShape(3U), true },
112 { TensorShape(16U, 12U), TensorShape(3U, 16U), TensorShape(3U), true },
113 { TensorShape(64U, 4U), TensorShape(2U, 64U), TensorShape(2U), true },
114 { TensorShape(16U, 4U), TensorShape(2U, 32U), TensorShape(2U), false }, // Mismatch in the K dimension
115 { TensorShape(16U, 0U), TensorShape(2U, 16U), TensorShape(2U), false }, // Invalid dimension
116 { TensorShape(32U, 4U, 3U, 4U, 5U, 6U), TensorShape(2U, 32U, 3U, 4U, 5U, 6U), TensorShape(2U), true },
117 { TensorShape(32U, 4U, 3U, 4U, 5U, 1U), TensorShape(2U, 32U, 3U, 4U, 5U, 6U), TensorShape(2U), false }, // no batch broadcasting
118 { TensorShape(32U, 4U, 3U, 4U, 9U, 6U), TensorShape(2U, 32U, 3U, 4U, 5U, 6U), TensorShape(2U), false }, // mismatch in batch dimension
119 { TensorShape(32U, 1U), TensorShape(3U, 32U), TensorShape(1U), false }, // invalid broadcast of bias
120 { TensorShape(32U, 1U), TensorShape(3U, 32U), TensorShape(3U, 3U), false }, // 2d bias is invalid
121 { TensorShape(12U, 12U), TensorShape(3U, 12U), TensorShape(3U), false }, // K must be multiple of 16
Gunes Bayire87fa662023-09-07 12:20:33 +0100122 };
123
124 for(auto &tuple : shape_configurations)
125 {
Gunes Bayira116cd32023-09-13 11:59:34 +0100126 const bool expected = (std::get<3>(tuple) && arm_matrix_multiply_supported(CLKernelLibrary::get().get_device()));
Gunes Bayire87fa662023-09-07 12:20:33 +0100127
128 for(bool adj_lhs :
129 {
130 false, true
131 })
132 {
133 for(bool adj_rhs :
134 {
135 false, true
136 })
137 {
138 TensorShape lhs_shape = std::get<0>(tuple);
139 TensorShape rhs_shape = std::get<1>(tuple);
140 TensorShape bia_shape = std::get<2>(tuple);
141
142 if(adj_lhs)
143 {
144 permute(lhs_shape, PermutationVector(1U, 0U));
145 }
146
147 if(adj_rhs)
148 {
149 permute(rhs_shape, PermutationVector(1U, 0U));
150 }
151
152 const TensorInfo lhs_info = TensorInfo(lhs_shape, 1, DataType::QASYMM8_SIGNED);
153 const TensorInfo rhs_info = TensorInfo(rhs_shape, 1, DataType::QASYMM8_SIGNED);
154 const TensorInfo bia_info = TensorInfo(bia_shape, 1, DataType::S32);
155 TensorInfo output_info;
156
Gunes Bayira116cd32023-09-13 11:59:34 +0100157 MatMulKernelInfo matmul_kernel_info{ adj_lhs, adj_rhs, 1, 1, 4, false /* export_rhs_to_cl_image */ };
Gunes Bayire87fa662023-09-07 12:20:33 +0100158
159 Status status = ClMatMulLowpNativeMMULKernel::validate(&lhs_info, &rhs_info, &bia_info, &output_info, matmul_kernel_info);
160 ARM_COMPUTE_EXPECT(bool(status) == expected, framework::LogLevel::ERRORS);
161 }
162 }
163 }
164}
165
166TEST_CASE(ValidateDataTypes, framework::DatasetMode::ALL)
167{
168 using DataTypeConfigurationTuple = std::tuple<DataType, DataType, DataType, DataType, bool>;
169 const std::vector<DataTypeConfigurationTuple> data_type_configurations =
170 {
171 { DataType::F32, DataType::F32, DataType::F32, DataType::F32, false }, // no floating point types
172 { DataType::F16, DataType::F16, DataType::F16, DataType::F16, false }, // no floating point types
173 { DataType::F64, DataType::F64, DataType::F64, DataType::F64, false }, // no double precision
174 { DataType::QASYMM8, DataType::QASYMM8, DataType::S32, DataType::QASYMM8, true },
175 { DataType::QASYMM8_SIGNED, DataType::QASYMM8_SIGNED, DataType::S32, DataType::QASYMM8_SIGNED, true },
176 { DataType::QSYMM8_PER_CHANNEL, DataType::QSYMM8_PER_CHANNEL, DataType::S32, DataType::QSYMM8_PER_CHANNEL, false }, // only qasymm8/qasymm8_signed is supported
177 { DataType::QASYMM16, DataType::QASYMM16, DataType::S32, DataType::QASYMM16, false }, // only qasymm8/qasymm8_signed is supported
178 { DataType::QSYMM16, DataType::QSYMM16, DataType::S32, DataType::QSYMM16, false }, // only qasymm8/qasymm8_signed is supported
179 { DataType::QSYMM8, DataType::QSYMM8, DataType::S32, DataType::QSYMM8, false }, // only qasymm8/qasymm8_signed is supported
180 { DataType::QASYMM8, DataType::QASYMM8_SIGNED, DataType::S32, DataType::QASYMM8, false }, // no mixed data types
181 { DataType::S64, DataType::S64, DataType::S64, DataType::S64, false }, // no integral types
182 { DataType::S32, DataType::S32, DataType::S32, DataType::S32, false }, // no integral types
183 { DataType::S16, DataType::S16, DataType::S16, DataType::S16, false }, // no integral types
184 { DataType::S8, DataType::S8, DataType::S8, DataType::S8, false }, // no integral types
185 { DataType::U64, DataType::U64, DataType::U64, DataType::U64, false }, // no integral types
186 { DataType::U32, DataType::U32, DataType::U32, DataType::U32, false }, // no integral types
187 { DataType::U16, DataType::U16, DataType::U16, DataType::U16, false }, // no integral types
188 { DataType::U8, DataType::U8, DataType::U8, DataType::U8, false }, // no integral types
189 { DataType::QASYMM8, DataType::QASYMM8, DataType::F32, DataType::QASYMM8, false } // Only S32 bias is supported
190 };
191
192 // It's enough to test a single shape and block size configuration while checking data types
193 const TensorShape shape = TensorShape(48U, 48U);
194 const TensorShape bia_shape = TensorShape(48U);
Gunes Bayira116cd32023-09-13 11:59:34 +0100195 const MatMulKernelInfo matmul_kernel_info{ false, false, 1, 1, 4, false };
Gunes Bayire87fa662023-09-07 12:20:33 +0100196 for(auto &tuple : data_type_configurations)
197 {
Gunes Bayira116cd32023-09-13 11:59:34 +0100198 const bool expected = (std::get<4>(tuple) && arm_matrix_multiply_supported(CLKernelLibrary::get().get_device()));
Gunes Bayire87fa662023-09-07 12:20:33 +0100199
200 const TensorInfo lhs_info(shape, 1, std::get<0>(tuple));
201 const TensorInfo rhs_info(shape, 1, std::get<1>(tuple));
202 const TensorInfo bia_info(bia_shape, 1, std::get<2>(tuple));
203 TensorInfo output_info(shape, 1, std::get<3>(tuple));
204
205 Status status = ClMatMulLowpNativeMMULKernel::validate(&lhs_info, &rhs_info, &bia_info, &output_info, matmul_kernel_info);
Gunes Bayira116cd32023-09-13 11:59:34 +0100206
Gunes Bayire87fa662023-09-07 12:20:33 +0100207 ARM_COMPUTE_EXPECT(bool(status) == expected, framework::LogLevel::ERRORS);
208 }
209}
210
211TEST_SUITE_END() // Validate
212
213TEST_SUITE(Quantized)
214TEST_SUITE(QASYMM8_SIGNED)
215
Gunes Bayira116cd32023-09-13 11:59:34 +0100216FIXTURE_DATA_TEST_CASE(RunSmall, CLMatMulLowpNativeMMULKernelFixture<int8_t>,
217 framework::DatasetMode::ALL,
218 combine(datasets::SmallMatMulLowpMMULDataset(),
219 make("TransposeA", { false }),
Gunes Bayir2ad0a6b2023-09-19 15:37:38 +0100220 make("TransposeB", { false, true }),
Gunes Bayira116cd32023-09-13 11:59:34 +0100221 m0_values_precommit,
222 n0_values_precommit,
223 make("K0", { 4 }),
224 make("ExportRhsToCLImage", { false }),
225 make("DataType", DataType::QASYMM8_SIGNED)))
226{
227 if(_device_supports_mmul)
228 {
229 // Validate output
230 validate(CLAccessor(_target), _reference, tolerance_quant);
231 }
232}
233
234FIXTURE_DATA_TEST_CASE(RunWithBias, CLMatMulLowpNativeMMULKernelWithBiasFixture<int8_t>,
235 framework::DatasetMode::ALL,
236 combine(datasets::SmallMatMulLowpMMULWithBiasDataset(),
237 make("TransposeA", { false }),
Gunes Bayir2ad0a6b2023-09-19 15:37:38 +0100238 make("TransposeB", { false, true }),
Gunes Bayira116cd32023-09-13 11:59:34 +0100239 m0_values_precommit,
240 n0_values_precommit,
241 make("K0", { 4 }),
242 make("ExportRhsToCLImage", { false }),
243 make("DataType", DataType::QASYMM8_SIGNED)))
244{
245 if(_device_supports_mmul)
246 {
247 // Validate output
248 validate(CLAccessor(_target), _reference, tolerance_quant);
249 }
250}
251
252FIXTURE_DATA_TEST_CASE(RunLargeNoTranspose, CLMatMulLowpNativeMMULKernelFixture<int8_t>,
253 framework::DatasetMode::NIGHTLY,
254 combine(datasets::LargeMatMulLowpMMULDataset(),
255 make("TransposeA", { false }),
Gunes Bayir2ad0a6b2023-09-19 15:37:38 +0100256 make("TransposeB", { false, true }),
Gunes Bayira116cd32023-09-13 11:59:34 +0100257 m0_values_nightly_lhs_nt,
258 n0_values_nightly_rhs_nt,
259 make("K0", { 4 }),
260 make("ExportRhsToCLImage", { false }),
261 make("DataType", DataType::QASYMM8_SIGNED)))
262{
263 if(_device_supports_mmul)
264 {
265 // Validate output
266 validate(CLAccessor(_target), _reference, tolerance_quant);
267 }
268}
269
270// Running High Dimensional test is enough for qasymm8_signed, because we're stressing the number of dimensions, not data type or M0/N0/K0
271// It's a good idea to test for each Lhs/Rhs T/NT combinations because they're different CL kernels
272FIXTURE_DATA_TEST_CASE(RunHighDimensional, CLMatMulLowpNativeMMULKernelFixture<int8_t>,
273 framework::DatasetMode::ALL,
274 combine(datasets::HighDimensionalMatMulLowpMMULDataset(),
275 make("TransposeA", { false }),
Gunes Bayir2ad0a6b2023-09-19 15:37:38 +0100276 make("TransposeB", { false, true }),
Gunes Bayira116cd32023-09-13 11:59:34 +0100277 make("M0", { 2 }),
278 make("N0", { 2 }),
279 make("K0", { 4 }),
280 make("ExportRhsToCLImage", { false }),
281 make("DataType", DataType::QASYMM8_SIGNED)))
282{
283 if(_device_supports_mmul)
284 {
285 // Validate output
286 validate(CLAccessor(_target), _reference, tolerance_quant);
287 }
288}
Gunes Bayire87fa662023-09-07 12:20:33 +0100289
290TEST_SUITE_END() // QASYMM8_SIGNED
Gunes Bayira116cd32023-09-13 11:59:34 +0100291
Gunes Bayire87fa662023-09-07 12:20:33 +0100292TEST_SUITE(QASYMM8)
293
Gunes Bayira116cd32023-09-13 11:59:34 +0100294FIXTURE_DATA_TEST_CASE(RunSmall, CLMatMulLowpNativeMMULKernelFixture<uint8_t>,
295 framework::DatasetMode::ALL,
296 combine(datasets::SmallMatMulLowpMMULDatasetSubset(),
297 make("TransposeA", { false }),
Gunes Bayir2ad0a6b2023-09-19 15:37:38 +0100298 make("TransposeB", { false, true }),
Gunes Bayira116cd32023-09-13 11:59:34 +0100299 m0_values_precommit,
300 n0_values_precommit,
301 make("K0", { 4 }),
302 make("ExportRhsToCLImage", { false }),
303 make("DataType", DataType::QASYMM8)))
304{
305 if(_device_supports_mmul)
306 {
307 // Validate output
308 validate(CLAccessor(_target), _reference, tolerance_quant);
309 }
310}
311
312FIXTURE_DATA_TEST_CASE(RunWithBias, CLMatMulLowpNativeMMULKernelWithBiasFixture<uint8_t>,
313 framework::DatasetMode::ALL,
314 combine(datasets::SmallMatMulLowpMMULWithBiasDataset(),
315 make("TransposeA", { false }),
Gunes Bayir2ad0a6b2023-09-19 15:37:38 +0100316 make("TransposeB", { false, true }),
Gunes Bayira116cd32023-09-13 11:59:34 +0100317 m0_values_precommit,
318 n0_values_precommit,
319 make("K0", { 4 }),
320 make("ExportRhsToCLImage", { false }),
321 make("DataType", DataType::QASYMM8)))
322{
323 if(_device_supports_mmul)
324 {
325 // Validate output
326 validate(CLAccessor(_target), _reference, tolerance_quant);
327 }
328}
329
330FIXTURE_DATA_TEST_CASE(RunLargeNoTranspose, CLMatMulLowpNativeMMULKernelFixture<uint8_t>,
331 framework::DatasetMode::NIGHTLY,
332 combine(datasets::LargeMatMulLowpMMULDataset(),
333 make("TransposeA", { false }),
Gunes Bayir2ad0a6b2023-09-19 15:37:38 +0100334 make("TransposeB", { false, true }),
Gunes Bayira116cd32023-09-13 11:59:34 +0100335 m0_values_nightly_lhs_nt,
336 n0_values_nightly_rhs_nt,
337 make("K0", { 4 }),
338 make("ExportRhsToCLImage", { false }),
339 make("DataType", DataType::QASYMM8)))
340{
341 if(_device_supports_mmul)
342 {
343 // Validate output
344 validate(CLAccessor(_target), _reference, tolerance_quant);
345 }
346}
Gunes Bayire87fa662023-09-07 12:20:33 +0100347
348TEST_SUITE_END() // QASYMM8
349TEST_SUITE_END() // Quantized
350TEST_SUITE_END() // MatMulLowpNativeMMULKernel
351TEST_SUITE_END() // CL
352} // namespace validation
353} // namespace test
354} // namespace arm_compute