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 TensorInfo inputTensorInfo = runtime->GetInputTensorInfo(networkIdentifier, it.first);
424 inputTensors.push_back({it.first,
428 outputTensors.reserve(expectedOutputData.size());
429 std::map<int, std::vector<float>> outputStorage;
430 for (
auto&& it : expectedOutputData)
432 std::vector<float> out(it.second.size());
433 outputStorage.emplace(it.first, out);
434 outputTensors.push_back({it.first,
435 Tensor(runtime->GetOutputTensorInfo(networkIdentifier, it.first),
436 outputStorage.at(it.first).data())});
440 runtime->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
443 float tolerance = 0.000001f;
444 for (
auto&& it : expectedOutputData)
446 std::vector<float> out = outputStorage.at(it.first);
447 for (
unsigned int i = 0; i < out.size(); ++i)
449 CHECK_MESSAGE(Compare<armnn::DataType::Float32>(it.second[i], out[i], tolerance) ==
true,
450 "Actual output: " << out[i] <<
". Expected output:" << it.second[i]);
456 TEST_CASE(
"SplitteronXorYPaddingRequiredTest")
458 using namespace armnn;
460 unsigned int splitAxis = 2;
461 unsigned int numSplit = 2;
465 const std::vector<TensorShape> outputShapes{{ 1, 1, 2, 4 },
468 const float qScale = 1.0f;
469 const int32_t qOffset = 0;
472 std::vector<float> inputData{
473 9.0f, 27.0f, 18.0f, 36.0f,
474 18.0f, 9.0f, 18.0f, 9.0f,
475 27.0f, 18.0f, 9.0f, 27.0f,
476 9.0f, 27.0f, 9.0f, 18.0f,
479 std::vector<float> expectedOutput0{
480 7.0f, 11.0f, 13.0f, 9.0f,
481 7.0f, 11.0f, 13.0f, 9.0f
484 std::vector<float> expectedOutput1{
485 9.0f, 11.0f, 12.0f, 7.0f,
486 9.0f, 11.0f, 12.0f, 7.0f
511 splitterDimSizes[i] = inputTensorInfo.
GetShape()[i];
514 if (splitterDimSizes[splitAxis] % numSplit != 0)
516 throw ParseException(
"Number of splits must evenly divide the dimension");
519 splitterDimSizes[splitAxis] /= numSplit;
523 for (
unsigned int g = 0; g < numSplit; ++g)
526 for (
unsigned int dimIdx = 0; dimIdx < splitterDimSizes.size(); ++dimIdx)
528 splitDesc.
SetViewSize(g, dimIdx, splitterDimSizes[dimIdx]);
530 splitDesc.SetViewOriginCoord(g, splitAxis, splitterDimSizes[splitAxis] * g);
534 IConnectableLayer* pooling2d0 = net->AddPooling2dLayer(descriptor,
"pooling2d_0");
535 IConnectableLayer* pooling2d1 = net->AddPooling2dLayer(descriptor,
"pooling2d_1");
539 Connect(input, splitter, inputTensorInfo, 0, 0);
540 Connect(splitter, pooling2d0, intermediateInfo, 0, 0);
541 Connect(splitter, pooling2d1, intermediateInfo, 1, 0);
543 std::vector<IConnectableLayer*> pooling2dLayers{pooling2d0, pooling2d1};
545 for (
unsigned int i = 0; i < outputShapes.size(); ++i)
548 IConnectableLayer* output = net->AddOutputLayer(armnn::numeric_cast<LayerBindingId>(i));
549 Connect(pooling2dLayers[i], output, outputTensorInfo, 0, 0);
552 std::map<int, std::vector<float>> inputTensorData = {{ 0,inputData }};
553 std::map<int, std::vector<float>> expectedOutputData = {{ 0, expectedOutput0 }, { 1, expectedOutput1 }};
565 runtime->LoadNetwork(networkIdentifier, std::move(optimizedNet));
570 if (subTensorHandle && subTensorHandle->GetParent())
577 for (
auto&& layer : theGraph)
581 unsigned int numberOfSubTensors = 0;
582 for (
unsigned int i = 0; i < layer->GetNumInputSlots(); ++i)
587 ++numberOfSubTensors;
596 inputTensors.reserve(inputTensorData.size());
597 for (
auto&& it : inputTensorData)
599 TensorInfo inputTensorInfo = runtime->GetInputTensorInfo(networkIdentifier, it.first);
601 inputTensors.push_back({it.first,
605 outputTensors.reserve(expectedOutputData.size());
606 std::map<int, std::vector<float>> outputStorage;
607 for (
auto&& it : expectedOutputData)
609 std::vector<float> out(it.second.size());
610 outputStorage.emplace(it.first, out);
611 outputTensors.push_back({it.first,
612 Tensor(runtime->GetOutputTensorInfo(networkIdentifier, it.first),
613 outputStorage.at(it.first).data())});
617 runtime->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
620 float tolerance = 0.000001f;
621 for (
auto&& it : expectedOutputData)
623 std::vector<float> out = outputStorage.at(it.first);
624 for (
unsigned int i = 0; i < out.size(); ++i)
626 CHECK_MESSAGE(Compare<armnn::DataType::Float32>(it.second[i], out[i], tolerance) ==
true,
627 "Actual output: " << out[i] <<
". Expected output:" << it.second[i]);
633 TEST_CASE(
"NeonTensorHandleFactoryMemoryManaged")
635 std::shared_ptr<NeonMemoryManager> memoryManager = std::make_shared<NeonMemoryManager>(
636 std::make_unique<arm_compute::Allocator>(),
642 auto handle = handleFactory.CreateTensorHandle(info,
true);
646 memoryManager->Acquire();
648 float* buffer =
reinterpret_cast<float*
>(handle->Map());
649 CHECK(buffer !=
nullptr);
652 CHECK(buffer[0] == 1.5f);
653 CHECK(buffer[1] == 2.5f);
655 memoryManager->Release();
657 memoryManager->Acquire();
659 float* buffer =
reinterpret_cast<float*
>(handle->Map());
660 CHECK(buffer !=
nullptr);
663 CHECK(buffer[0] == 3.5f);
664 CHECK(buffer[1] == 4.5f);
666 memoryManager->Release();
668 float testPtr[2] = { 2.5f, 5.5f };
673 TEST_CASE(
"NeonTensorHandleFactoryImport")
675 std::shared_ptr<NeonMemoryManager> memoryManager = std::make_shared<NeonMemoryManager>(
676 std::make_unique<arm_compute::Allocator>(),
682 auto handle = handleFactory.CreateTensorHandle(info,
false);
685 memoryManager->Acquire();
688 CHECK((PolymorphicDowncast<NeonTensorHandle*>(handle.get()))->GetTensor().buffer() ==
nullptr);
690 float testPtr[2] = { 2.5f, 5.5f };
693 float* buffer =
reinterpret_cast<float*
>(handle->Map());
694 CHECK(buffer !=
nullptr);
695 CHECK(buffer == testPtr);
697 CHECK(buffer[0] == 2.5f);
698 CHECK(buffer[1] == 5.5f);
701 CHECK(buffer[0] == 3.5f);
702 CHECK(buffer[1] == 10.0f);
703 memoryManager->Release();
706 TEST_CASE(
"NeonTensorHandleCanBeImported")
708 std::shared_ptr<NeonMemoryManager> memoryManager = std::make_shared<NeonMemoryManager>(
709 std::make_unique<arm_compute::Allocator>(),
715 auto handle = handleFactory.CreateTensorHandle(info,
false);
718 float alignedBuffer[2] = { 2.5f, 5.5f };
723 float* misalignedBuffer =
reinterpret_cast<float*
>(
reinterpret_cast<char*
>(alignedBuffer) + 1);
725 CHECK(handle->CanBeImported(static_cast<void*>(misalignedBuffer),
MemorySource::Malloc) ==
false);
728 TEST_CASE(
"NeonTensorHandleSupportsInPlaceComputation")
730 std::shared_ptr<NeonMemoryManager> memoryManager = std::make_shared<NeonMemoryManager>();
734 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.
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.
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.
void SetConstant(const bool IsConstant=true)
Marks the data corresponding to this tensor info as constant.
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.