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