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);
529 TensorInfo inputTensorInfo = run->GetInputTensorInfo(networkIdentifier, 0);
534 std::vector<float> optimizedData(32, -std::numeric_limits<float>::infinity());
537 run->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
539 run->UnloadNetwork(networkIdentifier);
550 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
551 std::vector<float> goldenData(32, 0.0f);
552 std::vector<float> padOutputData(72, 0.0f);
554 {1,
Tensor(paddedInfo, padOutputData.data())}};
555 run->EnqueueWorkload(networkIdentifier, inputTensors, goldenTensors);
558 CHECK(std::equal(goldenData.begin(), goldenData.end(), optimizedData.begin()));
560 catch (
const std::exception& e)
562 std::cerr << e.what() << std::endl;
567 TEST_CASE(
"FoldPadLayerIntoConv2dLayer_ExecuteInferenceWithAndWithoutOptimization")
572 const unsigned int inputShape[] = {1, 4, 4, 3};
573 const unsigned int paddedShape[] = {1, 6, 6, 3};
574 const unsigned int weightsShape[] = {4, 2, 2, 3};
575 const unsigned int outputShape[] = {1, 5, 5, 4};
577 std::vector<float> inputData({2.0f, 2.0f, 6.0f, 6.0f,
578 4.0f, 4.0f, 8.0f, 8.0f,
579 10.0f, 12.0f, 14.0f, 16.0f,
580 10.0f, 12.0f, 16.0f, 14.0f,
582 18.0f, 20.0f, 24.0f, 22.0f,
583 20.0f, 18.0f, 22.0f, 24.0f,
584 26.0f, 28.0f, 0.0f, 0.0f,
585 26.0f, 28.0f, 0.0f, 0.0f,
587 2.0f, 2.0f, 6.0f, 6.0f,
588 4.0f, 4.0f, 8.0f, 8.0f,
589 10.0f, 12.0f, 14.0f, 16.0f,
590 10.0f, 12.0f, 16.0f, 14.0f,
607 padLayer->GetOutputSlot(0).SetTensorInfo(paddedInfo);
615 std::vector<float> weightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
616 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
617 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
618 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42};
621 std::vector<float> biasVector = {5, 6, 7, 8};
632 conv2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
638 padLayer->GetOutputSlot(0).Connect(conv2dLayer->GetInputSlot(0));
639 conv2dLayer->GetOutputSlot(0).Connect(outputLayer->
GetInputSlot(0));
647 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
649 TensorInfo inputTensorInfo = run->GetInputTensorInfo(networkIdentifier, 0);
654 std::vector<float> optimizedData(100, -std::numeric_limits<float>::infinity());
657 run->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
659 run->UnloadNetwork(networkIdentifier);
670 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
671 std::vector<float> goldenData(100, 0.0f);
672 std::vector<float> padOutputData(108, 0.0f);
674 {1,
Tensor(paddedInfo, padOutputData.data())}};
675 run->EnqueueWorkload(networkIdentifier, inputTensors, goldenTensors);
678 CHECK(std::equal(goldenData.begin(), goldenData.end(), optimizedData.begin()));
680 catch (
const std::exception& e)
682 std::cerr << e.what() << std::endl;
687 TEST_CASE(
"FoldPadLayerIntoDepthwiseConv2dLayer_ExecuteInferenceWithAndWithoutOptimization")
692 const unsigned int inputShape[] = {1, 4, 4, 3};
693 const unsigned int paddedShape[] = {1, 6, 6, 3};
694 const unsigned int weightsShape[] = {1, 2, 2, 12};
695 const unsigned int outputShape[] = {1, 5, 5, 12};
697 std::vector<float> inputData({2.0f, 2.0f, 6.0f, 6.0f,
698 4.0f, 4.0f, 8.0f, 8.0f,
699 10.0f, 12.0f, 14.0f, 16.0f,
700 10.0f, 12.0f, 16.0f, 14.0f,
702 18.0f, 20.0f, 24.0f, 22.0f,
703 20.0f, 18.0f, 22.0f, 24.0f,
704 26.0f, 28.0f, 0.0f, 0.0f,
705 26.0f, 28.0f, 0.0f, 0.0f,
707 2.0f, 2.0f, 6.0f, 6.0f,
708 4.0f, 4.0f, 8.0f, 8.0f,
709 10.0f, 12.0f, 14.0f, 16.0f,
710 10.0f, 12.0f, 16.0f, 14.0f,
727 padLayer->GetOutputSlot(0).SetTensorInfo(paddedInfo);
735 std::vector<float> weightsData = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12,
736 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22,
737 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31, 32,
738 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42};
741 std::vector<float> biasVector = {5, 6, 7, 8, 9, 10, 11, 12, 5, 6, 7, 8};
746 IConnectableLayer* conv2dLayer = network->AddDepthwiseConvolution2dLayer(convDescriptor,
752 conv2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
758 padLayer->GetOutputSlot(0).Connect(conv2dLayer->GetInputSlot(0));
759 conv2dLayer->GetOutputSlot(0).Connect(outputLayer->
GetInputSlot(0));
767 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
769 TensorInfo inputTensorInfo = run->GetInputTensorInfo(networkIdentifier, 0);
774 std::vector<float> optimizedData(300, -std::numeric_limits<float>::infinity());
777 run->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
779 run->UnloadNetwork(networkIdentifier);
790 CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) ==
Status::Success);
791 std::vector<float> goldenData(300, 0.0f);
792 std::vector<float> padOutputData(108, 0.0f);
794 {1,
Tensor(paddedInfo, padOutputData.data())}};
795 run->EnqueueWorkload(networkIdentifier, inputTensors, goldenTensors);
798 CHECK(std::equal(goldenData.begin(), goldenData.end(), optimizedData.begin()));
800 catch (
const std::exception& e)
802 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.
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.