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 conv2dLayer->
m_Weight = std::make_unique<ScopedTensorHandle>(weights);
58 padLayer->GetOutputSlot().Connect(conv2dLayer->
GetInputSlot(0));
61 auto checkSimpleConv2d = [](
const Layer*
const layer)->
bool {
64 return IsLayerOfType<Convolution2dLayer>(layer) && (layer->GetNameStr() ==
"conv2d") &&
65 (conv2dLayerParams.m_PadLeft == 0) && (conv2dLayerParams.m_PadRight == 0) &&
66 (conv2dLayerParams.m_PadTop == 0) && (conv2dLayerParams.m_PadBottom == 0) &&
67 (conv2dLayerParams.m_StrideX == 1) && (conv2dLayerParams.m_StrideY == 1) &&
68 (conv2dLayerParams.m_BiasEnabled ==
false) && (conv2dLayerParams.m_DataLayout ==
DataLayout::NHWC);
72 &IsLayerOfType<InputLayer>,
73 &IsLayerOfType<PadLayer>,
75 &IsLayerOfType<OutputLayer>));
79 auto checkPadFoldedIntoConv2d = [](
const Layer*
const layer)->
bool {
82 return IsLayerOfType<Convolution2dLayer>(layer) && (layer->GetNameStr() ==
"folded-pad-into-conv2d") &&
83 (conv2dLayerParams.m_PadLeft == 2) && (conv2dLayerParams.m_PadRight == 2) &&
84 (conv2dLayerParams.m_PadTop == 2) && (conv2dLayerParams.m_PadBottom == 2) &&
85 (conv2dLayerParams.m_StrideX == 1) && (conv2dLayerParams.m_StrideY == 1) &&
86 (conv2dLayerParams.m_BiasEnabled ==
false) && (conv2dLayerParams.m_DataLayout ==
DataLayout::NHWC);
90 &IsLayerOfType<InputLayer>,
91 checkPadFoldedIntoConv2d,
92 &IsLayerOfType<OutputLayer>));
95 TEST_CASE(
"FoldPadLayerIntoDepthwiseConvolution2dLayer")
98 const unsigned int inputShape[] = {1, 2, 2, 3};
99 const unsigned int paddedShape[] = {1, 6, 6, 3};
100 const unsigned int weightsShape[] = {1, 2, 3, 3};
101 const unsigned int outputShape[] = {1, 2, 1, 3};
120 depthwiseConvolution2dDescriptor.
m_StrideX = 1;
121 depthwiseConvolution2dDescriptor.
m_StrideY = 1;
124 std::vector<float> weightsVector(18);
129 depthwiseConv2dLayer->
m_Weight = std::make_unique<ScopedTensorHandle>(weights);
130 depthwiseConv2dLayer->GetOutputSlot().SetTensorInfo(outputInfo);
136 padLayer->GetOutputSlot().Connect(depthwiseConv2dLayer->GetInputSlot(0));
137 depthwiseConv2dLayer->GetOutputSlot().Connect(output->
GetInputSlot(0));
139 auto checkSimpleDepthwiseConv2d = [](
const Layer*
const layer)->
bool {
141 const auto depthwiseConv2dLayerParams = depthwiseConv2dLayer->
GetParameters();
142 return IsLayerOfType<DepthwiseConvolution2dLayer>(layer) && (layer->GetNameStr() ==
"depthwiseConv2d") &&
143 (depthwiseConv2dLayerParams.m_PadLeft == 0) && (depthwiseConv2dLayerParams.m_PadRight == 0) &&
144 (depthwiseConv2dLayerParams.m_PadTop == 0) && (depthwiseConv2dLayerParams.m_PadBottom == 0) &&
145 (depthwiseConv2dLayerParams.m_StrideX == 1) && (depthwiseConv2dLayerParams.m_StrideY == 1) &&
146 (depthwiseConv2dLayerParams.m_BiasEnabled ==
false) &&
151 &IsLayerOfType<InputLayer>,
152 &IsLayerOfType<PadLayer>,
153 checkSimpleDepthwiseConv2d,
154 &IsLayerOfType<OutputLayer>));
158 auto checkPadFoldedIntoDepthwiseConv2d = [](
const Layer*
const layer)->
bool {
160 const auto depthwiseConv2dLayerParams = depthwiseConv2dLayer->
GetParameters();
161 return IsLayerOfType<DepthwiseConvolution2dLayer>(layer) &&
162 (layer->GetNameStr() ==
"folded-pad-into-depthwiseConv2d") &&
163 (depthwiseConv2dLayerParams.m_PadLeft == 2) && (depthwiseConv2dLayerParams.m_PadRight == 2) &&
164 (depthwiseConv2dLayerParams.m_PadTop == 2) && (depthwiseConv2dLayerParams.m_PadBottom == 2) &&
165 (depthwiseConv2dLayerParams.m_StrideX == 1) && (depthwiseConv2dLayerParams.m_StrideY == 1) &&
166 (depthwiseConv2dLayerParams.m_BiasEnabled ==
false) &&
171 &IsLayerOfType<InputLayer>,
172 checkPadFoldedIntoDepthwiseConv2d,
173 &IsLayerOfType<OutputLayer>));
176 TEST_CASE(
"FoldPadLayerIntoPooling2dLayer")
179 const unsigned int inputShape[] = {1, 2, 2, 3};
180 const unsigned int paddedShape[] = {1, 4, 4, 3};
181 const unsigned int outputShape[] = {1, 2, 2, 3};
213 padLayer->GetOutputSlot().Connect(pool2dLayer->
GetInputSlot(0));
216 auto checkSimplePool2d = [&](
const Layer*
const layer) {
217 const auto pool2dLayer =
static_cast<const Pooling2dLayer*
>(layer);
218 return IsLayerOfType<Pooling2dLayer>(layer) && (layer->GetNameStr() ==
"pool2d") &&
223 &IsLayerOfType<InputLayer>,
224 &IsLayerOfType<PadLayer>,
226 &IsLayerOfType<OutputLayer>));
230 auto checkPadFoldedIntoPool2d = [&](
const Layer*
const layer) {
231 if (!IsLayerOfType<Pooling2dLayer>(layer) || (layer->GetNameStr() !=
"folded-pad-into-pool2d"))
236 const auto pool2dLayer =
static_cast<const Pooling2dLayer*
>(layer);
242 pool2dLayerParamsNoPad.
m_PadTop = 0;
247 return (pool2dLayerParamsNoPad == pooling2dDescriptor) && (pool2dLayerParams.
m_PadLeft == 1) &&
253 &IsLayerOfType<InputLayer>,
254 checkPadFoldedIntoPool2d,
255 &IsLayerOfType<OutputLayer>));
258 TEST_CASE(
"FoldPadLayerIntoPooling2d_PadWithMultipleOutputsShouldNotBeOptimized")
264 const unsigned int inputShape[] = {1, 2, 2, 3};
265 const unsigned int paddedShape[] = {1, 4, 4, 3};
266 const unsigned int outputShape[] = {1, 2, 2, 3};
298 padLayer->GetOutputSlot().Connect(pool2dLayer->
GetInputSlot(0));
305 auto checkSimplePool2d = [&](
const Layer*
const layer) {
306 const auto pool2dLayer =
static_cast<const Pooling2dLayer*
>(layer);
307 return IsLayerOfType<Pooling2dLayer>(layer) && (layer->GetNameStr() ==
"pool2d") &&
313 &IsLayerOfType<InputLayer>,
314 &IsLayerOfType<PadLayer>,
316 &IsLayerOfType<OutputLayer>,
317 &IsLayerOfType<OutputLayer>));
323 &IsLayerOfType<InputLayer>,
324 &IsLayerOfType<PadLayer>,
326 &IsLayerOfType<OutputLayer>,
327 &IsLayerOfType<OutputLayer>));
330 TEST_CASE(
"FoldPadLayerIntoPooling2dLayer_PoolingLayerWithExcludePaddingShouldNotTakeMorePadding")
335 const unsigned int inputShape[] = {1, 2, 2, 3};
336 const unsigned int paddedShape[] = {1, 4, 4, 3};
337 const unsigned int outputShape[] = {1, 2, 2, 3};
375 padLayer->GetOutputSlot().Connect(pool2dLayer->
GetInputSlot(0));
378 auto checkSimplePool2d = [&](
const Layer*
const layer) {
379 const auto pool2dLayer =
static_cast<const Pooling2dLayer*
>(layer);
380 return IsLayerOfType<Pooling2dLayer>(layer) && (layer->GetNameStr() ==
"pool2d") &&
385 &IsLayerOfType<InputLayer>,
386 &IsLayerOfType<PadLayer>,
388 &IsLayerOfType<OutputLayer>));
394 &IsLayerOfType<InputLayer>,
395 &IsLayerOfType<PadLayer>,
397 &IsLayerOfType<OutputLayer>));
400 TEST_CASE(
"FoldPadLayerIntoPooling2dLayer_MaxPoolingLayerWithLargePadValueShouldNotBeFolded")
405 const unsigned int inputShape[] = {1, 2, 2, 3};
406 const unsigned int paddedShape[] = {1, 4, 4, 3};
407 const unsigned int outputShape[] = {1, 2, 2, 3};
422 padDescriptor.m_PadValue = 0;
445 auto checkSimplePool2d = [&](
const Layer*
const layer) {
446 const auto pool2dLayer =
static_cast<const Pooling2dLayer*
>(layer);
447 return IsLayerOfType<Pooling2dLayer>(layer) && (layer->GetNameStr() ==
"pool2d") &&
452 &IsLayerOfType<InputLayer>,
453 &IsLayerOfType<PadLayer>,
455 &IsLayerOfType<OutputLayer>));
461 &IsLayerOfType<InputLayer>,
462 &IsLayerOfType<PadLayer>,
464 &IsLayerOfType<OutputLayer>));
467 #if defined(ARMNNREF_ENABLED) 468 TEST_CASE(
"FoldPadLayerIntoPooling2dLayer_ExecuteInferenceWithAndWithoutOptimization")
473 const unsigned int inputShape[] = {1, 4, 4, 2};
474 const unsigned int paddedShape[] = {1, 6, 6, 2};
475 const unsigned int outputShape[] = {1, 4, 4, 2};
476 std::vector<float> inputData({2.0f, 2.0f, 6.0f, 6.0f,
477 4.0f, 4.0f, 8.0f, 8.0f,
478 10.0f, 12.0f, 14.0f, 16.0f,
479 10.0f, 12.0f, 16.0f, 14.0f,
481 18.0f, 20.0f, 24.0f, 22.0f,
482 20.0f, 18.0f, 22.0f, 24.0f,
483 26.0f, 28.0f, 0.0f, 0.0f,
484 26.0f, 28.0f, 0.0f, 0.0f,
501 padLayer->GetOutputSlot(0).SetTensorInfo(paddedInfo);
510 IConnectableLayer* pool2dLayer = network->AddPooling2dLayer(pooling2dDescriptor,
"Pool2D");
518 padLayer->GetOutputSlot(0).Connect(pool2dLayer->
GetInputSlot(0));
527 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
532 std::vector<float> optimizedData(32, -std::numeric_limits<float>::infinity());
535 run->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
537 run->UnloadNetwork(networkIdentifier);
548 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
549 std::vector<float> goldenData(32, 0.0f);
550 std::vector<float> padOutputData(72, 0.0f);
552 {1,
Tensor(paddedInfo, padOutputData.data())}};
553 run->EnqueueWorkload(networkIdentifier, inputTensors, goldenTensors);
556 CHECK(std::equal(goldenData.begin(), goldenData.end(), optimizedData.begin()));
558 catch (
const std::exception& e)
560 std::cerr << e.what() << std::endl;
565 TEST_CASE(
"FoldPadLayerIntoConv2dLayer_ExecuteInferenceWithAndWithoutOptimization")
570 const unsigned int inputShape[] = {1, 4, 4, 3};
571 const unsigned int paddedShape[] = {1, 6, 6, 3};
572 const unsigned int weightsShape[] = {4, 2, 2, 3};
573 const unsigned int outputShape[] = {1, 5, 5, 4};
575 std::vector<float> inputData({2.0f, 2.0f, 6.0f, 6.0f,
576 4.0f, 4.0f, 8.0f, 8.0f,
577 10.0f, 12.0f, 14.0f, 16.0f,
578 10.0f, 12.0f, 16.0f, 14.0f,
580 18.0f, 20.0f, 24.0f, 22.0f,
581 20.0f, 18.0f, 22.0f, 24.0f,
582 26.0f, 28.0f, 0.0f, 0.0f,
583 26.0f, 28.0f, 0.0f, 0.0f,
585 2.0f, 2.0f, 6.0f, 6.0f,
586 4.0f, 4.0f, 8.0f, 8.0f,
587 10.0f, 12.0f, 14.0f, 16.0f,
588 10.0f, 12.0f, 16.0f, 14.0f,
605 padLayer->GetOutputSlot(0).SetTensorInfo(paddedInfo);
613 std::vector<float> weightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
614 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
615 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
616 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42};
619 std::vector<float> biasVector = {5, 6, 7, 8};
630 conv2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
636 padLayer->GetOutputSlot(0).Connect(conv2dLayer->GetInputSlot(0));
637 conv2dLayer->GetOutputSlot(0).Connect(outputLayer->
GetInputSlot(0));
645 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
650 std::vector<float> optimizedData(100, -std::numeric_limits<float>::infinity());
653 run->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
655 run->UnloadNetwork(networkIdentifier);
666 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
667 std::vector<float> goldenData(100, 0.0f);
668 std::vector<float> padOutputData(108, 0.0f);
670 {1,
Tensor(paddedInfo, padOutputData.data())}};
671 run->EnqueueWorkload(networkIdentifier, inputTensors, goldenTensors);
674 CHECK(std::equal(goldenData.begin(), goldenData.end(), optimizedData.begin()));
676 catch (
const std::exception& e)
678 std::cerr << e.what() << std::endl;
683 TEST_CASE(
"FoldPadLayerIntoDepthwiseConv2dLayer_ExecuteInferenceWithAndWithoutOptimization")
688 const unsigned int inputShape[] = {1, 4, 4, 3};
689 const unsigned int paddedShape[] = {1, 6, 6, 3};
690 const unsigned int weightsShape[] = {1, 2, 2, 12};
691 const unsigned int outputShape[] = {1, 5, 5, 12};
693 std::vector<float> inputData({2.0f, 2.0f, 6.0f, 6.0f,
694 4.0f, 4.0f, 8.0f, 8.0f,
695 10.0f, 12.0f, 14.0f, 16.0f,
696 10.0f, 12.0f, 16.0f, 14.0f,
698 18.0f, 20.0f, 24.0f, 22.0f,
699 20.0f, 18.0f, 22.0f, 24.0f,
700 26.0f, 28.0f, 0.0f, 0.0f,
701 26.0f, 28.0f, 0.0f, 0.0f,
703 2.0f, 2.0f, 6.0f, 6.0f,
704 4.0f, 4.0f, 8.0f, 8.0f,
705 10.0f, 12.0f, 14.0f, 16.0f,
706 10.0f, 12.0f, 16.0f, 14.0f,
723 padLayer->GetOutputSlot(0).SetTensorInfo(paddedInfo);
731 std::vector<float> weightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
732 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
733 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
734 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42};
737 std::vector<float> biasVector = {5, 6, 7, 8, 9, 10, 11, 12, 5, 6, 7, 8};
742 IConnectableLayer* conv2dLayer = network->AddDepthwiseConvolution2dLayer(convDescriptor,
748 conv2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
754 padLayer->GetOutputSlot(0).Connect(conv2dLayer->GetInputSlot(0));
755 conv2dLayer->GetOutputSlot(0).Connect(outputLayer->
GetInputSlot(0));
763 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
768 std::vector<float> optimizedData(300, -std::numeric_limits<float>::infinity());
771 run->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
773 run->UnloadNetwork(networkIdentifier);
784 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
785 std::vector<float> goldenData(300, 0.0f);
786 std::vector<float> padOutputData(108, 0.0f);
788 {1,
Tensor(paddedInfo, padOutputData.data())}};
789 run->EnqueueWorkload(networkIdentifier, inputTensors, goldenTensors);
792 CHECK(std::equal(goldenData.begin(), goldenData.end(), optimizedData.begin()));
794 catch (
const std::exception& e)
796 std::cerr << e.what() << std::endl;
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.
const Parameters & GetParameters() const
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)
OptimizeForExclusiveConnection< PadLayer, DepthwiseConvolution2dLayer, pad_fold::FoldPadIntoDepthwiseConvolution2dImpl > FoldPadIntoDepthwiseConvolution2d
DataLayout m_DataLayout
The data layout to be used (NCHW, NHWC).
This layer represents a depthwise convolution 2d operation.
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.
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.
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.
std::shared_ptr< ConstTensorHandle > m_Weight
A unique pointer to store Weight values.
OptimizeForExclusiveConnection< PadLayer, Pooling2dLayer, pad_fold::FoldPadIntoPooling2dImpl > FoldPadIntoPooling2d
bool CheckSequence(const armnn::Graph::ConstIterator first, const armnn::Graph::ConstIterator last)
void SetTensorInfo(const TensorInfo &tensorInfo) override
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
Get a const input slot handle by slot index.
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.