2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // See LICENSE file in the project root for full license information.
5 #include "backends/RefWorkloadFactory.hpp"
6 #include "backends/RefWorkloads.hpp"
7 #include "backends/CpuTensorHandle.hpp"
9 #include "test/CreateWorkload.hpp"
14 template<typename Workload>
15 void CheckInputOutput(std::unique_ptr<Workload> workload, const TensorInfo& inputInfo, const TensorInfo& outputInfo)
17 auto queueDescriptor = workload->GetData();
18 auto inputHandle = boost::polymorphic_downcast<ConstCpuTensorHandle*>(queueDescriptor.m_Inputs[0]);
19 auto outputHandle = boost::polymorphic_downcast<CpuTensorHandle*>(queueDescriptor.m_Outputs[0]);
20 BOOST_TEST((inputHandle->GetTensorInfo() == inputInfo));
21 BOOST_TEST((outputHandle->GetTensorInfo() == outputInfo));
24 template <typename Workload>
25 void CheckInputsOutput(std::unique_ptr<Workload> workload,
26 const TensorInfo& inputInfo0,
27 const TensorInfo& inputInfo1,
28 const TensorInfo& outputInfo)
30 auto queueDescriptor = workload->GetData();
31 auto inputHandle0 = boost::polymorphic_downcast<ConstCpuTensorHandle*>(queueDescriptor.m_Inputs[0]);
32 auto inputHandle1 = boost::polymorphic_downcast<ConstCpuTensorHandle*>(queueDescriptor.m_Inputs[1]);
33 auto outputHandle = boost::polymorphic_downcast<CpuTensorHandle*>(queueDescriptor.m_Outputs[0]);
34 BOOST_TEST((inputHandle0->GetTensorInfo() == inputInfo0));
35 BOOST_TEST((inputHandle1->GetTensorInfo() == inputInfo1));
36 BOOST_TEST((outputHandle->GetTensorInfo() == outputInfo));
40 BOOST_AUTO_TEST_SUITE(CreateWorkloadRef)
42 template <typename ActivationWorkloadType, armnn::DataType DataType>
43 static void RefCreateActivationWorkloadTest()
46 RefWorkloadFactory factory;
47 auto workload = CreateActivationWorkloadTest<ActivationWorkloadType, DataType>(factory, graph);
49 // Checks that outputs are as we expect them (see definition of CreateActivationWorkloadTest).
50 CheckInputOutput(std::move(workload),
51 TensorInfo({ 1, 1 }, DataType),
52 TensorInfo({ 1, 1 }, DataType));
55 BOOST_AUTO_TEST_CASE(CreateActivationFloat32Workload)
57 RefCreateActivationWorkloadTest<RefActivationFloat32Workload, armnn::DataType::Float32>();
60 BOOST_AUTO_TEST_CASE(CreateActivationUint8Workload)
62 RefCreateActivationWorkloadTest<RefActivationUint8Workload, armnn::DataType::QuantisedAsymm8>();
65 template <typename AdditionWorkloadType, armnn::DataType DataType>
66 static void RefCreateAdditionWorkloadTest()
69 RefWorkloadFactory factory;
70 auto workload = CreateAdditionWorkloadTest<AdditionWorkloadType, DataType>(factory, graph);
72 // Checks that outputs are as we expect them (see definition of CreateAdditionWorkloadTest).
73 CheckInputsOutput(std::move(workload),
74 TensorInfo({ 2, 3 }, DataType),
75 TensorInfo({ 2, 3 }, DataType),
76 TensorInfo({ 2, 3 }, DataType));
79 BOOST_AUTO_TEST_CASE(CreateAdditionFloatWorkload)
81 RefCreateAdditionWorkloadTest<RefAdditionFloat32Workload, armnn::DataType::Float32>();
84 BOOST_AUTO_TEST_CASE(CreateAdditionUint8Workload)
86 RefCreateAdditionWorkloadTest<RefAdditionUint8Workload, armnn::DataType::QuantisedAsymm8>();
89 BOOST_AUTO_TEST_CASE(CreateBatchNormalizationWorkload)
92 RefWorkloadFactory factory;
93 auto workload = CreateBatchNormalizationWorkloadTest<RefBatchNormalizationFloat32Workload, armnn::DataType::Float32>
96 // Checks that outputs and inputs are as we expect them (see definition of CreateBatchNormalizationWorkloadTest).
98 std::move(workload), TensorInfo({2, 3, 1, 1}, DataType::Float32), TensorInfo({2, 3, 1, 1}, DataType::Float32));
101 BOOST_AUTO_TEST_CASE(CreateConvertFp16ToFp32Float32Workload)
104 RefWorkloadFactory factory;
105 auto workload = CreateConvertFp16ToFp32WorkloadTest<RefConvertFp16ToFp32Workload>(factory, graph);
107 // Checks that outputs and inputs are as we expect them
109 std::move(workload), TensorInfo({1, 3, 2, 3}, DataType::Float16), TensorInfo({1, 3, 2, 3}, DataType::Float32));
112 BOOST_AUTO_TEST_CASE(CreateConvertFp32ToFp16Float16Workload)
115 RefWorkloadFactory factory;
116 auto workload = CreateConvertFp32ToFp16WorkloadTest<RefConvertFp32ToFp16Workload>(factory, graph);
118 // Checks that outputs and inputs are as we expect them
120 std::move(workload), TensorInfo({1, 3, 2, 3}, DataType::Float32), TensorInfo({1, 3, 2, 3}, DataType::Float16));
123 BOOST_AUTO_TEST_CASE(CreateConvolution2dWorkload)
126 RefWorkloadFactory factory;
127 auto workload = CreateConvolution2dWorkloadTest<RefConvolution2dFloat32Workload,
128 DataType::Float32>(factory, graph);
130 // Checks that outputs and inputs are as we expect them (see definition of CreateConvolution2dWorkloadTest).
131 CheckInputOutput(std::move(workload),
132 TensorInfo({2, 3, 8, 16}, DataType::Float32),
133 TensorInfo({2, 2, 2, 10}, DataType::Float32));
136 BOOST_AUTO_TEST_CASE(CreateDepthwiseConvolution2dWorkload)
139 RefWorkloadFactory factory;
141 CreateDepthwiseConvolution2dWorkloadTest<RefDepthwiseConvolution2dFloat32Workload>(factory, graph);
143 // Checks that outputs and inputs are as we expect them (see definition of CreateConvolution2dWorkloadTest).
144 CheckInputOutput(std::move(workload),
145 TensorInfo({2, 3, 8, 16}, DataType::Float32),
146 TensorInfo({2, 9, 2, 10}, DataType::Float32));
149 template <typename FullyConnectedWorkloadType, armnn::DataType DataType>
150 static void RefCreateFullyConnectedWorkloadTest()
153 RefWorkloadFactory factory;
154 auto workload = CreateFullyConnectedWorkloadTest<FullyConnectedWorkloadType, DataType>(factory, graph);
156 // Checks that outputs and inputs are as we expect them (see definition of CreateFullyConnectedWorkloadTest).
157 float inputsQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 1.0f : 0.0;
158 float outputQScale = DataType == armnn::DataType::QuantisedAsymm8 ? 2.0f : 0.0;
159 CheckInputOutput(std::move(workload),
160 TensorInfo({ 3, 1, 4, 5 }, DataType, inputsQScale),
161 TensorInfo({ 3, 7 }, DataType, outputQScale));
164 BOOST_AUTO_TEST_CASE(CreateFullyConnectedFloat32Workload)
166 RefCreateFullyConnectedWorkloadTest<RefFullyConnectedFloat32Workload, armnn::DataType::Float32>();
169 BOOST_AUTO_TEST_CASE(CreateFullyConnectedUint8Workload)
171 RefCreateFullyConnectedWorkloadTest<RefFullyConnectedUint8Workload, armnn::DataType::QuantisedAsymm8>();
174 template <typename MultiplicationWorkloadType, armnn::DataType DataType>
175 static void RefCreateMultiplicationWorkloadTest()
178 RefWorkloadFactory factory;
179 auto workload = CreateMultiplicationWorkloadTest<MultiplicationWorkloadType, DataType>(factory, graph);
181 // Checks that outputs are as we expect them (see definition of CreateMultiplicationWorkloadTest).
182 CheckInputsOutput(std::move(workload),
183 TensorInfo({ 2, 3 }, DataType),
184 TensorInfo({ 2, 3 }, DataType),
185 TensorInfo({ 2, 3 }, DataType));
188 BOOST_AUTO_TEST_CASE(CreateMultiplicationFloatWorkload)
190 RefCreateMultiplicationWorkloadTest<RefMultiplicationFloat32Workload, armnn::DataType::Float32>();
193 BOOST_AUTO_TEST_CASE(CreateMultiplicationUint8Workload)
195 RefCreateMultiplicationWorkloadTest<RefMultiplicationUint8Workload, armnn::DataType::QuantisedAsymm8>();
198 BOOST_AUTO_TEST_CASE(CreateNormalizationWorkload)
201 RefWorkloadFactory factory;
202 auto workload = CreateNormalizationWorkloadTest<RefNormalizationFloat32Workload,
203 armnn::DataType::Float32>(factory, graph);
205 // Checks that outputs and inputs are as we expect them (see definition of CreateNormalizationWorkloadTest).
206 CheckInputOutput(std::move(workload),
207 TensorInfo({3, 5, 5, 1}, DataType::Float32),
208 TensorInfo({3, 5, 5, 1}, DataType::Float32));
211 template <typename Pooling2dWorkloadType, armnn::DataType DataType>
212 static void RefCreatePooling2dWorkloadTest()
215 RefWorkloadFactory factory;
216 auto workload = CreatePooling2dWorkloadTest<Pooling2dWorkloadType, DataType>(factory, graph);
218 // Checks that outputs and inputs are as we expect them (see definition of CreatePooling2dWorkloadTest).
221 TensorInfo({3, 2, 5, 5}, DataType),
222 TensorInfo({3, 2, 2, 4}, DataType));
225 BOOST_AUTO_TEST_CASE(CreatePooling2dFloat32Workload)
227 RefCreatePooling2dWorkloadTest<RefPooling2dFloat32Workload, armnn::DataType::Float32>();
230 BOOST_AUTO_TEST_CASE(CreatePooling2dUint8Workload)
232 RefCreatePooling2dWorkloadTest<RefPooling2dUint8Workload, armnn::DataType::QuantisedAsymm8>();
235 template <typename SoftmaxWorkloadType, armnn::DataType DataType>
236 static void RefCreateSoftmaxWorkloadTest()
239 RefWorkloadFactory factory;
240 auto workload = CreateSoftmaxWorkloadTest<SoftmaxWorkloadType, DataType>(factory, graph);
242 // Checks that outputs and inputs are as we expect them (see definition of CreateSoftmaxWorkloadTest).
245 TensorInfo({4, 1}, DataType),
246 TensorInfo({4, 1}, DataType));
249 BOOST_AUTO_TEST_CASE(CreateSoftmaxFloat32Workload)
251 RefCreateSoftmaxWorkloadTest<RefSoftmaxFloat32Workload, armnn::DataType::Float32>();
254 BOOST_AUTO_TEST_CASE(CreateSoftmaxUint8Workload)
256 RefCreateSoftmaxWorkloadTest<RefSoftmaxUint8Workload, armnn::DataType::QuantisedAsymm8>();
259 template <typename SplitterWorkloadType, armnn::DataType DataType>
260 static void RefCreateSplitterWorkloadTest()
263 RefWorkloadFactory factory;
264 auto workload = CreateSplitterWorkloadTest<SplitterWorkloadType, DataType>(factory, graph);
266 // Checks that outputs are as we expect them (see definition of CreateSplitterWorkloadTest).
267 SplitterQueueDescriptor queueDescriptor = workload->GetData();
268 auto inputHandle = boost::polymorphic_downcast<ConstCpuTensorHandle*>(queueDescriptor.m_Inputs[0]);
269 BOOST_TEST((inputHandle->GetTensorInfo() == TensorInfo({ 5, 7, 7 }, DataType)));
271 auto outputHandle0 = boost::polymorphic_downcast<CpuTensorHandle*>(queueDescriptor.m_Outputs[0]);
272 BOOST_TEST((outputHandle0->GetTensorInfo() == TensorInfo({ 1, 7, 7 }, DataType)));
274 auto outputHandle1 = boost::polymorphic_downcast<CpuTensorHandle*>(queueDescriptor.m_Outputs[1]);
275 BOOST_TEST((outputHandle1->GetTensorInfo() == TensorInfo({ 2, 7, 7 }, DataType)));
277 auto outputHandle2 = boost::polymorphic_downcast<CpuTensorHandle*>(queueDescriptor.m_Outputs[2]);
278 BOOST_TEST((outputHandle2->GetTensorInfo() == TensorInfo({ 2, 7, 7 }, DataType)));
281 BOOST_AUTO_TEST_CASE(CreateSplitterFloat32Workload)
283 RefCreateSplitterWorkloadTest<RefSplitterFloat32Workload, armnn::DataType::Float32>();
286 BOOST_AUTO_TEST_CASE(CreateSplitterUint8Workload)
288 RefCreateSplitterWorkloadTest<RefSplitterUint8Workload, armnn::DataType::QuantisedAsymm8>();
291 template <typename SplitterWorkloadType, typename MergerWorkloadType, armnn::DataType DataType>
292 static void RefCreateSplitterMergerWorkloadTest()
294 // Tests that it is possible to decide which output of the splitter layer
295 // should be lined to which input of the merger layer.
296 // We tested that is is possible to specify 0th output
297 // of the splitter to be the 1st input to the merger and the 1st output of the splitter to be 0th input
301 RefWorkloadFactory factory;
302 auto workloads = CreateSplitterMergerWorkloadTest<SplitterWorkloadType, MergerWorkloadType, DataType>
305 auto wlSplitter = std::move(workloads.first);
306 auto wlMerger = std::move(workloads.second);
308 //Checks that the index of inputs/outputs matches what we declared on InputDescriptor construction.
309 armnn::CpuTensorHandle* sOut0 = dynamic_cast<armnn::CpuTensorHandle*>(wlSplitter->GetData().m_Outputs[0]);
310 armnn::CpuTensorHandle* sOut1 = dynamic_cast<armnn::CpuTensorHandle*>(wlSplitter->GetData().m_Outputs[1]);
311 armnn::CpuTensorHandle* mIn0 = dynamic_cast<armnn::CpuTensorHandle*>(wlMerger->GetData().m_Inputs[0]);
312 armnn::CpuTensorHandle* mIn1 = dynamic_cast<armnn::CpuTensorHandle*>(wlMerger->GetData().m_Inputs[1]);
319 bool validDataPointers = (sOut0 == mIn1) && (sOut1 == mIn0);
321 BOOST_TEST(validDataPointers);
324 BOOST_AUTO_TEST_CASE(CreateSplitterMergerFloat32)
326 RefCreateSplitterMergerWorkloadTest<RefSplitterFloat32Workload, RefMergerFloat32Workload, DataType::Float32>();
329 BOOST_AUTO_TEST_CASE(CreateSplitterMergerUint8)
331 RefCreateSplitterMergerWorkloadTest<RefSplitterUint8Workload, RefMergerUint8Workload, DataType::QuantisedAsymm8>();
334 template <typename SplitterWorkloadType, typename ActivationWorkloadType, armnn::DataType DataType>
335 static void RefCreateSingleOutputMultipleInputsTest()
337 // Tests that it is possible to assign multiple (two) different layers to each of the outputs of a splitter layer.
338 // We created a splitter with two outputs. That each of those outputs is used by two different activation layers.
341 RefWorkloadFactory factory;
342 std::unique_ptr<SplitterWorkloadType> wlSplitter;
343 std::unique_ptr<ActivationWorkloadType> wlActiv0_0;
344 std::unique_ptr<ActivationWorkloadType> wlActiv0_1;
345 std::unique_ptr<ActivationWorkloadType> wlActiv1_0;
346 std::unique_ptr<ActivationWorkloadType> wlActiv1_1;
348 CreateSplitterMultipleInputsOneOutputWorkloadTest<SplitterWorkloadType,
349 ActivationWorkloadType, DataType>(factory, graph, wlSplitter, wlActiv0_0, wlActiv0_1, wlActiv1_0, wlActiv1_1);
351 armnn::CpuTensorHandle* sOut0 = dynamic_cast<armnn::CpuTensorHandle*>(wlSplitter->GetData().m_Outputs[0]);
352 armnn::CpuTensorHandle* sOut1 = dynamic_cast<armnn::CpuTensorHandle*>(wlSplitter->GetData().m_Outputs[1]);
353 armnn::CpuTensorHandle* activ0_0Im = dynamic_cast<armnn::CpuTensorHandle*>(wlActiv0_0->GetData().m_Inputs[0]);
354 armnn::CpuTensorHandle* activ0_1Im = dynamic_cast<armnn::CpuTensorHandle*>(wlActiv0_1->GetData().m_Inputs[0]);
355 armnn::CpuTensorHandle* activ1_0Im = dynamic_cast<armnn::CpuTensorHandle*>(wlActiv1_0->GetData().m_Inputs[0]);
356 armnn::CpuTensorHandle* activ1_1Im = dynamic_cast<armnn::CpuTensorHandle*>(wlActiv1_1->GetData().m_Inputs[0]);
361 BOOST_TEST(activ0_0Im);
362 BOOST_TEST(activ0_1Im);
363 BOOST_TEST(activ1_0Im);
364 BOOST_TEST(activ1_1Im);
366 bool validDataPointers = (sOut0 == activ0_0Im) && (sOut0 == activ0_1Im) &&
367 (sOut1 == activ1_0Im) && (sOut1 == activ1_1Im);
369 BOOST_TEST(validDataPointers);
372 BOOST_AUTO_TEST_CASE(CreateSingleOutputMultipleInputsFloat32)
374 RefCreateSingleOutputMultipleInputsTest<RefSplitterFloat32Workload, RefActivationFloat32Workload,
375 armnn::DataType::Float32>();
378 BOOST_AUTO_TEST_CASE(CreateSingleOutputMultipleInputsUint8)
380 RefCreateSingleOutputMultipleInputsTest<RefSplitterUint8Workload, RefActivationUint8Workload,
381 armnn::DataType::QuantisedAsymm8>();
384 template <typename ResizeBilinearWorkloadType, armnn::DataType DataType>
385 static void RefCreateResizeBilinearTest()
388 RefWorkloadFactory factory;
389 auto workload = CreateResizeBilinearWorkloadTest<ResizeBilinearWorkloadType, DataType>(factory, graph);
391 // Checks that outputs and inputs are as we expect them (see definition of CreateResizeBilinearWorkloadTest).
394 TensorInfo({ 2, 3, 4, 4 }, DataType),
395 TensorInfo({ 2, 3, 2, 2 }, DataType));
398 BOOST_AUTO_TEST_CASE(CreateResizeBilinearFloat32)
400 RefCreateResizeBilinearTest<RefResizeBilinearFloat32Workload, armnn::DataType::Float32>();
403 BOOST_AUTO_TEST_CASE(CreateResizeBilinearUint8)
405 RefCreateResizeBilinearTest<RefResizeBilinearUint8Workload, armnn::DataType::QuantisedAsymm8>();
408 BOOST_AUTO_TEST_CASE(CreateL2NormalizationFloat32)
411 RefWorkloadFactory factory;
412 auto workload = CreateL2NormalizationWorkloadTest<RefL2NormalizationFloat32Workload, armnn::DataType::Float32>
415 // Checks that outputs and inputs are as we expect them (see definition of CreateL2NormalizationWorkloadTest).
418 TensorInfo({ 5, 20, 50, 67 }, armnn::DataType::Float32),
419 TensorInfo({ 5, 20, 50, 67 }, armnn::DataType::Float32));
422 template <typename ReshapeWorkloadType, armnn::DataType DataType>
423 static void RefCreateReshapeWorkloadTest()
426 RefWorkloadFactory factory;
427 auto workload = CreateReshapeWorkloadTest<ReshapeWorkloadType, DataType>(factory, graph);
429 // Checks that outputs and inputs are as we expect them (see definition of CreateReshapeWorkloadTest).
432 TensorInfo({ 4, 1 }, DataType),
433 TensorInfo({ 1, 4 }, DataType));
436 BOOST_AUTO_TEST_CASE(CreateReshapeFloat32Workload)
438 RefCreateReshapeWorkloadTest<RefReshapeFloat32Workload, armnn::DataType::Float32>();
441 BOOST_AUTO_TEST_CASE(CreateReshapeUint8Workload)
443 RefCreateReshapeWorkloadTest<RefReshapeUint8Workload, armnn::DataType::QuantisedAsymm8>();
446 BOOST_AUTO_TEST_SUITE_END()