ArmNN
 22.05
FoldPadTests.cpp File Reference
#include "LayersFwd.hpp"
#include <Network.hpp>
#include <TestUtils.hpp>
#include <doctest/doctest.h>
#include <armnn/backends/TensorHandle.hpp>
#include <Optimizer.hpp>

Go to the source code of this file.

Functions

 TEST_SUITE ("Optimizer")
 

Function Documentation

◆ TEST_SUITE()

TEST_SUITE ( "Optimizer"  )

Definition at line 13 of file FoldPadTests.cpp.

References Graph::AddLayer(), armnn::Average, Graph::cbegin(), Graph::cend(), CheckSequence(), IOutputSlot::Connect(), OutputSlot::Connect(), INetwork::Create(), armnn::Exclude, armnn::Float32, BaseTensor< MemoryType >::GetInfo(), IConnectableLayer::GetInputSlot(), Layer::GetInputSlot(), IConnectableLayer::GetOutputSlot(), Layer::GetOutputSlot(), LayerWithParameters< Parameters >::GetParameters(), armnn::IgnoreValue, Convolution2dDescriptor::m_BiasEnabled, DepthwiseConvolution2dDescriptor::m_BiasEnabled, Pooling2dDescriptor::m_DataLayout, Convolution2dDescriptor::m_DataLayout, DepthwiseConvolution2dDescriptor::m_DataLayout, ConstantLayer::m_LayerOutput, Pooling2dDescriptor::m_PadBottom, Pooling2dDescriptor::m_PaddingMethod, Pooling2dDescriptor::m_PadLeft, Pooling2dDescriptor::m_PadRight, Pooling2dDescriptor::m_PadTop, PadDescriptor::m_PadValue, Pooling2dDescriptor::m_PoolHeight, Pooling2dDescriptor::m_PoolType, Pooling2dDescriptor::m_PoolWidth, Pooling2dDescriptor::m_StrideX, Convolution2dDescriptor::m_StrideX, DepthwiseConvolution2dDescriptor::m_StrideX, Pooling2dDescriptor::m_StrideY, Convolution2dDescriptor::m_StrideY, DepthwiseConvolution2dDescriptor::m_StrideY, Convolution2dLayer::m_Weight, armnn::MakeOptimizations(), armnn::Max, armnn::NHWC, Optimizer::Pass(), IOutputSlot::SetTensorInfo(), and OutputSlot::SetTensorInfo().

14 {
15 using namespace armnn;
16 using namespace armnn::optimizations;
17 
18 TEST_CASE("FoldPadLayerIntoConvolution2dLayer")
19 {
20  Graph graph;
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};
25 
26  TensorInfo inputInfo(4, inputShape, DataType::Float32);
27  TensorInfo paddedInfo(4, paddedShape, DataType::Float32);
28  TensorInfo outputInfo(4, outputShape, DataType::Float32);
29 
30  Layer* input = graph.AddLayer<InputLayer>(0, "input");
31  input->GetOutputSlot().SetTensorInfo(inputInfo);
32 
33  PadDescriptor padDescriptor({{0, 0},
34  {2, 2},
35  {2, 2},
36  {0, 0}});
37 
38  PadLayer* padLayer = graph.AddLayer<PadLayer>(padDescriptor, "pad");
39  padLayer->GetOutputSlot().SetTensorInfo(paddedInfo);
40 
41  Convolution2dDescriptor convolution2dDescriptor;
42  convolution2dDescriptor.m_BiasEnabled = false;
43  convolution2dDescriptor.m_StrideX = 1;
44  convolution2dDescriptor.m_StrideY = 1;
45  convolution2dDescriptor.m_DataLayout = DataLayout::NHWC;
46 
47  std::vector<float> weightsVector(18);
48  ConstTensor weights(TensorInfo(4, weightsShape, DataType::Float32, 0.0f, 0, true), weightsVector);
49 
50  ConstantLayer* weightsLayer = graph.AddLayer<ConstantLayer>("Weights");
51  weightsLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(weights);
52 
53  TensorInfo weightsInfo = weightsLayer->m_LayerOutput->GetTensorInfo();
54  weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsInfo);
55 
56  Convolution2dLayer* conv2dLayer = graph.AddLayer<Convolution2dLayer>(convolution2dDescriptor, "conv2d");
57  conv2dLayer->m_Weight = std::make_unique<ScopedTensorHandle>(weights);
58  conv2dLayer->GetOutputSlot().SetTensorInfo(outputInfo);
59 
60  Layer* output = graph.AddLayer<OutputLayer>(0, "output");
61 
62  // Connect up layers - input -> pad -> conv2d -> output
63  input->GetOutputSlot().Connect(padLayer->GetInputSlot(0));
64  padLayer->GetOutputSlot().Connect(conv2dLayer->GetInputSlot(0));
65  weightsLayer->GetOutputSlot().Connect(conv2dLayer->GetInputSlot(1));
66  conv2dLayer->GetOutputSlot().Connect(output->GetInputSlot(0));
67 
68  auto checkSimpleConv2d = [](const Layer* const layer)->bool {
69  const auto conv2dLayer = static_cast<const Convolution2dLayer*>(layer);
70  const auto conv2dLayerParams = conv2dLayer->GetParameters();
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);
76  };
77 
78  CHECK(CheckSequence(graph.cbegin(), graph.cend(),
79  &IsLayerOfType<InputLayer>,
80  &IsLayerOfType<PadLayer>,
81  &IsLayerOfType<ConstantLayer>,
82  checkSimpleConv2d,
83  &IsLayerOfType<OutputLayer>));
84 
86 
87  auto checkPadFoldedIntoConv2d = [](const Layer* const layer)->bool {
88  const auto conv2dLayer = static_cast<const Convolution2dLayer*>(layer);
89  const auto conv2dLayerParams = conv2dLayer->GetParameters();
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);
95  };
96 
97  CHECK(CheckSequence(graph.cbegin(), graph.cend(),
98  &IsLayerOfType<InputLayer>,
99  checkPadFoldedIntoConv2d,
100  &IsLayerOfType<ConstantLayer>,
101  &IsLayerOfType<OutputLayer>));
102 }
103 
104 TEST_CASE("FoldPadLayerIntoDepthwiseConvolution2dLayer")
105 {
106  Graph graph;
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};
111 
112  TensorInfo inputInfo(4, inputShape, DataType::Float32);
113  TensorInfo paddedInfo(4, paddedShape, DataType::Float32);
114  TensorInfo outputInfo(4, outputShape, DataType::Float32);
115 
116  Layer* input = graph.AddLayer<InputLayer>(0, "input");
117  input->GetOutputSlot().SetTensorInfo(inputInfo);
118 
119  PadDescriptor padDescriptor({{0, 0},
120  {2, 2},
121  {2, 2},
122  {0, 0}});
123 
124  PadLayer* padLayer = graph.AddLayer<PadLayer>(padDescriptor, "pad");
125  padLayer->GetOutputSlot().SetTensorInfo(paddedInfo);
126 
127  DepthwiseConvolution2dDescriptor depthwiseConvolution2dDescriptor;
128  depthwiseConvolution2dDescriptor.m_BiasEnabled = false;
129  depthwiseConvolution2dDescriptor.m_StrideX = 1;
130  depthwiseConvolution2dDescriptor.m_StrideY = 1;
131  depthwiseConvolution2dDescriptor.m_DataLayout = DataLayout::NHWC;
132 
133  std::vector<float> weightsVector(18);
134  ConstTensor weights(TensorInfo(4, weightsShape, DataType::Float32, 0.0f, 0, true), weightsVector);
135 
136  auto* depthwiseConv2dLayer = graph.AddLayer<DepthwiseConvolution2dLayer>(depthwiseConvolution2dDescriptor,
137  "depthwiseConv2d");
138  auto* weightsLayer = graph.AddLayer<ConstantLayer>("weights");
139 
140  weightsLayer->GetOutputSlot().SetTensorInfo(weights.GetInfo());
141  depthwiseConv2dLayer->GetOutputSlot().SetTensorInfo(outputInfo);
142  depthwiseConv2dLayer->m_Weight = std::make_shared<ScopedTensorHandle>(weights);
143 
144  Layer* output = graph.AddLayer<OutputLayer>(0, "output");
145 
146  // Connect up layers - input -> pad -> depthwiseConv2d -> output
147  input->GetOutputSlot().Connect(padLayer->GetInputSlot(0));
148  padLayer->GetOutputSlot().Connect(depthwiseConv2dLayer->GetInputSlot(0));
149  weightsLayer->GetOutputSlot().Connect(depthwiseConv2dLayer->GetInputSlot(1));
150  depthwiseConv2dLayer->GetOutputSlot().Connect(output->GetInputSlot(0));
151 
152  auto checkSimpleDepthwiseConv2d = [](const Layer* const layer)->bool {
153  const auto depthwiseConv2dLayer = static_cast<const DepthwiseConvolution2dLayer*>(layer);
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) &&
160  (depthwiseConv2dLayerParams.m_DataLayout == DataLayout::NHWC);
161  };
162 
163  CHECK(CheckSequence(graph.cbegin(), graph.cend(),
164  &IsLayerOfType<InputLayer>,
165  &IsLayerOfType<PadLayer>,
166  checkSimpleDepthwiseConv2d,
167  &IsLayerOfType<ConstantLayer>,
168  &IsLayerOfType<OutputLayer>));
169 
171 
172  auto checkPadFoldedIntoDepthwiseConv2d = [](const Layer* const layer)->bool {
173  const auto depthwiseConv2dLayer = static_cast<const DepthwiseConvolution2dLayer*>(layer);
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) &&
181  (depthwiseConv2dLayerParams.m_DataLayout == DataLayout::NHWC);
182  };
183 
184  CHECK(CheckSequence(graph.cbegin(), graph.cend(),
185  &IsLayerOfType<InputLayer>,
186  checkPadFoldedIntoDepthwiseConv2d,
187  &IsLayerOfType<ConstantLayer>,
188  &IsLayerOfType<OutputLayer>));
189 }
190 
191 TEST_CASE("FoldPadLayerIntoPooling2dLayer")
192 {
193  Graph graph;
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};
197 
198  TensorInfo inputInfo(4, inputShape, DataType::Float32);
199  TensorInfo paddedInfo(4, paddedShape, DataType::Float32);
200  TensorInfo outputInfo(4, outputShape, DataType::Float32);
201 
202  Layer* input = graph.AddLayer<InputLayer>(0, "input");
203  input->GetOutputSlot().SetTensorInfo(inputInfo);
204 
205  PadDescriptor padDescriptor({{0, 0},
206  {1, 1},
207  {1, 1},
208  {0, 0}});
209 
210  PadLayer* padLayer = graph.AddLayer<PadLayer>(padDescriptor, "pad");
211  padLayer->GetOutputSlot().SetTensorInfo(paddedInfo);
212 
213  Pooling2dDescriptor pooling2dDescriptor;
214  pooling2dDescriptor.m_PoolType = PoolingAlgorithm::Average;
215  pooling2dDescriptor.m_PoolWidth = 3;
216  pooling2dDescriptor.m_PoolHeight = 3;
217  pooling2dDescriptor.m_StrideX = 1;
218  pooling2dDescriptor.m_StrideY = 1;
219  pooling2dDescriptor.m_DataLayout = DataLayout::NHWC;
220 
221  Pooling2dLayer* pool2dLayer = graph.AddLayer<Pooling2dLayer>(pooling2dDescriptor, "pool2d");
222  pool2dLayer->GetOutputSlot().SetTensorInfo(outputInfo);
223 
224  Layer* output = graph.AddLayer<OutputLayer>(0, "output");
225 
226  // Connect up layers - input -> pad -> pool2d -> output
227  input->GetOutputSlot().Connect(padLayer->GetInputSlot(0));
228  padLayer->GetOutputSlot().Connect(pool2dLayer->GetInputSlot(0));
229  pool2dLayer->GetOutputSlot().Connect(output->GetInputSlot(0));
230 
231  auto checkSimplePool2d = [&](const Layer* const layer) {
232  const auto pool2dLayer = static_cast<const Pooling2dLayer*>(layer);
233  return IsLayerOfType<Pooling2dLayer>(layer) && (layer->GetNameStr() == "pool2d") &&
234  (pool2dLayer->GetParameters() == pooling2dDescriptor);
235  };
236 
237  CHECK(CheckSequence(graph.cbegin(), graph.cend(),
238  &IsLayerOfType<InputLayer>,
239  &IsLayerOfType<PadLayer>,
240  checkSimplePool2d,
241  &IsLayerOfType<OutputLayer>));
242 
244 
245  auto checkPadFoldedIntoPool2d = [&](const Layer* const layer) {
246  if (!IsLayerOfType<Pooling2dLayer>(layer) || (layer->GetNameStr() != "folded-pad-into-pool2d"))
247  {
248  return false;
249  }
250 
251  const auto pool2dLayer = static_cast<const Pooling2dLayer*>(layer);
252  const Pooling2dDescriptor pool2dLayerParams = pool2dLayer->GetParameters();
253 
254  Pooling2dDescriptor pool2dLayerParamsNoPad = pool2dLayerParams;
255  pool2dLayerParamsNoPad.m_PadLeft = 0;
256  pool2dLayerParamsNoPad.m_PadRight = 0;
257  pool2dLayerParamsNoPad.m_PadTop = 0;
258  pool2dLayerParamsNoPad.m_PadBottom = 0;
259  // If we fold then PaddingMethod will be set to Ignore. The original will be Exclude.
260  pool2dLayerParamsNoPad.m_PaddingMethod = PaddingMethod::Exclude;
261 
262  return (pool2dLayerParamsNoPad == pooling2dDescriptor) && (pool2dLayerParams.m_PadLeft == 1) &&
263  (pool2dLayerParams.m_PadRight == 1) && (pool2dLayerParams.m_PadTop == 1) &&
264  (pool2dLayerParams.m_PadBottom == 1) && (pool2dLayerParams.m_PaddingMethod == PaddingMethod::IgnoreValue);
265  };
266 
267  CHECK(CheckSequence(graph.cbegin(), graph.cend(),
268  &IsLayerOfType<InputLayer>,
269  checkPadFoldedIntoPool2d,
270  &IsLayerOfType<OutputLayer>));
271 }
272 
273 TEST_CASE("FoldPadLayerIntoPooling2d_PadWithMultipleOutputsShouldNotBeOptimized")
274 {
275  // In this test case we'll setup a pad layer with two outputs. One goes to a polling layers and the other
276  // goes to an output layer. FoldPadLayerIntoPooling2d should not optimize this graph as it uses the
277  // OptimizeForExclusiveConnection method.
278  Graph graph;
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};
282 
283  TensorInfo inputInfo(4, inputShape, DataType::Float32);
284  TensorInfo paddedInfo(4, paddedShape, DataType::Float32);
285  TensorInfo outputInfo(4, outputShape, DataType::Float32);
286 
287  Layer* input = graph.AddLayer<InputLayer>(0, "input");
288  input->GetOutputSlot().SetTensorInfo(inputInfo);
289 
290  PadDescriptor padDescriptor({{0, 0},
291  {1, 1},
292  {1, 1},
293  {0, 0}});
294 
295  PadLayer* padLayer = graph.AddLayer<PadLayer>(padDescriptor, "pad");
296  padLayer->GetOutputSlot().SetTensorInfo(paddedInfo);
297 
298  Pooling2dDescriptor pooling2dDescriptor;
299  pooling2dDescriptor.m_PoolType = PoolingAlgorithm::Average;
300  pooling2dDescriptor.m_PoolWidth = 3;
301  pooling2dDescriptor.m_PoolHeight = 3;
302  pooling2dDescriptor.m_StrideX = 1;
303  pooling2dDescriptor.m_StrideY = 1;
304  pooling2dDescriptor.m_DataLayout = DataLayout::NHWC;
305 
306  Pooling2dLayer* pool2dLayer = graph.AddLayer<Pooling2dLayer>(pooling2dDescriptor, "pool2d");
307  pool2dLayer->GetOutputSlot().SetTensorInfo(outputInfo);
308 
309  Layer* output = graph.AddLayer<OutputLayer>(0, "output");
310 
311  // Connect up layers - input -> pad -> pool2d -> output
312  input->GetOutputSlot().Connect(padLayer->GetInputSlot(0));
313  padLayer->GetOutputSlot().Connect(pool2dLayer->GetInputSlot(0));
314  pool2dLayer->GetOutputSlot().Connect(output->GetInputSlot(0));
315 
316  // Add the alternative branch from the pas layer to an output layer.
317  Layer* secondOutput = graph.AddLayer<OutputLayer>(1, "dummy output");
318  padLayer->GetOutputSlot().Connect(secondOutput->GetInputSlot(0));
319 
320  auto checkSimplePool2d = [&](const Layer* const layer) {
321  const auto pool2dLayer = static_cast<const Pooling2dLayer*>(layer);
322  return IsLayerOfType<Pooling2dLayer>(layer) && (layer->GetNameStr() == "pool2d") &&
323  (pool2dLayer->GetParameters() == pooling2dDescriptor);
324  };
325 
326  // Initial sequence.
327  CHECK(CheckSequence(graph.cbegin(), graph.cend(),
328  &IsLayerOfType<InputLayer>,
329  &IsLayerOfType<PadLayer>,
330  checkSimplePool2d,
331  &IsLayerOfType<OutputLayer>,
332  &IsLayerOfType<OutputLayer>));
333 
335 
336  // The network should not change.
337  CHECK(CheckSequence(graph.cbegin(), graph.cend(),
338  &IsLayerOfType<InputLayer>,
339  &IsLayerOfType<PadLayer>,
340  checkSimplePool2d,
341  &IsLayerOfType<OutputLayer>,
342  &IsLayerOfType<OutputLayer>));
343 }
344 
345 TEST_CASE("FoldPadLayerIntoPooling2dLayer_PoolingLayerWithExcludePaddingShouldNotTakeMorePadding")
346 {
347  // In this test setup input, Pad layer, Pooling layer that includes padding, output layer. The optimization
348  // should not work as the pooling layer already includes and existing pad and specifies PaddingMethod::Exclude.
349  Graph graph;
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};
353 
354  TensorInfo inputInfo(4, inputShape, DataType::Float32);
355  TensorInfo paddedInfo(4, paddedShape, DataType::Float32);
356  TensorInfo outputInfo(4, outputShape, DataType::Float32);
357 
358  Layer* input = graph.AddLayer<InputLayer>(0, "input");
359  input->GetOutputSlot().SetTensorInfo(inputInfo);
360 
361  PadDescriptor padDescriptor({{0, 0},
362  {1, 1},
363  {1, 1},
364  {0, 0}});
365 
366  PadLayer* padLayer = graph.AddLayer<PadLayer>(padDescriptor, "pad");
367  padLayer->GetOutputSlot().SetTensorInfo(paddedInfo);
368 
369  Pooling2dDescriptor pooling2dDescriptor;
370  pooling2dDescriptor.m_PoolType = PoolingAlgorithm::Average;
371  pooling2dDescriptor.m_PoolWidth = 3;
372  pooling2dDescriptor.m_PoolHeight = 3;
373  pooling2dDescriptor.m_StrideX = 1;
374  pooling2dDescriptor.m_StrideY = 1;
375  pooling2dDescriptor.m_DataLayout = DataLayout::NHWC;
376  // Include a pad with the pooling layer. This should prevent the optimization working.
377  pooling2dDescriptor.m_PadLeft = 1;
378  pooling2dDescriptor.m_PadRight = 1;
379  pooling2dDescriptor.m_PadTop = 1;
380  pooling2dDescriptor.m_PadBottom = 1;
381  pooling2dDescriptor.m_PaddingMethod = PaddingMethod::Exclude;
382 
383  Pooling2dLayer* pool2dLayer = graph.AddLayer<Pooling2dLayer>(pooling2dDescriptor, "pool2d");
384  pool2dLayer->GetOutputSlot().SetTensorInfo(outputInfo);
385 
386  Layer* output = graph.AddLayer<OutputLayer>(0, "output");
387 
388  // Connect up layers - input -> pad -> pool2d -> output
389  input->GetOutputSlot().Connect(padLayer->GetInputSlot(0));
390  padLayer->GetOutputSlot().Connect(pool2dLayer->GetInputSlot(0));
391  pool2dLayer->GetOutputSlot().Connect(output->GetInputSlot(0));
392 
393  auto checkSimplePool2d = [&](const Layer* const layer) {
394  const auto pool2dLayer = static_cast<const Pooling2dLayer*>(layer);
395  return IsLayerOfType<Pooling2dLayer>(layer) && (layer->GetNameStr() == "pool2d") &&
396  (pool2dLayer->GetParameters() == pooling2dDescriptor);
397  };
398 
399  CHECK(CheckSequence(graph.cbegin(), graph.cend(),
400  &IsLayerOfType<InputLayer>,
401  &IsLayerOfType<PadLayer>,
402  checkSimplePool2d,
403  &IsLayerOfType<OutputLayer>));
404 
406 
407  // The optimization should not have modified the graph.
408  CHECK(CheckSequence(graph.cbegin(), graph.cend(),
409  &IsLayerOfType<InputLayer>,
410  &IsLayerOfType<PadLayer>,
411  checkSimplePool2d,
412  &IsLayerOfType<OutputLayer>));
413 }
414 
415 TEST_CASE("FoldPadLayerIntoPooling2dLayer_MaxPoolingLayerWithLargePadValueShouldNotBeFolded")
416 {
417  // In this test setup input, Pad layer with a large pad value, Max Pooling layer, output layer. The optimization
418  // should not work as the pad value will modify the result of the max pooling layer.
419  Graph graph;
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};
423 
424  TensorInfo inputInfo(4, inputShape, DataType::Float32);
425  TensorInfo paddedInfo(4, paddedShape, DataType::Float32);
426  TensorInfo outputInfo(4, outputShape, DataType::Float32);
427 
428  Layer* input = graph.AddLayer<InputLayer>(0, "input");
429  input->GetOutputSlot().SetTensorInfo(inputInfo);
430 
431  PadDescriptor padDescriptor({{0, 0},
432  {1, 1},
433  {1, 1},
434  {0, 0}});
435  // For Max pooling of a float a pad value of 0 is more than enough to stop the fold happening.
436  // Set this to -std::numeric_limits<float>::infinity() to make the fold happen.
437  padDescriptor.m_PadValue = 0;
438 
439  PadLayer* padLayer = graph.AddLayer<PadLayer>(padDescriptor, "pad");
440  padLayer->GetOutputSlot().SetTensorInfo(paddedInfo);
441 
442  Pooling2dDescriptor pooling2dDescriptor;
443  pooling2dDescriptor.m_PoolType = PoolingAlgorithm::Max;
444  pooling2dDescriptor.m_PoolWidth = 3;
445  pooling2dDescriptor.m_PoolHeight = 3;
446  pooling2dDescriptor.m_StrideX = 1;
447  pooling2dDescriptor.m_StrideY = 1;
448  pooling2dDescriptor.m_DataLayout = DataLayout::NHWC;
449 
450  Pooling2dLayer* pool2dLayer = graph.AddLayer<Pooling2dLayer>(pooling2dDescriptor, "pool2d");
451  pool2dLayer->GetOutputSlot().SetTensorInfo(outputInfo);
452 
453  Layer* output = graph.AddLayer<OutputLayer>(0, "output");
454 
455  // Connect up layers - input -> pad -> pool2d -> output
456  input->GetOutputSlot().Connect(padLayer->GetInputSlot(0));
457  padLayer->GetOutputSlot().Connect(pool2dLayer->GetInputSlot(0));
458  pool2dLayer->GetOutputSlot().Connect(output->GetInputSlot(0));
459 
460  auto checkSimplePool2d = [&](const Layer* const layer) {
461  const auto pool2dLayer = static_cast<const Pooling2dLayer*>(layer);
462  return IsLayerOfType<Pooling2dLayer>(layer) && (layer->GetNameStr() == "pool2d") &&
463  (pool2dLayer->GetParameters() == pooling2dDescriptor);
464  };
465 
466  CHECK(CheckSequence(graph.cbegin(), graph.cend(),
467  &IsLayerOfType<InputLayer>,
468  &IsLayerOfType<PadLayer>,
469  checkSimplePool2d,
470  &IsLayerOfType<OutputLayer>));
471 
473 
474  // The optimization should not have modified the graph.
475  CHECK(CheckSequence(graph.cbegin(), graph.cend(),
476  &IsLayerOfType<InputLayer>,
477  &IsLayerOfType<PadLayer>,
478  checkSimplePool2d,
479  &IsLayerOfType<OutputLayer>));
480 }
481 
482 #if defined(ARMNNREF_ENABLED)
483 TEST_CASE("FoldPadLayerIntoPooling2dLayer_ExecuteInferenceWithAndWithoutOptimization")
484 {
485  // The idea of this test to run a simple pad+pool2d network twice. Once
486  // with FoldPadLayerIntoPooling2dLayer enabled and a second time with it
487  // avoided. The output tensors of each should match.
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,
495 
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,
500  });
501  try
502  {
503  // Create a network of input, pad, pooling 2D, output.
504  INetworkPtr network = INetwork::Create();
505 
506  IConnectableLayer* inputLayer = network->AddInputLayer(0);
507  TensorInfo inputInfo(4, inputShape, DataType::Float32);
508  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
509 
510  PadDescriptor padDescriptor({{0, 0},
511  {1, 1},
512  {1, 1},
513  {0, 0}});
514  IConnectableLayer* padLayer = network->AddPadLayer(padDescriptor, "Pad");
515  TensorInfo paddedInfo(4, paddedShape, DataType::Float32);
516  padLayer->GetOutputSlot(0).SetTensorInfo(paddedInfo);
517 
518  Pooling2dDescriptor pooling2dDescriptor;
519  pooling2dDescriptor.m_PoolType = PoolingAlgorithm::Average;
520  pooling2dDescriptor.m_PoolWidth = 3;
521  pooling2dDescriptor.m_PoolHeight = 3;
522  pooling2dDescriptor.m_StrideX = 1;
523  pooling2dDescriptor.m_StrideY = 1;
524  pooling2dDescriptor.m_DataLayout = DataLayout::NHWC;
525  IConnectableLayer* pool2dLayer = network->AddPooling2dLayer(pooling2dDescriptor, "Pool2D");
526  TensorInfo outputInfo(4, outputShape, DataType::Float32);
527  pool2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
528 
529  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
530 
531  // Connect layers
532  inputLayer->GetOutputSlot(0).Connect(padLayer->GetInputSlot(0));
533  padLayer->GetOutputSlot(0).Connect(pool2dLayer->GetInputSlot(0));
534  pool2dLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
535 
536  // Create ArmNN runtime
537  IRuntimePtr run = IRuntime::Create(IRuntime::CreationOptions()); // default options
538  // Optimise the network
539  IOptimizedNetworkPtr optimizedNetwork = Optimize(*network, {Compute::CpuRef}, run->GetDeviceSpec());
540  // Load network into runtime
541  NetworkId networkIdentifier;
542  CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) == Status::Success);
543 
544  TensorInfo inputTensorInfo = run->GetInputTensorInfo(networkIdentifier, 0);
545  inputTensorInfo.SetConstant(true);
546  InputTensors inputTensors{{0, ConstTensor(inputTensorInfo, inputData.data())}};
547 
548  // Set the initial values of the data to different values to the golden data just in case the inference fails.
549  std::vector<float> optimizedData(32, -std::numeric_limits<float>::infinity());
550  OutputTensors outputTensors{{0, Tensor(outputInfo, optimizedData.data())}};
551  // Execute network
552  run->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
553  // Unload it.
554  run->UnloadNetwork(networkIdentifier);
555 
556  // In this second case the pad will have two outputs, one connected to the pooling layer the second connected to
557  // a second output layer. This will prevent the FoldPadLayerIntoPooling2dLayer optimization from working.
558  // A previous test, FoldPadLayerIntoPooling2d_PadWithMultipleOutputsShouldNotBeOptimized, has proved that doing
559  // this will avoid the optimization.
560  IConnectableLayer* dummyOutputLayer = network->AddOutputLayer(1);
561  padLayer->GetOutputSlot(0).Connect(dummyOutputLayer->GetInputSlot(0));
562 
563  // Optimize and load and execute it a second time.
564  optimizedNetwork = Optimize(*network, {Compute::CpuRef}, run->GetDeviceSpec());
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);
568  OutputTensors goldenTensors{{0, Tensor(outputInfo, goldenData.data())},
569  {1, Tensor(paddedInfo, padOutputData.data())}};
570  run->EnqueueWorkload(networkIdentifier, inputTensors, goldenTensors);
571 
572  // Now we can compare goldenData against optimizedData. They should be the same.
573  CHECK(std::equal(goldenData.begin(), goldenData.end(), optimizedData.begin()));
574  }
575  catch (const std::exception& e)
576  {
577  std::cerr << e.what() << std::endl;
578  ARMNN_ASSERT_MSG(false, e.what());
579  }
580 }
581 
582 TEST_CASE("FoldPadLayerIntoConv2dLayer_ExecuteInferenceWithAndWithoutOptimization")
583 {
584  // The idea of this test to run a simple pad+conv2d network twice. Once
585  // with FoldPadLayerIntoConv2dLayer enabled and a second time with it
586  // avoided. The output tensors of each should match.
587  const unsigned int inputShape[] = {1, 4, 4, 3}; // NHWCin
588  const unsigned int paddedShape[] = {1, 6, 6, 3};
589  const unsigned int weightsShape[] = {4, 2, 2, 3}; // CoutHWCin
590  const unsigned int outputShape[] = {1, 5, 5, 4}; // NHWCout
591 
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,
596 
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,
601 
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,
606  });
607  try
608  {
609  // Create a network of input, pad, pooling 2D, output.
610  INetworkPtr network = INetwork::Create();
611 
612  IConnectableLayer* inputLayer = network->AddInputLayer(0);
613  TensorInfo inputInfo(4, inputShape, DataType::Float32);
614  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
615 
616  PadDescriptor padDescriptor({{0, 0},
617  {1, 1},
618  {1, 1},
619  {0, 0}});
620  IConnectableLayer* padLayer = network->AddPadLayer(padDescriptor, "Pad");
621  TensorInfo paddedInfo(4, paddedShape, DataType::Float32);
622  padLayer->GetOutputSlot(0).SetTensorInfo(paddedInfo);
623 
624  Convolution2dDescriptor convDescriptor;
625  convDescriptor.m_DataLayout = DataLayout::NHWC;
626  convDescriptor.m_StrideX = 1;
627  convDescriptor.m_StrideY = 1;
628  convDescriptor.m_BiasEnabled = true;
629 
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};
634  TensorInfo weightsInfo(4, weightsShape, DataType::Float32, 0.0f, 0, true);
635  ConstTensor weights(weightsInfo, weightsData);
636  std::vector<float> biasVector = {5, 6, 7, 8};
637  TensorInfo biasInfo({4}, DataType::Float32, 0.0f, 0, true);
638  ConstTensor bias(biasInfo, biasVector);
639  Optional<ConstTensor> optionalBias = Optional<ConstTensor>(bias);
641  IConnectableLayer* conv2dLayer = network->AddConvolution2dLayer(convDescriptor,
642  weights,
643  optionalBias,
644  "Conv2D");
646  TensorInfo outputInfo(4, outputShape, DataType::Float32);
647  conv2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
648 
649  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
650 
651  // Connect layers
652  inputLayer->GetOutputSlot(0).Connect(padLayer->GetInputSlot(0));
653  padLayer->GetOutputSlot(0).Connect(conv2dLayer->GetInputSlot(0));
654  conv2dLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
655 
656  // Create ArmNN runtime
657  IRuntimePtr run = IRuntime::Create(IRuntime::CreationOptions()); // default options
658  // Optimise the network
659  IOptimizedNetworkPtr optimizedNetwork = Optimize(*network, {Compute::CpuRef}, run->GetDeviceSpec());
660  // Load network into runtime
661  NetworkId networkIdentifier;
662  CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) == Status::Success);
663 
664  TensorInfo inputTensorInfo = run->GetInputTensorInfo(networkIdentifier, 0);
665  inputTensorInfo.SetConstant(true);
666  InputTensors inputTensors{{0, ConstTensor(inputTensorInfo, inputData.data())}};
667 
668  // Set the initial values of the data to different values to the golden data just in case the inference fails.
669  std::vector<float> optimizedData(100, -std::numeric_limits<float>::infinity());
670  OutputTensors outputTensors{{0, Tensor(outputInfo, optimizedData.data())}};
671  // Execute network
672  run->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
673  // Unload it.
674  run->UnloadNetwork(networkIdentifier);
675 
676  // In this second case the pad will have two outputs, one connected to the conv layer the second connected to
677  // a second output layer. This will prevent the FoldPadLayerIntoConv2dLayer optimization from working.
678  // A previous test, FoldPadLayerIntoConv2d_PadWithMultipleOutputsShouldNotBeOptimized, has proved that doing
679  // this will avoid the optimization.
680  IConnectableLayer* dummyOutputLayer = network->AddOutputLayer(1);
681  padLayer->GetOutputSlot(0).Connect(dummyOutputLayer->GetInputSlot(0));
682 
683  // Optimize and load and execute it a second time.
684  optimizedNetwork = Optimize(*network, {Compute::CpuRef}, run->GetDeviceSpec());
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);
688  OutputTensors goldenTensors{{0, Tensor(outputInfo, goldenData.data())},
689  {1, Tensor(paddedInfo, padOutputData.data())}};
690  run->EnqueueWorkload(networkIdentifier, inputTensors, goldenTensors);
691 
692  // Now we can compare goldenData against optimizedData. They should be the same.
693  CHECK(std::equal(goldenData.begin(), goldenData.end(), optimizedData.begin()));
694  }
695  catch (const std::exception& e)
696  {
697  std::cerr << e.what() << std::endl;
698  ARMNN_ASSERT_MSG(false, e.what());
699  }
700 }
701 
702 TEST_CASE("FoldPadLayerIntoDepthwiseConv2dLayer_ExecuteInferenceWithAndWithoutOptimization")
703 {
704  // The idea of this test to run a simple pad+depthwiseconv2d network twice. Once
705  // with FoldPadLayerIntoDeptwiseConv2dLayer enabled and a second time with it
706  // avoided. The output tensors of each should match.
707  const unsigned int inputShape[] = {1, 4, 4, 3}; // NHWCin
708  const unsigned int paddedShape[] = {1, 6, 6, 3};
709  const unsigned int weightsShape[] = {1, 2, 2, 12}; // 1HWCout
710  const unsigned int outputShape[] = {1, 5, 5, 12}; // NHWCout
711 
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,
716 
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,
721 
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,
726  });
727  try
728  {
729  // Create a network of input, pad, pooling 2D, output.
730  INetworkPtr network = INetwork::Create();
731 
732  IConnectableLayer* inputLayer = network->AddInputLayer(0);
733  TensorInfo inputInfo(4, inputShape, DataType::Float32);
734  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
735 
736  PadDescriptor padDescriptor({{0, 0},
737  {1, 1},
738  {1, 1},
739  {0, 0}});
740  IConnectableLayer* padLayer = network->AddPadLayer(padDescriptor, "Pad");
741  TensorInfo paddedInfo(4, paddedShape, DataType::Float32);
742  padLayer->GetOutputSlot(0).SetTensorInfo(paddedInfo);
743 
744  DepthwiseConvolution2dDescriptor convDescriptor;
745  convDescriptor.m_DataLayout = DataLayout::NHWC;
746  convDescriptor.m_StrideX = 1;
747  convDescriptor.m_StrideY = 1;
748  convDescriptor.m_BiasEnabled = true;
749 
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};
754  TensorInfo weightsInfo(4, weightsShape, DataType::Float32, 0.0f, 0, true);
755  ConstTensor weights(weightsInfo, weightsData);
756  std::vector<float> biasVector = {5, 6, 7, 8, 9, 10, 11, 12, 5, 6, 7, 8};
757  TensorInfo biasInfo({12}, DataType::Float32, 0.0f, 0, true);
758  ConstTensor bias(biasInfo, biasVector);
759 
760  IConnectableLayer* conv2dLayer = network->AddDepthwiseConvolution2dLayer(convDescriptor,
761  "DepthwiseConv2D");
762 
763  TensorInfo outputInfo(4, outputShape, DataType::Float32);
764  conv2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
765 
766  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
767 
768  // Connect layers
769  inputLayer->GetOutputSlot(0).Connect(padLayer->GetInputSlot(0));
770  padLayer->GetOutputSlot(0).Connect(conv2dLayer->GetInputSlot(0));
771  conv2dLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
772 
773  auto weightsLayer = network->AddConstantLayer(weights, "Weights");
774  weightsLayer->GetOutputSlot(0).SetTensorInfo(weights.GetInfo());
775  weightsLayer->GetOutputSlot(0).Connect(conv2dLayer->GetInputSlot(1));
776 
777  auto biasLayer = network->AddConstantLayer(bias, "Bias");
778  biasLayer->GetOutputSlot(0).SetTensorInfo(bias.GetInfo());
779  biasLayer->GetOutputSlot(0).Connect(conv2dLayer->GetInputSlot(2));
780 
781  // Create ArmNN runtime
782  IRuntimePtr run = IRuntime::Create(IRuntime::CreationOptions()); // default options
783  // Optimise the network
784  IOptimizedNetworkPtr optimizedNetwork = Optimize(*network, {Compute::CpuRef}, run->GetDeviceSpec());
785  // Load network into runtime
786  NetworkId networkIdentifier;
787  CHECK(run->LoadNetwork(networkIdentifier, std::move(optimizedNetwork)) == Status::Success);
788 
789  TensorInfo inputTensorInfo = run->GetInputTensorInfo(networkIdentifier, 0);
790  inputTensorInfo.SetConstant(true);
791  InputTensors inputTensors{{0, ConstTensor(inputTensorInfo, inputData.data())}};
792 
793  // Set the initial values of the data to different values to the golden data just in case the inference fails.
794  std::vector<float> optimizedData(300, -std::numeric_limits<float>::infinity());
795  OutputTensors outputTensors{{0, Tensor(outputInfo, optimizedData.data())}};
796  // Execute network
797  run->EnqueueWorkload(networkIdentifier, inputTensors, outputTensors);
798  // Unload it.
799  run->UnloadNetwork(networkIdentifier);
800 
801  // In this second case the pad will have two outputs, one connected to the conv layer the second connected to
802  // a second output layer. This will prevent the FoldPadLayerIntoDepthwiseConv2dLayer optimization from working.
803  // A previous test, FoldPadLayerIntoDepthwiseConv2d_PadWithMultipleOutputsShouldNotBeOptimized, has proved that
804  // doing this will avoid the optimization.
805  IConnectableLayer* dummyOutputLayer = network->AddOutputLayer(1);
806  padLayer->GetOutputSlot(0).Connect(dummyOutputLayer->GetInputSlot(0));
807 
808  // Optimize and load and execute it a second time.
809  optimizedNetwork = Optimize(*network, {Compute::CpuRef}, run->GetDeviceSpec());
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);
813  OutputTensors goldenTensors{{0, Tensor(outputInfo, goldenData.data())},
814  {1, Tensor(paddedInfo, padOutputData.data())}};
815  run->EnqueueWorkload(networkIdentifier, inputTensors, goldenTensors);
816 
817  // Now we can compare goldenData against optimizedData. They should be the same.
818  CHECK(std::equal(goldenData.begin(), goldenData.end(), optimizedData.begin()));
819  }
820  catch (const std::exception& e)
821  {
822  std::cerr << e.what() << std::endl;
823  ARMNN_ASSERT_MSG(false, e.what());
824  }
825 }
826 #endif
827 
828 }
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)
Definition: Runtime.cpp:49
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:66
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)
Definition: Optimizer.hpp:43
bool CheckSequence(const armnn::Graph::ConstIterator first, const armnn::Graph::ConstIterator last)
Definition: TestUtils.hpp:21
OptimizeForExclusiveConnection< PadLayer, DepthwiseConvolution2dLayer, pad_fold::FoldPadIntoDepthwiseConvolution2dImpl > FoldPadIntoDepthwiseConvolution2d
#define ARMNN_NO_DEPRECATE_WARN_BEGIN
Definition: Deprecated.hpp:33
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.
Definition: Graph.hpp:425
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...
Definition: Graph.hpp:179
A Convolution2dDescriptor for the Convolution2dLayer.
int Connect(InputSlot &destination)
Definition: Layer.cpp:112
static void Pass(Graph &graph, const Optimizations &optimizations)
Definition: Optimizer.cpp:16
std::unique_ptr< IRuntime, void(*)(IRuntime *runtime)> IRuntimePtr
Definition: IRuntime.hpp:33
The padding fields don&#39;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
Definition: Tensor.hpp:392
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.
Definition: PadLayer.hpp:14
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.
Definition: Tensor.hpp:319
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.
Definition: Layer.hpp:322
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).
Definition: OutputLayer.hpp:13
uint32_t m_PadRight
Padding right value in the width dimension.
#define ARMNN_NO_DEPRECATE_WARN_END
Definition: Deprecated.hpp:34
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.
Definition: Network.cpp:1847
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15
int NetworkId
Definition: IRuntime.hpp:27
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:327
std::vector< std::pair< LayerBindingId, class Tensor > > OutputTensors
Definition: Tensor.hpp:393
std::unique_ptr< IOptimizedNetwork, void(*)(IOptimizedNetwork *network)> IOptimizedNetworkPtr
Definition: INetwork.hpp:242
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
A layer user-provided data can be bound to (e.g. inputs, outputs).
Definition: InputLayer.hpp:13
void SetTensorInfo(const TensorInfo &tensorInfo) override
Definition: Layer.cpp:87
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.
Definition: Tensor.cpp:514
const OutputSlot & GetOutputSlot(unsigned int index=0) const override
Get the const output slot handle by slot index.
Definition: Layer.hpp:324
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...
Definition: Graph.hpp:181
This layer represents a convolution 2d operation.
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
Definition: INetwork.hpp:241
virtual int Connect(IInputSlot &destination)=0
A Pooling2dDescriptor for the Pooling2dLayer.
static INetworkPtr Create(NetworkOptions networkOptions={})
Definition: Network.cpp:476
uint32_t m_StrideY
Stride value when proceeding through input for the height dimension.
A DepthwiseConvolution2dDescriptor for the DepthwiseConvolution2dLayer.