15 using namespace armnn;
18 TEST_CASE(
"FoldPadLayerIntoConvolution2dLayer")
21 const unsigned int inputShape[] = {1, 2, 2, 3};
22 const unsigned int paddedShape[] = {1, 6, 6, 3};
23 const unsigned int weightsShape[] = {1, 2, 3, 3};
24 const unsigned int outputShape[] = {1, 2, 1, 1};
47 std::vector<float> weightsVector(18);
51 weightsLayer->
m_LayerOutput = std::make_shared<ScopedTensorHandle>(weights);
57 conv2dLayer->
m_Weight = std::make_unique<ScopedTensorHandle>(weights);
64 padLayer->GetOutputSlot().Connect(conv2dLayer->
GetInputSlot(0));
68 auto checkSimpleConv2d = [](
const Layer*
const layer)->
bool {
71 return IsLayerOfType<Convolution2dLayer>(layer) && (layer->GetNameStr() ==
"conv2d") &&
72 (conv2dLayerParams.m_PadLeft == 0) && (conv2dLayerParams.m_PadRight == 0) &&
73 (conv2dLayerParams.m_PadTop == 0) && (conv2dLayerParams.m_PadBottom == 0) &&
74 (conv2dLayerParams.m_StrideX == 1) && (conv2dLayerParams.m_StrideY == 1) &&
75 (conv2dLayerParams.m_BiasEnabled ==
false) && (conv2dLayerParams.m_DataLayout ==
DataLayout::NHWC);
79 &IsLayerOfType<InputLayer>,
80 &IsLayerOfType<PadLayer>,
81 &IsLayerOfType<ConstantLayer>,
83 &IsLayerOfType<OutputLayer>));
87 auto checkPadFoldedIntoConv2d = [](
const Layer*
const layer)->
bool {
90 return IsLayerOfType<Convolution2dLayer>(layer) && (layer->GetNameStr() ==
"folded-pad-into-conv2d") &&
91 (conv2dLayerParams.m_PadLeft == 2) && (conv2dLayerParams.m_PadRight == 2) &&
92 (conv2dLayerParams.m_PadTop == 2) && (conv2dLayerParams.m_PadBottom == 2) &&
93 (conv2dLayerParams.m_StrideX == 1) && (conv2dLayerParams.m_StrideY == 1) &&
94 (conv2dLayerParams.m_BiasEnabled ==
false) && (conv2dLayerParams.m_DataLayout ==
DataLayout::NHWC);
98 &IsLayerOfType<InputLayer>,
99 checkPadFoldedIntoConv2d,
100 &IsLayerOfType<ConstantLayer>,
101 &IsLayerOfType<OutputLayer>));
104 TEST_CASE(
"FoldPadLayerIntoDepthwiseConvolution2dLayer")
107 const unsigned int inputShape[] = {1, 2, 2, 3};
108 const unsigned int paddedShape[] = {1, 6, 6, 3};
109 const unsigned int weightsShape[] = {1, 2, 3, 3};
110 const unsigned int outputShape[] = {1, 2, 1, 3};
129 depthwiseConvolution2dDescriptor.
m_StrideX = 1;
130 depthwiseConvolution2dDescriptor.
m_StrideY = 1;
133 std::vector<float> weightsVector(18);
141 depthwiseConv2dLayer->GetOutputSlot().SetTensorInfo(outputInfo);
142 depthwiseConv2dLayer->m_Weight = std::make_shared<ScopedTensorHandle>(weights);
148 padLayer->GetOutputSlot().Connect(depthwiseConv2dLayer->GetInputSlot(0));
150 depthwiseConv2dLayer->GetOutputSlot().Connect(output->GetInputSlot(0));
152 auto checkSimpleDepthwiseConv2d = [](
const Layer*
const layer)->
bool {
154 const auto depthwiseConv2dLayerParams = depthwiseConv2dLayer->
GetParameters();
155 return IsLayerOfType<DepthwiseConvolution2dLayer>(layer) && (layer->GetNameStr() ==
"depthwiseConv2d") &&
156 (depthwiseConv2dLayerParams.m_PadLeft == 0) && (depthwiseConv2dLayerParams.m_PadRight == 0) &&
157 (depthwiseConv2dLayerParams.m_PadTop == 0) && (depthwiseConv2dLayerParams.m_PadBottom == 0) &&
158 (depthwiseConv2dLayerParams.m_StrideX == 1) && (depthwiseConv2dLayerParams.m_StrideY == 1) &&
159 (depthwiseConv2dLayerParams.m_BiasEnabled ==
false) &&
164 &IsLayerOfType<InputLayer>,
165 &IsLayerOfType<PadLayer>,
166 checkSimpleDepthwiseConv2d,
167 &IsLayerOfType<ConstantLayer>,
168 &IsLayerOfType<OutputLayer>));
172 auto checkPadFoldedIntoDepthwiseConv2d = [](
const Layer*
const layer)->
bool {
174 const auto depthwiseConv2dLayerParams = depthwiseConv2dLayer->
GetParameters();
175 return IsLayerOfType<DepthwiseConvolution2dLayer>(layer) &&
176 (layer->GetNameStr() ==
"folded-pad-into-depthwiseConv2d") &&
177 (depthwiseConv2dLayerParams.m_PadLeft == 2) && (depthwiseConv2dLayerParams.m_PadRight == 2) &&
178 (depthwiseConv2dLayerParams.m_PadTop == 2) && (depthwiseConv2dLayerParams.m_PadBottom == 2) &&
179 (depthwiseConv2dLayerParams.m_StrideX == 1) && (depthwiseConv2dLayerParams.m_StrideY == 1) &&
180 (depthwiseConv2dLayerParams.m_BiasEnabled ==
false) &&
185 &IsLayerOfType<InputLayer>,
186 checkPadFoldedIntoDepthwiseConv2d,
187 &IsLayerOfType<ConstantLayer>,
188 &IsLayerOfType<OutputLayer>));
191 TEST_CASE(
"FoldPadLayerIntoPooling2dLayer")
194 const unsigned int inputShape[] = {1, 2, 2, 3};
195 const unsigned int paddedShape[] = {1, 4, 4, 3};
196 const unsigned int outputShape[] = {1, 2, 2, 3};
228 padLayer->GetOutputSlot().Connect(pool2dLayer->
GetInputSlot(0));
231 auto checkSimplePool2d = [&](
const Layer*
const layer) {
232 const auto pool2dLayer =
static_cast<const Pooling2dLayer*
>(layer);
233 return IsLayerOfType<Pooling2dLayer>(layer) && (layer->GetNameStr() ==
"pool2d") &&
238 &IsLayerOfType<InputLayer>,
239 &IsLayerOfType<PadLayer>,
241 &IsLayerOfType<OutputLayer>));
245 auto checkPadFoldedIntoPool2d = [&](
const Layer*
const layer) {
246 if (!IsLayerOfType<Pooling2dLayer>(layer) || (layer->GetNameStr() !=
"folded-pad-into-pool2d"))
251 const auto pool2dLayer =
static_cast<const Pooling2dLayer*
>(layer);
257 pool2dLayerParamsNoPad.
m_PadTop = 0;
262 return (pool2dLayerParamsNoPad == pooling2dDescriptor) && (pool2dLayerParams.
m_PadLeft == 1) &&
268 &IsLayerOfType<InputLayer>,
269 checkPadFoldedIntoPool2d,
270 &IsLayerOfType<OutputLayer>));
273 TEST_CASE(
"FoldPadLayerIntoPooling2d_PadWithMultipleOutputsShouldNotBeOptimized")
279 const unsigned int inputShape[] = {1, 2, 2, 3};
280 const unsigned int paddedShape[] = {1, 4, 4, 3};
281 const unsigned int outputShape[] = {1, 2, 2, 3};
313 padLayer->GetOutputSlot().Connect(pool2dLayer->
GetInputSlot(0));
320 auto checkSimplePool2d = [&](
const Layer*
const layer) {
321 const auto pool2dLayer =
static_cast<const Pooling2dLayer*
>(layer);
322 return IsLayerOfType<Pooling2dLayer>(layer) && (layer->GetNameStr() ==
"pool2d") &&
328 &IsLayerOfType<InputLayer>,
329 &IsLayerOfType<PadLayer>,
331 &IsLayerOfType<OutputLayer>,
332 &IsLayerOfType<OutputLayer>));
338 &IsLayerOfType<InputLayer>,
339 &IsLayerOfType<PadLayer>,
341 &IsLayerOfType<OutputLayer>,
342 &IsLayerOfType<OutputLayer>));
345 TEST_CASE(
"FoldPadLayerIntoPooling2dLayer_PoolingLayerWithExcludePaddingShouldNotTakeMorePadding")
350 const unsigned int inputShape[] = {1, 2, 2, 3};
351 const unsigned int paddedShape[] = {1, 4, 4, 3};
352 const unsigned int outputShape[] = {1, 2, 2, 3};
390 padLayer->GetOutputSlot().Connect(pool2dLayer->
GetInputSlot(0));
393 auto checkSimplePool2d = [&](
const Layer*
const layer) {
394 const auto pool2dLayer =
static_cast<const Pooling2dLayer*
>(layer);
395 return IsLayerOfType<Pooling2dLayer>(layer) && (layer->GetNameStr() ==
"pool2d") &&
400 &IsLayerOfType<InputLayer>,
401 &IsLayerOfType<PadLayer>,
403 &IsLayerOfType<OutputLayer>));
409 &IsLayerOfType<InputLayer>,
410 &IsLayerOfType<PadLayer>,
412 &IsLayerOfType<OutputLayer>));
415 TEST_CASE(
"FoldPadLayerIntoPooling2dLayer_MaxPoolingLayerWithLargePadValueShouldNotBeFolded")
420 const unsigned int inputShape[] = {1, 2, 2, 3};
421 const unsigned int paddedShape[] = {1, 4, 4, 3};
422 const unsigned int outputShape[] = {1, 2, 2, 3};
437 padDescriptor.m_PadValue = 0;
460 auto checkSimplePool2d = [&](
const Layer*
const layer) {
461 const auto pool2dLayer =
static_cast<const Pooling2dLayer*
>(layer);
462 return IsLayerOfType<Pooling2dLayer>(layer) && (layer->GetNameStr() ==
"pool2d") &&
467 &IsLayerOfType<InputLayer>,
468 &IsLayerOfType<PadLayer>,
470 &IsLayerOfType<OutputLayer>));
476 &IsLayerOfType<InputLayer>,
477 &IsLayerOfType<PadLayer>,
479 &IsLayerOfType<OutputLayer>));
482 #if defined(ARMNNREF_ENABLED) 483 TEST_CASE(
"FoldPadLayerIntoPooling2dLayer_ExecuteInferenceWithAndWithoutOptimization")
488 const unsigned int inputShape[] = {1, 4, 4, 2};
489 const unsigned int paddedShape[] = {1, 6, 6, 2};
490 const unsigned int outputShape[] = {1, 4, 4, 2};
491 std::vector<float> inputData({2.0f, 2.0f, 6.0f, 6.0f,
492 4.0f, 4.0f, 8.0f, 8.0f,
493 10.0f, 12.0f, 14.0f, 16.0f,
494 10.0f, 12.0f, 16.0f, 14.0f,
496 18.0f, 20.0f, 24.0f, 22.0f,
497 20.0f, 18.0f, 22.0f, 24.0f,
498 26.0f, 28.0f, 0.0f, 0.0f,
499 26.0f, 28.0f, 0.0f, 0.0f,
516 padLayer->GetOutputSlot(0).SetTensorInfo(paddedInfo);
525 IConnectableLayer* pool2dLayer = network->AddPooling2dLayer(pooling2dDescriptor,
"Pool2D");
533 padLayer->GetOutputSlot(0).Connect(pool2dLayer->
GetInputSlot(0));
542 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
544 TensorInfo inputTensorInfo = run->GetInputTensorInfo(networkIdentifier, 0);
549 std::vector<float> optimizedData(32, -std::numeric_limits<float>::infinity());
552 run->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
554 run->UnloadNetwork(networkIdentifier);
565 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
566 std::vector<float> goldenData(32, 0.0f);
567 std::vector<float> padOutputData(72, 0.0f);
569 {1,
Tensor(paddedInfo, padOutputData.data())}};
570 run->EnqueueWorkload(networkIdentifier, inputTensors, goldenTensors);
573 CHECK(std::equal(goldenData.begin(), goldenData.end(), optimizedData.begin()));
575 catch (
const std::exception& e)
577 std::cerr << e.what() << std::endl;
582 TEST_CASE(
"FoldPadLayerIntoConv2dLayer_ExecuteInferenceWithAndWithoutOptimization")
587 const unsigned int inputShape[] = {1, 4, 4, 3};
588 const unsigned int paddedShape[] = {1, 6, 6, 3};
589 const unsigned int weightsShape[] = {4, 2, 2, 3};
590 const unsigned int outputShape[] = {1, 5, 5, 4};
592 std::vector<float> inputData({2.0f, 2.0f, 6.0f, 6.0f,
593 4.0f, 4.0f, 8.0f, 8.0f,
594 10.0f, 12.0f, 14.0f, 16.0f,
595 10.0f, 12.0f, 16.0f, 14.0f,
597 18.0f, 20.0f, 24.0f, 22.0f,
598 20.0f, 18.0f, 22.0f, 24.0f,
599 26.0f, 28.0f, 0.0f, 0.0f,
600 26.0f, 28.0f, 0.0f, 0.0f,
602 2.0f, 2.0f, 6.0f, 6.0f,
603 4.0f, 4.0f, 8.0f, 8.0f,
604 10.0f, 12.0f, 14.0f, 16.0f,
605 10.0f, 12.0f, 16.0f, 14.0f,
622 padLayer->GetOutputSlot(0).SetTensorInfo(paddedInfo);
630 std::vector<float> weightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
631 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
632 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
633 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42};
636 std::vector<float> biasVector = {5, 6, 7, 8};
647 conv2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
653 padLayer->GetOutputSlot(0).Connect(conv2dLayer->GetInputSlot(0));
654 conv2dLayer->GetOutputSlot(0).Connect(outputLayer->
GetInputSlot(0));
662 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
664 TensorInfo inputTensorInfo = run->GetInputTensorInfo(networkIdentifier, 0);
669 std::vector<float> optimizedData(100, -std::numeric_limits<float>::infinity());
672 run->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
674 run->UnloadNetwork(networkIdentifier);
685 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
686 std::vector<float> goldenData(100, 0.0f);
687 std::vector<float> padOutputData(108, 0.0f);
689 {1,
Tensor(paddedInfo, padOutputData.data())}};
690 run->EnqueueWorkload(networkIdentifier, inputTensors, goldenTensors);
693 CHECK(std::equal(goldenData.begin(), goldenData.end(), optimizedData.begin()));
695 catch (
const std::exception& e)
697 std::cerr << e.what() << std::endl;
702 TEST_CASE(
"FoldPadLayerIntoDepthwiseConv2dLayer_ExecuteInferenceWithAndWithoutOptimization")
707 const unsigned int inputShape[] = {1, 4, 4, 3};
708 const unsigned int paddedShape[] = {1, 6, 6, 3};
709 const unsigned int weightsShape[] = {1, 2, 2, 12};
710 const unsigned int outputShape[] = {1, 5, 5, 12};
712 std::vector<float> inputData({2.0f, 2.0f, 6.0f, 6.0f,
713 4.0f, 4.0f, 8.0f, 8.0f,
714 10.0f, 12.0f, 14.0f, 16.0f,
715 10.0f, 12.0f, 16.0f, 14.0f,
717 18.0f, 20.0f, 24.0f, 22.0f,
718 20.0f, 18.0f, 22.0f, 24.0f,
719 26.0f, 28.0f, 0.0f, 0.0f,
720 26.0f, 28.0f, 0.0f, 0.0f,
722 2.0f, 2.0f, 6.0f, 6.0f,
723 4.0f, 4.0f, 8.0f, 8.0f,
724 10.0f, 12.0f, 14.0f, 16.0f,
725 10.0f, 12.0f, 16.0f, 14.0f,
742 padLayer->GetOutputSlot(0).SetTensorInfo(paddedInfo);
750 std::vector<float> weightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
751 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
752 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
753 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42};
756 std::vector<float> biasVector = {5, 6, 7, 8, 9, 10, 11, 12, 5, 6, 7, 8};
760 IConnectableLayer* conv2dLayer = network->AddDepthwiseConvolution2dLayer(convDescriptor,
770 padLayer->GetOutputSlot(0).Connect(conv2dLayer->
GetInputSlot(0));
773 auto weightsLayer = network->AddConstantLayer(weights,
"Weights");
777 auto biasLayer = network->AddConstantLayer(bias,
"Bias");
778 biasLayer->GetOutputSlot(0).SetTensorInfo(bias.GetInfo());
779 biasLayer->GetOutputSlot(0).Connect(conv2dLayer->
GetInputSlot(2));
787 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
789 TensorInfo inputTensorInfo = run->GetInputTensorInfo(networkIdentifier, 0);
794 std::vector<float> optimizedData(300, -std::numeric_limits<float>::infinity());
797 run->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
799 run->UnloadNetwork(networkIdentifier);
810 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
811 std::vector<float> goldenData(300, 0.0f);
812 std::vector<float> padOutputData(108, 0.0f);
814 {1,
Tensor(paddedInfo, padOutputData.data())}};
815 run->EnqueueWorkload(networkIdentifier, inputTensors, goldenTensors);
818 CHECK(std::equal(goldenData.begin(), goldenData.end(), optimizedData.begin()));
820 catch (
const std::exception& e)
822 std::cerr << e.what() << std::endl;
A layer that the constant data can be bound to.
bool m_BiasEnabled
Enable/disable bias.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
static IRuntimePtr Create(const CreationOptions &options)
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.
bool m_BiasEnabled
Enable/disable bias.
CPU Execution: Reference C++ kernels.
uint32_t m_PadLeft
Padding left value in the width dimension.
OptimizeForExclusiveConnection< PadLayer, Convolution2dLayer, pad_fold::FoldPadIntoConvolution2dImpl > FoldPadIntoConvolution2d
Optimizer::Optimizations MakeOptimizations(Args &&... args)
bool CheckSequence(const armnn::Graph::ConstIterator first, const armnn::Graph::ConstIterator last)
OptimizeForExclusiveConnection< PadLayer, DepthwiseConvolution2dLayer, pad_fold::FoldPadIntoDepthwiseConvolution2dImpl > FoldPadIntoDepthwiseConvolution2d
#define ARMNN_NO_DEPRECATE_WARN_BEGIN
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
This layer represents a depthwise convolution 2d operation.
std::shared_ptr< ConstTensorHandle > m_LayerOutput
LayerT * AddLayer(Args &&... args)
Adds a new layer, of type LayerType, to the graph constructed with the arguments passed.
uint32_t m_PoolWidth
Pooling width value.
ConstIterator cbegin() const
Returns const iterator pointing to the beginning of the list. Lowercase for range-based for loops...
A Convolution2dDescriptor for the Convolution2dLayer.
int Connect(InputSlot &destination)
static void Pass(Graph &graph, const Optimizations &optimizations)
std::unique_ptr< IRuntime, void(*)(IRuntime *runtime)> IRuntimePtr
The padding fields don't count and are ignored.
PaddingMethod m_PaddingMethod
The padding method to be used. (Exclude, IgnoreValue).
std::shared_ptr< ConstTensorHandle > m_Weight
A unique pointer to store Weight values.
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.
const Parameters & GetParameters() const override
If the layer has a descriptor return it.
This layer represents a pad operation.
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.
A PadDescriptor for the PadLayer.
const InputSlot & GetInputSlot(unsigned int index) const override
Get a const input slot handle by slot index.
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
uint32_t m_StrideX
Stride value when proceeding through input for the width dimension.
A layer user-provided data can be bound to (e.g. inputs, outputs).
uint32_t m_PadRight
Padding right value in the width dimension.
#define ARMNN_NO_DEPRECATE_WARN_END
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.
#define ARMNN_ASSERT_MSG(COND, MSG)
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
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
This layer represents a pooling 2d operation.
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
PoolingAlgorithm m_PoolType
The pooling algorithm to use (Max. Average, L2).
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
The padding fields count, but are ignored.
OptimizeForExclusiveConnection< PadLayer, Pooling2dLayer, pad_fold::FoldPadIntoPooling2dImpl > FoldPadIntoPooling2d
void SetTensorInfo(const TensorInfo &tensorInfo) override
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 OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
Get the const output slot handle by slot index.
ConstIterator cend() const
Returns const iterator pointing to the end of the list. Lowercase for range-based for loops...
This layer represents a convolution 2d operation.
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
virtual int Connect(IInputSlot &destination)=0
A Pooling2dDescriptor for the Pooling2dLayer.
static INetworkPtr Create(NetworkOptions networkOptions={})
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
A DepthwiseConvolution2dDescriptor for the DepthwiseConvolution2dLayer.