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