ArmNN
 21.02
QuantizerTest.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd and Contributors. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include "../Graph.hpp"
7 #include "../Network.hpp"
8 #include "../NetworkQuantizerUtils.hpp"
9 #include "../OverrideInputRangeVisitor.hpp"
10 
11 #include <armnn/INetwork.hpp>
12 #include <armnn/Tensor.hpp>
13 #include <armnn/Types.hpp>
17 #include <QuantizeHelper.hpp>
18 
19 #include <boost/test/unit_test.hpp>
20 
21 #include <unordered_map>
22 
23 namespace armnn
24 {
25 using MinMaxRange = std::pair<float, float>;
26 using MinMaxRanges = std::vector<MinMaxRange>;
27 using MinMaxRangeMap = std::unordered_map<LayerGuid, MinMaxRanges>;
28 
29 const float g_AsymmU8QuantizationBase = 255.0f;
30 // Coinciding with calcution which for AsymmS8 which calculates scale on an unsigned basis
31 const float g_AsymmS8QuantizationBase = 255.0f;
32 const float g_SymmS8QuantizationBase = 127.0f;
33 const float g_SymmS16QuantizationBase = 32767.0f;
34 const float g_TestTolerance = 0.000001f;
35 
36 class TestConnectionPreservation : public LayerVisitorBase<VisitorNoThrowPolicy>
37 {
38 public:
39  TestConnectionPreservation(INetwork* network)
41  , m_Network(network)
42  {}
43 
44  void VisitAdditionLayer(const IConnectableLayer* layer, const char*) override
45  {
46  CheckLayerName(layer->GetInputSlot(0).GetConnection()->GetOwningLayerGuid(), "reLU1");
47  CheckLayerName(layer->GetInputSlot(1).GetConnection()->GetOwningLayerGuid(), "reLU2");
48  }
49 
50  void CheckLayerName(LayerGuid guid, std::string expectedName)
51  {
52  auto graph = m_Network->pNetworkImpl->GetGraph();
53  bool guidFound = false;
54  for (Layer* layer : graph)
55  {
56  if (layer->GetGuid() == guid)
57  {
58  BOOST_CHECK_EQUAL(layer->GetName(), expectedName.c_str());
59  guidFound = true;
60  break;
61  }
62  }
63  if (!guidFound)
64  {
65  BOOST_FAIL("No layer matching the GUID was found");
66  }
67  }
68 
69 private:
70  INetwork* m_Network;
71 };
72 
73 void VisitLayersTopologically(const INetwork* inputNetwork, IStrategy& visitor)
74 {
75  auto graph = inputNetwork->pNetworkImpl->GetGraph().TopologicalSort();
76 
77  ApplyStrategyToLayers(graph, visitor);
78 }
79 
81 {
82  for (auto&& inputLayer : network->pNetworkImpl->GetGraph().GetInputLayers())
83  {
84  ARMNN_ASSERT_MSG(inputLayer->GetNumOutputSlots() == 1, "Input layer should have exactly 1 output slot");
85  return inputLayer->GetOutputSlot(0).GetTensorInfo();
86  }
87  throw InvalidArgumentException("Network has no input layers");
88 }
89 
91 {
92  for (auto&& inputLayer : network->GetGraph().GetInputLayers())
93  {
94  ARMNN_ASSERT_MSG(inputLayer->GetNumOutputSlots() == 1, "Input layer should have exactly 1 output slot");
95  return inputLayer->GetOutputSlot(0).GetTensorInfo();
96  }
97  throw InvalidArgumentException("Network has no input layers");
98 }
99 
100 BOOST_AUTO_TEST_SUITE(Quantizer)
101 
102 class TestQuantization : public IStrategy
103 {
104 public:
105  TestQuantization(const TensorShape &inputShape, const TensorShape &outputShape)
106  : m_InputShape(inputShape), m_OutputShape(outputShape), m_QuantizerOptions(QuantizerOptions())
107  {}
108 
109  TestQuantization(const QuantizerOptions& options, const TensorShape& inputShape, const TensorShape& outputShape)
110  : m_InputShape(inputShape)
111  , m_OutputShape(outputShape)
112  , m_QuantizerOptions(options) {}
113 
114  void ExecuteStrategy(const armnn::IConnectableLayer *layer,
115  const BaseDescriptor &descriptor,
116  const std::vector<armnn::ConstTensor> &constants,
117  const char *name,
118  const armnn::LayerBindingId id) override
119  {
120  IgnoreUnused(id, name);
121 
122  if (layer->GetType() == armnn::LayerType::Output)
123  {
124  const TensorInfo &info = layer->GetInputSlot(0).GetConnection()->GetTensorInfo();
125  BOOST_TEST(m_OutputShape == info.GetShape());
126  return;
127  }
128 
129  const TensorInfo& info = layer->GetOutputSlot(0).GetTensorInfo();
130 
131  switch (layer->GetType())
132  {
141  {
142  CheckDefaultQuantizationSettings(info);
143  break;
144  }
146  {
147 
148  // Based off default static range [-20.0f, 20.0f]
149  TestQuantizationParams(info, {40.0f / g_AsymmU8QuantizationBase, 128},
150  {40.0f / g_AsymmS8QuantizationBase, 0},
151  {20.0f / g_SymmS8QuantizationBase, 0},
152  {20.0f / g_SymmS16QuantizationBase, 0});
153  break;
154  }
156  {
157  const ActivationDescriptor& activationDescriptor = static_cast<const ActivationDescriptor&>(descriptor);
158 
159  switch (activationDescriptor.m_Function)
160  {
162  {
163  // Based off default static range [0.0f, 3.5f]
164  TestQuantizationParams(info, {3.5f / g_AsymmU8QuantizationBase, 0},
165  {3.5f / g_AsymmS8QuantizationBase, -128},
166  {3.5f / g_SymmS8QuantizationBase, 0},
167  {3.5f / g_SymmS16QuantizationBase, 0});
168  break;
169  }
171  {
172  TestQuantizationParams(
173  info, {30.0f / g_AsymmU8QuantizationBase, 128},
174  {30.0f / g_AsymmS8QuantizationBase, 0},
175  {15.0f / g_SymmS8QuantizationBase, 0},
176  {15.0f / g_SymmS16QuantizationBase, 0});
177  break;
178  }
180  {
181  TestQuantizationParams(info, {30.0f / g_AsymmU8QuantizationBase, 128},
182  {30.0f / g_AsymmS8QuantizationBase, 0},
183  {15.0f / g_SymmS8QuantizationBase, 0},
184  {15.0f / g_SymmS16QuantizationBase, 0});
185  break;
186  }
188  {
189  // Based off default static range [-5.0f, 15.0f]
190  TestQuantizationParams(info, {20.0f / g_AsymmU8QuantizationBase, 64},
191  {20.0f / g_AsymmS8QuantizationBase,-64},
192  {15.0f / g_SymmS8QuantizationBase , 0},
193  {15.0f / g_SymmS16QuantizationBase, 0});
194  break;
195  }
197  {
198  TestQuantizationParams(info, {2.0f / g_AsymmU8QuantizationBase, 128},
199  {2.0f / g_AsymmS8QuantizationBase, 0},
200  {1.0f / g_SymmS8QuantizationBase , 0},
201  {1.0f / g_SymmS16QuantizationBase, 0});
202  break;
203  }
204  default:
205  {
206  // Based off default static range [0.0f, 15.0f]
207  TestQuantizationParams(info, {15.0f / g_AsymmU8QuantizationBase, 0},
208  {15.0f / g_AsymmS8QuantizationBase, -128},
209  {15.0f / g_SymmS8QuantizationBase, 0},
210  {15.0f / g_SymmS16QuantizationBase, 0});
211  break;
212  }
213  }
214  break;
215  }
217  {
218  const ArgMinMaxDescriptor& argMinMaxDescriptor = static_cast<const ArgMinMaxDescriptor&>(descriptor);
219 
220  if(argMinMaxDescriptor.m_Function == ArgMinMaxFunction::Max)
221  {
222  break;
223  }
224  TestQuantizationParams(info,
225  { 30.0f / g_AsymmU8QuantizationBase, 128 },
226  { 30.0f / g_AsymmS8QuantizationBase, 0},
227  { 15.0f / g_SymmS8QuantizationBase, 0},
228  { 15.0f / g_SymmS16QuantizationBase, 0 });
229  break;
230  }
232  {
233 
234  // Based off default static range [-15.0f, 15.0f]
235  TestQuantizationParams(
236  info, {30.0f / g_AsymmU8QuantizationBase, 128},
237  {30.0f / g_AsymmS8QuantizationBase, 0},
238  {15.0f / g_SymmS8QuantizationBase, 0},
239  {15.0f / g_SymmS16QuantizationBase, 0});
240 
241  // Test constants
242  TestConstantQuantizationParams(constants[0].GetInfo(), {3.0f / g_AsymmU8QuantizationBase, 85});
243  TestConstantQuantizationParams(constants[1].GetInfo(), {3.0f / g_AsymmU8QuantizationBase, 85});
244  TestConstantQuantizationParams(constants[2].GetInfo(), {3.0f / g_AsymmU8QuantizationBase, 85});
245  TestConstantQuantizationParams(constants[3].GetInfo(), {3.0f / g_AsymmU8QuantizationBase, 85});
246  break;
247  }
249  {
250 
251  const OffsetScalePair qAsymmU8Params{ 30.0f / g_AsymmU8QuantizationBase, 128 };
252  const OffsetScalePair qAsymmS8Params { 30.0f / g_AsymmS8QuantizationBase, 0};
253  const OffsetScalePair qSymmS8Params { 15.0f / g_SymmS8QuantizationBase, 0};
254  const OffsetScalePair qSymmS16Params{ 15.0f / g_SymmS16QuantizationBase, 0 };
255 
256  TestQuantizationParams(info, qAsymmU8Params, qAsymmS8Params, qSymmS8Params, qSymmS16Params);
257 
258  break;
259  }
261  {
262 
263  // Based off the range of values in the const tensor used for the test: [-2.0f, 6.0f]
264  TestQuantizationParams(info, {8.0f / g_AsymmU8QuantizationBase, 64},
265  {8.0f / g_AsymmS8QuantizationBase, -64},
266  {6.0f / g_SymmS8QuantizationBase, 0},
267  {6.0f / g_SymmS16QuantizationBase, 0});
268 
269  break;
270  }
272  {
273  if (constants.size() == 1)
274  {
275  TestQuantizationOnLayersWithBiases(layer, constants[0], armnn::EmptyOptional());
276  }
277  else if (constants.size() == 1)
278  {
279  TestQuantizationOnLayersWithBiases(layer, constants[0], constants[1]);
280  }
281  break;
282  }
284  {
285  if (constants.size() == 2)
286  {
287  TestQuantizationOnLayersWithBiases(layer, constants[0], constants[1]);
288  }
289  else if (constants.size() == 1)
290  {
291  TestQuantizationOnLayersWithBiases(layer, constants[0], armnn::EmptyOptional());
292  }
293  break;
294  }
296  {
297  const OffsetScalePair qAsymmU8Params{30.0f / g_AsymmU8QuantizationBase, 128};
298  const OffsetScalePair qAsymmS8Params{30.0f / g_AsymmS8QuantizationBase, 0};
299  const OffsetScalePair qSymmS8Params{15.0f / g_SymmS8QuantizationBase, 0};
300  const OffsetScalePair qSymmS16Params{15.0f / g_SymmS16QuantizationBase, 0};
301 
302  TestQuantizationParams(info, qAsymmU8Params, qAsymmS8Params, qSymmS8Params, qSymmS16Params);
303  break;
304  }
306  {
307  if (constants.size() == 2)
308  {
309  TestQuantizationOnLayersWithBiases(layer, constants[0], constants[1]);
310  }
311  else if (constants.size() == 1)
312  {
313  TestQuantizationOnLayersWithBiases(layer, constants[0], armnn::EmptyOptional());
314  }
315 
316  break;
317  }
319  {
320  const OffsetScalePair qAsymmU8Params{ 30.0f / g_AsymmU8QuantizationBase, 128 };
321  const OffsetScalePair qAsymmS8Params { 30.0f / g_AsymmS8QuantizationBase, 0};
322  const OffsetScalePair qSymmS8Params { 15.0f / g_SymmS8QuantizationBase, 0};
323  const OffsetScalePair qSymmS16Params{ 15.0f / g_SymmS16QuantizationBase, 0 };
324 
325  TestQuantizationParams(info, qAsymmU8Params, qAsymmS8Params, qSymmS8Params, qSymmS16Params);
326  break;
327  }
329  {
330  BOOST_TEST(m_InputShape == info.GetShape());
331  // Based off current default [-15.0f, 15.0f]
332  TestQuantizationParams(info, {30.0f / g_AsymmU8QuantizationBase, 128},
333  {30.0f / g_AsymmS8QuantizationBase, 0},
334  {15.0f / g_SymmS8QuantizationBase, 0},
335  {15.0f / g_SymmS16QuantizationBase, 0});
336  break;
337  }
339  {
340  const OffsetScalePair qAsymmU8Params{ 30.0f / g_AsymmU8QuantizationBase, 128 };
341  const OffsetScalePair qAsymmS8Params { 30.0f / g_AsymmS8QuantizationBase, 0};
342  const OffsetScalePair qSymmS8Params { 15.0f / g_SymmS8QuantizationBase, 0};
343  const OffsetScalePair qSymmS16Params{ 15.0f / g_SymmS16QuantizationBase, 0 };
344 
345  TestQuantizationParams(info, qAsymmU8Params, qAsymmS8Params, qSymmS8Params, qSymmS16Params);
346  break;
347  }
349  {
350  const OffsetScalePair qAsymmU8Params{ 30.0f / g_AsymmU8QuantizationBase, 128 };
351  const OffsetScalePair qAsymmS8Params { 30.0f / g_AsymmS8QuantizationBase, 0};
352  const OffsetScalePair qSymmS8Params { 15.0f / g_SymmS8QuantizationBase, 0};
353  const OffsetScalePair qSymmS16Params{ 15.0f / g_SymmS16QuantizationBase, 0 };
354 
355  TestQuantizationParams(info, qAsymmU8Params, qAsymmS8Params, qSymmS8Params, qSymmS16Params);
356  break;
357  }
359  {
360  const OffsetScalePair qAsymmU8Params{ 30.0f / g_AsymmU8QuantizationBase, 128 };
361  const OffsetScalePair qAsymmS8Params{ 30.0f / g_AsymmS8QuantizationBase, 0 };
362  const OffsetScalePair qSymmS8Params { 15.0f / g_SymmS8QuantizationBase, 0 };
363  const OffsetScalePair qSymmS16Params{ 15.0f / g_SymmS16QuantizationBase, 0 };
364 
365  TestQuantizationParams(info, qAsymmU8Params, qAsymmS8Params, qSymmS8Params, qSymmS16Params);
366  break;
367  }
369  {
370  // Based off default static range [0.0f, 1.0f]
371  TestQuantizationParams(info, {1.0f / g_AsymmU8QuantizationBase, 0},
372  {1.0f / g_AsymmS8QuantizationBase, -128},
373  {1.0f / g_SymmS8QuantizationBase, 0},
374  {1.0f / g_SymmS16QuantizationBase, 0});
375  break;
376  }
378  {
379  TestQuantizationParams(info,
380  { 30.0f / g_AsymmU8QuantizationBase, 128 },
381  { 30.0f / g_AsymmS8QuantizationBase, 0 },
382  { 15.0f / g_SymmS8QuantizationBase, 0 },
383  { 15.0f / g_SymmS16QuantizationBase, 0 });
384 
385  break;
386  }
388  {
389  TensorInfo outputInfo = layer->GetOutputSlot(0).GetTensorInfo();
390 
391  TestQuantizationParams(outputInfo,
392  { 30.0f / g_AsymmU8QuantizationBase, 128 },
393  { 30.0f / g_AsymmS8QuantizationBase, 0},
394  { 15.0f / g_SymmS8QuantizationBase, 0},
395  { 15.0f / g_SymmS16QuantizationBase, 0 });
396  break;
397  }
399  {
400  if (constants.size() == 2)
401  {
402  TestQuantizationOnLayersWithBiases(layer, constants[0], constants[1]);
403  }
404  else if (constants.size() == 1)
405  {
406  TestQuantizationOnLayersWithBiases(layer, constants[0], armnn::EmptyOptional());
407  }
408  break;
409  }
410  default:
411  {
412  throw UnimplementedException("Unimplemented layer encountered");
413  }
414  }
415  }
416 
417 
418 protected:
419 
420  void CheckDefaultQuantizationSettings(const TensorInfo& info)
421  {
422  TestQuantizationParams(info, {20.0f / g_AsymmU8QuantizationBase, 64},
423  {20.0f / g_AsymmS8QuantizationBase,-64},
424  {15.0f / g_SymmS8QuantizationBase, 0},
425  {15.0f / g_SymmS16QuantizationBase, 0});
426  }
427 
428  void TestQuantizationParams(const TensorInfo& info,
429  const OffsetScalePair& qAsymmU8Params,
430  const OffsetScalePair& qAsymmS8Params,
431  const OffsetScalePair& qSymmS8Params,
432  const OffsetScalePair& qSymmS16Params)
433  {
434  switch (m_QuantizerOptions.m_ActivationFormat)
435  {
436  case DataType::QAsymmU8:
437  TestQuantizationParamsImpl(
438  info, DataType::QAsymmU8, qAsymmU8Params.first, qAsymmU8Params.second);
439  break;
440  case DataType::QAsymmS8:
441  TestQuantizationParamsImpl(
442  info, DataType::QAsymmS8, qAsymmS8Params.first, qAsymmS8Params.second);
443  break;
444  case DataType::QSymmS8:
445  TestQuantizationParamsImpl(
446  info, DataType::QSymmS8, qSymmS8Params.first, qSymmS8Params.second);
447  break;
448  case DataType::QSymmS16:
449  TestQuantizationParamsImpl(
450  info, DataType::QSymmS16, qSymmS16Params.first, qSymmS16Params.second);
451  break;
452  default:
453  throw InvalidArgumentException("Unsupported quantization target");
454  }
455  }
456 
457  void TestDifferentQuantizationScale(const TensorInfo& info0, const TensorInfo& info1)
458  {
459  BOOST_TEST(info0.GetQuantizationScale() != info1.GetQuantizationScale());
460  }
461 
462  void TestConstantQuantizationParams(const TensorInfo& info,
463  const OffsetScalePair& params,
464  DataType dataType = DataType::QAsymmU8)
465  {
466  IgnoreUnused(dataType);
467  TestQuantizationParamsImpl(info, dataType, params.first, params.second);
468  }
469 
470  void TestBiasQuantizationParams(const TensorInfo& info,
471  const OffsetScalePair& qAsymmU8Params,
472  const OffsetScalePair& qAsymmS8Params,
473  const OffsetScalePair& qSymmS8Params,
474  const OffsetScalePair& qSymmS16Params,
475  DataType dataType = DataType::QAsymmU8)
476  {
477  switch (m_QuantizerOptions.m_ActivationFormat)
478  {
479  case DataType::QAsymmU8:
480  TestQuantizationParamsImpl(info, dataType, qAsymmU8Params.first, qAsymmU8Params.second);
481  break;
482  case DataType::QAsymmS8:
483  TestQuantizationParamsImpl(info, dataType, qAsymmS8Params.first, qAsymmS8Params.second);
484  break;
485  case DataType::QSymmS8:
486  TestQuantizationParamsImpl(info, dataType, qSymmS8Params.first, qSymmS8Params.second);
487  break;
488  case DataType::QSymmS16:
489  TestQuantizationParamsImpl(info, dataType, qSymmS16Params.first, qSymmS16Params.second);
490  break;
491  default:
492  throw InvalidArgumentException("Unsupported quantization target");
493  }
494  }
495 
496  void TestQuantizationOnLayersWithBiases(const IConnectableLayer* layer,
497  const ConstTensor& weights,
498  const Optional<ConstTensor>& biases)
499  {
500  TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
501  float inputScaleQAsymmU8 = 30.0f / g_AsymmU8QuantizationBase;
502  float inputScaleQAsymmS8 = 30.0f / g_AsymmS8QuantizationBase;
503  float inputScaleQSymmS8 = 15.0f / g_SymmS8QuantizationBase;
504  float inputScaleQSymmS16 = 15.0f / g_SymmS16QuantizationBase;
505  float weightsScale = 3.0f / g_AsymmU8QuantizationBase;
506 
507  // Based off default static range [-15.0f, 15.0f]
508  TestQuantizationParams(info, {inputScaleQAsymmU8, 128},
509  {inputScaleQAsymmS8, 0},
510  {inputScaleQSymmS8, 0},
511  {inputScaleQSymmS16, 0});
512 
513  TestConstantQuantizationParams(weights.GetInfo(), {weightsScale, 85});
514 
515  if (biases.has_value())
516  {
517  TestBiasQuantizationParams(biases.value().GetInfo(),
518  {inputScaleQAsymmU8 * weightsScale, 0},
519  {inputScaleQAsymmS8 * weightsScale, 0},
520  {inputScaleQSymmS8 * weightsScale, 0},
521  {inputScaleQSymmS16 * weightsScale, 0},
523  }
524  }
525 
526  TensorShape m_InputShape;
527  TensorShape m_OutputShape;
528 
529 private:
530  void TestQuantizationParamsImpl(const TensorInfo& info, DataType dataType, float scale, int32_t offset)
531  {
532  BOOST_TEST((info.GetDataType() == dataType));
533  BOOST_TEST(info.GetQuantizationOffset() == offset);
534  BOOST_CHECK_CLOSE(info.GetQuantizationScale(), scale, g_TestTolerance);
535  }
536 
537  QuantizerOptions m_QuantizerOptions;
538 };
539 
540 void TestNetwork(INetwork* network, const TensorShape inShape, const TensorShape outShape)
541 {
542  const QuantizerOptions qAsymmU8Options(DataType::QAsymmU8);
543  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network, qAsymmU8Options)->ExportNetwork();
544  TestQuantization validatorQAsymmU8(inShape, outShape);
545  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
546 
547  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
548  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network, qAsymmS8Options)->ExportNetwork();
549  TestQuantization validatorQAsymmS8(qAsymmS8Options, inShape, outShape);
550  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
551 
552  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
553  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network, qSymmS8Options)->ExportNetwork();
554  TestQuantization validatorQSymmS8(qSymmS8Options, inShape, outShape);
555  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
556 
557  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
558  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network, qSymmS16options)->ExportNetwork();
559  TestQuantization validatorQSymmS16(qSymmS16options, inShape, outShape);
560  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
561 }
562 
563 void TestNetwork(INetwork* network, const TensorShape shape)
564 {
565  TestNetwork(network, shape, shape);
566 }
567 
568 BOOST_AUTO_TEST_CASE(QuantizeAddition)
569 {
570  INetworkPtr network = INetwork::Create();
571 
572  // Add the layers
573  IConnectableLayer* input0 = network->AddInputLayer(0);
574  IConnectableLayer* input1 = network->AddInputLayer(1);
575  IConnectableLayer* addition = network->AddAdditionLayer();
576  IConnectableLayer* output = network->AddOutputLayer(2);
577 
578  // Establish connections
579  input0->GetOutputSlot(0).Connect(addition->GetInputSlot(0));
580  input1->GetOutputSlot(0).Connect(addition->GetInputSlot(1));
581  addition->GetOutputSlot(0).Connect(output->GetInputSlot(0));
582 
583  // Set TensorInfo
584  const TensorShape shape{1U};
586  input0->GetOutputSlot(0).SetTensorInfo(info);
587  input1->GetOutputSlot(0).SetTensorInfo(info);
588  addition->GetOutputSlot(0).SetTensorInfo(info);
589 
590  TestNetwork(network.get(), shape);
591 }
592 
594 {
595  INetworkPtr network = INetwork::Create();
596 
597  // Add the layers
598  IConnectableLayer* input0 = network->AddInputLayer(0);
599  IConnectableLayer* activation = network->AddActivationLayer(descriptor);
600  IConnectableLayer* output = network->AddOutputLayer(2);
601 
602  // Establish connections
603  input0->GetOutputSlot(0).Connect(activation->GetInputSlot(0));
604  activation->GetOutputSlot(0).Connect(output->GetInputSlot(0));
605 
606  // Set TensorInfo
608  input0->GetOutputSlot(0).SetTensorInfo(info);
609  activation->GetOutputSlot(0).SetTensorInfo(info);
610 
611  return network;
612 }
613 
615 {
616  INetworkPtr network = INetwork::Create();
617 
618  // Add the layers
619  IConnectableLayer* input0 = network->AddInputLayer(0);
620  IConnectableLayer* activation = network->AddArgMinMaxLayer(descriptor);
621  IConnectableLayer* output = network->AddOutputLayer(2);
622 
623  // Establish connections
624  input0->GetOutputSlot(0).Connect(activation->GetInputSlot(0));
625  activation->GetOutputSlot(0).Connect(output->GetInputSlot(0));
626 
627  // Set TensorInfo
628  TensorInfo inInfo(shape, DataType::Float32);
629  input0->GetOutputSlot(0).SetTensorInfo(inInfo);
630  TensorInfo outInfo({1}, DataType::Signed32);
631  activation->GetOutputSlot(0).SetTensorInfo(outInfo);
632 
633  return network;
634 }
635 
637 {
638  INetworkPtr network = INetwork::Create();
639 
640  // Add input/output layers
641  IConnectableLayer* inputLayer = network->AddInputLayer(0);
642  IConnectableLayer* output = network->AddOutputLayer(1);
643 
644  // Establish connections
645  inputLayer->GetOutputSlot(0).Connect(output->GetInputSlot(0));
646 
647  // Set TensorInfo
648  TensorShape shape{8U};
650  inputLayer->GetOutputSlot(0).SetTensorInfo(info);
651 
652  return network;
653 }
654 
655 BOOST_AUTO_TEST_CASE(InputOutputLayerDynamicQuant)
656 {
658 
659  armnn::TensorInfo tensorInfo = GetInputTensorInfo(network.get());
660 
661  // Outliers -56 and 98
662  std::vector<float> inputData({0, 0, 0, -56, 98, 0, 0, 0});
663  armnn::ConstTensor inputTensor(tensorInfo, inputData.data());
664 
665  InputTensors inputTensors;
666  inputTensors.push_back(std::make_pair(0, inputTensor));
667 
669 
670  quantizer->Refine(inputTensors);
671 
672  // Outliers -77 and 65
673  std::vector<float> inputData2({0, -77, 0, -56, 65, 0, 0, 0});
674  armnn::ConstTensor inputTensor2(tensorInfo, inputData2.data());
675  InputTensors inputTensors2;
676  inputTensors2.push_back(std::make_pair(0, inputTensor2));
677 
678  quantizer->Refine(inputTensors2);
679 
680  INetworkPtr quantizedNetwork = quantizer->ExportNetwork();
681  // Output Layer should be quantized for a min max of -77 and 98
682  // according to QU8 Quantization Scheme
683  std::unique_ptr<IQuantizationScheme> quantizationScheme = std::make_unique<QAsymmU8QuantizationScheme>();
684  OffsetScalePair qParams = quantizationScheme->ComputeScheme(-77.0, 98.0);
685 
686 class TestOutputStrategy : public IStrategy
687 {
688  public :
689  TestOutputStrategy(const OffsetScalePair& offsetScalePair, const DataType& dataType) :
690  m_OffsetScalePair(offsetScalePair), m_DataType(dataType) {}
691 
692  void ExecuteStrategy(const armnn::IConnectableLayer* layer,
693  const BaseDescriptor& descriptor,
694  const std::vector<armnn::ConstTensor>& constants,
695  const char* name,
696  const armnn::LayerBindingId id) override
697  {
698  IgnoreUnused(name, constants, id, descriptor);
699 
700  switch (layer->GetType())
701  {
703  {
704  const TensorInfo &info = layer->GetInputSlot(0).GetConnection()->GetTensorInfo();
705  BOOST_CHECK_MESSAGE(info.GetDataType() == m_DataType,
706  std::string(armnn::GetDataTypeName(info.GetDataType()))
707  .append(" == ").append(armnn::GetDataTypeName(m_DataType)));
708  // int_32t
709  BOOST_CHECK(info.GetQuantizationOffset() == m_OffsetScalePair.second);
710  // float
711  BOOST_TEST(info.GetQuantizationScale() == m_OffsetScalePair.first,
712  boost::test_tools::tolerance(0.001));
713  break;
714  }
715  default:
716  {}
717  }
718  }
719 
720 private:
721  const OffsetScalePair m_OffsetScalePair;
722  const DataType m_DataType;
723 };
724 
725  TestOutputStrategy strategy(qParams, quantizationScheme->GetDataType());
726  quantizedNetwork->ExecuteStrategy(strategy);
727 }
728 
729 BOOST_AUTO_TEST_CASE(QuantizeAbsActivation)
730 {
731  ActivationDescriptor descriptor;
732  descriptor.m_Function = ActivationFunction::Abs;
733  descriptor.m_A = 3.5f;
734  descriptor.m_B = -10.0f;
735 
736  const TensorShape shape{1U};
737  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
738 
739  TestNetwork(network.get(), shape);
740 }
741 
742 BOOST_AUTO_TEST_CASE(QuantizeArgMax)
743 {
744  ArgMinMaxDescriptor descriptor;
745  descriptor.m_Function = ArgMinMaxFunction::Max;
746 
747  const TensorShape shape{1U};
748  INetworkPtr network = CreateNetworkWithArgMinMaxLayer(descriptor, shape);
749 
750  TestNetwork(network.get(), shape);
751 }
752 
753 BOOST_AUTO_TEST_CASE(QuantizeLinearActivation)
754 {
755  ActivationDescriptor descriptor;
757  descriptor.m_A = 3.5f;
758  descriptor.m_B = -10.0f;
759 
760  const TensorShape shape{1U};
761  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
762 
763 
764  TestNetwork(network.get(), shape);
765 }
766 
767 BOOST_AUTO_TEST_CASE(QuantizeReLuActivation)
768 {
769  ActivationDescriptor descriptor;
771  descriptor.m_A = 3.5f;
772  descriptor.m_B = -10.0f;
773 
774  const TensorShape shape{1U};
775  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
776 
777  TestNetwork(network.get(), shape);
778 }
779 
780 BOOST_AUTO_TEST_CASE(QuantizeSoftReLuActivation)
781 {
782  ActivationDescriptor descriptor;
784  descriptor.m_A = 3.5f;
785  descriptor.m_B = -10.0f;
786 
787  const TensorShape shape{1U};
788  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
789 
790  TestNetwork(network.get(), shape);
791 }
792 
793 BOOST_AUTO_TEST_CASE(QuantizeBoundedReluActivation)
794 {
795  ActivationDescriptor descriptor;
797  descriptor.m_A = 3.5f;
798  descriptor.m_B = -10.0f;
799 
800  const TensorShape shape{1U};
801  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
802 
803  TestNetwork(network.get(), shape);
804 }
805 
806 BOOST_AUTO_TEST_CASE(QuantizeTanHActivation)
807 {
808  ActivationDescriptor descriptor;
810  descriptor.m_A = 3.5f;
811  descriptor.m_B = -10.0f;
812 
813  const TensorShape shape{1U};
814  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
815 
816  TestNetwork(network.get(), shape);
817 }
818 
819 BOOST_AUTO_TEST_CASE(QuantizeLeakyReLuActivation)
820 {
821  ActivationDescriptor descriptor;
823  descriptor.m_A = 3.5f;
824  descriptor.m_B = -10.0f;
825 
826  const TensorShape shape{1U};
827  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
828 
829  TestNetwork(network.get(), shape);
830 }
831 
832 
833 BOOST_AUTO_TEST_CASE(QuantizeELuActivation)
834 {
835  ActivationDescriptor descriptor;
836  descriptor.m_Function = ActivationFunction::Elu;
837 
838  const TensorShape shape{1U};
839  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
840 
841  TestNetwork(network.get(), shape);
842 }
843 BOOST_AUTO_TEST_CASE(QuantizeHardSwishActivation)
844 {
845  ActivationDescriptor descriptor;
847 
848  const TensorShape shape{1U};
849  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
850 
851  TestNetwork(network.get(), shape);
852 }
853 
854 
855 BOOST_AUTO_TEST_CASE(QuantizeBatchNorm)
856 {
857  INetworkPtr network = INetwork::Create();
858 
859  const TensorShape shape{3U};
861 
862  std::vector<float> meanData{-1.0f, 1.5f, 2.0f};
863  std::vector<float> varData{-1.0f, 1.5f, 2.0f};
864  std::vector<float> betaData{-1.0f, 1.5f, 2.0f};
865  std::vector<float> gammaData{-1.0f, 1.5f, 2.0f};
866 
867  ConstTensor mean(info, meanData);
868  ConstTensor var(info, varData);
869  ConstTensor beta(info, betaData);
870  ConstTensor gamma(info, gammaData);
871 
873 
874  // Add the layers
875  IConnectableLayer* input0 = network->AddInputLayer(0);
876  IConnectableLayer* batchNorm = network->AddBatchNormalizationLayer(desc, mean, var, beta, gamma);
877  IConnectableLayer* output = network->AddOutputLayer(1);
878 
879  // Establish connections
880  input0->GetOutputSlot(0).Connect(batchNorm->GetInputSlot(0));
881  batchNorm->GetOutputSlot(0).Connect(output->GetInputSlot(0));
882 
883  // Set TensorInfo
884  input0->GetOutputSlot(0).SetTensorInfo(info);
885  batchNorm->GetOutputSlot(0).SetTensorInfo(info);
886 
887  TestNetwork(network.get(), shape);
888 }
889 
890 BOOST_AUTO_TEST_CASE(QuantizeDepthToSpace)
891 {
892  const TensorShape inputShape { 1, 2, 2, 4 };
893  const TensorShape outputShape{ 1, 4, 4, 1 };
894 
895  const TensorInfo inputInfo (inputShape, DataType::Float32);
896  const TensorInfo outputInfo(outputShape, DataType::Float32);
897 
898  INetworkPtr network = INetwork::Create();
899  const DepthToSpaceDescriptor descriptor(2, armnn::DataLayout::NHWC);
900 
901  IConnectableLayer* inputLayer = network->AddInputLayer(0);
902  IConnectableLayer* depthToSpaceLayer = network->AddDepthToSpaceLayer(descriptor);
903  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
904 
905  inputLayer->GetOutputSlot(0).Connect(depthToSpaceLayer->GetInputSlot(0));
906  depthToSpaceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
907 
908  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
909  depthToSpaceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
910 
911  TestNetwork(network.get(), inputShape, outputShape);
912 }
913 
914 BOOST_AUTO_TEST_CASE(OverrideInputRangeEmptyNetwork)
915 {
916  RangeTracker ranges;
917  RangeTracker::MinMaxRange minMaxRange(-12.3f, 45.6f); // Range to use for the override
918 
919  NetworkImpl network; // Empty network
920  auto inputLayers = network.GetGraph().GetInputLayers(); // Empty list of input layers
921 
922  OverrideInputRangeStrategy overrideInputRangeStrategy(ranges, 0, minMaxRange);
923  ApplyStrategyToLayers(inputLayers, overrideInputRangeStrategy);
924 
925  BOOST_CHECK(ranges.IsEmpty()); // Check that the map of ranges remained untouched
926 }
927 
928 BOOST_AUTO_TEST_CASE(OverrideInputRangeNoInputLayers)
929 {
930  RangeTracker ranges;
931  MinMaxRange minMaxRange(-12.3f, 45.6f); // Range to use for the override
932 
933  NetworkImpl network;
934  network.AddAdditionLayer(); // Network with no input layers
935  auto inputLayers = network.GetGraph().GetInputLayers(); // Empty list of input layers
936 
937  OverrideInputRangeStrategy overrideInputRangeStrategy(ranges, 0, minMaxRange);
938  ApplyStrategyToLayers(inputLayers, overrideInputRangeStrategy);
939 
940  BOOST_CHECK(ranges.IsEmpty()); // Check that the map of ranges remained untouched
941 }
942 
943 BOOST_AUTO_TEST_CASE(OverrideInputRangeInputLayers)
944 {
945  RangeTracker ranges;
946  MinMaxRange minMaxRange(-12.3f, 45.6f); // Range to use for the override
947 
948  NetworkImpl network;
949 
950  // Adding the layers
951  IConnectableLayer* input0 = network.AddInputLayer(0);
952  IConnectableLayer* input1 = network.AddInputLayer(1);
953  IConnectableLayer* addition = network.AddAdditionLayer();
954  IConnectableLayer* output = network.AddOutputLayer(2);
955 
956  // Connecting the layer
957  input0->GetOutputSlot(0).Connect(addition->GetInputSlot(0));
958  input1->GetOutputSlot(0).Connect(addition->GetInputSlot(1));
959  addition->GetOutputSlot(0).Connect(output->GetInputSlot(0));
960 
961  // Setting the TensorInfos
962  TensorShape shape{1U};
964  input0->GetOutputSlot(0).SetTensorInfo(info);
965  input1->GetOutputSlot(0).SetTensorInfo(info);
966  addition->GetOutputSlot(0).SetTensorInfo(info);
967 
968  auto inputLayers = network.GetGraph().GetInputLayers(); // List of input layers
969 
970  // Trying to override the input range for the input layer with binding id 3 (does not exist in the network)
971  OverrideInputRangeStrategy overrideInputRangeStrategy3(ranges, 3, minMaxRange);
972  ApplyStrategyToLayers(inputLayers, overrideInputRangeStrategy3);
973 
974  // Check that the map of ranges remained untouched
975  BOOST_CHECK(ranges.IsEmpty());
976 
977  // Override the input range for the input layer with binding id 1
978  OverrideInputRangeStrategy overrideInputRangeStrategy1(ranges, 1, minMaxRange);
979  ApplyStrategyToLayers(inputLayers, overrideInputRangeStrategy1);
980 
981  // Check that the map of ranges has been populated
982  BOOST_CHECK(!ranges.IsEmpty());
983 
984  // Check that an entry for the input layer with binding id 0 does not exist
985  BOOST_CHECK(!ranges.HasRanges(input0->GetGuid()));
986 
987  // Check that an entry for the input layer with binding id 1 exists
988  BOOST_CHECK(ranges.HasRanges(input1->GetGuid()));
989 
990  // Check the the overridden values are what we intended to set
991  BOOST_CHECK(ranges.GetRange(input1->GetGuid(), 0) == minMaxRange);
992 }
993 
995  const TensorShape& inputShape,
996  const TensorShape& outputShape)
997 {
999  desc.m_BiasEnabled = biasEnabled;
1000  INetworkPtr network = INetwork::Create();
1001 
1002  const TensorInfo info(inputShape, DataType::Float32);
1003  const TensorInfo outputInfo(outputShape, DataType::Float32);
1004 
1005  std::vector<float> weightsData{-1.0f, 1.5f, 2.0f};
1006  ConstTensor weights(info, weightsData);
1007 
1008  // Add the layers
1009  IConnectableLayer* input0 = network->AddInputLayer(0);
1010  IConnectableLayer* fullyConnected;
1011  Optional<ConstTensor> optionalBias;
1012  std::vector<float> biasData{10.0f, 20.0f, 30.0f};
1013  if (desc.m_BiasEnabled)
1014  {
1015  ConstTensor bias(info, biasData);
1016  optionalBias = Optional<ConstTensor>(bias);
1017  }
1018  fullyConnected = network->AddFullyConnectedLayer(desc, weights, optionalBias);
1019  IConnectableLayer* output = network->AddOutputLayer(1);
1020 
1021  // Establish connections
1022  input0->GetOutputSlot(0).Connect(fullyConnected->GetInputSlot(0));
1023  fullyConnected->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1024 
1025  // Set TensorInfo
1026  input0->GetOutputSlot(0).SetTensorInfo(info);
1027  fullyConnected->GetOutputSlot(0).SetTensorInfo(outputInfo);
1028 
1029  return network;
1030 }
1031 
1032 void ValidateFullyConnectedLayer(const bool biasEnabled)
1033 {
1034  const TensorShape shape{3U};
1035  INetworkPtr network = CreateNetworkWithFullyConnectedLayer(biasEnabled, shape, shape);
1036 
1037  TestNetwork(network.get(), shape);
1038 }
1039 
1041 {
1042  const TensorShape tensorShape{ 1U };
1043  const TensorInfo tensorInfo(tensorShape, DataType::Float32);
1044 
1045  INetworkPtr network = INetwork::Create();
1046 
1047  FillDescriptor descriptor;
1048  descriptor.m_Value = 1;
1049 
1050  IConnectableLayer* inputLayer = network->AddInputLayer(0);
1051  IConnectableLayer* fillLayer = network->AddFillLayer(descriptor);
1052  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
1053 
1054  inputLayer->GetOutputSlot(0).Connect(fillLayer->GetInputSlot(0));
1055  fillLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1056 
1057  inputLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1058  fillLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1059 
1060  TestNetwork(network.get(), tensorShape);
1061 }
1062 
1063 BOOST_AUTO_TEST_CASE(QuantizeFullyConnected)
1064 {
1066 }
1067 
1068 BOOST_AUTO_TEST_CASE(QuantizeFullyConnectedBiasEnabled)
1069 {
1071 }
1072 
1073 void TestQuantizeConvolution2d(bool useBiases)
1074 {
1075  INetworkPtr network = INetwork::Create();
1076 
1077  TensorShape shape{3U};
1079 
1080  std::vector<float> weightsData{-1.0f, 1.5f, 2.0f};
1081  ConstTensor weights(info, weightsData);
1082 
1083  Convolution2dDescriptor descriptor;
1084  descriptor.m_BiasEnabled = useBiases;
1085 
1086  // Add the layers
1087  IConnectableLayer* input0 = network->AddInputLayer(0);
1088  IConnectableLayer* conv2d;
1089  Optional<ConstTensor> optionalBiases;
1090  std::vector<float> biasesData{-1.0f, 1.5f, 2.0f};
1091  if (useBiases)
1092  {
1093  ConstTensor biases(info, biasesData);
1094  optionalBiases = Optional<ConstTensor>(biases);
1095  }
1096  conv2d = network->AddConvolution2dLayer(descriptor, weights, optionalBiases);
1097  IConnectableLayer* output = network->AddOutputLayer(1);
1098 
1099  // Establish connections
1100  input0->GetOutputSlot(0).Connect(conv2d->GetInputSlot(0));
1101  conv2d->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1102 
1103  // Set TensorInfo
1104  input0->GetOutputSlot(0).SetTensorInfo(info);
1105  conv2d->GetOutputSlot(0).SetTensorInfo(info);
1106 
1107  TestNetwork(network.get(), shape);
1108 }
1109 
1110 BOOST_AUTO_TEST_CASE(QuantizeConvolution2d)
1111 {
1113 }
1114 
1115 BOOST_AUTO_TEST_CASE(QuantizeConvolution2dWithBiases)
1116 {
1118 }
1119 
1121 {
1122  INetworkPtr network = INetwork::Create();
1123 
1124  TensorShape shape{3U};
1126 
1127  std::vector<float> weightsData{-1.0f, 1.5f, 2.0f};
1128  ConstTensor weights(info, weightsData);
1129 
1131  descriptor.m_BiasEnabled = useBiases;
1132 
1133  // Add the layers
1134  IConnectableLayer* input0 = network->AddInputLayer(0);
1135  IConnectableLayer* depthwiseConv2d;
1136  Optional<ConstTensor> optionalBiases;
1137  std::vector<float> biasesData{-1.0f, 1.5f, 2.0f};
1138  if (useBiases)
1139  {
1140  ConstTensor biases(info, biasesData);
1141  optionalBiases = Optional<ConstTensor>(biases);
1142  }
1143  depthwiseConv2d = network->AddDepthwiseConvolution2dLayer(descriptor, weights, optionalBiases);
1144  IConnectableLayer* output = network->AddOutputLayer(1);
1145 
1146  // Establish connections
1147  input0->GetOutputSlot(0).Connect(depthwiseConv2d->GetInputSlot(0));
1148  depthwiseConv2d->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1149 
1150  //Set TensorInfo
1151  input0->GetOutputSlot(0).SetTensorInfo(info);
1152  depthwiseConv2d->GetOutputSlot(0).SetTensorInfo(info);
1153 
1154  TestNetwork(network.get(), shape);
1155 }
1156 
1157 BOOST_AUTO_TEST_CASE(QuantizeDepthwiseConvolution2d)
1158 {
1160 }
1161 
1162 BOOST_AUTO_TEST_CASE(QuantizeDepthwiseConvolution2dWithBiases)
1163 {
1165 }
1166 
1167 BOOST_AUTO_TEST_CASE(QuantizeInstanceNormalization)
1168 {
1169  const TensorShape shape{ 1, 4, 4, 1 };
1170  const TensorInfo tensorInfo(shape, DataType::Float32);
1171 
1172  INetworkPtr network = INetwork::Create();
1173 
1174  IConnectableLayer* inputLayer = network->AddInputLayer(0);
1175  IConnectableLayer* instanceNormLayer = network->AddInstanceNormalizationLayer(InstanceNormalizationDescriptor());
1176  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
1177 
1178  inputLayer->GetOutputSlot(0).Connect(instanceNormLayer->GetInputSlot(0));
1179  instanceNormLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1180 
1181  inputLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1182  instanceNormLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1183 
1184  TestNetwork(network.get(), shape);
1185 }
1186 
1187 BOOST_AUTO_TEST_CASE(QuantizeLogSoftmax)
1188 {
1189  const TensorShape tensorShape{ 1U };
1190  const TensorInfo tensorInfo(tensorShape, DataType::Float32);
1191 
1192  INetworkPtr network = INetwork::Create();
1193 
1194  LogSoftmaxDescriptor descriptor;
1195  descriptor.m_Beta = 1.0f;
1196 
1197  IConnectableLayer* inputLayer = network->AddInputLayer(0);
1198  IConnectableLayer* logSoftmaxLayer = network->AddLogSoftmaxLayer(descriptor);
1199  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
1200 
1201  inputLayer->GetOutputSlot(0).Connect(logSoftmaxLayer->GetInputSlot(0));
1202  logSoftmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1203 
1204  inputLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1205  logSoftmaxLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1206 
1207  TestNetwork(network.get(), tensorShape);
1208 }
1209 
1211 {
1212  INetworkPtr network = INetwork::Create();
1213 
1214  // Add the layers
1215  IConnectableLayer* input0 = network->AddInputLayer(0);
1216  IConnectableLayer* softmax = network->AddSoftmaxLayer(descriptor);
1217  IConnectableLayer* output = network->AddOutputLayer(2);
1218 
1219  // Establish connections
1220  input0->GetOutputSlot(0).Connect(softmax->GetInputSlot(0));
1221  softmax->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1222 
1223  // Set TensorInfo
1225  input0->GetOutputSlot(0).SetTensorInfo(info);
1226  softmax->GetOutputSlot(0).SetTensorInfo(info);
1227 
1228  return network;
1229 }
1230 
1231 BOOST_AUTO_TEST_CASE(QuantizeSoftmax)
1232 {
1233  SoftmaxDescriptor descriptor;
1234  descriptor.m_Beta = 1.0f;
1235 
1236  const TensorShape shape{1U};
1237  INetworkPtr network = CreateNetworkWithSoftmaxLayer(descriptor, shape);
1238 
1239  TestNetwork(network.get(), shape);
1240 }
1241 
1242 BOOST_AUTO_TEST_CASE(QuantizeStandIn)
1243 {
1244  const TensorShape tensorShape{ 1U };
1245  const TensorInfo tensorInfo(tensorShape, DataType::Float32);
1246 
1247  INetworkPtr network = INetwork::Create();
1248 
1249  StandInDescriptor descriptor;
1250  descriptor.m_NumInputs = 1;
1251  descriptor.m_NumOutputs = 1;
1252 
1253  IConnectableLayer* inputLayer = network->AddInputLayer(0);
1254  IConnectableLayer* standInLayer = network->AddStandInLayer(descriptor);
1255  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
1256 
1257  inputLayer->GetOutputSlot(0).Connect(standInLayer->GetInputSlot(0));
1258  standInLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1259 
1260  inputLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1261  standInLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1262 
1263  // test QAsymmU8 quantization
1264  BOOST_CHECK_THROW(INetworkQuantizer::Create(network.get())->ExportNetwork(),
1266 
1267  // test QAsymmS8 quantization
1268  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1269  BOOST_CHECK_THROW(INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork(),
1271 
1272  // test QuantisedSymmS16 quantization
1273  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1274  BOOST_CHECK_THROW(INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork(),
1276 
1277  // test QuantisedSymmS16 quantization
1278  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
1279  BOOST_CHECK_THROW(INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork(),
1281 }
1282 
1284 {
1285  ActivationDescriptor activationDescriptor;
1286  activationDescriptor.m_Function = ActivationFunction::LeakyReLu;
1287  activationDescriptor.m_A = 3.5f;
1288  activationDescriptor.m_B = -10.0f;
1289 
1290  // Add the layers
1291  IConnectableLayer* input0 = network->AddInputLayer(0);
1292  IConnectableLayer* activation = network->AddActivationLayer(activationDescriptor);
1293 
1294  // Establish connections
1295  input0->GetOutputSlot(0).Connect(activation->GetInputSlot(0));
1296 
1297  // Set TensorInfo
1298  input0->GetOutputSlot(0).SetTensorInfo(info);
1299  activation->GetOutputSlot(0).SetTensorInfo(info);
1300 
1301  return activation;
1302 }
1303 
1305  IConnectableLayer* activation,
1306  IConnectableLayer* layerUnderTest,
1307  const TensorInfo& info)
1308 {
1309  // Add the output Layer
1310  IConnectableLayer* output = network->AddOutputLayer(3);
1311 
1312  // Establish connections
1313  activation->GetOutputSlot(0).Connect(layerUnderTest->GetInputSlot(0));
1314  layerUnderTest->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1315 
1316  //Set TensorInfo
1317  layerUnderTest->GetOutputSlot(0).SetTensorInfo(info);
1318 }
1319 
1320 BOOST_AUTO_TEST_CASE(QuantizePermute)
1321 {
1322  INetworkPtr network = INetwork::Create();
1323 
1324  const TensorShape shape{1U};
1326 
1327  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
1328 
1329  // Add the layer under test
1330  PermuteDescriptor desc;
1331  IConnectableLayer* permute = network->AddPermuteLayer(desc);
1332 
1333  CompleteLeakyReluNetwork(network.get(), activation, permute, info);
1334 
1335  TestNetwork(network.get(), shape);
1336 }
1337 
1338 BOOST_AUTO_TEST_CASE(QuantizeSpaceToBatch)
1339 {
1340  INetworkPtr network = INetwork::Create();
1341 
1342  const TensorShape shape{1U};
1344 
1345  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
1346 
1347  // Add the layer under test
1348  SpaceToBatchNdDescriptor descriptor;
1349  IConnectableLayer* spaceToBatch = network->AddSpaceToBatchNdLayer(descriptor);
1350 
1351  CompleteLeakyReluNetwork(network.get(), activation, spaceToBatch, info);
1352 
1353  TestNetwork(network.get(), shape);
1354 }
1355 
1356 BOOST_AUTO_TEST_CASE(QuantizeSpaceToDepth)
1357 {
1358  INetworkPtr network = INetwork::Create();
1359 
1360  const TensorShape shape{ 1u };
1362 
1363  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
1364  IConnectableLayer* spaceToDepth = network->AddSpaceToDepthLayer(SpaceToDepthDescriptor());
1365 
1366  CompleteLeakyReluNetwork(network.get(), activation, spaceToDepth, info);
1367 
1368  TestNetwork(network.get(), shape);
1369 }
1370 
1371 BOOST_AUTO_TEST_CASE(QuantizePooling2d)
1372 {
1373  auto network = INetwork::Create();
1374 
1375  TensorShape shape{1U};
1377 
1378  Pooling2dDescriptor desc;
1379  ActivationDescriptor activationDescriptor;
1380  activationDescriptor.m_Function = ActivationFunction::LeakyReLu;
1381  activationDescriptor.m_A = 3.5f;
1382  activationDescriptor.m_B = -10.0f;
1383 
1384  // Add the layers
1385  IConnectableLayer* input0 = network->AddInputLayer(0);
1386  IConnectableLayer* activation = network->AddActivationLayer(activationDescriptor);
1387  IConnectableLayer* pooling2d = network->AddPooling2dLayer(desc);
1388  IConnectableLayer* output = network->AddOutputLayer(3);
1389 
1390  // Establish connections
1391  input0->GetOutputSlot(0).Connect(activation->GetInputSlot(0));
1392  activation->GetOutputSlot(0).Connect(pooling2d->GetInputSlot(0));
1393  pooling2d->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1394 
1395  // Set TensorInfo
1396  input0->GetOutputSlot(0).SetTensorInfo(info);
1397  activation->GetOutputSlot(0).SetTensorInfo(info);
1398  pooling2d->GetOutputSlot(0).SetTensorInfo(info);
1399 
1400  TestNetwork(network.get(), shape);
1401 }
1402 
1404 {
1405  INetworkPtr network = INetwork::Create();
1406 
1407  // Constant layer data
1408  std::vector<float> data = {-2.0f, -1.0f, 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f};
1409  const TensorShape shape{1U, 1U, 3U, 3U};
1410  TensorInfo tensorInfo(shape, DataType::Float32);
1411  ConstTensor constantTensor(tensorInfo, data);
1412 
1413  // Add the layers
1414  IConnectableLayer* input = network->AddInputLayer(0);
1415  IConnectableLayer* constant = network->AddConstantLayer(constantTensor);
1416  IConnectableLayer* addition = network->AddAdditionLayer();
1417  IConnectableLayer* output = network->AddOutputLayer(1);
1418 
1419  // Establish connections
1420  input->GetOutputSlot(0).Connect(addition->GetInputSlot(0));
1421  constant->GetOutputSlot(0).Connect(addition->GetInputSlot(1));
1422  addition->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1423 
1424  // Set TensorInfo in the remaining layers
1425  input->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1426  addition->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1427  constant->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1428 
1429  TestNetwork(network.get(), shape);
1430 }
1431 
1432 BOOST_AUTO_TEST_CASE(QuantizeArgMinMax)
1433 {
1434  INetworkPtr network = INetwork::Create();
1435 
1436  const TensorShape inputShape{ 1, 1, 1, 5 };
1437  const TensorShape outputShape{ 1, 1, 1 };
1438 
1439  TensorInfo inputInfo(inputShape, DataType::Float32);
1440  TensorInfo outputInfo(outputShape, DataType::Float32);
1441 
1442  // Add the input layers
1443  IConnectableLayer* input = network->AddInputLayer(0);
1444 
1445  // Add the layer under test
1446  ArgMinMaxDescriptor argMinMaxDescriptor;
1447  argMinMaxDescriptor.m_Function = ArgMinMaxFunction::Max;
1448  IConnectableLayer* argMinMaxLayer = network->AddArgMinMaxLayer(argMinMaxDescriptor);
1449 
1450  // Add the output layers
1451  IConnectableLayer* output = network->AddOutputLayer(1);
1452 
1453  // Establish connections
1454  input->GetOutputSlot(0).Connect(argMinMaxLayer->GetInputSlot(0));
1455  argMinMaxLayer->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1456 
1457  // Set tensor info
1458  input->GetOutputSlot(0).SetTensorInfo(inputInfo);
1459  argMinMaxLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1460 
1461  TestNetwork(network.get(), inputShape, outputShape);
1462 }
1463 
1464 BOOST_AUTO_TEST_CASE(QuantizeComparison)
1465 {
1466  const TensorShape tensorShape{ 1u };
1467  const TensorInfo tensorInfo(tensorShape, DataType::Float32);
1468 
1469  INetworkPtr network = INetwork::Create();
1471 
1472  IConnectableLayer* inputLayer0 = network->AddInputLayer(0);
1473  IConnectableLayer* inputLayer1 = network->AddInputLayer(1);
1474  IConnectableLayer* comparisonLayer = network->AddComparisonLayer(descriptor);
1475  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
1476 
1477  inputLayer0->GetOutputSlot(0).Connect(comparisonLayer->GetInputSlot(0));
1478  inputLayer1->GetOutputSlot(0).Connect(comparisonLayer->GetInputSlot(1));
1479  comparisonLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1480 
1481  inputLayer0->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1482  inputLayer1->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1483  comparisonLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1484 
1485  TestNetwork(network.get(), tensorShape);
1486 }
1487 
1488 BOOST_AUTO_TEST_CASE(QuantizeConcat)
1489 {
1490  class TestConcatQuantization : public TestQuantization
1491  {
1492  public:
1493  TestConcatQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
1494  : TestQuantization(inputShape, outputShape) {}
1495 
1496  TestConcatQuantization(const QuantizerOptions& options,
1497  const TensorShape& inputShape,
1498  const TensorShape& outputShape)
1499  : TestQuantization(options, inputShape, outputShape) {}
1500 
1501  void ExecuteStrategy(const armnn::IConnectableLayer* layer,
1502  const BaseDescriptor& descriptor,
1503  const std::vector<armnn::ConstTensor>& constants,
1504  const char* name,
1505  const armnn::LayerBindingId id) override
1506  {
1507  IgnoreUnused(name, constants, id, descriptor);
1508 
1509  switch (layer->GetType())
1510  {
1512  break;
1514  break;
1516  {
1517  TensorInfo outputInfo = layer->GetOutputSlot(0).GetTensorInfo();
1518  TestQuantizationParams(
1519  outputInfo, {60.8f / g_AsymmU8QuantizationBase, 65},
1520  {60.8f / g_SymmS8QuantizationBase, -63},
1521  {45.3f / g_SymmS8QuantizationBase, 0},
1522  {45.3f / g_SymmS16QuantizationBase, 0});
1523 
1524  TensorInfo inputInfo0 = layer->GetInputSlot(0).GetConnection()->GetTensorInfo();
1525  TensorInfo inputInfo1 = layer->GetInputSlot(1).GetConnection()->GetTensorInfo();
1526  TensorInfo inputInfo2 = layer->GetInputSlot(2).GetConnection()->GetTensorInfo();
1527 
1528  TestDifferentQuantizationScale(inputInfo0, inputInfo1);
1529  TestDifferentQuantizationScale(inputInfo0, inputInfo2);
1530  TestDifferentQuantizationScale(inputInfo1, inputInfo2);
1531  TestDifferentQuantizationScale(inputInfo0, outputInfo);
1532  break;
1533  }
1534  default:
1535  {}
1536  }
1537  }
1538  };
1539 
1540  INetworkPtr network = INetwork::Create();
1541 
1542  IConnectableLayer* input0 = network->AddInputLayer(0);
1543  IConnectableLayer* input1 = network->AddInputLayer(1);
1544  IConnectableLayer* input2 = network->AddInputLayer(2);
1545 
1546  OriginsDescriptor descriptor(3, 1);
1547  IConnectableLayer* concatLayer = network->AddConcatLayer(descriptor);
1548 
1549  IConnectableLayer* output0 = network->AddOutputLayer(3);
1550 
1551  // Establish connections
1552  input0->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(0));
1553  input1->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(1));
1554  input2->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(2));
1555  concatLayer->GetOutputSlot(0).Connect(output0->GetInputSlot(0));
1556 
1557  // Set TensorInfo
1558  const TensorShape shape{1U};
1560 
1561  input0->GetOutputSlot(0).SetTensorInfo(info);
1562  input1->GetOutputSlot(0).SetTensorInfo(info);
1563  input2->GetOutputSlot(0).SetTensorInfo(info);
1564  concatLayer->GetOutputSlot(0).SetTensorInfo(info);
1565 
1566  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1567  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
1568  INetworkQuantizerPtr quantizerPtrQAsymmU8 = INetworkQuantizer::Create(network.get());
1569  INetworkQuantizerPtr quantizerPtrQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options);
1570  INetworkQuantizerPtr quantizerPtrQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options);
1571  // Override the input ranges
1572  float min = -15.5f;
1573  float max = 45.3f;
1574 
1575  quantizerPtrQAsymmU8->OverrideInputRange(0, (min + 2.1f), (max - 3.2f));
1576  quantizerPtrQAsymmU8->OverrideInputRange(1, (min + 6.7f), max);
1577  quantizerPtrQAsymmU8->OverrideInputRange(2, min, (max - 7.8f));
1578 
1579  quantizerPtrQSymmS8->OverrideInputRange(0, (min + 2.1f), (max - 3.2f));
1580  quantizerPtrQSymmS8->OverrideInputRange(1, (min + 6.7f), max);
1581  quantizerPtrQSymmS8->OverrideInputRange(2, min, (max - 7.8f));
1582 
1583  quantizerPtrQSymmS16->OverrideInputRange(0, (min + 2.1f), (max - 3.2f));
1584  quantizerPtrQSymmS16->OverrideInputRange(1, (min + 6.7f), max);
1585  quantizerPtrQSymmS16->OverrideInputRange(2, min, (max - 7.8f));
1586 
1587  INetworkPtr quantizedNetworkQAsymmU8 = quantizerPtrQAsymmU8->ExportNetwork();
1588  TestConcatQuantization validatorQAsymmU8(shape, shape);
1589  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1590 
1591  INetworkPtr quantizedNetworkQSymmS8 = quantizerPtrQSymmS8->ExportNetwork();
1592  TestConcatQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
1593  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1594 
1595  INetworkPtr quantizedNetworkQSymmS16 = quantizerPtrQSymmS16->ExportNetwork();
1596  TestConcatQuantization validatorQSymmS16(qSymmS16options, shape, shape);
1597  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1598 }
1599 
1600 BOOST_AUTO_TEST_CASE(QuantizeReshape)
1601 {
1602  INetworkPtr network = INetwork::Create();
1603 
1604  const TensorShape shape{1U};
1606 
1607  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
1608 
1609  // Add the layer under test
1610  ReshapeDescriptor descriptor({1, 2, 3, 4});
1611  IConnectableLayer* reshape = network->AddReshapeLayer(descriptor);
1612 
1613  CompleteLeakyReluNetwork(network.get(), activation, reshape, info);
1614 
1615  TestNetwork(network.get(), shape);
1616 }
1617 
1618 BOOST_AUTO_TEST_CASE(QuantizeSplitter)
1619 {
1620  INetworkPtr network = INetwork::Create();
1621 
1622  const TensorShape shape{3U};
1624 
1625  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
1626 
1627  // Add the layer under test
1628  ViewsDescriptor splitterDesc(2,4);
1629  IConnectableLayer* splitter = network->AddSplitterLayer(splitterDesc);
1630  CompleteLeakyReluNetwork(network.get(), activation, splitter, info);
1631 
1632  TestNetwork(network.get(), shape);
1633 }
1634 
1635 BOOST_AUTO_TEST_CASE(QuantizeResize)
1636 {
1637  INetworkPtr network = INetwork::Create();
1638 
1639  const TensorShape shape{1U};
1641 
1642  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
1643 
1644  // Add the layer under test
1645  ResizeDescriptor descriptor;
1646  descriptor.m_TargetHeight = 3;
1647  descriptor.m_TargetWidth = 3;
1648  IConnectableLayer* resizeLayer = network->AddResizeLayer(descriptor);
1649 
1650  CompleteLeakyReluNetwork(network.get(), activation, resizeLayer, info);
1651 
1652  TestNetwork(network.get(), shape);
1653 }
1654 
1655 BOOST_AUTO_TEST_CASE(QuantizeStridedSlice)
1656 {
1657  INetworkPtr network = INetwork::Create();
1658 
1659  const TensorShape shape{3U};
1661 
1662  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
1663 
1664  // Add the layer under test
1665  StridedSliceDescriptor stridedSliceDesc;
1666  IConnectableLayer* stridedSlice = network->AddStridedSliceLayer(stridedSliceDesc);
1667 
1668  CompleteLeakyReluNetwork(network.get(), activation, stridedSlice, info);
1669 
1670  TestNetwork(network.get(), shape);
1671 }
1672 
1673 BOOST_AUTO_TEST_CASE(QuantizeBatchToSpace)
1674 {
1675  INetworkPtr network = INetwork::Create();
1676 
1677  const TensorShape shape{1U};
1679 
1680  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
1681 
1682  // Add the layer under test
1683  BatchToSpaceNdDescriptor descriptor;
1684  IConnectableLayer* batchToSpace = network->AddBatchToSpaceNdLayer(descriptor);
1685 
1686  CompleteLeakyReluNetwork(network.get(), activation, batchToSpace, info);
1687 
1688  TestNetwork(network.get(), shape);
1689 }
1690 
1691 BOOST_AUTO_TEST_CASE(QuantizePrelu)
1692 {
1693  class TestPreluQuantization : public TestQuantization
1694  {
1695  public:
1696  TestPreluQuantization(const TensorShape& inputShape,
1697  const TensorShape& alphaShape,
1698  const TensorShape& outputShape)
1699  : TestQuantization(inputShape, outputShape)
1700  , m_AlphaShape(alphaShape)
1701  {}
1702 
1703  TestPreluQuantization(const QuantizerOptions& options,
1704  const TensorShape& inputShape,
1705  const TensorShape& alphaShape,
1706  const TensorShape& outputShape)
1707  : TestQuantization(options, inputShape, outputShape)
1708  , m_AlphaShape(alphaShape)
1709  {}
1710 
1711  void ExecuteStrategy(const armnn::IConnectableLayer* layer,
1712  const BaseDescriptor& descriptor,
1713  const std::vector<armnn::ConstTensor>& constants,
1714  const char* name,
1715  const armnn::LayerBindingId id) override
1716  {
1717  IgnoreUnused(name, constants, id, descriptor);
1718 
1719  switch (layer->GetType())
1720  {
1722  {
1723  const TensorInfo& info = layer->GetOutputSlot(0).GetTensorInfo();
1724 
1725  switch (id)
1726  {
1727  case 0: // Input
1728  BOOST_TEST(m_InputShape == info.GetShape());
1729  break;
1730  case 1: // Alpha
1731  BOOST_TEST(m_AlphaShape == info.GetShape());
1732  break;
1733  default:
1734  throw InvalidArgumentException("Invalid layer binding id for PReLU layer");
1735  }
1736 
1737  // Based off current default [-15.0f, 15.0f]
1738  TestQuantizationParams(info,
1739  { 30.0f / g_AsymmU8QuantizationBase, 128 }, // QASymmU8
1740  { 30.0f / g_AsymmS8QuantizationBase, 0}, // QASymmS8
1741  { 15.0f / g_SymmS8QuantizationBase, 0}, // QSymmS8
1742  { 15.0f / g_SymmS16QuantizationBase, 0 }); // QSymmS16
1743  break;
1744  }
1746  {
1747  const TensorInfo& info = layer->GetInputSlot(0).GetConnection()->GetTensorInfo();
1748  BOOST_TEST(m_OutputShape == info.GetShape());
1749  break;
1750  }
1752  {
1753  const TensorInfo& info = layer->GetOutputSlot(0).GetTensorInfo();
1754  TestQuantizationParams(info,
1755  { 30.0f / g_AsymmU8QuantizationBase, 128 }, // QASymmU8
1756  { 30.0f / g_AsymmS8QuantizationBase, 0}, // QAsymmS8
1757  { 15.0f / g_SymmS8QuantizationBase, 0}, // QSymmS8
1758  { 15.0f / g_SymmS16QuantizationBase, 0 }); // QSymmS16
1759  break;
1760  }
1761  default:
1762  {}
1763  }
1764  }
1765 
1766  private:
1767  TensorShape m_AlphaShape;
1768  };
1769 
1770  INetworkPtr network = INetwork::Create();
1771 
1772  const TensorShape inputShape{ 4, 1, 2 };
1773  const TensorShape alphaShape{ 5, 4, 3, 1 };
1774  const TensorShape outputShape{ 5, 4, 3, 2 };
1775  TensorInfo inputInfo(inputShape, DataType::Float32);
1776  TensorInfo alphaInfo(alphaShape, DataType::Float32);
1777  TensorInfo outputInfo(outputShape, DataType::Float32);
1778 
1779  // Add the input layers
1780  IConnectableLayer* input = network->AddInputLayer(0);
1781  IConnectableLayer* alpha = network->AddInputLayer(1);
1782 
1783  // Add the layer under test
1784  IConnectableLayer* prelu = network->AddPreluLayer("prelu");
1785 
1786  // Add the output layers
1787  IConnectableLayer* output = network->AddOutputLayer(0);
1788 
1789  // Establish connections
1790  input->GetOutputSlot(0).Connect(prelu->GetInputSlot(0));
1791  alpha->GetOutputSlot(0).Connect(prelu->GetInputSlot(1));
1792  prelu->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1793 
1794  // Set tensor info
1795  input->GetOutputSlot(0).SetTensorInfo(inputInfo);
1796  alpha->GetOutputSlot(0).SetTensorInfo(alphaInfo);
1797  prelu->GetOutputSlot(0).SetTensorInfo(outputInfo);
1798 
1799  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
1800  TestPreluQuantization validatorQAsymmU8(inputShape, alphaShape, outputShape);
1801  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1802 
1803  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1804  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
1805  TestPreluQuantization validatorQAsymmS8(qAsymmS8Options, inputShape, alphaShape, outputShape);
1806  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
1807 
1808  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1809  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
1810  TestPreluQuantization validatorQSymmS8(qSymmS8Options, inputShape, alphaShape, outputShape);
1811  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1812 
1813  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
1814  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
1815  TestPreluQuantization validatorQSymmS16(qSymmS16options, inputShape, alphaShape, outputShape);
1816  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1817 }
1818 
1820 {
1821  INetworkPtr network = INetwork::Create();
1822 
1823  TensorShape shape{ 3 };
1825 
1826  std::initializer_list<float> floatData{ -1.0f, 1.5f, 2.0f };
1827  std::vector<float> weightsData(floatData);
1828  ConstTensor weights(info, weightsData);
1829 
1831  descriptor.m_BiasEnabled = useBiases;
1832 
1833  // construct network
1834  IConnectableLayer* input = network->AddInputLayer(0);
1835  Optional<ConstTensor> optionalBiases;
1836  std::vector<float> biasesData(floatData);
1837  if (useBiases)
1838  {
1839  ConstTensor biases(info, biasesData);
1840  optionalBiases = Optional<ConstTensor>(biases);
1841  }
1842  IConnectableLayer* transposeConv2d = network->AddTransposeConvolution2dLayer(descriptor, weights, optionalBiases);
1843  IConnectableLayer* output = network->AddOutputLayer(1);
1844 
1845  input->GetOutputSlot(0).Connect(transposeConv2d->GetInputSlot(0));
1846  transposeConv2d->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1847 
1848  input->GetOutputSlot(0).SetTensorInfo(info);
1849  transposeConv2d->GetOutputSlot(0).SetTensorInfo(info);
1850 
1851  TestNetwork(network.get(), shape);
1852 }
1853 
1854 BOOST_AUTO_TEST_CASE(QuantizeTransposeConvolution2d)
1855 {
1857 }
1858 
1859 BOOST_AUTO_TEST_CASE(QuantizeTransposeConvolution2dWithBiases)
1860 {
1862 }
1863 
1864 BOOST_AUTO_TEST_CASE(QuantizeStack)
1865 {
1866  class TestStackQuantization : public TestQuantization
1867  {
1868  public:
1869  TestStackQuantization(const TensorShape& inputShape,
1870  const TensorShape& outputShape)
1871  : TestQuantization(inputShape, outputShape) {}
1872 
1873  TestStackQuantization(const QuantizerOptions& options,
1874  const TensorShape& inputShape,
1875  const TensorShape& outputShape)
1876  : TestQuantization(options, inputShape, outputShape) {}
1877 
1878  void ExecuteStrategy(const armnn::IConnectableLayer* layer,
1879  const BaseDescriptor& descriptor,
1880  const std::vector<armnn::ConstTensor>& constants,
1881  const char* name,
1882  const armnn::LayerBindingId id) override
1883  {
1884  IgnoreUnused(name, constants, id, descriptor);
1885 
1886  switch (layer->GetType())
1887  {
1889  {
1890  break;
1891  }
1893  {
1894  break;
1895  }
1897  {
1898  TensorInfo outputInfo = layer->GetOutputSlot(0).GetTensorInfo();
1899 
1900  TestQuantizationParams(outputInfo,
1901  { 30.0f / g_AsymmU8QuantizationBase, 128 },
1902  { 30.0f / g_AsymmS8QuantizationBase, 0},
1903  { 15.0f / g_SymmS8QuantizationBase, 0},
1904  { 15.0f / g_SymmS16QuantizationBase, 0 });
1905  break;
1906  }
1907  default:
1908  {}
1909  }
1910  }
1911  };
1912 
1913  INetworkPtr network = INetwork::Create();
1914 
1915  IConnectableLayer* input0 = network->AddInputLayer(0);
1916  IConnectableLayer* input1 = network->AddInputLayer(1);
1917 
1918  const TensorShape inputShape{ 3, 4, 5 };
1919  const TensorShape outputShape{ 3, 4, 2, 5 };
1920 
1921  StackDescriptor descriptor(2, 2, inputShape);
1922  IConnectableLayer* stackLayer = network->AddStackLayer(descriptor);
1923 
1924  IConnectableLayer* output = network->AddOutputLayer(0);
1925 
1926  input0->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(0));
1927  input1->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(1));
1928  stackLayer->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1929 
1930  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
1931  TestStackQuantization validatorQAsymmU8(inputShape, outputShape);
1932  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1933 
1934  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1935  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
1936  TestStackQuantization validatorQAsymmS8(qAsymmS8Options, inputShape, inputShape);
1937  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
1938 
1939  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1940  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
1941  TestStackQuantization validatorQSymmS8(qSymmS8Options, inputShape, inputShape);
1942  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1943 
1944  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
1945  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
1946  TestStackQuantization validatorQSymmS16(qSymmS16options, inputShape, outputShape);
1947  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1948 }
1949 
1950 BOOST_AUTO_TEST_CASE(QuantizeSlice)
1951 {
1952  TensorShape shape{ 3 };
1954 
1955  INetworkPtr network = INetwork::Create();
1956 
1957  IConnectableLayer* inputLayer = network->AddInputLayer(0);
1958  IConnectableLayer* sliceLayer = network->AddSliceLayer(SliceDescriptor());
1959  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
1960 
1961  inputLayer->GetOutputSlot(0).Connect(sliceLayer->GetInputSlot(0));
1962  sliceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1963 
1964  inputLayer->GetOutputSlot(0).SetTensorInfo(info);
1965  sliceLayer->GetOutputSlot(0).SetTensorInfo(info);
1966 
1967  TestNetwork(network.get(), shape);
1968 }
1969 
1970 std::vector<uint8_t> SetupQuantize(float value)
1971 {
1972  armnn::TensorInfo inputInfo({ 1, 2, 2 }, armnn::DataType::Float32);
1973  inputInfo.SetQuantizationScale(1.0f);
1974  inputInfo.SetQuantizationOffset(1);
1975  std::vector<float> input({ value, 0.0f, 0.0f, 1.0f });
1976  const std::vector<float> &inputRef = input;
1977 
1978  auto output = armnnUtils::QuantizedVector<uint8_t>(inputRef,
1979  inputInfo.GetQuantizationScale(),
1980  inputInfo.GetQuantizationOffset());
1981 
1982  return output;
1983 }
1984 
1986 {
1987  BOOST_CHECK_EQUAL(SetupQuantize(std::numeric_limits<float>::infinity())[0], 255);
1988 }
1989 
1990 BOOST_AUTO_TEST_CASE(QuantizeNegativeInf)
1991 {
1992  BOOST_CHECK_EQUAL(SetupQuantize(-1 * std::numeric_limits<float>::infinity())[0], 0);
1993 }
1994 
1995 class TestPreserveType : public TestQuantization
1996 {
1997 public:
1998  TestPreserveType(const QuantizerOptions& options,
1999  const DataType& dataType,
2000  const TensorShape& inputShape,
2001  const TensorShape& outputShape)
2002  : TestQuantization(options, inputShape, outputShape)
2003  , m_DataType(dataType)
2004  , m_VisitedQuantizeLayer(false)
2005  , m_VisitedDequantizeLayer(false) {}
2006 
2007  void ExecuteStrategy(const armnn::IConnectableLayer* layer,
2008  const BaseDescriptor& descriptor,
2009  const std::vector<armnn::ConstTensor>& constants,
2010  const char* name,
2011  const armnn::LayerBindingId id) override
2012  {
2013  IgnoreUnused(name, constants, id, descriptor);
2014 
2015  switch (layer->GetType())
2016  {
2018  {
2019  const TensorInfo& info = layer->GetOutputSlot(0).GetTensorInfo();
2020  BOOST_TEST(GetDataTypeName(info.GetDataType()) == GetDataTypeName(m_DataType));
2021  BOOST_TEST(m_InputShape == info.GetShape());
2022  break;
2023  }
2025  {
2026  const TensorInfo& info = layer->GetInputSlot(0).GetConnection()->GetTensorInfo();
2027  BOOST_TEST(GetDataTypeName(info.GetDataType()) == GetDataTypeName(m_DataType));
2028  BOOST_TEST(m_OutputShape == info.GetShape());
2029  break;
2030  }
2032  {
2033  m_VisitedQuantizeLayer = true;
2034  break;
2035  }
2037  {
2038  m_VisitedDequantizeLayer = true;
2039  break;
2040  }
2041  default:
2042  {}
2043  }
2044  }
2045 
2046  void CheckQuantizeDequantizeLayerVisited(bool expected)
2047  {
2048  if (expected)
2049  {
2050  BOOST_CHECK(m_VisitedQuantizeLayer);
2051  BOOST_CHECK(m_VisitedDequantizeLayer);
2052  }
2053  else
2054  {
2055  BOOST_CHECK(!m_VisitedQuantizeLayer);
2056  BOOST_CHECK(!m_VisitedDequantizeLayer);
2057  }
2058  }
2059 private:
2060  const DataType m_DataType;
2061  bool m_VisitedQuantizeLayer;
2062  bool m_VisitedDequantizeLayer;
2063 };
2064 
2065 void PreserveTypeTestImpl(const DataType& dataType)
2066 {
2067  INetworkPtr network = INetwork::Create();
2068 
2069  // Add the layers
2070  IConnectableLayer* input0 = network->AddInputLayer(0);
2071  IConnectableLayer* input1 = network->AddInputLayer(1);
2072  IConnectableLayer* addition = network->AddAdditionLayer();
2073  IConnectableLayer* output = network->AddOutputLayer(2);
2074 
2075  input0->GetOutputSlot(0).Connect(addition->GetInputSlot(0));
2076  input1->GetOutputSlot(0).Connect(addition->GetInputSlot(1));
2077  addition->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2078 
2079  const TensorShape shape{1U, 2U, 3U};
2080  const TensorInfo info(shape, dataType);
2081  input0->GetOutputSlot(0).SetTensorInfo(info);
2082  input1->GetOutputSlot(0).SetTensorInfo(info);
2083  addition->GetOutputSlot(0).SetTensorInfo(info);
2084 
2085  QuantizerOptions options = dataType == DataType::Float32 ?
2086  QuantizerOptions(DataType::QAsymmU8, true) : QuantizerOptions(dataType, true);
2087 
2088  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get(), options)->ExportNetwork();
2089  TestPreserveType validatorQAsymmU8(options, dataType, shape, shape);
2090  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
2091  validatorQAsymmU8.CheckQuantizeDequantizeLayerVisited(
2092  dataType == DataType::Float32 || dataType == DataType::Float16);
2093 }
2094 
2095 BOOST_AUTO_TEST_CASE(PreserveTypeFloat32)
2096 {
2098 }
2099 
2100 BOOST_AUTO_TEST_CASE(PreserveTypeQAsymmU8)
2101 {
2103 }
2104 
2105 BOOST_AUTO_TEST_CASE(PreserveTypeQsymm8)
2106 {
2108 }
2109 
2110 BOOST_AUTO_TEST_CASE(PreserveTypeQsymm16)
2111 {
2113 }
2114 
2115 BOOST_AUTO_TEST_CASE(TestConnectionPreservationAfterDynamicQuant)
2116 {
2117  class TestConnectionPreservation : public IStrategy
2118  {
2119  public:
2120  TestConnectionPreservation(const Graph& graph)
2121  : m_Graph(graph)
2122  {}
2123 
2124  void ExecuteStrategy(const armnn::IConnectableLayer* layer,
2125  const BaseDescriptor& descriptor,
2126  const std::vector<armnn::ConstTensor>& constants,
2127  const char* name,
2128  const armnn::LayerBindingId id) override
2129  {
2130  IgnoreUnused(name, constants, id, descriptor);
2131 
2132  switch (layer->GetType())
2133  {
2135  {
2136  CheckLayerName(layer->GetInputSlot(0).GetConnection()->GetOwningLayerGuid(), "reLU1");
2137  CheckLayerName(layer->GetInputSlot(1).GetConnection()->GetOwningLayerGuid(), "reLU2");
2138  break;
2139  }
2140  default:
2141  {}
2142  }
2143  }
2144 
2145  void CheckLayerName(LayerGuid guid, std::string expectedName)
2146  {
2147  bool guidFound = false;
2148  for (Layer* layer : m_Graph)
2149  {
2150  if (layer->GetGuid() == guid)
2151  {
2152  BOOST_CHECK_EQUAL(layer->GetName(), expectedName.c_str());
2153  guidFound = true;
2154  break;
2155  }
2156  }
2157  if (!guidFound)
2158  {
2159  BOOST_FAIL("No layer matching the GUID was found");
2160  }
2161  }
2162  private:
2163  Graph m_Graph;
2164  };
2165 
2166  class TestNetwork : public INetwork
2167  {
2168  public :
2169  NetworkImpl* GetPNetworkImpl()
2170  {
2171  return pNetworkImpl.get();
2172  }
2173  };
2174 
2175  TestNetwork testNetwork;
2176 
2177  IConnectableLayer* inputLayer = testNetwork.AddInputLayer(0,"inputLayer1");
2178  armnn::ActivationDescriptor ReLUDesc;
2180 
2181  IConnectableLayer* reLULayer1 = testNetwork.AddActivationLayer(ReLUDesc, "reLU1");
2182  IConnectableLayer* reLULayer2 = testNetwork.AddActivationLayer(ReLUDesc, "reLU2");
2183  IConnectableLayer* addLayer1 = testNetwork.AddAdditionLayer("addLayer1");
2184  IConnectableLayer* outputLayer = testNetwork.AddOutputLayer(0,"outPutLayer1");
2185 
2186  inputLayer->GetOutputSlot(0).Connect(reLULayer1->GetInputSlot(0));
2187  reLULayer1->GetOutputSlot(0).Connect(reLULayer2->GetInputSlot(0));
2188  reLULayer1->GetOutputSlot(0).Connect(addLayer1->GetInputSlot(0));
2189  reLULayer2->GetOutputSlot(0).Connect(addLayer1->GetInputSlot(1));
2190  addLayer1->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2191 
2192  inputLayer->GetOutputSlot(0).SetTensorInfo(TensorInfo(TensorShape({1, 2, 2, 1}), DataType::Float32));
2193  reLULayer1->GetOutputSlot(0).SetTensorInfo(TensorInfo(TensorShape({1, 2, 2, 1}), DataType::Float32));
2194  reLULayer2->GetOutputSlot(0).SetTensorInfo(TensorInfo(TensorShape({1, 2, 2, 1}), DataType::Float32));
2195  addLayer1->GetOutputSlot(0).SetTensorInfo(TensorInfo(TensorShape({1, 2, 2, 1}), DataType::Float32));
2196 
2197  TestConnectionPreservation strategy1(testNetwork.GetPNetworkImpl()->GetGraph());
2198  VisitLayersTopologically(&testNetwork, strategy1);
2199 
2201 
2202  armnn::TensorInfo tensorInfo = GetInputTensorInfo(&testNetwork);
2203 
2204  std::vector<float> inputData({0, 2, 0, 4});
2205  armnn::ConstTensor inputTensor(tensorInfo, inputData.data());
2206 
2207  InputTensors inputTensors;
2208  inputTensors.push_back(std::make_pair(0, inputTensor));
2209  quantizer->Refine(inputTensors);
2210 
2211  INetworkPtr quantNetwork = quantizer->ExportNetwork();
2212 
2213  TestNetwork* testQuantNetwork = static_cast<TestNetwork*>(quantNetwork.get());
2214 
2215  TestConnectionPreservation strategy2(testQuantNetwork->GetPNetworkImpl()->GetGraph());
2216  VisitLayersTopologically(quantNetwork.get(), strategy2);
2217 }
2218 
2220 } // namespace armnn
BOOST_AUTO_TEST_SUITE(TensorflowLiteParser)
const float g_AsymmU8QuantizationBase
bool m_BiasEnabled
Enable/disable bias.
IConnectableLayer * AddActivationLayer(const ActivationDescriptor &activationDescriptor, const char *name=nullptr)
Adds an activation layer to the network.
Definition: Network.cpp:218
std::pair< float, int > OffsetScalePair
A ViewsDescriptor for the SplitterLayer.
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:62
bool m_BiasEnabled
Enable/disable bias.
A TransposeConvolution2dDescriptor for the TransposeConvolution2dLayer.
const TensorShape & GetShape() const
Definition: Tensor.hpp:187
A ReshapeDescriptor for the ReshapeLayer.
IConnectableLayer * AddAdditionLayer(const char *name=nullptr)
Definition: Network.cpp:1947
TensorInfo GetInputTensorInfo(const INetwork *network)
INetworkPtr CreateNetworkWithActivationLayer(const ActivationDescriptor &descriptor, const TensorShape &shape)
A ComparisonDescriptor for the ComparisonLayer.
Definition: Descriptors.hpp:78
void TestNetwork(INetwork *network, const TensorShape inShape, const TensorShape outShape)
A Convolution2dDescriptor for the Convolution2dLayer.
INetworkPtr CreateNetworkWithInputOutputLayers()
bool m_BiasEnabled
Enable/disable bias.
float m_Beta
Exponentiation value.
const float g_SymmS8QuantizationBase
ArgMinMaxFunction m_Function
Specify if the function is to find Min or Max.
Definition: Descriptors.hpp:70
std::unique_ptr< class INetworkQuantizer, void(*)(INetworkQuantizer *quantizer)> INetworkQuantizerPtr
Main network class which provides the interface for building up a neural network. ...
Definition: INetwork.hpp:178
std::vector< std::pair< LayerBindingId, class ConstTensor > > InputTensors
Definition: Tensor.hpp:340
std::vector< uint8_t > SetupQuantize(float value)
Copyright (c) 2021 ARM Limited and Contributors.
void IgnoreUnused(Ts &&...)
INetworkPtr CreateNetworkWithFullyConnectedLayer(const bool biasEnabled, const TensorShape &inputShape, const TensorShape &outputShape)
A SpaceToDepthDescriptor for the SpaceToDepthLayer.
A BatchToSpaceNdDescriptor for the BatchToSpaceNdLayer.
std::pair< float, float > MinMaxRange
Private implementation of INetwork.
Definition: Network.hpp:31
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
Definition: Types.hpp:210
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
IConnectableLayer * AddInputLayer(LayerBindingId id, const char *name=nullptr)
Adds an input layer to the network.
Definition: Network.cpp:50
uint32_t m_NumOutputs
Number of output tensors.
INetworkPtr CreateNetworkWithArgMinMaxLayer(const ArgMinMaxDescriptor &descriptor, const TensorShape &shape)
constexpr const char * GetDataTypeName(DataType dataType)
Definition: TypesUtils.hpp:180
A ResizeDescriptor for the ResizeLayer.
MinMaxRange GetRange(LayerGuid guid, unsigned int idx) const
Retrieve the Range for a particular output slot on a particular layer.
Base class for all descriptors.
Definition: Descriptors.hpp:22
A StackDescriptor for the StackLayer.
std::unique_ptr< NetworkImpl > pNetworkImpl
Definition: INetwork.hpp:693
IConnectableLayer * AddInputLayer(LayerBindingId id, const char *name=nullptr)
Definition: Network.cpp:1682
DataType
Definition: Types.hpp:32
IConnectableLayer * CreateStartOfLeakyReluNetwork(INetwork *network, const TensorInfo &info)
#define ARMNN_ASSERT_MSG(COND, MSG)
Definition: Assert.hpp:15
void ApplyStrategyToLayers(const LayerContainer &layerContainer, IStrategy &strategy)
int32_t GetQuantizationOffset() const
Definition: Tensor.cpp:469
An ArgMinMaxDescriptor for ArgMinMaxLayer.
Definition: Descriptors.hpp:56
float GetQuantizationScale() const
Definition: Tensor.cpp:452
DataType GetDataType() const
Definition: Tensor.hpp:194
An OriginsDescriptor for the ConcatLayer.
bool has_value() const noexcept
Definition: Optional.hpp:53
std::unordered_map< LayerGuid, MinMaxRanges > MinMaxRangeMap
A FullyConnectedDescriptor for the FullyConnectedLayer.
virtual LayerGuid GetGuid() const =0
Returns the unique id of the layer.
bool m_BiasEnabled
Enable/disable bias.
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:314
IConnectableLayer * AddOutputLayer(LayerBindingId id, const char *name=nullptr)
Adds an output layer to the network.
Definition: Network.cpp:359
bool HasRanges(LayerGuid guid) const
Query that there is an entry for a layer.
void TestQuantizeDepthwiseConvolution2d(bool useBiases)
IConnectableLayer * AddOutputLayer(LayerBindingId id, const char *name=nullptr)
Definition: Network.cpp:1957
std::vector< MinMaxRange > MinMaxRanges
void SetQuantizationScale(float scale)
Definition: Tensor.cpp:464
A StandInDescriptor for the StandIn layer.
BOOST_AUTO_TEST_CASE(CheckConvolution2dLayer)
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:25
const TensorInfo & GetInfo() const
Definition: Tensor.hpp:282
min(a, max(b, input)) ReLu1 & ReLu6.
uint32_t m_TargetHeight
Target height value.
A SliceDescriptor for the SliceLayer.
Visitor base class with empty implementations.
const float g_TestTolerance
virtual LayerType GetType() const =0
Returns the armnn::LayerType of this layer.
void ValidateFullyConnectedLayer(const bool biasEnabled)
const float g_SymmS16QuantizationBase
bool IsEmpty() const
Query function to check that the RangeTracker is empty.
A SpaceToBatchNdDescriptor for the SpaceToBatchNdLayer.
float m_A
Alpha upper bound value used by the activation functions. (BoundedReLu, Linear, TanH, Elu).
Definition: Descriptors.hpp:50
BOOST_AUTO_TEST_SUITE_END()
EmptyOptional is used to initialize the Optional class in case we want to have default value for an O...
Definition: Optional.hpp:32
std::pair< float, float > MinMaxRange
void QuantizeConstant(const srcType *src, uint8_t *dst, size_t numElements, float &scale, int &offset)
uint32_t m_NumInputs
Number of input tensors.
void TestQuantizeConvolution2d(bool useBiases)
void VisitLayersTopologically(const INetwork *inputNetwork, IStrategy &visitor)
const Graph & GetGraph() const
Definition: Network.hpp:37
void CompleteLeakyReluNetwork(INetwork *network, IConnectableLayer *activation, IConnectableLayer *layerUnderTest, const TensorInfo &info)
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
Get a const input slot handle by slot index.
virtual const IOutputSlot * GetConnection() const =0
A StridedSliceDescriptor for the StridedSliceLayer.
virtual const TensorInfo & GetTensorInfo() const =0
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
Get the const output slot handle by slot index.
virtual const char * GetName() const =0
Returns the name of the layer.
InputLayersAccessor GetInputLayers() const
Returns a wrapper object with begin(), end() methods to iterate over the input layers in a range-base...
Definition: Graph.hpp:185
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
Definition: INetwork.hpp:173
INetworkPtr CreateNetworkWithSoftmaxLayer(const SoftmaxDescriptor &descriptor, const TensorShape &shape)
virtual int Connect(IInputSlot &destination)=0
virtual LayerGuid GetOwningLayerGuid() const =0
void PreserveTypeTestImpl(const DataType &dataType)
A Pooling2dDescriptor for the Pooling2dLayer.
An InstanceNormalizationDescriptor for InstanceNormalizationLayer.
static INetworkPtr Create(NetworkOptions networkOptions={})
Definition: Network.cpp:510
float m_B
Beta lower bound value used by the activation functions. (BoundedReLu, Linear, TanH).
Definition: Descriptors.hpp:52
A SoftmaxDescriptor for the SoftmaxLayer.
ActivationFunction m_Function
The activation function to use (Sigmoid, TanH, Linear, ReLu, BoundedReLu, SoftReLu, LeakyReLu, Abs, Sqrt, Square, Elu).
Definition: Descriptors.hpp:48
void TestQuantizeTransposeConvolution2d(bool useBiases)
const float g_AsymmS8QuantizationBase
A DepthwiseConvolution2dDescriptor for the DepthwiseConvolution2dLayer.
static INetworkQuantizerPtr Create(INetwork *inputNetwork, const QuantizerOptions &options=QuantizerOptions())
Create Quantizer object wrapped in unique_ptr.
A FillDescriptor for the FillLayer.
A BatchNormalizationDescriptor for the BatchNormalizationLayer.
A PermuteDescriptor for the PermuteLayer.