ArmNN  NotReleased
QuantizerTest.cpp
Go to the documentation of this file.
1 //
2 // Copyright © 2017 Arm Ltd. All rights reserved.
3 // SPDX-License-Identifier: MIT
4 //
5 
6 #include <armnn/INetwork.hpp>
8 #include <armnn/Tensor.hpp>
9 #include <armnn/Types.hpp>
10 
12 
13 #include <QuantizeHelper.hpp>
14 
15 #include "../Graph.hpp"
16 #include "../Network.hpp"
17 #include "../NetworkQuantizerUtils.hpp"
18 #include "../OverrideInputRangeVisitor.hpp"
19 #include "../RangeTracker.hpp"
20 #include "../../armnnQuantizer/CommandLineProcessor.hpp"
21 
22 #include <boost/core/ignore_unused.hpp>
23 #include <boost/test/unit_test.hpp>
24 
25 #include <unordered_map>
26 
27 namespace armnn
28 {
29 using MinMaxRange = std::pair<float, float>;
30 using MinMaxRanges = std::vector<MinMaxRange>;
31 using MinMaxRangeMap = std::unordered_map<LayerGuid, MinMaxRanges>;
32 
33 const float g_AsymmU8QuantizationBase = 255.0f;
34 // Coinciding with calcution which for AsymmS8 which calculates scale on an unsigned basis
35 const float g_AsymmS8QuantizationBase = 255.0f;
36 const float g_SymmS8QuantizationBase = 127.0f;
37 const float g_SymmS16QuantizationBase = 32767.0f;
38 const float g_TestTolerance = 0.000001f;
39 
40 BOOST_AUTO_TEST_SUITE(Quantizer)
41 
42 class TestQuantization : public LayerVisitorBase<VisitorThrowingPolicy>
43 {
44 public:
45  TestQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
47  , m_InputShape(inputShape)
48  , m_OutputShape(outputShape)
49  , m_QuantizerOptions(QuantizerOptions()) {}
50 
51  TestQuantization(const QuantizerOptions& options, const TensorShape& inputShape, const TensorShape& outputShape)
53  , m_InputShape(inputShape)
54  , m_OutputShape(outputShape)
55  , m_QuantizerOptions(options) {}
56 
57  void VisitInputLayer(const IConnectableLayer* layer,
58  LayerBindingId id,
59  const char* name = nullptr) override
60  {
61  boost::ignore_unused(id, name);
62  const TensorInfo& info = layer->GetOutputSlot(0).GetTensorInfo();
63  BOOST_TEST(m_InputShape == info.GetShape());
64  // Based off current default [-15.0f, 15.0f]
65  TestQuantizationParams(info, {30.0f / g_AsymmU8QuantizationBase, 128},
66  {30.0f / g_AsymmS8QuantizationBase, 0},
67  {15.0f / g_SymmS8QuantizationBase , 0},
68  {15.0f / g_SymmS16QuantizationBase, 0});
69  }
70 
71  void VisitOutputLayer(const IConnectableLayer* layer,
72  LayerBindingId id,
73  const char* name = nullptr) override
74  {
75  boost::ignore_unused(id, name);
76  const TensorInfo& info = layer->GetInputSlot(0).GetConnection()->GetTensorInfo();
77  BOOST_TEST(m_OutputShape == info.GetShape());
78  }
79 
80 protected:
81  void TestQuantizationParams(const TensorInfo& info,
82  const OffsetScalePair& qAsymmU8Params,
83  const OffsetScalePair& qAsymmS8Params,
84  const OffsetScalePair& qSymmS8Params,
85  const OffsetScalePair& qSymmS16Params)
86  {
87  switch (m_QuantizerOptions.m_ActivationFormat)
88  {
89  case DataType::QAsymmU8:
90  TestQuantizationParamsImpl(
91  info, DataType::QAsymmU8, qAsymmU8Params.first, qAsymmU8Params.second);
92  break;
93  case DataType::QAsymmS8:
94  TestQuantizationParamsImpl(
95  info, DataType::QAsymmS8, qAsymmS8Params.first, qAsymmS8Params.second);
96  break;
97  case DataType::QSymmS8:
98  TestQuantizationParamsImpl(
99  info, DataType::QSymmS8, qSymmS8Params.first, qSymmS8Params.second);
100  break;
101  case DataType::QSymmS16:
102  TestQuantizationParamsImpl(
103  info, DataType::QSymmS16, qSymmS16Params.first, qSymmS16Params.second);
104  break;
105  default:
106  throw InvalidArgumentException("Unsupported quantization target");
107  }
108  }
109 
110  void TestDifferentQuantizationScale(const TensorInfo& info0, const TensorInfo& info1)
111  {
112  BOOST_TEST(info0.GetQuantizationScale() != info1.GetQuantizationScale());
113  }
114 
115  void TestConstantQuantizationParams(const TensorInfo& info,
116  const OffsetScalePair& params,
117  DataType dataType = DataType::QAsymmU8)
118  {
119  boost::ignore_unused(dataType);
120  TestQuantizationParamsImpl(info, dataType, params.first, params.second);
121  }
122 
123  void TestBiasQuantizationParams(const TensorInfo& info,
124  const OffsetScalePair& qAsymmU8Params,
125  const OffsetScalePair& qAsymmS8Params,
126  const OffsetScalePair& qSymmS8Params,
127  const OffsetScalePair& qSymmS16Params,
128  DataType dataType = DataType::QAsymmU8)
129  {
130  switch (m_QuantizerOptions.m_ActivationFormat)
131  {
132  case DataType::QAsymmU8:
133  TestQuantizationParamsImpl(info, dataType, qAsymmU8Params.first, qAsymmU8Params.second);
134  break;
135  case DataType::QAsymmS8:
136  TestQuantizationParamsImpl(info, dataType, qAsymmS8Params.first, qAsymmS8Params.second);
137  break;
138  case DataType::QSymmS8:
139  TestQuantizationParamsImpl(info, dataType, qSymmS8Params.first, qSymmS8Params.second);
140  break;
141  case DataType::QSymmS16:
142  TestQuantizationParamsImpl(info, dataType, qSymmS16Params.first, qSymmS16Params.second);
143  break;
144  default:
145  throw InvalidArgumentException("Unsupported quantization target");
146  }
147  }
148 
149  void TestQuantizationOnLayersWithBiases(const IConnectableLayer* layer,
150  const ConstTensor& weights,
151  const Optional<ConstTensor>& biases)
152  {
153  TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
154  float inputScaleQAsymmU8 = 30.0f / g_AsymmU8QuantizationBase;
155  float inputScaleQAsymmS8 = 30.0f / g_AsymmS8QuantizationBase;
156  float inputScaleQSymmS8 = 15.0f / g_SymmS8QuantizationBase;
157  float inputScaleQSymmS16 = 15.0f / g_SymmS16QuantizationBase;
158  float weightsScale = 3.0f / g_AsymmU8QuantizationBase;
159 
160  // Based off default static range [-15.0f, 15.0f]
161  TestQuantizationParams(info, {inputScaleQAsymmU8, 128},
162  {inputScaleQAsymmS8, 0},
163  {inputScaleQSymmS8, 0},
164  {inputScaleQSymmS16, 0});
165 
166  TestConstantQuantizationParams(weights.GetInfo(), {weightsScale, 85});
167 
168  if (biases.has_value())
169  {
170  TestBiasQuantizationParams(biases.value().GetInfo(),
171  {inputScaleQAsymmU8 * weightsScale, 0},
172  {inputScaleQAsymmS8 * weightsScale, 0},
173  {inputScaleQSymmS8 * weightsScale, 0},
174  {inputScaleQSymmS16 * weightsScale, 0},
176  }
177  }
178 
179  TensorShape m_InputShape;
180  TensorShape m_OutputShape;
181 
182 private:
183  void TestQuantizationParamsImpl(const TensorInfo& info, DataType dataType, float scale, int32_t offset)
184  {
185  BOOST_TEST((info.GetDataType() == dataType));
186  BOOST_TEST(info.GetQuantizationOffset() == offset);
187  BOOST_CHECK_CLOSE(info.GetQuantizationScale(), scale, g_TestTolerance);
188  }
189 
190  QuantizerOptions m_QuantizerOptions;
191 };
192 
193 void VisitLayersTopologically(const INetwork* inputNetwork, ILayerVisitor& visitor)
194 {
195  auto network = boost::polymorphic_downcast<const Network*>(inputNetwork);
196  auto graph = network->GetGraph().TopologicalSort();
197 
198  VisitLayers(graph, visitor);
199 }
200 
201 class TestAdditionQuantization : public TestQuantization
202 {
203 public:
204  TestAdditionQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
205  : TestQuantization(inputShape, outputShape) {}
206 
207  TestAdditionQuantization(const QuantizerOptions& options,
208  const TensorShape& inputShape,
209  const TensorShape& outputShape)
210  : TestQuantization(options, inputShape, outputShape) {}
211 
212  void VisitAdditionLayer(const IConnectableLayer* layer,
213  const char* name = nullptr) override
214  {
215  boost::ignore_unused(name);
217 
218  // Based off default static range [-20.0f, 20.0f]
219  TestQuantizationParams(info, {40.0f / g_AsymmU8QuantizationBase, 128},
220  {40.0f / g_AsymmS8QuantizationBase, 0},
221  {20.0f / g_SymmS8QuantizationBase, 0},
222  {20.0f / g_SymmS16QuantizationBase, 0});
223  }
224 };
225 
226 
227 BOOST_AUTO_TEST_CASE(QuantizeAddition)
228 {
229  INetworkPtr network = INetwork::Create();
230 
231  // Add the layers
232  IConnectableLayer* input0 = network->AddInputLayer(0);
233  IConnectableLayer* input1 = network->AddInputLayer(1);
234  IConnectableLayer* addition = network->AddAdditionLayer();
235  IConnectableLayer* output = network->AddOutputLayer(2);
236 
237  // Establish connections
238  input0->GetOutputSlot(0).Connect(addition->GetInputSlot(0));
239  input1->GetOutputSlot(0).Connect(addition->GetInputSlot(1));
240  addition->GetOutputSlot(0).Connect(output->GetInputSlot(0));
241 
242  // Set TensorInfo
243  const TensorShape shape{1U};
245  input0->GetOutputSlot(0).SetTensorInfo(info);
246  input1->GetOutputSlot(0).SetTensorInfo(info);
247  addition->GetOutputSlot(0).SetTensorInfo(info);
248 
249  const QuantizerOptions qAsymmU8Options(DataType::QAsymmU8);
250  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get(), qAsymmU8Options)->ExportNetwork();
251  TestAdditionQuantization validatorQAsymmU8(shape, shape);
252  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
253 
254  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
255  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
256  TestAdditionQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
257  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
258 
259  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
260  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
261  TestAdditionQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
262  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
263 
264  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
265  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
266  TestAdditionQuantization validatorQSymmS16(qSymmS16options, shape, shape);
267  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
268 }
269 
270 class TestActivationQuantization : public TestQuantization
271 {
272 public:
273  TestActivationQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
274  : TestQuantization(inputShape, outputShape) {}
275 
276  TestActivationQuantization(const QuantizerOptions& options,
277  const TensorShape& inputShape,
278  const TensorShape& outputShape)
279  : TestQuantization(options, inputShape, outputShape) {}
280 
281  void VisitActivationLayer(const IConnectableLayer* layer,
282  const ActivationDescriptor& descriptor,
283  const char* name = nullptr) override
284  {
285  boost::ignore_unused(descriptor, name);
286 
288 
289  // Based off default static range [0.0f, 15.0f]
290  TestQuantizationParams(info, {15.0f / g_AsymmU8QuantizationBase, 0},
291  {15.0f / g_AsymmS8QuantizationBase, -128},
292  {15.0f / g_SymmS8QuantizationBase, 0},
293  {15.0f / g_SymmS16QuantizationBase, 0});
294  }
295 };
296 
298 {
299  INetworkPtr network = INetwork::Create();
300 
301  // Add the layers
302  IConnectableLayer* input0 = network->AddInputLayer(0);
303  IConnectableLayer* activation = network->AddActivationLayer(descriptor);
304  IConnectableLayer* output = network->AddOutputLayer(2);
305 
306  // Establish connections
307  input0->GetOutputSlot(0).Connect(activation->GetInputSlot(0));
308  activation->GetOutputSlot(0).Connect(output->GetInputSlot(0));
309 
310  // Set TensorInfo
312  input0->GetOutputSlot(0).SetTensorInfo(info);
313  activation->GetOutputSlot(0).SetTensorInfo(info);
314 
315  return network;
316 }
317 
319 {
320  INetworkPtr network = INetwork::Create();
321 
322  // Add input/output layers
323  IConnectableLayer* inputLayer = network->AddInputLayer(0);
324  IConnectableLayer* output = network->AddOutputLayer(1);
325 
326  // Establish connections
327  inputLayer->GetOutputSlot(0).Connect(output->GetInputSlot(0));
328 
329  // Set TensorInfo
330  TensorShape shape{8U};
332  inputLayer->GetOutputSlot(0).SetTensorInfo(info);
333 
334  return network;
335 }
336 
338 {
339  for (auto&& inputLayer : network->GetGraph().GetInputLayers())
340  {
341  BOOST_ASSERT_MSG(inputLayer->GetNumOutputSlots() == 1, "Input layer should have exactly 1 output slot");
342  return inputLayer->GetOutputSlot(0).GetTensorInfo();
343  }
344  throw InvalidArgumentException("Network has no input layers");
345 }
346 
347 BOOST_AUTO_TEST_CASE(InputOutputLayerDynamicQuant)
348 {
350 
351  armnn::TensorInfo tensorInfo = GetInputTensorInfo(boost::polymorphic_downcast<const Network*>(network.get()));
352 
353  // Outliers -56 and 98
354  std::vector<float> inputData({0, 0, 0, -56, 98, 0, 0, 0});
355  armnn::ConstTensor inputTensor(tensorInfo, inputData.data());
356 
357  InputTensors inputTensors;
358  inputTensors.push_back(std::make_pair(0, inputTensor));
359 
361 
362  quantizer->Refine(inputTensors);
363 
364  // Outliers -77 and 65
365  std::vector<float> inputData2({0, -77, 0, -56, 65, 0, 0, 0});
366  armnn::ConstTensor inputTensor2(tensorInfo, inputData2.data());
367  InputTensors inputTensors2;
368  inputTensors2.push_back(std::make_pair(0, inputTensor2));
369 
370  quantizer->Refine(inputTensors2);
371 
372  INetworkPtr quantizedNetwork = quantizer->ExportNetwork();
373  // Output Layer should be quantized for a min max of -77 and 98
374  // according to QU8 Quantization Scheme
375  std::unique_ptr<IQuantizationScheme> quantizationScheme = std::make_unique<QAsymmU8QuantizationScheme>();
376  OffsetScalePair qParams = quantizationScheme->ComputeScheme(-77.0, 98.0);
377 
378  class TestOutputLayerVisitor : public LayerVisitorBase<VisitorNoThrowPolicy>
379  {
380  public:
381  TestOutputLayerVisitor(const OffsetScalePair& offsetScalePair, const DataType& dataType) :
382  m_OffsetScalePair(offsetScalePair), m_DataType(dataType) {}
383 
384  void VisitOutputLayer(const IConnectableLayer* layer,
385  LayerBindingId id,
386  const char* name = nullptr) override
387  {
388  boost::ignore_unused(id, name);
389  const TensorInfo& info = layer->GetInputSlot(0).GetConnection()->GetTensorInfo();
390  BOOST_CHECK_MESSAGE(info.GetDataType() == m_DataType,
391  std::string(armnn::GetDataTypeName(info.GetDataType()))
392  .append(" == ").append(armnn::GetDataTypeName(m_DataType)));
393  // int_32t
394  BOOST_CHECK(info.GetQuantizationOffset() == m_OffsetScalePair.second);
395  // float
396  BOOST_TEST(info.GetQuantizationScale() == m_OffsetScalePair.first, boost::test_tools::tolerance(0.001));
397  }
398 
399  private:
400  const OffsetScalePair m_OffsetScalePair;
401  const DataType m_DataType;
402  };
403 
404  TestOutputLayerVisitor visitor(qParams, quantizationScheme->GetDataType());
405  quantizedNetwork->Accept(visitor);
406 }
407 
408 BOOST_AUTO_TEST_CASE(QuantizeAbsActivation)
409 {
410  ActivationDescriptor descriptor;
411  descriptor.m_Function = ActivationFunction::Abs;
412  descriptor.m_A = 3.5f;
413  descriptor.m_B = -10.0f;
414 
415  const TensorShape shape{1U};
416  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
417 
418  const QuantizerOptions qAsymmU8Options(DataType::QAsymmU8);
419  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get(), qAsymmU8Options)->ExportNetwork();
420  TestActivationQuantization validatorQAsymmU8(shape, shape);
421  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
422 
423  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
424  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
425  TestActivationQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
426  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
427 
428  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
429  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
430  TestActivationQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
431  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
432 
433  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
434  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
435  TestActivationQuantization validatorQSymmS16(qSymmS16options, shape, shape);
436  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
437 }
438 
439 BOOST_AUTO_TEST_CASE(QuantizeLinearActivation)
440 {
441  ActivationDescriptor descriptor;
443  descriptor.m_A = 3.5f;
444  descriptor.m_B = -10.0f;
445 
446  const TensorShape shape{1U};
447  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
448 
449  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
450  TestActivationQuantization validatorQAsymmU8(shape, shape);
451  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
452 
453  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
454  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
455  TestActivationQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
456  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
457 
458  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
459  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
460  TestActivationQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
461  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
462 
463  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
464  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
465  TestActivationQuantization validatorQSymmS16(qSymmS16options, shape, shape);
466  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
467 }
468 
469 BOOST_AUTO_TEST_CASE(QuantizeReLuActivation)
470 {
471  ActivationDescriptor descriptor;
473  descriptor.m_A = 3.5f;
474  descriptor.m_B = -10.0f;
475 
476  const TensorShape shape{1U};
477  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
478 
479  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
480  TestActivationQuantization validatorQAsymmU8(shape, shape);
481  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
482 
483  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
484  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
485  TestActivationQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
486  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
487 
488  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
489  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
490  TestActivationQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
491  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
492 
493  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
494  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
495  TestActivationQuantization validatorQSymmS16(qSymmS16options, shape, shape);
496  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
497 }
498 
499 BOOST_AUTO_TEST_CASE(QuantizeSoftReLuActivation)
500 {
501  ActivationDescriptor descriptor;
503  descriptor.m_A = 3.5f;
504  descriptor.m_B = -10.0f;
505 
506  const TensorShape shape{1U};
507  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
508 
509  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
510  TestActivationQuantization validatorQAsymmU8(shape, shape);
511  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
512 
513  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
514  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
515  TestActivationQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
516  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
517 
518  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
519  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
520  TestActivationQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
521  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
522 
523  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
524  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
525  TestActivationQuantization validatorQSymmS16(qSymmS16options, shape, shape);
526  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
527 }
528 
529 BOOST_AUTO_TEST_CASE(QuantizeBoundedReluActivation)
530 {
531  class TestBoundedReluActivationQuantization : public TestQuantization
532  {
533  public:
534  TestBoundedReluActivationQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
535  : TestQuantization(inputShape, outputShape) {}
536 
537  TestBoundedReluActivationQuantization(const QuantizerOptions& options,
538  const TensorShape& inputShape,
539  const TensorShape& outputShape)
540  : TestQuantization(options, inputShape, outputShape) {}
541 
542  void VisitActivationLayer(const IConnectableLayer* layer,
543  const ActivationDescriptor& descriptor,
544  const char* name = nullptr) override
545  {
546  boost::ignore_unused(descriptor, name);
548 
549  // Based off default static range [0.0f, 3.5f]
550  TestQuantizationParams(info, {3.5f / g_AsymmU8QuantizationBase, 0},
551  {3.5f / g_AsymmS8QuantizationBase, -128},
552  {3.5f / g_SymmS8QuantizationBase, 0},
553  {3.5f / g_SymmS16QuantizationBase, 0});
554  }
555  };
556 
557  ActivationDescriptor descriptor;
559  descriptor.m_A = 3.5f;
560  descriptor.m_B = -10.0f;
561 
562  const TensorShape shape{1U};
563  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
564 
565  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
566  TestBoundedReluActivationQuantization validatorQAsymmU8(shape, shape);
567  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
568 
569  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
570  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
571  TestBoundedReluActivationQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
572  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
573 
574  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
575  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
576  TestBoundedReluActivationQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
577  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
578 
579  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
580  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
581  TestBoundedReluActivationQuantization validatorQSymmS16(qSymmS16options, shape, shape);
582  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
583 }
584 
585 BOOST_AUTO_TEST_CASE(QuantizeTanHActivation)
586 {
587  class TestTanHActivationQuantization : public TestQuantization
588  {
589  public:
590  TestTanHActivationQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
591  : TestQuantization(inputShape, outputShape) {}
592 
593  TestTanHActivationQuantization(const QuantizerOptions& options,
594  const TensorShape& inputShape,
595  const TensorShape& outputShape)
596  : TestQuantization(options, inputShape, outputShape) {}
597 
598  void VisitActivationLayer(const IConnectableLayer* layer,
599  const ActivationDescriptor& descriptor,
600  const char* name = nullptr) override
601  {
602  boost::ignore_unused(descriptor, name);
604 
605  // Based off default static range [-1.0f, 1.0f]
606  TestQuantizationParams(
607  info, {2.0f / g_AsymmU8QuantizationBase, 128},
608  {2.0f / g_AsymmS8QuantizationBase, 0},
609  {1.0f / g_SymmS8QuantizationBase , 0},
610  {1.0f / g_SymmS16QuantizationBase, 0});
611  }
612  };
613 
614  ActivationDescriptor descriptor;
616  descriptor.m_A = 3.5f;
617  descriptor.m_B = -10.0f;
618 
619  const TensorShape shape{1U};
620  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
621 
622  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
623  TestTanHActivationQuantization validatorQAsymmU8(shape, shape);
624  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
625 
626  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
627  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
628  TestTanHActivationQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
629  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
630 
631  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
632  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
633  TestTanHActivationQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
634  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
635 
636  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
637  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
638  TestTanHActivationQuantization validatorQSymmS16(qSymmS16options, shape, shape);
639  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
640 }
641 
642 class TestLeakyReLuActivationQuantization : public TestQuantization
643 {
644 public:
645  TestLeakyReLuActivationQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
646  : TestQuantization(inputShape, outputShape) {}
647 
648  TestLeakyReLuActivationQuantization(const QuantizerOptions& options,
649  const TensorShape& inputShape,
650  const TensorShape& outputShape)
651  : TestQuantization(options, inputShape, outputShape) {}
652 
653  void VisitActivationLayer(const IConnectableLayer* layer,
654  const ActivationDescriptor& descriptor,
655  const char* name = nullptr) override
656  {
657  boost::ignore_unused(descriptor, name);
659 
660  // Based off default static range [-5.0f, 15.0f]
661  TestQuantizationParams(info, {20.0f / g_AsymmU8QuantizationBase, 64},
662  {20.0f / g_AsymmS8QuantizationBase,-64},
663  {15.0f / g_SymmS8QuantizationBase , 0},
664  {15.0f / g_SymmS16QuantizationBase, 0});
665  }
666 
667 protected:
668  // Used by the descendant classes which test layers
669  // that are forwarding their parent layer settings
670  void CheckForwardedQuantizationSettings(const IConnectableLayer* layer)
671  {
673  TestQuantizationParams(info, {20.0f / g_AsymmU8QuantizationBase, 64},
674  {20.0f / g_AsymmS8QuantizationBase,-64},
675  {15.0f / g_SymmS8QuantizationBase, 0},
676  {15.0f / g_SymmS16QuantizationBase, 0});
677  }
678 };
679 
680 BOOST_AUTO_TEST_CASE(QuantizeLeakyReLuActivation)
681 {
682  ActivationDescriptor descriptor;
684  descriptor.m_A = 3.5f;
685  descriptor.m_B = -10.0f;
686 
687  const TensorShape shape{1U};
688  INetworkPtr network = CreateNetworkWithActivationLayer(descriptor, shape);
689 
690  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
691  TestLeakyReLuActivationQuantization validatorQAsymmU8(shape, shape);
692  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
693 
694  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
695  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
696  TestLeakyReLuActivationQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
697  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
698 
699  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
700  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
701  TestLeakyReLuActivationQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
702  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
703 
704  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
705  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
706  TestLeakyReLuActivationQuantization validatorQSymmS16(qSymmS16options, shape, shape);
707  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
708 }
709 
710 BOOST_AUTO_TEST_CASE(QuantizeBatchNorm)
711 {
712  class TestBatchNormalizationQuantization : public TestQuantization
713  {
714  public:
715  TestBatchNormalizationQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
716  : TestQuantization(inputShape, outputShape) {}
717 
718  TestBatchNormalizationQuantization(const QuantizerOptions& options,
719  const TensorShape& inputShape,
720  const TensorShape& outputShape)
721  : TestQuantization(options, inputShape, outputShape) {}
722 
723  void VisitBatchNormalizationLayer(const IConnectableLayer* layer,
724  const BatchNormalizationDescriptor& desc,
725  const ConstTensor& mean,
726  const ConstTensor& variance,
727  const ConstTensor& beta,
728  const ConstTensor& gamma,
729  const char* name = nullptr) override
730  {
731  boost::ignore_unused(desc, name);
733 
734  // Based off default static range [-15.0f, 15.0f]
735  TestQuantizationParams(
736  info, {30.0f / g_AsymmU8QuantizationBase, 128},
737  {30.0f / g_AsymmS8QuantizationBase, 0},
738  {15.0f / g_SymmS8QuantizationBase, 0},
739  {15.0f / g_SymmS16QuantizationBase, 0});
740 
741  // Test constants
742  TestConstantQuantizationParams(mean.GetInfo(), {3.0f / g_AsymmU8QuantizationBase, 85});
743  TestConstantQuantizationParams(variance.GetInfo(), {3.0f / g_AsymmU8QuantizationBase, 85});
744  TestConstantQuantizationParams(beta.GetInfo(), {3.0f / g_AsymmU8QuantizationBase, 85});
745  TestConstantQuantizationParams(gamma.GetInfo(), {3.0f / g_AsymmU8QuantizationBase, 85});
746  }
747  };
748 
749  INetworkPtr network = INetwork::Create();
750 
751  const TensorShape shape{3U};
753 
754  std::vector<float> meanData{-1.0f, 1.5f, 2.0f};
755  std::vector<float> varData{-1.0f, 1.5f, 2.0f};
756  std::vector<float> betaData{-1.0f, 1.5f, 2.0f};
757  std::vector<float> gammaData{-1.0f, 1.5f, 2.0f};
758 
759  ConstTensor mean(info, meanData);
760  ConstTensor var(info, varData);
761  ConstTensor beta(info, betaData);
762  ConstTensor gamma(info, gammaData);
763 
765 
766  // Add the layers
767  IConnectableLayer* input0 = network->AddInputLayer(0);
768  IConnectableLayer* batchNorm = network->AddBatchNormalizationLayer(desc, mean, var, beta, gamma);
769  IConnectableLayer* output = network->AddOutputLayer(1);
770 
771  // Establish connections
772  input0->GetOutputSlot(0).Connect(batchNorm->GetInputSlot(0));
773  batchNorm->GetOutputSlot(0).Connect(output->GetInputSlot(0));
774 
775  // Set TensorInfo
776  input0->GetOutputSlot(0).SetTensorInfo(info);
777  batchNorm->GetOutputSlot(0).SetTensorInfo(info);
778 
779  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
780  TestBatchNormalizationQuantization validatorQAsymmU8(shape, shape);
781  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
782 
783  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
784  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
785  TestBatchNormalizationQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
786  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
787 
788  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
789  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
790  TestBatchNormalizationQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
791  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
792 
793  const QuantizerOptions QQsymm16Options(DataType::QSymmS16);
794  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), QQsymm16Options)->ExportNetwork();
795  TestBatchNormalizationQuantization validatorQSymmS16(QQsymm16Options, shape, shape);
796  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
797 }
798 
799 BOOST_AUTO_TEST_CASE(QuantizeDepthToSpace)
800 {
801  class TestDepthToSpaceQuantization : public TestQuantization
802  {
803  public:
804  TestDepthToSpaceQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
805  : TestQuantization(inputShape, outputShape) {}
806 
807  TestDepthToSpaceQuantization(const QuantizerOptions& options,
808  const TensorShape& inputShape,
809  const TensorShape& outputShape)
810  : TestQuantization(options, inputShape, outputShape) {}
811 
812  virtual void VisitDepthToSpaceLayer(const IConnectableLayer* layer,
813  const DepthToSpaceDescriptor& desc,
814  const char* name = nullptr)
815  {
816  boost::ignore_unused(desc, name);
817  const TensorInfo& info = layer->GetOutputSlot(0).GetTensorInfo();
818 
819  const OffsetScalePair qAsymmU8Params{ 30.0f / g_AsymmU8QuantizationBase, 128 };
820  const OffsetScalePair qAsymmS8Params{ 30.0f / g_AsymmS8QuantizationBase, 0 };
821  const OffsetScalePair qSymmS8Params { 15.0f / g_SymmS8QuantizationBase, 0 };
822  const OffsetScalePair qSymmS16Params{ 15.0f / g_SymmS16QuantizationBase, 0 };
823 
824  TestQuantizationParams(info, qAsymmU8Params, qAsymmS8Params, qSymmS8Params, qSymmS16Params);
825  }
826  };
827 
828  const TensorShape inputShape { 1, 2, 2, 4 };
829  const TensorShape outputShape{ 1, 4, 4, 1 };
830 
831  const TensorInfo inputInfo (inputShape, DataType::Float32);
832  const TensorInfo outputInfo(outputShape, DataType::Float32);
833 
834  INetworkPtr network = INetwork::Create();
835  const DepthToSpaceDescriptor descriptor(2, armnn::DataLayout::NHWC);
836 
837  IConnectableLayer* inputLayer = network->AddInputLayer(0);
838  IConnectableLayer* depthToSpaceLayer = network->AddDepthToSpaceLayer(descriptor);
839  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
840 
841  inputLayer->GetOutputSlot(0).Connect(depthToSpaceLayer->GetInputSlot(0));
842  depthToSpaceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
843 
844  inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
845  depthToSpaceLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
846 
847  // test QAsymmU8 quantization
848  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
849  TestDepthToSpaceQuantization validatorQAsymmU8(inputShape, outputShape);
850  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
851 
852  // test QAsymmS8 quantization
853  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
854  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
855  TestDepthToSpaceQuantization validatorQAsymmS8(qAsymmS8Options, inputShape, outputShape);
856  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
857 
858  // test QSymmS8 quantization
859  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
860  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
861  TestDepthToSpaceQuantization validatorQSymmS8(qSymmS8Options, inputShape, outputShape);
862  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
863 
864  // test QSymmS16 quantization
865  const QuantizerOptions Qsymm16Options(DataType::QSymmS16);
866  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), Qsymm16Options)->ExportNetwork();
867  TestDepthToSpaceQuantization validatorQSymmS16(Qsymm16Options, inputShape, outputShape);
868  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
869 }
870 
871 BOOST_AUTO_TEST_CASE(OverrideInputRangeEmptyNetwork)
872 {
873  RangeTracker ranges;
874  RangeTracker::MinMaxRange minMaxRange(-12.3f, 45.6f); // Range to use for the override
875 
876  Network network; // Empty network
877  auto inputLayers = network.GetGraph().GetInputLayers(); // Empty list of input layers
878 
879  OverrideInputRangeVisitor overrideInputRangeVisitor(ranges, 0, minMaxRange);
880  VisitLayers(inputLayers, overrideInputRangeVisitor);
881 
882  BOOST_CHECK(ranges.IsEmpty()); // Check that the map of ranges remained untouched
883 }
884 
885 BOOST_AUTO_TEST_CASE(OverrideInputRangeNoInputLayers)
886 {
887  RangeTracker ranges;
888  MinMaxRange minMaxRange(-12.3f, 45.6f); // Range to use for the override
889 
890  Network network;
891  network.AddAdditionLayer(); // Network with no input layers
892  auto inputLayers = network.GetGraph().GetInputLayers(); // Empty list of input layers
893 
894  OverrideInputRangeVisitor overrideInputRangeVisitor(ranges, 0, minMaxRange);
895  VisitLayers(inputLayers, overrideInputRangeVisitor);
896 
897  BOOST_CHECK(ranges.IsEmpty()); // Check that the map of ranges remained untouched
898 }
899 
900 BOOST_AUTO_TEST_CASE(OverrideInputRangeInputLayers)
901 {
902  RangeTracker ranges;
903  MinMaxRange minMaxRange(-12.3f, 45.6f); // Range to use for the override
904 
905  Network network;
906 
907  // Adding the layers
908  IConnectableLayer* input0 = network.AddInputLayer(0);
909  IConnectableLayer* input1 = network.AddInputLayer(1);
910  IConnectableLayer* addition = network.AddAdditionLayer();
911  IConnectableLayer* output = network.AddOutputLayer(2);
912 
913  // Connecting the layer
914  input0->GetOutputSlot(0).Connect(addition->GetInputSlot(0));
915  input1->GetOutputSlot(0).Connect(addition->GetInputSlot(1));
916  addition->GetOutputSlot(0).Connect(output->GetInputSlot(0));
917 
918  // Setting the TensorInfos
919  TensorShape shape{1U};
921  input0->GetOutputSlot(0).SetTensorInfo(info);
922  input1->GetOutputSlot(0).SetTensorInfo(info);
923  addition->GetOutputSlot(0).SetTensorInfo(info);
924 
925  auto inputLayers = network.GetGraph().GetInputLayers(); // List of input layers
926 
927  // Trying to override the input range for the input layer with binding id 3 (does not exist in the network)
928  OverrideInputRangeVisitor overrideInputRangeVisitorLayer3(ranges, 3, minMaxRange);
929  VisitLayers(inputLayers, overrideInputRangeVisitorLayer3);
930 
931  // Check that the map of ranges remained untouched
932  BOOST_CHECK(ranges.IsEmpty());
933 
934  // Override the input range for the input layer with binding id 1
935  OverrideInputRangeVisitor overrideInputRangeVisitorLayer1(ranges, 1, minMaxRange);
936  VisitLayers(inputLayers, overrideInputRangeVisitorLayer1);
937 
938  // Check that the map of ranges has been populated
939  BOOST_CHECK(!ranges.IsEmpty());
940 
941  // Check that an entry for the input layer with binding id 0 does not exist
942  BOOST_CHECK(!ranges.HasRanges(input0->GetGuid()));
943 
944  // Check that an entry for the input layer with binding id 1 exists
945  BOOST_CHECK(ranges.HasRanges(input1->GetGuid()));
946 
947  // Check the the overridden values are what we intended to set
948  BOOST_CHECK(ranges.GetRange(input1->GetGuid(), 0) == minMaxRange);
949 }
950 
952  const TensorShape& inputShape,
953  const TensorShape& outputShape)
954 {
956  desc.m_BiasEnabled = biasEnabled;
957  INetworkPtr network = INetwork::Create();
958 
959  const TensorInfo info(inputShape, DataType::Float32);
960  const TensorInfo outputInfo(outputShape, DataType::Float32);
961 
962  std::vector<float> weightsData{-1.0f, 1.5f, 2.0f};
963  ConstTensor weights(info, weightsData);
964 
965  // Add the layers
966  IConnectableLayer* input0 = network->AddInputLayer(0);
967  IConnectableLayer* fullyConnected;
968  Optional<ConstTensor> optionalBias;
969  std::vector<float> biasData{10.0f, 20.0f, 30.0f};
970  if (desc.m_BiasEnabled)
971  {
972  ConstTensor bias(info, biasData);
973  optionalBias = Optional<ConstTensor>(bias);
974  }
975  fullyConnected = network->AddFullyConnectedLayer(desc, weights, optionalBias);
976  IConnectableLayer* output = network->AddOutputLayer(1);
977 
978  // Establish connections
979  input0->GetOutputSlot(0).Connect(fullyConnected->GetInputSlot(0));
980  fullyConnected->GetOutputSlot(0).Connect(output->GetInputSlot(0));
981 
982  // Set TensorInfo
983  input0->GetOutputSlot(0).SetTensorInfo(info);
984  fullyConnected->GetOutputSlot(0).SetTensorInfo(outputInfo);
985 
986  return network;
987 }
988 
989 void ValidateFullyConnectedLayer(const bool biasEnabled)
990 {
991  class TestFullyConnectedQuantization : public TestQuantization
992  {
993  public:
994  TestFullyConnectedQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
995  : TestQuantization(inputShape, outputShape) {}
996 
997  TestFullyConnectedQuantization(const QuantizerOptions& options,
998  const TensorShape& inputShape,
999  const TensorShape& outputShape)
1000  : TestQuantization(options, inputShape, outputShape) {}
1001 
1002  void VisitFullyConnectedLayer(const IConnectableLayer* layer,
1003  const FullyConnectedDescriptor& desc,
1004  const ConstTensor& weights,
1005  const Optional<ConstTensor>& biases,
1006  const char* name = nullptr) override
1007  {
1008  boost::ignore_unused(desc, name);
1009  TestQuantizationOnLayersWithBiases(layer, weights, biases);
1010  }
1011  };
1012 
1013  const TensorShape shape{3U};
1014  INetworkPtr network = CreateNetworkWithFullyConnectedLayer(biasEnabled, shape, shape);
1015 
1016  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
1017  TestFullyConnectedQuantization validatorQAsymmU8(shape, shape);
1018  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1019 
1020  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1021  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
1022  TestFullyConnectedQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
1023  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
1024 
1025  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1026  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
1027  TestFullyConnectedQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
1028  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1029 
1030  const QuantizerOptions Qsymm16Options(DataType::QSymmS16);
1031  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), Qsymm16Options)->ExportNetwork();
1032  TestFullyConnectedQuantization validatorQSymmS16(Qsymm16Options, shape, shape);
1033  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1034 }
1035 
1036 BOOST_AUTO_TEST_CASE(QuantizeFullyConnected)
1037 {
1039 }
1040 
1041 BOOST_AUTO_TEST_CASE(QuantizeFullyConnectedBiasEnabled)
1042 {
1044 }
1045 
1046 void TestQuantizeConvolution2d(bool useBiases)
1047 {
1048  class TestConv2dQuantization : public TestQuantization
1049  {
1050  public:
1051  TestConv2dQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
1052  : TestQuantization(inputShape, outputShape) {}
1053 
1054  TestConv2dQuantization(const QuantizerOptions& options,
1055  const TensorShape& inputShape,
1056  const TensorShape& outputShape)
1057  : TestQuantization(options, inputShape, outputShape) {}
1058 
1059  void VisitConvolution2dLayer(const IConnectableLayer *layer,
1060  const Convolution2dDescriptor& convolution2dDescriptor,
1061  const ConstTensor& weights,
1062  const Optional<ConstTensor>& biases,
1063  const char *name = nullptr) override
1064  {
1065  boost::ignore_unused(convolution2dDescriptor, name);
1066  TestQuantizationOnLayersWithBiases(layer, weights, biases);
1067  }
1068  };
1069 
1070  INetworkPtr network = INetwork::Create();
1071 
1072  TensorShape shape{3U};
1074 
1075  std::vector<float> weightsData{-1.0f, 1.5f, 2.0f};
1076  ConstTensor weights(info, weightsData);
1077 
1078  Convolution2dDescriptor descriptor;
1079  descriptor.m_BiasEnabled = useBiases;
1080 
1081  // Add the layers
1082  IConnectableLayer* input0 = network->AddInputLayer(0);
1083  IConnectableLayer* conv2d;
1084  Optional<ConstTensor> optionalBiases;
1085  std::vector<float> biasesData{-1.0f, 1.5f, 2.0f};
1086  if (useBiases)
1087  {
1088  ConstTensor biases(info, biasesData);
1089  optionalBiases = Optional<ConstTensor>(biases);
1090  }
1091  conv2d = network->AddConvolution2dLayer(descriptor, weights, optionalBiases);
1092  IConnectableLayer* output = network->AddOutputLayer(1);
1093 
1094  // Establish connections
1095  input0->GetOutputSlot(0).Connect(conv2d->GetInputSlot(0));
1096  conv2d->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1097 
1098  // Set TensorInfo
1099  input0->GetOutputSlot(0).SetTensorInfo(info);
1100  conv2d->GetOutputSlot(0).SetTensorInfo(info);
1101 
1102  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
1103  TestConv2dQuantization validatorQAsymmU8(shape, shape);
1104  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1105 
1106  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1107  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
1108  TestConv2dQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
1109  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
1110 
1111  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1112  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
1113  TestConv2dQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
1114  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1115 
1116  const QuantizerOptions Qsymm16Options(DataType::QSymmS16);
1117  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), Qsymm16Options)->ExportNetwork();
1118  TestConv2dQuantization validatorQSymmS16(Qsymm16Options, shape, shape);
1119  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1120 }
1121 
1122 BOOST_AUTO_TEST_CASE(QuantizeConvolution2d)
1123 {
1125 }
1126 
1127 BOOST_AUTO_TEST_CASE(QuantizeConvolution2dWithBiases)
1128 {
1130 }
1131 
1133 {
1134  class TestDepthwiseConv2dQuantization : public TestQuantization
1135  {
1136  public:
1137  TestDepthwiseConv2dQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
1138  : TestQuantization(inputShape, outputShape) {}
1139 
1140  TestDepthwiseConv2dQuantization(const QuantizerOptions& options,
1141  const TensorShape& inputShape,
1142  const TensorShape& outputShape)
1143  : TestQuantization(options, inputShape, outputShape) {}
1144 
1145  void VisitDepthwiseConvolution2dLayer(const IConnectableLayer *layer,
1146  const DepthwiseConvolution2dDescriptor& convolution2dDescriptor,
1147  const ConstTensor& weights,
1148  const Optional<ConstTensor>& biases,
1149  const char *name = nullptr) override
1150  {
1151  boost::ignore_unused(convolution2dDescriptor, name);
1152  TestQuantizationOnLayersWithBiases(layer, weights, biases);
1153  }
1154  };
1155 
1156  INetworkPtr network = INetwork::Create();
1157 
1158  TensorShape shape{3U};
1160 
1161  std::vector<float> weightsData{-1.0f, 1.5f, 2.0f};
1162  ConstTensor weights(info, weightsData);
1163 
1165  descriptor.m_BiasEnabled = useBiases;
1166 
1167  // Add the layers
1168  IConnectableLayer* input0 = network->AddInputLayer(0);
1169  IConnectableLayer* depthwiseConv2d;
1170  Optional<ConstTensor> optionalBiases;
1171  std::vector<float> biasesData{-1.0f, 1.5f, 2.0f};
1172  if (useBiases)
1173  {
1174  ConstTensor biases(info, biasesData);
1175  optionalBiases = Optional<ConstTensor>(biases);
1176  }
1177  depthwiseConv2d = network->AddDepthwiseConvolution2dLayer(descriptor, weights, optionalBiases);
1178  IConnectableLayer* output = network->AddOutputLayer(1);
1179 
1180  // Establish connections
1181  input0->GetOutputSlot(0).Connect(depthwiseConv2d->GetInputSlot(0));
1182  depthwiseConv2d->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1183 
1184  //Set TensorInfo
1185  input0->GetOutputSlot(0).SetTensorInfo(info);
1186  depthwiseConv2d->GetOutputSlot(0).SetTensorInfo(info);
1187 
1188  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
1189  TestDepthwiseConv2dQuantization validatorQAsymmU8(shape, shape);
1190  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1191 
1192  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1193  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
1194  TestDepthwiseConv2dQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
1195  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
1196 
1197  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1198  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
1199  TestDepthwiseConv2dQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
1200  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1201 
1202  const QuantizerOptions Qsymm16Options(DataType::QSymmS16);
1203  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), Qsymm16Options)->ExportNetwork();
1204  TestDepthwiseConv2dQuantization validatorQSymmS16(Qsymm16Options, shape, shape);
1205  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1206 }
1207 
1208 BOOST_AUTO_TEST_CASE(QuantizeDepthwiseConvolution2d)
1209 {
1211 }
1212 
1213 BOOST_AUTO_TEST_CASE(QuantizeDepthwiseConvolution2dWithBiases)
1214 {
1216 }
1217 
1218 BOOST_AUTO_TEST_CASE(QuantizeInstanceNormalization)
1219 {
1220  class TestInstanceNormalizationQuantization : public TestQuantization
1221  {
1222  public:
1223  TestInstanceNormalizationQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
1224  : TestQuantization(inputShape, outputShape) {}
1225 
1226  TestInstanceNormalizationQuantization(const QuantizerOptions& options,
1227  const TensorShape& inputShape,
1228  const TensorShape& outputShape)
1229  : TestQuantization(options, inputShape, outputShape) {}
1230 
1231  virtual void VisitInstanceNormalizationLayer(const IConnectableLayer* layer,
1232  const InstanceNormalizationDescriptor& descriptor,
1233  const char* name = nullptr)
1234  {
1235  boost::ignore_unused(descriptor, name);
1236  const TensorInfo& info = layer->GetOutputSlot(0).GetTensorInfo();
1237 
1238  const OffsetScalePair qAsymmU8Params{ 30.0f / g_AsymmU8QuantizationBase, 128 };
1239  const OffsetScalePair qAsymmS8Params { 30.0f / g_AsymmS8QuantizationBase, 0};
1240  const OffsetScalePair qSymmS8Params { 15.0f / g_SymmS8QuantizationBase, 0};
1241  const OffsetScalePair qSymmS16Params{ 15.0f / g_SymmS16QuantizationBase, 0 };
1242 
1243  TestQuantizationParams(info, qAsymmU8Params, qAsymmS8Params, qSymmS8Params, qSymmS16Params);
1244  }
1245  };
1246 
1247  const TensorShape tensorShape{ 1, 4, 4, 1 };
1248  const TensorInfo tensorInfo(tensorShape, DataType::Float32);
1249 
1250  INetworkPtr network = INetwork::Create();
1251 
1252  IConnectableLayer* inputLayer = network->AddInputLayer(0);
1253  IConnectableLayer* instanceNormLayer = network->AddInstanceNormalizationLayer(InstanceNormalizationDescriptor());
1254  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
1255 
1256  inputLayer->GetOutputSlot(0).Connect(instanceNormLayer->GetInputSlot(0));
1257  instanceNormLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1258 
1259  inputLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1260  instanceNormLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1261 
1262  // test QAsymmU8 quantization
1263  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
1264  TestInstanceNormalizationQuantization validatorQAsymmU8(tensorShape, tensorShape);
1265  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1266 
1267  //test QAsymmS8 quantization
1268  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1269  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
1270  TestInstanceNormalizationQuantization validatorQAsymmS8(qAsymmS8Options, tensorShape, tensorShape);
1271  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
1272 
1273  // test QSymmS8 quantization
1274  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1275  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
1276  TestInstanceNormalizationQuantization validatorQSymmS8(qSymmS8Options, tensorShape, tensorShape);
1277  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1278 
1279  // test QSymmS16 quantization
1280  const QuantizerOptions qSymmS16Options(DataType::QSymmS16);
1281  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16Options)->ExportNetwork();
1282  TestInstanceNormalizationQuantization validatorQSymmS16(qSymmS16Options, tensorShape, tensorShape);
1283  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1284 }
1285 
1286 BOOST_AUTO_TEST_CASE(QuantizeLogSoftmax)
1287 {
1288  class TestLogSoftmaxQuantization : public TestQuantization
1289  {
1290  public:
1291  TestLogSoftmaxQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
1292  : TestQuantization(inputShape, outputShape) {}
1293 
1294  TestLogSoftmaxQuantization(const QuantizerOptions& options,
1295  const TensorShape& inputShape,
1296  const TensorShape& outputShape)
1297  : TestQuantization(options, inputShape, outputShape) {}
1298 
1299  void VisitLogSoftmaxLayer(const IConnectableLayer* layer,
1300  const SoftmaxDescriptor& descriptor,
1301  const char* name = nullptr) override
1302  {
1303  boost::ignore_unused(descriptor, name);
1305 
1306  const OffsetScalePair qAsymmU8Params{ 30.0f / g_AsymmU8QuantizationBase, 128 };
1307  const OffsetScalePair qAsymmS8Params { 30.0f / g_AsymmS8QuantizationBase, 0};
1308  const OffsetScalePair qSymmS8Params { 15.0f / g_SymmS8QuantizationBase, 0};
1309  const OffsetScalePair qSymmS16Params{ 15.0f / g_SymmS16QuantizationBase, 0 };
1310 
1311  TestQuantizationParams(info, qAsymmU8Params, qAsymmS8Params, qSymmS8Params, qSymmS16Params);
1312  }
1313  };
1314 
1315  const TensorShape tensorShape{ 1U };
1316  const TensorInfo tensorInfo(tensorShape, DataType::Float32);
1317 
1318  INetworkPtr network = INetwork::Create();
1319 
1320  LogSoftmaxDescriptor descriptor;
1321  descriptor.m_Beta = 1.0f;
1322 
1323  IConnectableLayer* inputLayer = network->AddInputLayer(0);
1324  IConnectableLayer* logSoftmaxLayer = network->AddLogSoftmaxLayer(descriptor);
1325  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
1326 
1327  inputLayer->GetOutputSlot(0).Connect(logSoftmaxLayer->GetInputSlot(0));
1328  logSoftmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1329 
1330  inputLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1331  logSoftmaxLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1332 
1333  // test QAsymmU8 quantization
1334  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
1335  TestLogSoftmaxQuantization validatorQAsymmU8(tensorShape, tensorShape);
1336  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1337 
1338  // test QAsymmS8 quantization
1339  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1340  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
1341  TestLogSoftmaxQuantization validatorQAsymmS8(qAsymmS8Options, tensorShape, tensorShape);
1342  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
1343 
1344  // test QSymmS8 quantization
1345  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1346  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
1347  TestLogSoftmaxQuantization validatorQSymmS8(qSymmS8Options, tensorShape, tensorShape);
1348  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1349 
1350  // test QuantisedSymmS16 quantization
1351  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
1352  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
1353  TestLogSoftmaxQuantization validatorQSymmS16(qSymmS16options, tensorShape, tensorShape);
1354  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1355 }
1356 
1358 {
1359  INetworkPtr network = INetwork::Create();
1360 
1361  // Add the layers
1362  IConnectableLayer* input0 = network->AddInputLayer(0);
1363  IConnectableLayer* softmax = network->AddSoftmaxLayer(descriptor);
1364  IConnectableLayer* output = network->AddOutputLayer(2);
1365 
1366  // Establish connections
1367  input0->GetOutputSlot(0).Connect(softmax->GetInputSlot(0));
1368  softmax->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1369 
1370  // Set TensorInfo
1372  input0->GetOutputSlot(0).SetTensorInfo(info);
1373  softmax->GetOutputSlot(0).SetTensorInfo(info);
1374 
1375  return network;
1376 }
1377 
1378 BOOST_AUTO_TEST_CASE(QuantizeSoftmax)
1379 {
1380  class TestSoftmaxQuantization : public TestQuantization
1381  {
1382  public:
1383  TestSoftmaxQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
1384  : TestQuantization(inputShape, outputShape) {}
1385 
1386  TestSoftmaxQuantization(const QuantizerOptions& options,
1387  const TensorShape& inputShape,
1388  const TensorShape& outputShape)
1389  : TestQuantization(options, inputShape, outputShape) {}
1390 
1391  void VisitSoftmaxLayer(const IConnectableLayer* layer,
1392  const SoftmaxDescriptor& descriptor,
1393  const char* name = nullptr) override
1394  {
1395  boost::ignore_unused(descriptor, name);
1397 
1398  // Based off default static range [0.0f, 1.0f]
1399  TestQuantizationParams(info, {1.0f / g_AsymmU8QuantizationBase, 0},
1400  {1.0f / g_AsymmS8QuantizationBase, -128},
1401  {1.0f / g_SymmS8QuantizationBase, 0},
1402  {1.0f / g_SymmS16QuantizationBase, 0});
1403  }
1404  };
1405 
1406  SoftmaxDescriptor descriptor;
1407  descriptor.m_Beta = 1.0f;
1408 
1409  const TensorShape shape{1U};
1410  INetworkPtr network = CreateNetworkWithSoftmaxLayer(descriptor, shape);
1411 
1412  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
1413  TestSoftmaxQuantization validatorQAsymmU8(shape, shape);
1414  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1415 
1416  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1417  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
1418  TestSoftmaxQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
1419  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
1420 
1421  // test QSymmS8 quantization
1422  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1423  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
1424  TestSoftmaxQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
1425  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1426 
1427  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
1428  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
1429  TestSoftmaxQuantization validatorQSymmS16(qSymmS16options, shape, shape);
1430  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1431 }
1432 
1433 BOOST_AUTO_TEST_CASE(QuantizeStandIn)
1434 {
1435  const TensorShape tensorShape{ 1U };
1436  const TensorInfo tensorInfo(tensorShape, DataType::Float32);
1437 
1438  INetworkPtr network = INetwork::Create();
1439 
1440  StandInDescriptor descriptor;
1441  descriptor.m_NumInputs = 1;
1442  descriptor.m_NumOutputs = 1;
1443 
1444  IConnectableLayer* inputLayer = network->AddInputLayer(0);
1445  IConnectableLayer* standInLayer = network->AddStandInLayer(descriptor);
1446  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
1447 
1448  inputLayer->GetOutputSlot(0).Connect(standInLayer->GetInputSlot(0));
1449  standInLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1450 
1451  inputLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1452  standInLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1453 
1454  // test QAsymmU8 quantization
1455  BOOST_CHECK_THROW(INetworkQuantizer::Create(network.get())->ExportNetwork(),
1457 
1458  // test QAsymmS8 quantization
1459  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1460  BOOST_CHECK_THROW(INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork(),
1462 
1463  // test QuantisedSymmS16 quantization
1464  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1465  BOOST_CHECK_THROW(INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork(),
1467 
1468  // test QuantisedSymmS16 quantization
1469  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
1470  BOOST_CHECK_THROW(INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork(),
1472 }
1473 
1475 {
1476  ActivationDescriptor activationDescriptor;
1477  activationDescriptor.m_Function = ActivationFunction::LeakyReLu;
1478  activationDescriptor.m_A = 3.5f;
1479  activationDescriptor.m_B = -10.0f;
1480 
1481  // Add the layers
1482  IConnectableLayer* input0 = network->AddInputLayer(0);
1483  IConnectableLayer* activation = network->AddActivationLayer(activationDescriptor);
1484 
1485  // Establish connections
1486  input0->GetOutputSlot(0).Connect(activation->GetInputSlot(0));
1487 
1488  // Set TensorInfo
1489  input0->GetOutputSlot(0).SetTensorInfo(info);
1490  activation->GetOutputSlot(0).SetTensorInfo(info);
1491 
1492  return activation;
1493 }
1494 
1496  IConnectableLayer* activation,
1497  IConnectableLayer* layerUnderTest,
1498  const TensorInfo& info)
1499 {
1500  // Add the output Layer
1501  IConnectableLayer* output = network->AddOutputLayer(3);
1502 
1503  // Establish connections
1504  activation->GetOutputSlot(0).Connect(layerUnderTest->GetInputSlot(0));
1505  layerUnderTest->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1506 
1507  //Set TensorInfo
1508  layerUnderTest->GetOutputSlot(0).SetTensorInfo(info);
1509 }
1510 
1511 BOOST_AUTO_TEST_CASE(QuantizePermute)
1512 {
1513  class TestPermuteQuantization : public TestLeakyReLuActivationQuantization
1514  {
1515  public:
1516  TestPermuteQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
1517  : TestLeakyReLuActivationQuantization(inputShape, outputShape) {}
1518 
1519  TestPermuteQuantization(const QuantizerOptions& options,
1520  const TensorShape& inputShape,
1521  const TensorShape& outputShape)
1522  : TestLeakyReLuActivationQuantization(options, inputShape, outputShape) {}
1523 
1524  void VisitPermuteLayer(const IConnectableLayer* layer,
1525  const PermuteDescriptor& desc,
1526  const char* name = nullptr) override
1527  {
1528  boost::ignore_unused(desc, name);
1529  CheckForwardedQuantizationSettings(layer);
1530  }
1531  };
1532 
1533  INetworkPtr network = INetwork::Create();
1534 
1535  const TensorShape shape{1U};
1537 
1538  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
1539 
1540  // Add the layer under test
1541  PermuteDescriptor desc;
1542  IConnectableLayer* permute = network->AddPermuteLayer(desc);
1543 
1544  CompleteLeakyReluNetwork(network.get(), activation, permute, info);
1545 
1546  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
1547  TestPermuteQuantization validatorQAsymmU8(shape, shape);
1548  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1549 
1550  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1551  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
1552  TestPermuteQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
1553  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
1554 
1555  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1556  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
1557  TestPermuteQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
1558  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1559 
1560  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
1561  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
1562  TestPermuteQuantization validatorQSymmS16(qSymmS16options, shape, shape);
1563  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1564 }
1565 
1566 BOOST_AUTO_TEST_CASE(QuantizeSpaceToBatch)
1567 {
1568  class TestSpaceToBatchQuantization : public TestLeakyReLuActivationQuantization
1569  {
1570  public:
1571  TestSpaceToBatchQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
1572  : TestLeakyReLuActivationQuantization(inputShape, outputShape) {}
1573 
1574  TestSpaceToBatchQuantization(const QuantizerOptions& options,
1575  const TensorShape& inputShape,
1576  const TensorShape& outputShape)
1577  : TestLeakyReLuActivationQuantization(options, inputShape, outputShape) {}
1578 
1579  void VisitSpaceToBatchNdLayer(const IConnectableLayer* layer,
1580  const SpaceToBatchNdDescriptor& spaceToBatchNdDescriptor,
1581  const char* name = nullptr) override
1582  {
1583  boost::ignore_unused(spaceToBatchNdDescriptor, name);
1584  CheckForwardedQuantizationSettings(layer);
1585  }
1586  };
1587 
1588  INetworkPtr network = INetwork::Create();
1589 
1590  const TensorShape shape{1U};
1592 
1593  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
1594 
1595  // Add the layer under test
1596  SpaceToBatchNdDescriptor descriptor;
1597  IConnectableLayer* spaceToBatch = network->AddSpaceToBatchNdLayer(descriptor);
1598 
1599  CompleteLeakyReluNetwork(network.get(), activation, spaceToBatch, info);
1600 
1601  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
1602  TestSpaceToBatchQuantization validatorQAsymmU8(shape, shape);
1603  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1604 
1605  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1606  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
1607  TestSpaceToBatchQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
1608  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
1609 
1610  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1611  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
1612  TestSpaceToBatchQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
1613  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1614 
1615  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
1616  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
1617  TestSpaceToBatchQuantization validatorQSymmS16(qSymmS16options, shape, shape);
1618  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1619 }
1620 
1621 BOOST_AUTO_TEST_CASE(QuantizeSpaceToDepth)
1622 {
1623  class TestSpaceToDepthQuantization : public TestLeakyReLuActivationQuantization
1624  {
1625  public:
1626  TestSpaceToDepthQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
1627  : TestLeakyReLuActivationQuantization(inputShape, outputShape)
1628  {}
1629 
1630  TestSpaceToDepthQuantization(const QuantizerOptions& options,
1631  const TensorShape& inputShape,
1632  const TensorShape& outputShape)
1633  : TestLeakyReLuActivationQuantization(options, inputShape, outputShape)
1634  {}
1635 
1636  void VisitSpaceToDepthLayer(const IConnectableLayer* layer,
1637  const SpaceToDepthDescriptor&,
1638  const char* = nullptr) override
1639  {
1641  TestQuantizationParams(info,
1642  { 30.0f / g_AsymmU8QuantizationBase, 128 },
1643  { 30.0f / g_AsymmS8QuantizationBase, 0 },
1644  { 15.0f / g_SymmS8QuantizationBase, 0 },
1645  { 15.0f / g_SymmS16QuantizationBase, 0 });
1646  }
1647  };
1648 
1649  INetworkPtr network = INetwork::Create();
1650 
1651  const TensorShape shape{ 1u };
1653 
1654  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
1655  IConnectableLayer* spaceToDepth = network->AddSpaceToDepthLayer(SpaceToDepthDescriptor());
1656 
1657  CompleteLeakyReluNetwork(network.get(), activation, spaceToDepth, info);
1658 
1659  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
1660  TestSpaceToDepthQuantization validatorQAsymmU8(shape, shape);
1661  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1662 
1663  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1664  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
1665  TestSpaceToDepthQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
1666  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
1667 
1668  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1669  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
1670  TestSpaceToDepthQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
1671  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1672 
1673  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
1674  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
1675  TestSpaceToDepthQuantization validatorQSymmS16(qSymmS16options, shape, shape);
1676  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1677 }
1678 
1679 BOOST_AUTO_TEST_CASE(QuantizePooling2d)
1680 {
1681  class TestPooling2dQuantization : public TestLeakyReLuActivationQuantization
1682  {
1683  public:
1684  TestPooling2dQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
1685  : TestLeakyReLuActivationQuantization(inputShape, outputShape) {}
1686 
1687  TestPooling2dQuantization(const QuantizerOptions& options,
1688  const TensorShape& inputShape,
1689  const TensorShape& outputShape)
1690  : TestLeakyReLuActivationQuantization(options, inputShape, outputShape) {}
1691 
1692  void VisitPooling2dLayer(const IConnectableLayer* layer,
1693  const Pooling2dDescriptor& desc,
1694  const char* name = nullptr) override
1695  {
1696  boost::ignore_unused(desc, name);
1697  CheckForwardedQuantizationSettings(layer);
1698  }
1699  };
1700 
1701  auto network = INetwork::Create();
1702 
1703  TensorShape shape{1U};
1705 
1706  Pooling2dDescriptor desc;
1707  ActivationDescriptor activationDescriptor;
1708  activationDescriptor.m_Function = ActivationFunction::LeakyReLu;
1709  activationDescriptor.m_A = 3.5f;
1710  activationDescriptor.m_B = -10.0f;
1711 
1712  // Add the layers
1713  IConnectableLayer* input0 = network->AddInputLayer(0);
1714  IConnectableLayer* activation = network->AddActivationLayer(activationDescriptor);
1715  IConnectableLayer* pooling2d = network->AddPooling2dLayer(desc);
1716  IConnectableLayer* output = network->AddOutputLayer(3);
1717 
1718  // Establish connections
1719  input0->GetOutputSlot(0).Connect(activation->GetInputSlot(0));
1720  activation->GetOutputSlot(0).Connect(pooling2d->GetInputSlot(0));
1721  pooling2d->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1722 
1723  // Set TensorInfo
1724  input0->GetOutputSlot(0).SetTensorInfo(info);
1725  activation->GetOutputSlot(0).SetTensorInfo(info);
1726  pooling2d->GetOutputSlot(0).SetTensorInfo(info);
1727 
1728  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
1729  TestPooling2dQuantization validatorQAsymmU8(shape, shape);
1730  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1731 
1732  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1733  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
1734  TestPooling2dQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
1735  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
1736 
1737  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1738  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
1739  TestPooling2dQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
1740  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1741 
1742  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
1743  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
1744  TestPooling2dQuantization validatorQSymmS16(qSymmS16options, shape, shape);
1745  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1746 }
1747 
1749 {
1750  class TestConstantQuantization : public TestAdditionQuantization
1751  {
1752  public:
1753  TestConstantQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
1754  : TestAdditionQuantization(inputShape, outputShape) {}
1755 
1756  TestConstantQuantization(const QuantizerOptions& options,
1757  const TensorShape& inputShape,
1758  const TensorShape& outputShape)
1759  : TestAdditionQuantization(options, inputShape, outputShape) {}
1760 
1761  void VisitConstantLayer(const IConnectableLayer* layer,
1762  const ConstTensor& input,
1763  const char* name = nullptr) override
1764  {
1765  boost::ignore_unused(input, name);
1767 
1768  // Based off the range of values in the const tensor used for the test: [-2.0f, 6.0f]
1769  TestQuantizationParams(info, {8.0f / g_AsymmU8QuantizationBase, 64},
1770  {8.0f / g_AsymmS8QuantizationBase, -64},
1771  {6.0f / g_SymmS8QuantizationBase, 0},
1772  {6.0f / g_SymmS16QuantizationBase, 0});
1773  }
1774  };
1775 
1776  INetworkPtr network = INetwork::Create();
1777 
1778  // Constant layer data
1779  std::vector<float> data = {-2.0f, -1.0f, 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f};
1780  const TensorShape shape{1U, 1U, 3U, 3U};
1781  TensorInfo tensorInfo(shape, DataType::Float32);
1782  ConstTensor constantTensor(tensorInfo, data);
1783 
1784  // Add the layers
1785  IConnectableLayer* input = network->AddInputLayer(0);
1786  IConnectableLayer* constant = network->AddConstantLayer(constantTensor);
1787  IConnectableLayer* addition = network->AddAdditionLayer();
1788  IConnectableLayer* output = network->AddOutputLayer(1);
1789 
1790  // Establish connections
1791  input->GetOutputSlot(0).Connect(addition->GetInputSlot(0));
1792  constant->GetOutputSlot(0).Connect(addition->GetInputSlot(1));
1793  addition->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1794 
1795  // Set TensorInfo in the remaining layers
1796  input->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1797  addition->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1798  constant->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1799 
1800  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
1801  TestConstantQuantization validatorQAsymmU8(shape, shape);
1802  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1803 
1804  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1805  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
1806  TestConstantQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
1807  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
1808 
1809  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1810  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
1811  TestConstantQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
1812  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1813 
1814  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
1815  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
1816  TestConstantQuantization validatorQSymmS16(qSymmS16options, shape, shape);
1817  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1818 }
1819 
1820 BOOST_AUTO_TEST_CASE(QuantizeArgMinMax)
1821 {
1822  class TestArgMinMaxQuantization : public TestQuantization
1823  {
1824  public:
1825  TestArgMinMaxQuantization(const TensorShape& inputShape, const TensorShape& outputShape) :
1826  TestQuantization(inputShape, outputShape) {}
1827 
1828  TestArgMinMaxQuantization(const QuantizerOptions& options,
1829  const TensorShape& inputShape,
1830  const TensorShape& outputShape) :
1831  TestQuantization(options, inputShape, outputShape)
1832  {}
1833 
1834  void VisitInputLayer(const IConnectableLayer* layer,
1835  LayerBindingId id,
1836  const char* name = nullptr) override
1837  {
1838  boost::ignore_unused(layer, id, name);
1839  }
1840 
1841  void VisitOutputLayer(const IConnectableLayer* layer,
1842  LayerBindingId id,
1843  const char* name = nullptr) override
1844  {
1845  boost::ignore_unused(layer, id, name);
1846  }
1847  void VisitArgMinMaxLayer(const IConnectableLayer* layer,
1848  const ArgMinMaxDescriptor& argMinMaxDescriptor,
1849  const char* name = nullptr) override
1850  {
1851  boost::ignore_unused(argMinMaxDescriptor, name);
1852  TensorInfo outputInfo = layer->GetOutputSlot(0).GetTensorInfo();
1853 
1854  TestQuantizationParams(outputInfo,
1855  { 30.0f / g_AsymmU8QuantizationBase, 128 },
1856  { 30.0f / g_AsymmS8QuantizationBase, 0},
1857  { 15.0f / g_SymmS8QuantizationBase, 0},
1858  { 15.0f / g_SymmS16QuantizationBase, 0 });
1859  }
1860  };
1861 
1862  INetworkPtr network = INetwork::Create();
1863 
1864  const TensorShape inputShape{ 1, 1, 1, 5 };
1865  const TensorShape outputShape{ 1, 1, 1 };
1866 
1867  TensorInfo inputInfo(inputShape, DataType::Float32);
1868  TensorInfo outputInfo(outputShape, DataType::Float32);
1869 
1870  // Add the input layers
1871  IConnectableLayer* input = network->AddInputLayer(0);
1872 
1873  // Add the layer under test
1874  ArgMinMaxDescriptor argMinMaxDescriptor;
1875  argMinMaxDescriptor.m_Function = ArgMinMaxFunction::Max;
1876  IConnectableLayer* argMinMaxLayer = network->AddArgMinMaxLayer(argMinMaxDescriptor);
1877 
1878  // Add the output layers
1879  IConnectableLayer* output = network->AddOutputLayer(1);
1880 
1881  // Establish connections
1882  input->GetOutputSlot(0).Connect(argMinMaxLayer->GetInputSlot(0));
1883  argMinMaxLayer->GetOutputSlot(0).Connect(output->GetInputSlot(0));
1884 
1885  // Set tensor info
1886  input->GetOutputSlot(0).SetTensorInfo(inputInfo);
1887  argMinMaxLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
1888 
1889  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
1890  TestArgMinMaxQuantization validatorQAsymmU8(inputShape, outputShape);
1891  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1892 
1893  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1894  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
1895  TestArgMinMaxQuantization validatorQAsymmS8(qAsymmS8Options, inputShape, outputShape);
1896  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
1897 
1898  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1899  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
1900  TestArgMinMaxQuantization validatorQSymmS8(qSymmS8Options, inputShape, outputShape);
1901  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1902 
1903  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
1904  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
1905  TestArgMinMaxQuantization validatorQSymmS16(qSymmS16options, inputShape, outputShape);
1906  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1907 }
1908 
1909 BOOST_AUTO_TEST_CASE(QuantizeComparison)
1910 {
1911  class TestComparisonQuantization : public TestQuantization
1912  {
1913  public:
1914  TestComparisonQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
1915  : TestQuantization(inputShape, outputShape) {}
1916 
1917  TestComparisonQuantization(const QuantizerOptions& options,
1918  const TensorShape& inputShape,
1919  const TensorShape& outputShape)
1920  : TestQuantization(options, inputShape, outputShape) {}
1921 
1922  void VisitComparisonLayer(const IConnectableLayer* layer,
1923  const ComparisonDescriptor& descriptor,
1924  const char* name = nullptr) override
1925  {
1926  boost::ignore_unused(descriptor, name);
1928 
1929  const OffsetScalePair qAsymmU8Params{ 30.0f / g_AsymmU8QuantizationBase, 128 };
1930  const OffsetScalePair qAsymmS8Params { 30.0f / g_AsymmS8QuantizationBase, 0};
1931  const OffsetScalePair qSymmS8Params { 15.0f / g_SymmS8QuantizationBase, 0};
1932  const OffsetScalePair qSymmS16Params{ 15.0f / g_SymmS16QuantizationBase, 0 };
1933 
1934  TestQuantizationParams(info, qAsymmU8Params, qAsymmS8Params, qSymmS8Params, qSymmS16Params);
1935  }
1936  };
1937 
1938  const TensorShape tensorShape{ 1u };
1939  const TensorInfo tensorInfo(tensorShape, DataType::Float32);
1940 
1941  INetworkPtr network = INetwork::Create();
1943 
1944  IConnectableLayer* inputLayer0 = network->AddInputLayer(0);
1945  IConnectableLayer* inputLayer1 = network->AddInputLayer(1);
1946  IConnectableLayer* comparisonLayer = network->AddComparisonLayer(descriptor);
1947  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
1948 
1949  inputLayer0->GetOutputSlot(0).Connect(comparisonLayer->GetInputSlot(0));
1950  inputLayer1->GetOutputSlot(0).Connect(comparisonLayer->GetInputSlot(1));
1951  comparisonLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
1952 
1953  inputLayer0->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1954  inputLayer1->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1955  comparisonLayer->GetOutputSlot(0).SetTensorInfo(tensorInfo);
1956 
1957  // test QAsymmU8 quantization
1958  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
1959  TestComparisonQuantization validatorQAsymmU8(tensorShape, tensorShape);
1960  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
1961 
1962  // test QAsymmS8 quantization
1963  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
1964  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
1965  TestComparisonQuantization validatorQAsymmS8(qAsymmS8Options, tensorShape, tensorShape);
1966  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
1967 
1968  // test QSymmS8 quantization
1969  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
1970  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
1971  TestComparisonQuantization validatorQSymmS8(qSymmS8Options, tensorShape, tensorShape);
1972  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
1973 
1974  // test QuantisedSymmS16 quantization
1975  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
1976  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
1977  TestComparisonQuantization validatorQSymmS16(qSymmS16options, tensorShape, tensorShape);
1978  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
1979 }
1980 
1981 BOOST_AUTO_TEST_CASE(QuantizeConcat)
1982 {
1983  class TestConcatQuantization : public TestQuantization
1984  {
1985  public:
1986  TestConcatQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
1987  : TestQuantization(inputShape, outputShape) {}
1988 
1989  TestConcatQuantization(const QuantizerOptions& options,
1990  const TensorShape& inputShape,
1991  const TensorShape& outputShape)
1992  : TestQuantization(options, inputShape, outputShape) {}
1993 
1994  void VisitInputLayer(const IConnectableLayer* layer,
1995  LayerBindingId id,
1996  const char* name = nullptr) override
1997  {
1998  boost::ignore_unused(layer, id, name);
1999  }
2000  void VisitOutputLayer(const IConnectableLayer* layer,
2001  LayerBindingId id,
2002  const char* name = nullptr) override
2003  {
2004  boost::ignore_unused(layer, id, name);
2005  }
2006  void VisitConcatLayer(const IConnectableLayer* layer,
2007  const OriginsDescriptor& originsDescriptor,
2008  const char* name = nullptr) override
2009  {
2010  boost::ignore_unused(originsDescriptor, name);
2011  TensorInfo outputInfo = layer->GetOutputSlot(0).GetTensorInfo();
2012  TestQuantizationParams(
2013  outputInfo, {60.8f / g_AsymmU8QuantizationBase, 65},
2014  {60.8f / g_SymmS8QuantizationBase, -63},
2015  {45.3f / g_SymmS8QuantizationBase, 0},
2016  {45.3f / g_SymmS16QuantizationBase, 0});
2017 
2018  TensorInfo inputInfo0 = layer->GetInputSlot(0).GetConnection()->GetTensorInfo();
2019  TensorInfo inputInfo1 = layer->GetInputSlot(1).GetConnection()->GetTensorInfo();
2020  TensorInfo inputInfo2 = layer->GetInputSlot(2).GetConnection()->GetTensorInfo();
2021 
2022  TestDifferentQuantizationScale(inputInfo0, inputInfo1);
2023  TestDifferentQuantizationScale(inputInfo0, inputInfo2);
2024  TestDifferentQuantizationScale(inputInfo1, inputInfo2);
2025  TestDifferentQuantizationScale(inputInfo0, outputInfo);
2026  }
2027  };
2028 
2029  INetworkPtr network = INetwork::Create();
2030 
2031  IConnectableLayer* input0 = network->AddInputLayer(0);
2032  IConnectableLayer* input1 = network->AddInputLayer(1);
2033  IConnectableLayer* input2 = network->AddInputLayer(2);
2034 
2035  OriginsDescriptor descriptor(3, 1);
2036  IConnectableLayer* concatLayer = network->AddConcatLayer(descriptor);
2037 
2038  IConnectableLayer* output0 = network->AddOutputLayer(3);
2039 
2040  // Establish connections
2041  input0->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(0));
2042  input1->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(1));
2043  input2->GetOutputSlot(0).Connect(concatLayer->GetInputSlot(2));
2044  concatLayer->GetOutputSlot(0).Connect(output0->GetInputSlot(0));
2045 
2046  // Set TensorInfo
2047  const TensorShape shape{1U};
2049 
2050  input0->GetOutputSlot(0).SetTensorInfo(info);
2051  input1->GetOutputSlot(0).SetTensorInfo(info);
2052  input2->GetOutputSlot(0).SetTensorInfo(info);
2053  concatLayer->GetOutputSlot(0).SetTensorInfo(info);
2054 
2055  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
2056  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
2057  INetworkQuantizerPtr quantizerPtrQAsymmU8 = INetworkQuantizer::Create(network.get());
2058  INetworkQuantizerPtr quantizerPtrQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options);
2059  INetworkQuantizerPtr quantizerPtrQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options);
2060  // Override the input ranges
2061  float min = -15.5f;
2062  float max = 45.3f;
2063 
2064  quantizerPtrQAsymmU8->OverrideInputRange(0, (min + 2.1f), (max - 3.2f));
2065  quantizerPtrQAsymmU8->OverrideInputRange(1, (min + 6.7f), max);
2066  quantizerPtrQAsymmU8->OverrideInputRange(2, min, (max - 7.8f));
2067 
2068  quantizerPtrQSymmS8->OverrideInputRange(0, (min + 2.1f), (max - 3.2f));
2069  quantizerPtrQSymmS8->OverrideInputRange(1, (min + 6.7f), max);
2070  quantizerPtrQSymmS8->OverrideInputRange(2, min, (max - 7.8f));
2071 
2072  quantizerPtrQSymmS16->OverrideInputRange(0, (min + 2.1f), (max - 3.2f));
2073  quantizerPtrQSymmS16->OverrideInputRange(1, (min + 6.7f), max);
2074  quantizerPtrQSymmS16->OverrideInputRange(2, min, (max - 7.8f));
2075 
2076  INetworkPtr quantizedNetworkQAsymmU8 = quantizerPtrQAsymmU8->ExportNetwork();
2077  TestConcatQuantization validatorQAsymmU8(shape, shape);
2078  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
2079 
2080  INetworkPtr quantizedNetworkQSymmS8 = quantizerPtrQSymmS8->ExportNetwork();
2081  TestConcatQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
2082  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
2083 
2084  INetworkPtr quantizedNetworkQSymmS16 = quantizerPtrQSymmS16->ExportNetwork();
2085  TestConcatQuantization validatorQSymmS16(qSymmS16options, shape, shape);
2086  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
2087 }
2088 
2089 BOOST_AUTO_TEST_CASE(QuantizeReshape)
2090 {
2091  class TestReshapeQuantization : public TestLeakyReLuActivationQuantization
2092  {
2093  public:
2094  TestReshapeQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
2095  : TestLeakyReLuActivationQuantization(inputShape, outputShape) {}
2096 
2097  TestReshapeQuantization(const QuantizerOptions& options,
2098  const TensorShape& inputShape,
2099  const TensorShape& outputShape)
2100  : TestLeakyReLuActivationQuantization(options, inputShape, outputShape) {}
2101 
2102  virtual void VisitReshapeLayer(const IConnectableLayer* layer,
2103  const ReshapeDescriptor& reshapeDescriptor,
2104  const char* name = nullptr) override
2105  {
2106  boost::ignore_unused(reshapeDescriptor, name);
2107  CheckForwardedQuantizationSettings(layer);
2108  }
2109  };
2110 
2111  INetworkPtr network = INetwork::Create();
2112 
2113  const TensorShape shape{1U};
2115 
2116  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
2117 
2118  // Add the layer under test
2119  ReshapeDescriptor descriptor({1, 2, 3, 4});
2120  IConnectableLayer* reshape = network->AddReshapeLayer(descriptor);
2121 
2122  CompleteLeakyReluNetwork(network.get(), activation, reshape, info);
2123 
2124  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
2125  TestReshapeQuantization validatorQAsymmU8(shape, shape);
2126  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
2127 
2128  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
2129  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
2130  TestReshapeQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
2131  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
2132 
2133  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
2134  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
2135  TestReshapeQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
2136  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
2137 
2138  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
2139  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
2140  TestReshapeQuantization validatorQSymmS16(qSymmS16options, shape, shape);
2141  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
2142 }
2143 
2144 BOOST_AUTO_TEST_CASE(QuantizeSplitter)
2145 {
2146  class TestSplitterQuantization : public TestLeakyReLuActivationQuantization
2147  {
2148  public:
2149  TestSplitterQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
2150  : TestLeakyReLuActivationQuantization(inputShape, outputShape) {}
2151 
2152  TestSplitterQuantization(const QuantizerOptions& options,
2153  const TensorShape& inputShape,
2154  const TensorShape& outputShape)
2155  : TestLeakyReLuActivationQuantization(options, inputShape, outputShape) {}
2156 
2157  virtual void VisitSplitterLayer(const IConnectableLayer* layer,
2158  const SplitterDescriptor& desc,
2159  const char* name = nullptr)
2160  {
2161  boost::ignore_unused(desc, name);
2162  CheckForwardedQuantizationSettings(layer);
2163  }
2164  };
2165 
2166  INetworkPtr network = INetwork::Create();
2167 
2168  const TensorShape shape{3U};
2170 
2171  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
2172 
2173  // Add the layer under test
2174  ViewsDescriptor splitterDesc(2,4);
2175  IConnectableLayer* splitter = network->AddSplitterLayer(splitterDesc);
2176  CompleteLeakyReluNetwork(network.get(), activation, splitter, info);
2177 
2178  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
2179  TestSplitterQuantization validatorQAsymmU8(shape, shape);
2180  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
2181 
2182  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
2183  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
2184  TestSplitterQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
2185  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
2186 
2187  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
2188  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
2189  TestSplitterQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
2190  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
2191 
2192  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
2193  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
2194  TestSplitterQuantization validatorQSymmS16(qSymmS16options, shape, shape);
2195  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
2196 }
2197 
2198 BOOST_AUTO_TEST_CASE(QuantizeResize)
2199 {
2200  class TestResizeQuantization : public TestLeakyReLuActivationQuantization
2201  {
2202  public:
2203  TestResizeQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
2204  : TestLeakyReLuActivationQuantization(inputShape, outputShape)
2205  {}
2206 
2207  TestResizeQuantization(const QuantizerOptions& options,
2208  const TensorShape& inputShape,
2209  const TensorShape& outputShape)
2210  : TestLeakyReLuActivationQuantization(options, inputShape, outputShape)
2211  {}
2212 
2213  void VisitResizeLayer(const IConnectableLayer* layer,
2214  const ResizeDescriptor& resizeDescriptor,
2215  const char* name = nullptr) override
2216  {
2217  boost::ignore_unused(resizeDescriptor, name);
2218  CheckForwardedQuantizationSettings(layer);
2219  }
2220  };
2221 
2222  INetworkPtr network = INetwork::Create();
2223 
2224  const TensorShape shape{1U};
2226 
2227  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
2228 
2229  // Add the layer under test
2230  ResizeDescriptor descriptor;
2231  descriptor.m_TargetHeight = 3;
2232  descriptor.m_TargetWidth = 3;
2233  IConnectableLayer* resizeLayer = network->AddResizeLayer(descriptor);
2234 
2235  CompleteLeakyReluNetwork(network.get(), activation, resizeLayer, info);
2236 
2237  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
2238  TestResizeQuantization validatorQAsymmU8(shape, shape);
2239  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
2240 
2241  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
2242  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
2243  TestResizeQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
2244  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
2245 
2246  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
2247  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
2248  TestResizeQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
2249  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
2250 
2251  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
2252  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
2253  TestResizeQuantization validatorQSymmS16(qSymmS16options, shape, shape);
2254  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
2255 }
2256 
2257 BOOST_AUTO_TEST_CASE(QuantizeStridedSlice)
2258 {
2259  class TestStridedSliceQuantization : public TestLeakyReLuActivationQuantization
2260  {
2261  public:
2262  TestStridedSliceQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
2263  : TestLeakyReLuActivationQuantization(inputShape, outputShape) {}
2264 
2265  TestStridedSliceQuantization(const QuantizerOptions& options,
2266  const TensorShape& inputShape,
2267  const TensorShape& outputShape)
2268  : TestLeakyReLuActivationQuantization(options, inputShape, outputShape) {}
2269 
2270  virtual void VisitStridedSliceLayer(const IConnectableLayer* layer,
2271  const StridedSliceDescriptor& desc,
2272  const char* name = nullptr)
2273  {
2274  boost::ignore_unused(desc, name);
2275  CheckForwardedQuantizationSettings(layer);
2276  }
2277  };
2278 
2279  INetworkPtr network = INetwork::Create();
2280 
2281  const TensorShape shape{3U};
2283 
2284  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
2285 
2286  // Add the layer under test
2287  StridedSliceDescriptor stridedSliceDesc;
2288  IConnectableLayer* stridedSlice = network->AddStridedSliceLayer(stridedSliceDesc);
2289 
2290  CompleteLeakyReluNetwork(network.get(), activation, stridedSlice, info);
2291 
2292  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
2293  TestStridedSliceQuantization validatorQAsymmU8(shape, shape);
2294  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
2295 
2296  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
2297  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
2298  TestStridedSliceQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
2299  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
2300 
2301  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
2302  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
2303  TestStridedSliceQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
2304  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
2305 
2306  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
2307  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
2308  TestStridedSliceQuantization validatorQSymmS16(qSymmS16options, shape, shape);
2309  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
2310 }
2311 
2312 BOOST_AUTO_TEST_CASE(QuantizeBatchToSpace)
2313 {
2314  class TestBatchToSpaceQuantization : public TestLeakyReLuActivationQuantization
2315  {
2316  public:
2317  TestBatchToSpaceQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
2318  : TestLeakyReLuActivationQuantization(inputShape, outputShape) {}
2319 
2320  TestBatchToSpaceQuantization(const QuantizerOptions& options,
2321  const TensorShape& inputShape,
2322  const TensorShape& outputShape)
2323  : TestLeakyReLuActivationQuantization(options, inputShape, outputShape) {}
2324 
2325  void VisitBatchToSpaceNdLayer(const IConnectableLayer* layer,
2326  const BatchToSpaceNdDescriptor& batchToSpaceNdDescriptor,
2327  const char* name = nullptr) override
2328  {
2329  boost::ignore_unused(batchToSpaceNdDescriptor, name);
2330  CheckForwardedQuantizationSettings(layer);
2331  }
2332  };
2333 
2334  INetworkPtr network = INetwork::Create();
2335 
2336  const TensorShape shape{1U};
2338 
2339  IConnectableLayer* activation = CreateStartOfLeakyReluNetwork(network.get(), info);
2340 
2341  // Add the layer under test
2342  BatchToSpaceNdDescriptor descriptor;
2343  IConnectableLayer* batchToSpace = network->AddBatchToSpaceNdLayer(descriptor);
2344 
2345  CompleteLeakyReluNetwork(network.get(), activation, batchToSpace, info);
2346 
2347  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
2348  TestBatchToSpaceQuantization validatorQAsymmU8(shape, shape);
2349  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
2350 
2351  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
2352  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
2353  TestBatchToSpaceQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
2354  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
2355 
2356  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
2357  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
2358  TestBatchToSpaceQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
2359  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
2360 
2361  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
2362  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
2363  TestBatchToSpaceQuantization validatorQSymmS16(qSymmS16options, shape, shape);
2364  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
2365 }
2366 
2367 BOOST_AUTO_TEST_CASE(QuantizePrelu)
2368 {
2369  class TestPreluQuantization : public TestQuantization
2370  {
2371  public:
2372  TestPreluQuantization(const TensorShape& inputShape,
2373  const TensorShape& alphaShape,
2374  const TensorShape& outputShape)
2375  : TestQuantization(inputShape, outputShape)
2376  , m_AlphaShape(alphaShape)
2377  {}
2378 
2379  TestPreluQuantization(const QuantizerOptions& options,
2380  const TensorShape& inputShape,
2381  const TensorShape& alphaShape,
2382  const TensorShape& outputShape)
2383  : TestQuantization(options, inputShape, outputShape)
2384  , m_AlphaShape(alphaShape)
2385  {}
2386 
2387  void VisitInputLayer(const IConnectableLayer* layer,
2388  LayerBindingId id,
2389  const char* name = nullptr) override
2390  {
2391  boost::ignore_unused(id, name);
2392  const TensorInfo& info = layer->GetOutputSlot(0).GetTensorInfo();
2393 
2394  switch (id)
2395  {
2396  case 0: // Input
2397  BOOST_TEST(m_InputShape == info.GetShape());
2398  break;
2399  case 1: // Alpha
2400  BOOST_TEST(m_AlphaShape == info.GetShape());
2401  break;
2402  default:
2403  throw InvalidArgumentException("Invalid layer binding id for PReLU layer");
2404  }
2405 
2406  // Based off current default [-15.0f, 15.0f]
2407  TestQuantizationParams(info,
2408  { 30.0f / g_AsymmU8QuantizationBase, 128 }, // QASymmU8
2409  { 30.0f / g_AsymmS8QuantizationBase, 0}, // QASymmS8
2410  { 15.0f / g_SymmS8QuantizationBase, 0}, // QSymmS8
2411  { 15.0f / g_SymmS16QuantizationBase, 0 }); // QSymmS16
2412  }
2413 
2414  void VisitOutputLayer(const IConnectableLayer* layer,
2415  LayerBindingId id,
2416  const char* name = nullptr) override
2417  {
2418  boost::ignore_unused(id, name);
2419  const TensorInfo& info = layer->GetInputSlot(0).GetConnection()->GetTensorInfo();
2420  BOOST_TEST(m_OutputShape == info.GetShape());
2421  }
2422 
2423  void VisitPreluLayer(const IConnectableLayer* layer,
2424  const char* name = nullptr) override
2425  {
2426  boost::ignore_unused(name);
2427  const TensorInfo& info = layer->GetOutputSlot(0).GetTensorInfo();
2428  TestQuantizationParams(info,
2429  { 30.0f / g_AsymmU8QuantizationBase, 128 }, // QASymmU8
2430  { 30.0f / g_AsymmS8QuantizationBase, 0}, // QAsymmS8
2431  { 15.0f / g_SymmS8QuantizationBase, 0}, // QSymmS8
2432  { 15.0f / g_SymmS16QuantizationBase, 0 }); // QSymmS16
2433  }
2434 
2435  private:
2436  TensorShape m_AlphaShape;
2437  };
2438 
2439  INetworkPtr network = INetwork::Create();
2440 
2441  const TensorShape inputShape{ 4, 1, 2 };
2442  const TensorShape alphaShape{ 5, 4, 3, 1 };
2443  const TensorShape outputShape{ 5, 4, 3, 2 };
2444  TensorInfo inputInfo(inputShape, DataType::Float32);
2445  TensorInfo alphaInfo(alphaShape, DataType::Float32);
2446  TensorInfo outputInfo(outputShape, DataType::Float32);
2447 
2448  // Add the input layers
2449  IConnectableLayer* input = network->AddInputLayer(0);
2450  IConnectableLayer* alpha = network->AddInputLayer(1);
2451 
2452  // Add the layer under test
2453  IConnectableLayer* prelu = network->AddPreluLayer("prelu");
2454 
2455  // Add the output layers
2456  IConnectableLayer* output = network->AddOutputLayer(0);
2457 
2458  // Establish connections
2459  input->GetOutputSlot(0).Connect(prelu->GetInputSlot(0));
2460  alpha->GetOutputSlot(0).Connect(prelu->GetInputSlot(1));
2461  prelu->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2462 
2463  // Set tensor info
2464  input->GetOutputSlot(0).SetTensorInfo(inputInfo);
2465  alpha->GetOutputSlot(0).SetTensorInfo(alphaInfo);
2466  prelu->GetOutputSlot(0).SetTensorInfo(outputInfo);
2467 
2468  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
2469  TestPreluQuantization validatorQAsymmU8(inputShape, alphaShape, outputShape);
2470  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
2471 
2472  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
2473  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
2474  TestPreluQuantization validatorQAsymmS8(qAsymmS8Options, inputShape, alphaShape, outputShape);
2475  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
2476 
2477  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
2478  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
2479  TestPreluQuantization validatorQSymmS8(qSymmS8Options, inputShape, alphaShape, outputShape);
2480  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
2481 
2482  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
2483  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
2484  TestPreluQuantization validatorQSymmS16(qSymmS16options, inputShape, alphaShape, outputShape);
2485  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
2486 }
2487 
2489 {
2490  class TestTransposeConvolution2dQuantization : public TestQuantization
2491  {
2492  public:
2493  TestTransposeConvolution2dQuantization(const TensorShape& inputShape, const TensorShape& outputShape) :
2494  TestQuantization(inputShape, outputShape)
2495  {}
2496 
2497  TestTransposeConvolution2dQuantization(const QuantizerOptions& options,
2498  const TensorShape& inputShape,
2499  const TensorShape& outputShape) :
2500  TestQuantization(options, inputShape, outputShape)
2501  {}
2502 
2503  void VisitTransposeConvolution2dLayer(const IConnectableLayer *layer,
2504  const TransposeConvolution2dDescriptor& descriptor,
2505  const ConstTensor& weights,
2506  const Optional<ConstTensor>& biases,
2507  const char *name = nullptr) override
2508  {
2509  boost::ignore_unused(descriptor, name);
2510  TestQuantizationOnLayersWithBiases(layer, weights, biases);
2511  }
2512  };
2513 
2514  INetworkPtr network = INetwork::Create();
2515 
2516  TensorShape shape{ 3 };
2518 
2519  std::initializer_list<float> floatData{ -1.0f, 1.5f, 2.0f };
2520  std::vector<float> weightsData(floatData);
2521  ConstTensor weights(info, weightsData);
2522 
2524  descriptor.m_BiasEnabled = useBiases;
2525 
2526  // construct network
2527  IConnectableLayer* input = network->AddInputLayer(0);
2528  Optional<ConstTensor> optionalBiases;
2529  std::vector<float> biasesData(floatData);
2530  if (useBiases)
2531  {
2532  ConstTensor biases(info, biasesData);
2533  optionalBiases = Optional<ConstTensor>(biases);
2534  }
2535  IConnectableLayer* transposeConv2d = network->AddTransposeConvolution2dLayer(descriptor, weights, optionalBiases);
2536  IConnectableLayer* output = network->AddOutputLayer(1);
2537 
2538  input->GetOutputSlot(0).Connect(transposeConv2d->GetInputSlot(0));
2539  transposeConv2d->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2540 
2541  input->GetOutputSlot(0).SetTensorInfo(info);
2542  transposeConv2d->GetOutputSlot(0).SetTensorInfo(info);
2543 
2544  // test QAsymmU8 quantization
2545  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
2546  TestTransposeConvolution2dQuantization validatorQAsymmU8(shape, shape);
2547  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
2548 
2549  //test QAsymmS8 quantization
2550  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
2551  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
2552  TestTransposeConvolution2dQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
2553  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
2554 
2555  // test QSymmS8 quantization
2556  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
2557  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
2558  TestTransposeConvolution2dQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
2559  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
2560 
2561  // test QSymmS16 quantization
2562  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
2563  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
2564  TestTransposeConvolution2dQuantization validatorQSymmS16(qSymmS16options, shape, shape);
2565  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
2566 }
2567 
2568 BOOST_AUTO_TEST_CASE(QuantizeTransposeConvolution2d)
2569 {
2571 }
2572 
2573 BOOST_AUTO_TEST_CASE(QuantizeTransposeConvolution2dWithBiases)
2574 {
2576 }
2577 
2578 BOOST_AUTO_TEST_CASE(QuantizeStack)
2579 {
2580  class TestStackQuantization : public TestQuantization
2581  {
2582  public:
2583  TestStackQuantization(const TensorShape& inputShape,
2584  const TensorShape& outputShape)
2585  : TestQuantization(inputShape, outputShape) {}
2586 
2587  TestStackQuantization(const QuantizerOptions& options,
2588  const TensorShape& inputShape,
2589  const TensorShape& outputShape)
2590  : TestQuantization(options, inputShape, outputShape) {}
2591 
2592  void VisitInputLayer(const IConnectableLayer* layer,
2593  LayerBindingId id,
2594  const char* name = nullptr) override
2595  {
2596  boost::ignore_unused(layer, id, name);
2597  }
2598  void VisitOutputLayer(const IConnectableLayer* layer,
2599  LayerBindingId id,
2600  const char* name = nullptr) override
2601  {
2602  boost::ignore_unused(layer, id, name);
2603  }
2604 
2605  void VisitStackLayer(const IConnectableLayer* layer,
2606  const StackDescriptor& descriptor,
2607  const char* name = nullptr) override
2608  {
2609  boost::ignore_unused(descriptor, name);
2610  TensorInfo outputInfo = layer->GetOutputSlot(0).GetTensorInfo();
2611 
2612  TestQuantizationParams(outputInfo,
2613  { 30.0f / g_AsymmU8QuantizationBase, 128 },
2614  { 30.0f / g_AsymmS8QuantizationBase, 0},
2615  { 15.0f / g_SymmS8QuantizationBase, 0},
2616  { 15.0f / g_SymmS16QuantizationBase, 0 });
2617  }
2618  };
2619 
2620  INetworkPtr network = INetwork::Create();
2621 
2622  IConnectableLayer* input0 = network->AddInputLayer(0);
2623  IConnectableLayer* input1 = network->AddInputLayer(1);
2624 
2625  const TensorShape inputShape{ 3, 4, 5 };
2626  const TensorShape outputShape{ 3, 4, 2, 5 };
2627 
2628  StackDescriptor descriptor(2, 2, inputShape);
2629  IConnectableLayer* stackLayer = network->AddStackLayer(descriptor);
2630 
2631  IConnectableLayer* output = network->AddOutputLayer(0);
2632 
2633  input0->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(0));
2634  input1->GetOutputSlot(0).Connect(stackLayer->GetInputSlot(1));
2635  stackLayer->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2636 
2637  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
2638  TestStackQuantization validatorQAsymmU8(inputShape, outputShape);
2639  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
2640 
2641  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
2642  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
2643  TestStackQuantization validatorQAsymmS8(qAsymmS8Options, inputShape, inputShape);
2644  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
2645 
2646  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
2647  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
2648  TestStackQuantization validatorQSymmS8(qSymmS8Options, inputShape, inputShape);
2649  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
2650 
2651  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
2652  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
2653  TestStackQuantization validatorQSymmS16(qSymmS16options, inputShape, outputShape);
2654  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
2655 }
2656 
2657 BOOST_AUTO_TEST_CASE(QuantizeSlice)
2658 {
2659  class TestSliceQuantization : public TestQuantization
2660  {
2661  public:
2662  TestSliceQuantization(const TensorShape& inputShape, const TensorShape& outputShape)
2663  : TestQuantization(inputShape, outputShape)
2664  {}
2665 
2666  TestSliceQuantization(const QuantizerOptions& options,
2667  const TensorShape& inputShape,
2668  const TensorShape& outputShape)
2669  : TestQuantization(options, inputShape, outputShape)
2670  {}
2671 
2672  virtual void VisitSliceLayer(const IConnectableLayer* layer,
2673  const SliceDescriptor& desc,
2674  const char* name = nullptr)
2675  {
2676  boost::ignore_unused(desc, name);
2677  const TensorInfo& info = layer->GetOutputSlot(0).GetTensorInfo();
2678 
2679  const OffsetScalePair qAsymmU8Params{ 30.0f / g_AsymmU8QuantizationBase, 128 };
2680  const OffsetScalePair qAsymmS8Params{ 30.0f / g_AsymmS8QuantizationBase, 0 };
2681  const OffsetScalePair qSymmS8Params { 15.0f / g_SymmS8QuantizationBase, 0 };
2682  const OffsetScalePair qSymmS16Params{ 15.0f / g_SymmS16QuantizationBase, 0 };
2683 
2684  TestQuantizationParams(info, qAsymmU8Params, qAsymmS8Params, qSymmS8Params, qSymmS16Params);
2685  }
2686  };
2687 
2688  TensorShape shape{ 3 };
2690 
2691  INetworkPtr network = INetwork::Create();
2692 
2693  IConnectableLayer* inputLayer = network->AddInputLayer(0);
2694  IConnectableLayer* sliceLayer = network->AddSliceLayer(SliceDescriptor());
2695  IConnectableLayer* outputLayer = network->AddOutputLayer(0);
2696 
2697  inputLayer->GetOutputSlot(0).Connect(sliceLayer->GetInputSlot(0));
2698  sliceLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2699 
2700  inputLayer->GetOutputSlot(0).SetTensorInfo(info);
2701  sliceLayer->GetOutputSlot(0).SetTensorInfo(info);
2702 
2703  // test QAsymmU8 quantization
2704  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get())->ExportNetwork();
2705  TestSliceQuantization validatorQAsymmU8(shape, shape);
2706  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
2707 
2708  // test QASymmS8 quantization
2709  const QuantizerOptions qAsymmS8Options(DataType::QAsymmS8);
2710  INetworkPtr quantizedNetworkQAsymmS8 = INetworkQuantizer::Create(network.get(), qAsymmS8Options)->ExportNetwork();
2711  TestSliceQuantization validatorQAsymmS8(qAsymmS8Options, shape, shape);
2712  VisitLayersTopologically(quantizedNetworkQAsymmS8.get(), validatorQAsymmS8);
2713 
2714  // test QSymmS8 quantization
2715  const QuantizerOptions qSymmS8Options(DataType::QSymmS8);
2716  INetworkPtr quantizedNetworkQSymmS8 = INetworkQuantizer::Create(network.get(), qSymmS8Options)->ExportNetwork();
2717  TestSliceQuantization validatorQSymmS8(qSymmS8Options, shape, shape);
2718  VisitLayersTopologically(quantizedNetworkQSymmS8.get(), validatorQSymmS8);
2719 
2720  // test QSymmS16 quantization
2721  const QuantizerOptions qSymmS16options(DataType::QSymmS16);
2722  INetworkPtr quantizedNetworkQSymmS16 = INetworkQuantizer::Create(network.get(), qSymmS16options)->ExportNetwork();
2723  TestSliceQuantization validatorQSymmS16(qSymmS16options, shape, shape);
2724  VisitLayersTopologically(quantizedNetworkQSymmS16.get(), validatorQSymmS16);
2725 }
2726 
2727 std::vector<uint8_t> SetupQuantize(float value)
2728 {
2729  armnn::TensorInfo inputInfo({ 1, 2, 2 }, armnn::DataType::Float32);
2730  inputInfo.SetQuantizationScale(1.0f);
2731  inputInfo.SetQuantizationOffset(1);
2732  std::vector<float> input({ value, 0.0f, 0.0f, 1.0f });
2733  const std::vector<float> &inputRef = input;
2734 
2735  auto output = armnnUtils::QuantizedVector<uint8_t>(inputRef,
2736  inputInfo.GetQuantizationScale(),
2737  inputInfo.GetQuantizationOffset());
2738 
2739  return output;
2740 }
2741 
2743 {
2744  BOOST_CHECK_EQUAL(SetupQuantize(std::numeric_limits<float>::infinity())[0], 255);
2745 }
2746 
2747 BOOST_AUTO_TEST_CASE(QuantizeNegativeInf)
2748 {
2749  BOOST_CHECK_EQUAL(SetupQuantize(-1 * std::numeric_limits<float>::infinity())[0], 0);
2750 }
2751 
2752 class TestPreserveType : public TestAdditionQuantization
2753 {
2754 public:
2755  TestPreserveType(const QuantizerOptions& options,
2756  const DataType& dataType,
2757  const TensorShape& inputShape,
2758  const TensorShape& outputShape)
2759  : TestAdditionQuantization(options, inputShape, outputShape)
2760  , m_DataType(dataType)
2761  , m_VisitedQuantizeLayer(false)
2762  , m_VisitedDequantizeLayer(false) {}
2763 
2764  void VisitInputLayer(const IConnectableLayer* layer,
2765  LayerBindingId id,
2766  const char* name = nullptr) override
2767  {
2768  boost::ignore_unused(id, name);
2769  const TensorInfo& info = layer->GetOutputSlot(0).GetTensorInfo();
2770  BOOST_TEST(GetDataTypeName(info.GetDataType()) == GetDataTypeName(m_DataType));
2771  BOOST_TEST(m_InputShape == info.GetShape());
2772  }
2773 
2774  void VisitOutputLayer(const IConnectableLayer* layer,
2775  LayerBindingId id,
2776  const char* name = nullptr) override
2777  {
2778  boost::ignore_unused(id, name);
2779  const TensorInfo& info = layer->GetInputSlot(0).GetConnection()->GetTensorInfo();
2780  BOOST_TEST(GetDataTypeName(info.GetDataType()) == GetDataTypeName(m_DataType));
2781  BOOST_TEST(m_OutputShape == info.GetShape());
2782  }
2783 
2784  void VisitQuantizeLayer(const IConnectableLayer* layer,
2785  const char* name = nullptr) override
2786  {
2787  boost::ignore_unused(layer, name);
2788  m_VisitedQuantizeLayer = true;
2789  }
2790 
2791  void VisitDequantizeLayer(const IConnectableLayer* layer,
2792  const char* name = nullptr) override
2793  {
2794  boost::ignore_unused(layer, name);
2795  m_VisitedDequantizeLayer = true;
2796  }
2797 
2798  void CheckQuantizeDequantizeLayerVisited(bool expected)
2799  {
2800  if (expected)
2801  {
2802  BOOST_CHECK(m_VisitedQuantizeLayer);
2803  BOOST_CHECK(m_VisitedDequantizeLayer);
2804  }
2805  else
2806  {
2807  BOOST_CHECK(!m_VisitedQuantizeLayer);
2808  BOOST_CHECK(!m_VisitedDequantizeLayer);
2809  }
2810  }
2811 private:
2812  const DataType m_DataType;
2813  bool m_VisitedQuantizeLayer;
2814  bool m_VisitedDequantizeLayer;
2815 };
2816 
2817 void PreserveTypeTestImpl(const DataType& dataType)
2818 {
2819  INetworkPtr network = INetwork::Create();
2820 
2821  // Add the layers
2822  IConnectableLayer* input0 = network->AddInputLayer(0);
2823  IConnectableLayer* input1 = network->AddInputLayer(1);
2824  IConnectableLayer* addition = network->AddAdditionLayer();
2825  IConnectableLayer* output = network->AddOutputLayer(2);
2826 
2827  input0->GetOutputSlot(0).Connect(addition->GetInputSlot(0));
2828  input1->GetOutputSlot(0).Connect(addition->GetInputSlot(1));
2829  addition->GetOutputSlot(0).Connect(output->GetInputSlot(0));
2830 
2831  const TensorShape shape{1U, 2U, 3U};
2832  const TensorInfo info(shape, dataType);
2833  input0->GetOutputSlot(0).SetTensorInfo(info);
2834  input1->GetOutputSlot(0).SetTensorInfo(info);
2835  addition->GetOutputSlot(0).SetTensorInfo(info);
2836 
2838  QuantizerOptions(DataType::QAsymmU8, true) : QuantizerOptions(dataType, true);
2839 
2840  INetworkPtr quantizedNetworkQAsymmU8 = INetworkQuantizer::Create(network.get(), options)->ExportNetwork();
2841  TestPreserveType validatorQAsymmU8(options, dataType, shape, shape);
2842  VisitLayersTopologically(quantizedNetworkQAsymmU8.get(), validatorQAsymmU8);
2843  validatorQAsymmU8.CheckQuantizeDequantizeLayerVisited(
2844  dataType == DataType::Float32 || dataType == DataType::Float16);
2845 }
2846 
2847 BOOST_AUTO_TEST_CASE(PreserveTypeFloat32)
2848 {
2850 }
2851 
2852 BOOST_AUTO_TEST_CASE(PreserveTypeQAsymmU8)
2853 {
2855 }
2856 
2857 BOOST_AUTO_TEST_CASE(PreserveTypeQsymm8)
2858 {
2860 }
2861 
2862 BOOST_AUTO_TEST_CASE(PreserveTypeQsymm16)
2863 {
2865 }
2866 
2867 BOOST_AUTO_TEST_CASE(TestConnectionPreservationAfterDynamicQuant)
2868 {
2869  class TestConnectionPreservation : public LayerVisitorBase<VisitorNoThrowPolicy>
2870  {
2871  public:
2872  TestConnectionPreservation(const Graph& graph)
2874  , m_Graph(graph)
2875  {}
2876 
2877  void VisitAdditionLayer(const IConnectableLayer* layer, const char*) override
2878  {
2879  CheckLayerName(layer->GetInputSlot(0).GetConnection()->GetOwningLayerGuid(), "reLU1");
2880  CheckLayerName(layer->GetInputSlot(1).GetConnection()->GetOwningLayerGuid(), "reLU2");
2881  }
2882 
2883  void CheckLayerName(LayerGuid guid, std::string expectedName)
2884  {
2885  bool guidFound = false;
2886  for (Layer* layer : m_Graph)
2887  {
2888  if (layer->GetGuid() == guid)
2889  {
2890  BOOST_CHECK_EQUAL(layer->GetName(), expectedName.c_str());
2891  guidFound = true;
2892  break;
2893  }
2894  }
2895  if (!guidFound)
2896  {
2897  BOOST_FAIL("No layer matching the GUID was found");
2898  }
2899  }
2900 
2901  private:
2902  Graph m_Graph;
2903  };
2904 
2905  INetworkPtr network = INetwork::Create();
2906 
2907  IConnectableLayer* inputLayer = network->AddInputLayer(0,"inputLayer1");
2908  armnn::ActivationDescriptor ReLUDesc;
2910 
2911  IConnectableLayer* reLULayer1 = network->AddActivationLayer(ReLUDesc, "reLU1");
2912  IConnectableLayer* reLULayer2 = network->AddActivationLayer(ReLUDesc, "reLU2");
2913  IConnectableLayer* addLayer1 = network->AddAdditionLayer("addLayer1");
2914  IConnectableLayer* outputLayer = network->AddOutputLayer(0,"outPutLayer1");
2915 
2916  inputLayer->GetOutputSlot(0).Connect(reLULayer1->GetInputSlot(0));
2917  reLULayer1->GetOutputSlot(0).Connect(reLULayer2->GetInputSlot(0));
2918  reLULayer1->GetOutputSlot(0).Connect(addLayer1->GetInputSlot(0));
2919  reLULayer2->GetOutputSlot(0).Connect(addLayer1->GetInputSlot(1));
2920  addLayer1->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
2921 
2922  inputLayer->GetOutputSlot(0).SetTensorInfo(TensorInfo(TensorShape({1, 2, 2, 1}), DataType::Float32));
2923  reLULayer1->GetOutputSlot(0).SetTensorInfo(TensorInfo(TensorShape({1, 2, 2, 1}), DataType::Float32));
2924  reLULayer2->GetOutputSlot(0).SetTensorInfo(TensorInfo(TensorShape({1, 2, 2, 1}), DataType::Float32));
2925  addLayer1->GetOutputSlot(0).SetTensorInfo(TensorInfo(TensorShape({1, 2, 2, 1}), DataType::Float32));
2926 
2927  TestConnectionPreservation visitor1(boost::polymorphic_downcast<const Network*>(network.get())->GetGraph());
2928  VisitLayersTopologically(network.get(), visitor1);
2929 
2931 
2932  armnn::TensorInfo tensorInfo = GetInputTensorInfo(boost::polymorphic_downcast<const Network*>(network.get()));
2933 
2934  std::vector<float> inputData({0, 2, 0, 4});
2935  armnn::ConstTensor inputTensor(tensorInfo, inputData.data());
2936 
2937  InputTensors inputTensors;
2938  inputTensors.push_back(std::make_pair(0, inputTensor));
2939  quantizer->Refine(inputTensors);
2940 
2941  INetworkPtr quantNetwork = quantizer->ExportNetwork();
2942 
2943  TestConnectionPreservation visitor2(boost::polymorphic_downcast<const Network*>(quantNetwork.get())->GetGraph());
2944  VisitLayersTopologically(quantNetwork.get(), visitor2);
2945 }
2946 
2948 } // namespace armnn
float m_A
Alpha upper bound value used by the activation functions. (BoundedReLu, Linear, TanH).
Definition: Descriptors.hpp:37
virtual const IOutputSlot * GetConnection() const =0
INetworkPtr CreateNetworkWithFullyConnectedLayer(const bool biasEnabled, const TensorShape &inputShape, const TensorShape &outputShape)
const float g_SymmS16QuantizationBase
virtual LayerGuid GetGuid() const =0
const float g_SymmS8QuantizationBase
Visitor object for overriding the input range of the quantized input layers in a network.
void ValidateFullyConnectedLayer(const bool biasEnabled)
virtual const IInputSlot & GetInputSlot(unsigned int index) const =0
int32_t GetQuantizationOffset() const
Definition: Tensor.cpp:264
A BatchToSpaceNdDescriptor for the BatchToSpaceNdLayer.
A tensor defined by a TensorInfo (shape and data type) and an immutable backing store.
Definition: Tensor.hpp:199
virtual const TensorInfo & GetTensorInfo() const =0
void PreserveTypeTestImpl(const DataType &dataType)
uint32_t m_NumOutputs
Number of output tensors.
IConnectableLayer * AddInputLayer(LayerBindingId id, const char *name=nullptr) override
Definition: Network.cpp:953
void VisitLayers(const LayerContainer &layerContainer, ILayerVisitor &visitor)
std::vector< MinMaxRange > MinMaxRanges
uint32_t m_TargetHeight
Target height value.
TensorInfo GetInputTensorInfo(const Network *network)
BOOST_AUTO_TEST_CASE(CheckConvolution2dLayer)
An ActivationDescriptor for the ActivationLayer.
Definition: Descriptors.hpp:20
const float g_TestTolerance
std::pair< float, float > MinMaxRange
A BatchNormalizationDescriptor for the BatchNormalizationLayer.
void QuantizeConstant(const srcType *src, uint8_t *dst, size_t numElements, float &scale, int &offset)
IConnectableLayer * AddAdditionLayer(const char *name=nullptr) override
Definition: Network.cpp:1212
bool IsEmpty() const
Query function to check that the RangeTracker is empty.
bool m_BiasEnabled
Enable/disable bias.
A ViewsDescriptor for the SplitterLayer. Descriptor to configure the splitting process. Number of Views must be equal to the number of outputs, and their order must match - e.g. first view corresponds to the first output, second view to the second output, etc.
ArgMinMaxFunction m_Function
Specify if the function is to find Min or Max.
Definition: Descriptors.hpp:56
IConnectableLayer * CreateStartOfLeakyReluNetwork(INetwork *network, const TensorInfo &info)
virtual LayerGuid GetOwningLayerGuid() const =0
A SpaceToDepthDescriptor for the SpaceToDepthLayer.
virtual const char * GetName() const =0
void TestQuantizeDepthwiseConvolution2d(bool useBiases)
float m_Beta
Exponentiation value.
virtual void SetTensorInfo(const TensorInfo &tensorInfo)=0
A ReshapeDescriptor for the ReshapeLayer.
A TransposeConvolution2dDescriptor for the TransposeConvolution2dLayer.
std::pair< float, float > MinMaxRange
virtual IConnectableLayer * AddInputLayer(LayerBindingId id, const char *name=nullptr)=0
bool HasRanges(LayerGuid guid) const
Query that there is an entry for a layer.
Private implementation of INetwork.
Definition: Network.hpp:27
float m_B
Beta lower bound value used by the activation functions. (BoundedReLu, Linear, TanH).
Definition: Descriptors.hpp:39
std::unique_ptr< class INetworkQuantizer, void(*)(INetworkQuantizer *quantizer)> INetworkQuantizerPtr
INetworkPtr CreateNetworkWithActivationLayer(const ActivationDescriptor &descriptor, const TensorShape &shape)
std::vector< std::pair< LayerBindingId, class ConstTensor > > InputTensors
Definition: Tensor.hpp:225
void VisitLayersTopologically(const INetwork *inputNetwork, ILayerVisitor &visitor)
void SetQuantizationScale(float scale)
Definition: Tensor.cpp:259
INetworkPtr CreateNetworkWithInputOutputLayers()
static INetworkPtr Create()
Definition: Network.cpp:48
An InstanceNormalizationDescriptor for InstanceNormalizationLayer.
BOOST_CHECK(profilingService.GetCurrentState()==ProfilingState::WaitingForAck)
A FullyConnectedDescriptor for the FullyConnectedLayer.
InputLayersAccessor GetInputLayers() const
Definition: Graph.hpp:181
std::unique_ptr< INetwork, void(*)(INetwork *network)> INetworkPtr
Definition: INetwork.hpp:85
bool m_BiasEnabled
Enable/disable bias.
const Graph & GetGraph() const
Definition: Network.hpp:33
std::unordered_map< LayerGuid, MinMaxRanges > MinMaxRangeMap
const TensorInfo & GetInfo() const
Definition: Tensor.hpp:167
A StackDescriptor for the StackLayer.
BOOST_AUTO_TEST_SUITE_END()
uint32_t m_NumInputs
Number of input tensors.
ActivationFunction m_Function
The activation function to use (Sigmoid, TanH, Linear, ReLu, BoundedReLu, SoftReLu, LeakyReLu, Abs, Sqrt, Square).
Definition: Descriptors.hpp:35
A SoftmaxDescriptor for the SoftmaxLayer.
const float g_AsymmS8QuantizationBase
bool m_BiasEnabled
Enable/disable bias.
DataType
Definition: Types.hpp:32
static INetworkQuantizerPtr Create(INetwork *inputNetwork, const QuantizerOptions &options=QuantizerOptions())
Create Quantizer object wrapped in unique_ptr.
MinMaxRange GetRange(LayerGuid guid, unsigned int idx) const
Retrieve the Range for a particular output slot on a particular layer.
Interface for a layer that is connectable to other layers via InputSlots and OutputSlots.
Definition: INetwork.hpp:61
DataType GetDataType() const
Definition: Tensor.hpp:95
BOOST_AUTO_TEST_SUITE(TensorflowLiteParser)
void TestQuantizeConvolution2d(bool useBiases)
const float g_AsymmU8QuantizationBase
A Pooling2dDescriptor for the Pooling2dLayer.
A StandInDescriptor for the StandIn layer.
A SliceDescriptor for the SliceLayer.
bool m_BiasEnabled
Enable/disable bias.
virtual IConnectableLayer * AddActivationLayer(const ActivationDescriptor &activationDescriptor, const char *name=nullptr)=0
virtual IConnectableLayer * AddOutputLayer(LayerBindingId id, const char *name=nullptr)=0
A DepthwiseConvolution2dDescriptor for the DepthwiseConvolution2dLayer.
std::pair< float, int > OffsetScalePair
A PermuteDescriptor for the PermuteLayer.
INetworkPtr CreateNetworkWithSoftmaxLayer(const SoftmaxDescriptor &descriptor, const TensorShape &shape)
A Convolution2dDescriptor for the Convolution2dLayer.
IConnectableLayer * AddOutputLayer(LayerBindingId id, const char *name=nullptr) override
Definition: Network.cpp:1222
void CompleteLeakyReluNetwork(INetwork *network, IConnectableLayer *activation, IConnectableLayer *layerUnderTest, const TensorInfo &info)
virtual int Connect(IInputSlot &destination)=0
armnn::Runtime::CreationOptions::ExternalProfilingOptions options
std::vector< uint8_t > SetupQuantize(float value)
A SpaceToBatchNdDescriptor for the SpaceToBatchNdLayer.
void TestQuantizeTransposeConvolution2d(bool useBiases)
const TensorShape & GetShape() const
Definition: Tensor.hpp:88
An ArgMinMaxDescriptor for ArgMinMaxLayer.
Definition: Descriptors.hpp:43
bool has_value() const noexcept
Definition: Optional.hpp:53
int LayerBindingId
Type of identifiers for bindable layers (inputs, outputs).
Definition: Types.hpp:168
constexpr const char * GetDataTypeName(DataType dataType)
Definition: TypesUtils.hpp:165
A ResizeDescriptor for the ResizeLayer.
A ComparisonDescriptor for the ComparisonLayer.
Definition: Descriptors.hpp:62
virtual const IOutputSlot & GetOutputSlot(unsigned int index) const =0
float GetQuantizationScale() const
Definition: Tensor.cpp:247
An OriginsDescriptor for the ConcatLayer. Descriptor to configure the concatenation process...
A StridedSliceDescriptor for the StridedSliceLayer.