blob: 7dd1a479fe49e679610fde0b1c4daef2bf514382 [file] [log] [blame]
Pablo Tello299025a2017-09-29 11:30:12 +01001/*
Sheri Zhangac6499a2021-02-10 15:32:38 +00002 * Copyright (c) 2017-2021 Arm Limited.
Pablo Tello299025a2017-09-29 11:30:12 +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 */
24#include "arm_compute/core/Types.h"
Gian Marcoe75a02b2017-11-08 12:24:09 +000025#include "arm_compute/runtime/NEON/functions/NEGEMMLowpMatrixMultiplyCore.h"
26#include "arm_compute/runtime/NEON/functions/NEGEMMLowpOutputStage.h"
Pablo Tello299025a2017-09-29 11:30:12 +010027#include "arm_compute/runtime/Tensor.h"
28#include "arm_compute/runtime/TensorAllocator.h"
Manuel Bottinicfac51c2021-06-18 15:47:28 +010029#include "src/core/helpers/MemoryHelpers.h"
Georgios Pinitas7891a732021-08-20 21:39:25 +010030#include "src/cpu/operators/CpuGemmLowpMatrixMultiplyCore.h"
Pablo Tello299025a2017-09-29 11:30:12 +010031#include "tests/NEON/Accessor.h"
Gian Marco Iodiceab182122017-10-09 15:05:40 +010032#include "tests/NEON/Helper.h"
Gian Marcoe75a02b2017-11-08 12:24:09 +000033#include "tests/PaddingCalculator.h"
George Wort2d7e6832019-02-22 16:37:41 +000034#include "tests/datasets/GEMMLowpFusedOffsetOutputDataset.h"
Gian Marcofa4cacd2017-10-18 17:05:02 +010035#include "tests/datasets/LargeGEMMLowpDataset.h"
Gian Marcoe75a02b2017-11-08 12:24:09 +000036#include "tests/datasets/ShapeDatasets.h"
Gian Marcofa4cacd2017-10-18 17:05:02 +010037#include "tests/datasets/SmallGEMMLowpDataset.h"
Pablo Tello299025a2017-09-29 11:30:12 +010038#include "tests/framework/Asserts.h"
39#include "tests/framework/Macros.h"
40#include "tests/framework/datasets/Datasets.h"
41#include "tests/validation/Validation.h"
42#include "tests/validation/fixtures/GEMMLowpFixture.h"
43
44namespace arm_compute
45{
46namespace test
47{
48namespace validation
49{
Pablo Tello299025a2017-09-29 11:30:12 +010050TEST_SUITE(NEON)
51TEST_SUITE(GEMMLowp)
Gian Marcoe75a02b2017-11-08 12:24:09 +000052TEST_SUITE(MatrixMultiplyCore)
53using NEGEMMLowpMatrixMultiplyCoreFixture = GEMMLowpMatrixMultiplyCoreValidationFixture<Tensor, Accessor, NEGEMMLowpMatrixMultiplyCore>;
Gian Marcofa4cacd2017-10-18 17:05:02 +010054
morgolock4adaddb2020-09-29 14:24:32 +010055DATA_TEST_CASE(Configuration, framework::DatasetMode::ALL, framework::dataset::concat(datasets::SmallGEMMLowpDataset(), datasets::LargeGEMMLowpDataset()),
56 shape_a, shape_b, shape_c, a_offset, b_offset)
57{
58 // Create tensors
59 Tensor a = create_tensor<Tensor>(shape_a, DataType::QASYMM8);
60 Tensor b = create_tensor<Tensor>(shape_b, DataType::QASYMM8);
61 Tensor c = create_tensor<Tensor>(shape_c, DataType::S32);
62
63 a.info()->set_quantization_info(QuantizationInfo(1.0f / 255, a_offset));
64 b.info()->set_quantization_info(QuantizationInfo(1.0f / 255, b_offset));
65
66 ARM_COMPUTE_EXPECT(a.info()->is_resizable(), framework::LogLevel::ERRORS);
67 ARM_COMPUTE_EXPECT(b.info()->is_resizable(), framework::LogLevel::ERRORS);
68 ARM_COMPUTE_EXPECT(c.info()->is_resizable(), framework::LogLevel::ERRORS);
69
70 // Create and configure function
71 NEGEMMLowpMatrixMultiplyCore gemmlowp_mm;
72 gemmlowp_mm.configure(&a, &b, nullptr, &c);
73
74 // Validate padding is zero
75 validate(a.info()->padding(), PaddingSize());
76 validate(b.info()->padding(), PaddingSize());
77 validate(c.info()->padding(), PaddingSize());
78}
79
Georgios Pinitasa3b1b462017-11-16 19:24:39 +000080// *INDENT-OFF*
81// clang-format off
82DATA_TEST_CASE(Validate, framework::DatasetMode::ALL, zip(zip(zip(
83 framework::dataset::make("InputAInfo", { TensorInfo(TensorShape(21U, 13U), 1, DataType::QASYMM8, QuantizationInfo(1.f/255, 10)), // Input not a multiple of 4
Vidhya Sudhan Loganathan7485d5a2018-07-04 09:34:00 +010084 TensorInfo(TensorShape(21U, 13U), 1, DataType::S32), // Mismatching data type
Georgios Pinitasa3b1b462017-11-16 19:24:39 +000085 TensorInfo(TensorShape(20U, 13U), 1, DataType::QASYMM8, QuantizationInfo(1.f/255, 10)), // Invalid dimensions
86 TensorInfo(TensorShape(21U, 13U), 1, DataType::QASYMM8, QuantizationInfo(1.f/255, 10)), // Invalid dimensions
87 TensorInfo(TensorShape(16U, 32U), 1, DataType::QASYMM8, QuantizationInfo(1.f/255, 10)),
88 }),
89 framework::dataset::make("InputBInfo",{ TensorInfo(TensorShape(33U, 21U), 1, DataType::QASYMM8, QuantizationInfo(1.f/256, 10)),
90 TensorInfo(TensorShape(33U, 21U), 1, DataType::QASYMM8, QuantizationInfo(1.f/256, 10)),
91 TensorInfo(TensorShape(33U, 21U), 1, DataType::QASYMM8, QuantizationInfo(1.f/256, 10)),
92 TensorInfo(TensorShape(33U, 21U), 1, DataType::QASYMM8, QuantizationInfo(1.f/256, 10)),
93 TensorInfo(TensorShape(64U, 16U), 1, DataType::QASYMM8, QuantizationInfo(1.f/256, 10)),
94 })),
95 framework::dataset::make("OutputInfo",{ TensorInfo(TensorShape(33U, 13U), 1, DataType::S32),
96 TensorInfo(TensorShape(33U, 13U), 1, DataType::S32),
97 TensorInfo(TensorShape(33U, 13U), 1, DataType::S32),
98 TensorInfo(TensorShape(8U, 11U), 1, DataType::S32),
99 TensorInfo(TensorShape(64U, 32U), 1, DataType::S32),
100 })),
morgolock4adaddb2020-09-29 14:24:32 +0100101 framework::dataset::make("Expected", { true, false, false, false, true })),
Georgios Pinitasa3b1b462017-11-16 19:24:39 +0000102 a_info, b_info, output_info, expected)
103{
104 // Lock tensors
Georgios Pinitas631c41a2017-12-06 11:53:03 +0000105 Status status = NEGEMMLowpMatrixMultiplyCore::validate(&a_info.clone()->set_is_resizable(false),
106 &b_info.clone()->set_is_resizable(false),
Gian Marco Iodice4b908652018-10-18 10:21:02 +0100107 nullptr,
Georgios Pinitas631c41a2017-12-06 11:53:03 +0000108 &output_info.clone()->set_is_resizable(false));
109 ARM_COMPUTE_EXPECT(bool(status) == expected, framework::LogLevel::ERRORS);
Georgios Pinitasa3b1b462017-11-16 19:24:39 +0000110}
111// clang-format on
112// *INDENT-ON*
113
Manuel Bottinicfac51c2021-06-18 15:47:28 +0100114/** Test case for memory injection in @ref cpu::CpuGemmLowpMatrixMultiplyCore.
115 *
116 * Configure the operator once and inject memory at run-time in multiple executions.
117 *
118 * Checks performed in order:
119 * - Both runs compute the same output
120 */
121TEST_CASE(MemoryInjection, framework::DatasetMode::ALL)
122{
123 auto gemm = std::make_unique<cpu::CpuGemmLowpMatrixMultiplyCore>();
124 auto a_info = TensorInfo(TensorShape(32U, 72U), 1, DataType::QASYMM8);
125 auto b_info = TensorInfo(TensorShape(17U, 32U), 1, DataType::QASYMM8);
126 auto dst_info = TensorInfo(TensorShape(17U, 72U), 1, DataType::S32);
127 a_info.set_quantization_info(QuantizationInfo(1.0f / 255, -9));
128 b_info.set_quantization_info(QuantizationInfo(1.0f / 255, 1));
129 const auto gemm_info = GEMMInfo{};
130 gemm->configure(&a_info, &b_info, nullptr, &dst_info, gemm_info);
131
132 // telhs are newly created every call of this lambda function
133 auto a = create_tensor<Tensor>(a_info);
134 auto b = create_tensor<Tensor>(b_info);
135 auto dst = create_tensor<Tensor>(dst_info);
136 a.allocator()->allocate();
137 b.allocator()->allocate();
138 dst.allocator()->allocate();
139
140 ITensorPack run_pack =
141 {
142 { TensorType::ACL_SRC_0, &a },
143 { TensorType::ACL_SRC_1, &b },
144 { TensorType::ACL_DST, &dst }
145 };
146 ITensorPack prep_pack =
147 {
148 { TensorType::ACL_SRC_1, &b },
149 };
150
151 auto mg = MemoryGroup{};
152 auto ws = manage_workspace<Tensor>(gemm->workspace(), mg, run_pack, prep_pack);
153
154 auto run_conv = [&]() -> Tensor
155 {
156 auto dst = create_tensor<Tensor>(dst_info);
157 dst.allocator()->allocate();
158 run_pack.add_tensor(TensorType::ACL_DST, &dst);
159
160 library->fill_tensor_value(Accessor(a), static_cast<uint8_t>(1));
161 library->fill_tensor_value(Accessor(b), static_cast<uint8_t>(2));
162 // This operator is configured once and captured by this lambda.
163 gemm->prepare(prep_pack);
164 gemm->run(run_pack);
165 return dst;
166 };
167 auto result_0 = run_conv();
168 auto result_1 = run_conv();
169 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
170 {
171 ARM_COMPUTE_EXPECT(((uint8_t *)result_0.buffer())[i] == ((uint8_t *)result_1.buffer())[i], framework::LogLevel::ERRORS);
172 }
173}
174
175/** Test case for memory injection in @ref NEGEMMLowpMatrixMultiplyCore.
176 *
177 * Make sure @ref NEGEMMLowpMatrixMultiplyCore still works through injecting the memory at configure time using the old API.
178 *
179 * Checks performed in order:
180 * - Both runs compute the same output
181 */
182TEST_CASE(MultipleExecutionWithConfigure, framework::DatasetMode::ALL)
183{
184 auto gemm = std::make_unique<NEGEMMLowpMatrixMultiplyCore>();
185 auto a_info = TensorInfo(TensorShape(32U, 72U), 1, DataType::QASYMM8);
186 auto b_info = TensorInfo(TensorShape(17U, 32U), 1, DataType::QASYMM8);
187 auto dst_info = TensorInfo(TensorShape(17U, 72U), 1, DataType::S32);
188 a_info.set_quantization_info(QuantizationInfo(1.0f / 255, -9));
189 b_info.set_quantization_info(QuantizationInfo(1.0f / 255, 1));
190 const auto gemm_info = GEMMInfo{};
191 auto run_conv = [&]()
192 {
193 auto a = create_tensor<Tensor>(a_info);
194 auto b = create_tensor<Tensor>(b_info);
195 auto dst = create_tensor<Tensor>(dst_info);
196 gemm->configure(&a, &b, nullptr, &dst, gemm_info);
197 a.allocator()->allocate();
198 b.allocator()->allocate();
199 dst.allocator()->allocate();
200 library->fill_tensor_value(Accessor(a), static_cast<uint8_t>(1));
201 library->fill_tensor_value(Accessor(b), static_cast<uint8_t>(2));
202 gemm->run();
203 return dst;
204 };
205 auto result_0 = run_conv();
206 auto result_1 = run_conv();
207 for(size_t i = 0; i < result_0.info()->tensor_shape().total_size(); ++i)
208 {
209 ARM_COMPUTE_EXPECT(((uint8_t *)result_0.buffer())[i] == ((uint8_t *)result_1.buffer())[i], framework::LogLevel::ERRORS);
210 }
211}
212
Gian Marcoe75a02b2017-11-08 12:24:09 +0000213FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMLowpMatrixMultiplyCoreFixture, framework::DatasetMode::ALL, datasets::SmallGEMMLowpDataset())
Pablo Tello299025a2017-09-29 11:30:12 +0100214{
215 // Validate output
Gian Marcofa4cacd2017-10-18 17:05:02 +0100216 validate(Accessor(_target), _reference);
217}
218
Gian Marcoe75a02b2017-11-08 12:24:09 +0000219FIXTURE_DATA_TEST_CASE(RunLarge, NEGEMMLowpMatrixMultiplyCoreFixture, framework::DatasetMode::NIGHTLY, datasets::LargeGEMMLowpDataset())
Gian Marcofa4cacd2017-10-18 17:05:02 +0100220{
221 // Validate output
222 validate(Accessor(_target), _reference);
Pablo Tello299025a2017-09-29 11:30:12 +0100223}
Pablo Tello299025a2017-09-29 11:30:12 +0100224
George Wort2d7e6832019-02-22 16:37:41 +0000225using NEGEMMLowpMatrixMultiplyCoreFusedOffsetOutputFixture = GEMMLowpMatrixMultiplyCoreFusedOffsetOutputValidationFixture<Tensor, Accessor, NEGEMMLowpMatrixMultiplyCore>;
226TEST_SUITE(FusedOffsetOutput)
Manuel Bottini959c26d2019-12-02 16:22:35 +0000227FIXTURE_DATA_TEST_CASE(RunSmall, NEGEMMLowpMatrixMultiplyCoreFusedOffsetOutputFixture, framework::DatasetMode::ALL, combine(datasets::SmallGEMMLowpFusedOffsetOutputUint8Dataset(),
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000228 framework::dataset::make("DataType", { DataType::QASYMM8 })))
George Wort2d7e6832019-02-22 16:37:41 +0000229{
230 // Validate output
231 validate(Accessor(_target), _reference);
232}
233
Manuel Bottini959c26d2019-12-02 16:22:35 +0000234FIXTURE_DATA_TEST_CASE(RunLarge, NEGEMMLowpMatrixMultiplyCoreFusedOffsetOutputFixture, framework::DatasetMode::NIGHTLY, combine(datasets::LargeGEMMLowpFusedOffsetOutputUint8Dataset(),
Vidhya Sudhan Loganathan951b8a42019-11-04 14:42:08 +0000235 framework::dataset::make("DataType", { DataType::QASYMM8 })))
George Wort2d7e6832019-02-22 16:37:41 +0000236{
237 // Validate output
238 validate(Accessor(_target), _reference);
239}
240TEST_SUITE_END() // FusedOffsetOutput
Gian Marcoe75a02b2017-11-08 12:24:09 +0000241TEST_SUITE_END() // MatrixMultiplyCore
Gian Marcoe75a02b2017-11-08 12:24:09 +0000242TEST_SUITE_END() // GEMMLowp
Manuel Bottiniae58bdf2021-06-17 17:18:45 +0100243TEST_SUITE_END() // NEON
Pablo Tello299025a2017-09-29 11:30:12 +0100244} // namespace validation
245} // namespace test
246} // namespace arm_compute