15 #include <arm_compute/runtime/Allocator.h> 18 #include <doctest/doctest.h> 23 using namespace armnn;
25 TEST_CASE(
"NeonTensorHandleGetCapabilitiesNoPadding")
27 std::shared_ptr<NeonMemoryManager> memoryManager = std::make_shared<NeonMemoryManager>();
44 std::vector<Capability> capabilities = handleFactory.GetCapabilities(input,
47 CHECK(capabilities.empty());
51 CHECK(capabilities.empty());
55 CHECK(capabilities.empty());
58 TEST_CASE(
"NeonTensorHandleGetCapabilitiesPadding")
60 std::shared_ptr<NeonMemoryManager> memoryManager = std::make_shared<NeonMemoryManager>();
76 std::vector<Capability> capabilities = handleFactory.GetCapabilities(input,
79 CHECK(capabilities.empty());
83 CHECK(capabilities.empty());
87 CHECK(capabilities.size() == 1);
89 CHECK(capabilities[0].m_Value);
92 TEST_CASE(
"ConcatOnXorYSubTensorsNoPaddingRequiredTest")
116 std::array<armnn::TensorShape, 2> concatInputShapes = { intermediateInfo.GetShape(), intermediateInfo.GetShape() };
118 concatInputShapes.begin(), concatInputShapes.end(), 2),
"concatenation");
136 runtime->LoadNetwork(networkIdentifier, std::move(optimizedNet));
141 if (subTensorHandle && subTensorHandle->GetParent())
148 for (
auto&& layer : theGraph)
152 unsigned int numberOfSubTensors = 0;
153 for (
unsigned int i = 0; i < layer->GetNumInputSlots(); ++i)
158 ++numberOfSubTensors;
167 TEST_CASE(
"ConcatonXorYPaddingRequiredTest")
178 descriptor.m_PoolWidth = descriptor.m_PoolHeight = 3;
179 descriptor.m_StrideX = descriptor.m_StrideY = 1;
180 descriptor.m_PadLeft = 1;
181 descriptor.m_PadRight = 1;
182 descriptor.m_PadTop = 1;
183 descriptor.m_PadBottom = 1;
199 std::array<armnn::TensorShape, 2> concatInputShapes = { intermediateInfo.GetShape(), intermediateInfo.GetShape() };
201 concatInputShapes.begin(), concatInputShapes.end(), 2),
"concatenation");
219 runtime->LoadNetwork(networkIdentifier, std::move(optimizedNet));
224 if (subTensorHandle && subTensorHandle->GetParent())
231 unsigned int numberOfSubTensors = 0;
232 for (
auto&& layer : theGraph)
236 for (
unsigned int i = 0; i < layer->GetNumInputSlots(); ++i)
241 ++numberOfSubTensors;
250 TEST_CASE(
"SplitteronXorYNoPaddingRequiredTest")
252 using namespace armnn;
254 unsigned int splitAxis = 2;
255 unsigned int numSplit = 2;
259 const std::vector<TensorShape> outputShapes{{ 2, 3, 2, 2 },
261 const float qScale = 1.0f;
262 const int32_t qOffset = 0;
265 std::vector<float> inputData{
292 std::vector<float> expectedOutput0{
307 std::vector<float> expectedOutput1{
335 splitterDimSizes[i] = inputTensorInfo.
GetShape()[i];
338 if (splitterDimSizes[splitAxis] % numSplit != 0)
340 throw ParseException(
"Number of splits must evenly divide the dimension");
343 splitterDimSizes[splitAxis] /= numSplit;
347 for (
unsigned int g = 0; g < numSplit; ++g)
350 for (
unsigned int dimIdx = 0; dimIdx < splitterDimSizes.size(); ++dimIdx)
352 splitDesc.
SetViewSize(g, dimIdx, splitterDimSizes[dimIdx]);
354 splitDesc.SetViewOriginCoord(g, splitAxis, splitterDimSizes[splitAxis] * g);
357 IConnectableLayer* elementWiseUnary0 = net->AddElementwiseUnaryLayer(descriptor,
"elementwiseunary_0");
358 IConnectableLayer* elementWiseUnary1 = net->AddElementwiseUnaryLayer(descriptor,
"elementwiseunary_0");
362 Connect(input, splitter, inputTensorInfo, 0, 0);
363 Connect(splitter, elementWiseUnary0, intermediateInfo, 0, 0);
364 Connect(splitter, elementWiseUnary1, intermediateInfo, 1, 0);
366 std::vector<IConnectableLayer*> pooling2dLayers{elementWiseUnary0, elementWiseUnary1};
368 for (
unsigned int i = 0; i < outputShapes.size(); ++i)
371 IConnectableLayer* output = net->AddOutputLayer(armnn::numeric_cast<LayerBindingId>(i));
372 Connect(pooling2dLayers[i], output, outputTensorInfo, 0, 0);
375 std::map<int, std::vector<float>> inputTensorData = {{ 0,inputData }};
376 std::map<int, std::vector<float>> expectedOutputData = {{ 0, expectedOutput0 }, { 1, expectedOutput1 }};
388 runtime->LoadNetwork(networkIdentifier, std::move(optimizedNet));
393 if (subTensorHandle && subTensorHandle->GetParent())
400 for (
auto&& layer : theGraph)
404 unsigned int numberOfSubTensors = 0;
405 for (
unsigned int i = 0; i < layer->GetNumInputSlots(); ++i)
410 ++numberOfSubTensors;
419 inputTensors.reserve(inputTensorData.size());
420 for (
auto&& it : inputTensorData)
422 inputTensors.push_back({it.first,
423 ConstTensor(runtime->GetInputTensorInfo(networkIdentifier, it.first), it.second.data())});
426 outputTensors.reserve(expectedOutputData.size());
427 std::map<int, std::vector<float>> outputStorage;
428 for (
auto&& it : expectedOutputData)
430 std::vector<float> out(it.second.size());
431 outputStorage.emplace(it.first, out);
432 outputTensors.push_back({it.first,
433 Tensor(runtime->GetOutputTensorInfo(networkIdentifier, it.first),
434 outputStorage.at(it.first).data())});
438 runtime->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
441 float tolerance = 0.000001f;
442 for (
auto&& it : expectedOutputData)
444 std::vector<float> out = outputStorage.at(it.first);
445 for (
unsigned int i = 0; i < out.size(); ++i)
447 CHECK_MESSAGE(Compare<armnn::DataType::Float32>(it.second[i], out[i], tolerance) ==
true,
448 "Actual output: " << out[i] <<
". Expected output:" << it.second[i]);
454 TEST_CASE(
"SplitteronXorYPaddingRequiredTest")
456 using namespace armnn;
458 unsigned int splitAxis = 2;
459 unsigned int numSplit = 2;
463 const std::vector<TensorShape> outputShapes{{ 1, 1, 2, 4 },
466 const float qScale = 1.0f;
467 const int32_t qOffset = 0;
470 std::vector<float> inputData{
471 9.0f, 27.0f, 18.0f, 36.0f,
472 18.0f, 9.0f, 18.0f, 9.0f,
473 27.0f, 18.0f, 9.0f, 27.0f,
474 9.0f, 27.0f, 9.0f, 18.0f,
477 std::vector<float> expectedOutput0{
478 7.0f, 11.0f, 13.0f, 9.0f,
479 7.0f, 11.0f, 13.0f, 9.0f
482 std::vector<float> expectedOutput1{
483 9.0f, 11.0f, 12.0f, 7.0f,
484 9.0f, 11.0f, 12.0f, 7.0f
509 splitterDimSizes[i] = inputTensorInfo.
GetShape()[i];
512 if (splitterDimSizes[splitAxis] % numSplit != 0)
514 throw ParseException(
"Number of splits must evenly divide the dimension");
517 splitterDimSizes[splitAxis] /= numSplit;
521 for (
unsigned int g = 0; g < numSplit; ++g)
524 for (
unsigned int dimIdx = 0; dimIdx < splitterDimSizes.size(); ++dimIdx)
526 splitDesc.
SetViewSize(g, dimIdx, splitterDimSizes[dimIdx]);
528 splitDesc.SetViewOriginCoord(g, splitAxis, splitterDimSizes[splitAxis] * g);
532 IConnectableLayer* pooling2d0 = net->AddPooling2dLayer(descriptor,
"pooling2d_0");
533 IConnectableLayer* pooling2d1 = net->AddPooling2dLayer(descriptor,
"pooling2d_1");
537 Connect(input, splitter, inputTensorInfo, 0, 0);
538 Connect(splitter, pooling2d0, intermediateInfo, 0, 0);
539 Connect(splitter, pooling2d1, intermediateInfo, 1, 0);
541 std::vector<IConnectableLayer*> pooling2dLayers{pooling2d0, pooling2d1};
543 for (
unsigned int i = 0; i < outputShapes.size(); ++i)
546 IConnectableLayer* output = net->AddOutputLayer(armnn::numeric_cast<LayerBindingId>(i));
547 Connect(pooling2dLayers[i], output, outputTensorInfo, 0, 0);
550 std::map<int, std::vector<float>> inputTensorData = {{ 0,inputData }};
551 std::map<int, std::vector<float>> expectedOutputData = {{ 0, expectedOutput0 }, { 1, expectedOutput1 }};
563 runtime->LoadNetwork(networkIdentifier, std::move(optimizedNet));
568 if (subTensorHandle && subTensorHandle->GetParent())
575 for (
auto&& layer : theGraph)
579 unsigned int numberOfSubTensors = 0;
580 for (
unsigned int i = 0; i < layer->GetNumInputSlots(); ++i)
585 ++numberOfSubTensors;
594 inputTensors.reserve(inputTensorData.size());
595 for (
auto&& it : inputTensorData)
597 inputTensors.push_back({it.first,
598 ConstTensor(runtime->GetInputTensorInfo(networkIdentifier, it.first), it.second.data())});
601 outputTensors.reserve(expectedOutputData.size());
602 std::map<int, std::vector<float>> outputStorage;
603 for (
auto&& it : expectedOutputData)
605 std::vector<float> out(it.second.size());
606 outputStorage.emplace(it.first, out);
607 outputTensors.push_back({it.first,
608 Tensor(runtime->GetOutputTensorInfo(networkIdentifier, it.first),
609 outputStorage.at(it.first).data())});
613 runtime->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
616 float tolerance = 0.000001f;
617 for (
auto&& it : expectedOutputData)
619 std::vector<float> out = outputStorage.at(it.first);
620 for (
unsigned int i = 0; i < out.size(); ++i)
622 CHECK_MESSAGE(Compare<armnn::DataType::Float32>(it.second[i], out[i], tolerance) ==
true,
623 "Actual output: " << out[i] <<
". Expected output:" << it.second[i]);
629 TEST_CASE(
"NeonTensorHandleFactoryMemoryManaged")
631 std::shared_ptr<NeonMemoryManager> memoryManager = std::make_shared<NeonMemoryManager>(
632 std::make_unique<arm_compute::Allocator>(),
642 memoryManager->Acquire();
644 float* buffer =
reinterpret_cast<float*
>(handle->Map());
645 CHECK(buffer !=
nullptr);
648 CHECK(buffer[0] == 1.5f);
649 CHECK(buffer[1] == 2.5f);
651 memoryManager->Release();
653 memoryManager->Acquire();
655 float* buffer =
reinterpret_cast<float*
>(handle->Map());
656 CHECK(buffer !=
nullptr);
659 CHECK(buffer[0] == 3.5f);
660 CHECK(buffer[1] == 4.5f);
662 memoryManager->Release();
664 float testPtr[2] = { 2.5f, 5.5f };
669 TEST_CASE(
"NeonTensorHandleFactoryImport")
671 std::shared_ptr<NeonMemoryManager> memoryManager = std::make_shared<NeonMemoryManager>(
672 std::make_unique<arm_compute::Allocator>(),
681 memoryManager->Acquire();
684 CHECK((PolymorphicDowncast<NeonTensorHandle*>(handle.get()))->GetTensor().buffer() ==
nullptr);
686 float testPtr[2] = { 2.5f, 5.5f };
689 float* buffer =
reinterpret_cast<float*
>(handle->Map());
690 CHECK(buffer !=
nullptr);
691 CHECK(buffer == testPtr);
693 CHECK(buffer[0] == 2.5f);
694 CHECK(buffer[1] == 5.5f);
697 CHECK(buffer[0] == 3.5f);
698 CHECK(buffer[1] == 10.0f);
699 memoryManager->Release();
702 TEST_CASE(
"NeonTensorHandleSupportsInPlaceComputation")
704 std::shared_ptr<NeonMemoryManager> memoryManager = std::make_shared<NeonMemoryManager>();
708 ARMNN_ASSERT(handleFactory.SupportsInPlaceComputation());
static IRuntimePtr Create(const CreationOptions &options)
A ViewsDescriptor for the SplitterLayer.
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
uint32_t m_PadBottom
Padding bottom value in the height dimension.
const TensorShape & GetShape() const
uint32_t m_PadLeft
Padding left value in the width dimension.
std::unique_ptr< ITensorHandle > CreateTensorHandle(const TensorInfo &tensorInfo) const override
uint32_t m_PoolWidth
Pooling width value.
float m_Beta
Exponentiation value.
std::unique_ptr< IRuntime, void(*)(IRuntime *runtime)> IRuntimePtr
PaddingMethod m_PaddingMethod
The padding method to be used. (Exclude, IgnoreValue).
uint32_t m_PadTop
Padding top value in the height dimension.
std::vector< std::pair< LayerBindingId, class ConstTensor > > InputTensors
Copyright (c) 2021 ARM Limited and Contributors.
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
A tensor defined by a TensorInfo (shape and data type) and a mutable backing store.
uint32_t m_PoolHeight
Pooling height value.
uint32_t m_PadRight
Padding right value in the width dimension.
IOptimizedNetworkPtr Optimize(const INetwork &network, const std::vector< BackendId > &backendPreferences, const IDeviceSpec &deviceSpec, const OptimizerOptions &options=OptimizerOptions(), Optional< std::vector< std::string > &> messages=EmptyOptional())
Create an optimized version of the network.
Status SetViewSize(uint32_t view, uint32_t coord, uint32_t value)
Set the size of the views.
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
std::vector< std::pair< LayerBindingId, class Tensor > > OutputTensors
std::unique_ptr< IOptimizedNetwork, void(*)(IOptimizedNetwork *network)> IOptimizedNetworkPtr
#define ARMNN_ASSERT(COND)
ITensorHandle * GetData() const
Gets the allocated tensor memory.
TEST_SUITE("NeonTensorHandleTests")
Graph & GetGraphForTesting(IOptimizedNetwork *optNet)
A ElementwiseUnaryDescriptor for the ElementwiseUnaryLayer.
PoolingAlgorithm m_PoolType
The pooling algorithm to use (Max. Average, L2).
The padding fields count, but are ignored.
CPU Execution: NEON: ArmCompute.
unsigned int GetNumDimensions() const
Function that returns the tensor rank.
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
Get a const input slot handle by slot index.
const OutputHandler & GetOutputHandler() const
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
Get the const output slot handle by slot index.
void Connect(armnn::IConnectableLayer *from, armnn::IConnectableLayer *to, const armnn::TensorInfo &tensorInfo, unsigned int fromIndex, unsigned int toIndex)
OriginsDescriptor CreateDescriptorForConcatenation(TensorShapeIt first, TensorShapeIt last, unsigned int concatenationDimension)
Convenience template to create an OriginsDescriptor to use when creating a ConcatLayer for performing...
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
virtual int Connect(IInputSlot &destination)=0
A Pooling2dDescriptor for the Pooling2dLayer.
static INetworkPtr Create(NetworkOptions networkOptions={})
A SoftmaxDescriptor for the SoftmaxLayer.
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.