aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatteo Martincigh <matteo.martincigh@arm.com>2019-02-11 13:24:38 +0000
committerMatteo Martincigh <matteo.martincigh@arm.com>2019-02-14 17:53:55 +0000
commit5b2159e43a5e078053e706883e3af44ae733b5b9 (patch)
tree6486b631f32c5f903ba609907ef3aa25002e3daa
parentec333914d5d38079083bcdb7fc88a54a19ebaa87 (diff)
downloadarmnn-5b2159e43a5e078053e706883e3af44ae733b5b9.tar.gz
IVGCVSW-2620 Support static quantization of Constant
* Added VisitConstantLayer to QuantizerVisitor * Added unit tests and refactored QuantizerTest.cpp * Code cleanup Change-Id: I118fd2be085fc98879c5cfaa09698a7c98ba13f0 Signed-off-by: Matteo Martincigh <matteo.martincigh@arm.com>
-rw-r--r--include/armnn/INetwork.hpp2
-rw-r--r--src/armnn/OverrideInputRangeVisitor.hpp3
-rw-r--r--src/armnn/QuantizerVisitor.cpp13
-rw-r--r--src/armnn/QuantizerVisitor.hpp4
-rw-r--r--src/armnn/StaticRangeVisitor.cpp31
-rw-r--r--src/armnn/StaticRangeVisitor.hpp4
-rw-r--r--src/armnn/layers/ConstantLayer.hpp4
-rw-r--r--src/armnn/test/ConstTensorLayerVisitor.hpp68
-rw-r--r--src/armnn/test/QuantizerTest.cpp318
-rw-r--r--src/armnn/test/TestLayerVisitor.cpp2
10 files changed, 280 insertions, 169 deletions
diff --git a/include/armnn/INetwork.hpp b/include/armnn/INetwork.hpp
index aaca13bba9..a59000b334 100644
--- a/include/armnn/INetwork.hpp
+++ b/include/armnn/INetwork.hpp
@@ -266,7 +266,7 @@ public:
/// @param name - Optional name for the layer.
/// @return - Interface for configuring the layer.
virtual IConnectableLayer* AddConstantLayer(const ConstTensor& input,
- const char* name = nullptr) = 0;
+ const char* name = nullptr) = 0;
/// Adds a reshape layer to the network.
/// @param reshapeDescriptor - Parameters for the reshape operation.
diff --git a/src/armnn/OverrideInputRangeVisitor.hpp b/src/armnn/OverrideInputRangeVisitor.hpp
index f09eeb9f50..511c851bef 100644
--- a/src/armnn/OverrideInputRangeVisitor.hpp
+++ b/src/armnn/OverrideInputRangeVisitor.hpp
@@ -18,8 +18,7 @@ namespace armnn
class OverrideInputRangeVisitor : public LayerVisitorBase<VisitorNoThrowPolicy>
{
private:
- using MinMaxRange = std::pair<float, float>;
- using MinMaxRanges = std::vector<MinMaxRange>;
+ using MinMaxRange = RangeTracker::MinMaxRange;
public:
OverrideInputRangeVisitor(RangeTracker& ranges,
diff --git a/src/armnn/QuantizerVisitor.cpp b/src/armnn/QuantizerVisitor.cpp
index 850a3c1fae..8e3265fb75 100644
--- a/src/armnn/QuantizerVisitor.cpp
+++ b/src/armnn/QuantizerVisitor.cpp
@@ -44,7 +44,7 @@ void QuantizerVisitor::SetQuantizedInputConnections(const IConnectableLayer* src
newOutputSlot.Connect(newInputSlot);
// Fetch the min/max ranges that were computed earlier
- auto range = m_Ranges.GetRange(layerToFind.GetGuid(), i);
+ auto range = m_Ranges.GetRange(layerToFind.GetGuid(), slotIdx);
auto qParams = ComputeQAsymmParams(8, range.first, range.second);
// Set the quantization params
@@ -242,4 +242,15 @@ void QuantizerVisitor::VisitSoftmaxLayer(const IConnectableLayer* layer,
SetQuantizedInputConnections(layer, newLayer);
}
+void QuantizerVisitor::VisitConstantLayer(const IConnectableLayer* layer,
+ const ConstTensor& input,
+ const char* name)
+{
+ std::vector<uint8_t> inputBacking;
+ ConstTensor qInput = CreateQuantizedConst(input, inputBacking);
+
+ IConnectableLayer* newLayer = m_QuantizedNetwork->AddConstantLayer(qInput, name);
+ RecordLayer(layer, newLayer);
+}
+
} //namespace armnn
diff --git a/src/armnn/QuantizerVisitor.hpp b/src/armnn/QuantizerVisitor.hpp
index 8829bdfaa8..1beaf5adde 100644
--- a/src/armnn/QuantizerVisitor.hpp
+++ b/src/armnn/QuantizerVisitor.hpp
@@ -80,6 +80,10 @@ public:
const Pooling2dDescriptor& pooling2dDescriptor,
const char* name = nullptr) override;
+ void VisitConstantLayer(const IConnectableLayer* layer,
+ const ConstTensor& input,
+ const char* name = nullptr) override;
+
/// Extract the quantized network
INetworkPtr RetrieveFinalNetwork() { return std::move(m_QuantizedNetwork); }
diff --git a/src/armnn/StaticRangeVisitor.cpp b/src/armnn/StaticRangeVisitor.cpp
index b1cbb2d574..cc1255e56e 100644
--- a/src/armnn/StaticRangeVisitor.cpp
+++ b/src/armnn/StaticRangeVisitor.cpp
@@ -9,6 +9,8 @@
#include <armnn/Descriptors.hpp>
#include <armnn/Types.hpp>
+#include <limits>
+
namespace armnn
{
@@ -150,4 +152,33 @@ void StaticRangeVisitor::VisitSoftmaxLayer(const IConnectableLayer* layer,
SetRange(layer, 0, 0.f, 1.f);
}
+void StaticRangeVisitor::VisitConstantLayer(const IConnectableLayer* layer,
+ const ConstTensor& input,
+ const char* name)
+{
+ boost::ignore_unused(name);
+
+ if (input.GetDataType() != DataType::Float32)
+ {
+ throw InvalidArgumentException("Quantization is supported only for FP32 tensors");
+ }
+
+ // Work out the range based on the input constants
+ unsigned int inputNumElements = input.GetNumElements();
+ const float* inputData = reinterpret_cast<const float*>(input.GetMemoryArea());
+
+ float min = std::numeric_limits<float>::max();
+ float max = std::numeric_limits<float>::lowest();
+
+ for (unsigned int i = 0; i < inputNumElements; i++)
+ {
+ const float inputValue = inputData[i];
+
+ min = std::min(min, inputValue);
+ max = std::max(max, inputValue);
+ }
+
+ SetRange(layer, 0, min, max);
+}
+
} //namespace armnn
diff --git a/src/armnn/StaticRangeVisitor.hpp b/src/armnn/StaticRangeVisitor.hpp
index a7028d7a51..2f80dcb45b 100644
--- a/src/armnn/StaticRangeVisitor.hpp
+++ b/src/armnn/StaticRangeVisitor.hpp
@@ -71,6 +71,10 @@ public:
const SoftmaxDescriptor& softmaxDescriptor,
const char* name = nullptr) override;
+ void VisitConstantLayer(const IConnectableLayer* layer,
+ const ConstTensor& input,
+ const char* name = nullptr) override;
+
private:
/// Set the range for an output slot on a layer
void SetRange(const IConnectableLayer* layer, unsigned int outputIdx, float min, float max);
diff --git a/src/armnn/layers/ConstantLayer.hpp b/src/armnn/layers/ConstantLayer.hpp
index d045952e7e..7a6cf9d10d 100644
--- a/src/armnn/layers/ConstantLayer.hpp
+++ b/src/armnn/layers/ConstantLayer.hpp
@@ -37,11 +37,12 @@ public:
std::vector<TensorShape> InferOutputShapes(const std::vector<TensorShape>& inputShapes) const override;
/// Free up the constant source data stored by the layer.
- void ReleaseConstantData() override {};
+ void ReleaseConstantData() override {}
void Accept(ILayerVisitor& visitor) const override;
std::unique_ptr<ScopedCpuTensorHandle> m_LayerOutput;
+
protected:
/// Constructor to create a ConstantLayer.
/// @param [in] name Optional name for the layer.
@@ -52,7 +53,6 @@ protected:
/// Retrieve the handles to the constant values stored by the layer.
ConstantTensors GetConstantTensorsByRef() override { return {m_LayerOutput}; }
-
};
} // namespace
diff --git a/src/armnn/test/ConstTensorLayerVisitor.hpp b/src/armnn/test/ConstTensorLayerVisitor.hpp
index 513a471465..80409b331f 100644
--- a/src/armnn/test/ConstTensorLayerVisitor.hpp
+++ b/src/armnn/test/ConstTensorLayerVisitor.hpp
@@ -17,12 +17,14 @@ public:
explicit TestConvolution2dLayerVisitor(const Convolution2dDescriptor& convolution2dDescriptor,
const ConstTensor& weights,
const Optional<ConstTensor>& biases,
- const char* name = nullptr) : TestLayerVisitor(name),
- m_Descriptor(convolution2dDescriptor),
- m_Weights(weights),
- m_Biases(biases) {};
+ const char* name = nullptr)
+ : TestLayerVisitor(name)
+ , m_Descriptor(convolution2dDescriptor)
+ , m_Weights(weights)
+ , m_Biases(biases)
+ {}
- virtual ~TestConvolution2dLayerVisitor() {};
+ virtual ~TestConvolution2dLayerVisitor() {}
void VisitConvolution2dLayer(const IConnectableLayer* layer,
const Convolution2dDescriptor& convolution2dDescriptor,
@@ -52,12 +54,14 @@ public:
explicit TestDepthwiseConvolution2dLayerVisitor(const DepthwiseConvolution2dDescriptor& descriptor,
const ConstTensor& weights,
const Optional<ConstTensor>& biases,
- const char* name = nullptr) : TestLayerVisitor(name),
- m_Descriptor(descriptor),
- m_Weights(weights),
- m_Biases(biases) {};
+ const char* name = nullptr)
+ : TestLayerVisitor(name)
+ , m_Descriptor(descriptor)
+ , m_Weights(weights)
+ , m_Biases(biases)
+ {}
- virtual ~TestDepthwiseConvolution2dLayerVisitor() {};
+ virtual ~TestDepthwiseConvolution2dLayerVisitor() {}
void VisitDepthwiseConvolution2dLayer(const IConnectableLayer* layer,
const DepthwiseConvolution2dDescriptor& convolution2dDescriptor,
@@ -87,12 +91,14 @@ public:
explicit TestFullyConnectedLayerVistor(const FullyConnectedDescriptor& descriptor,
const ConstTensor& weights,
const Optional<ConstTensor> biases,
- const char* name = nullptr) : TestLayerVisitor(name),
- m_Descriptor(descriptor),
- m_Weights(weights),
- m_Biases(biases) {};
+ const char* name = nullptr)
+ : TestLayerVisitor(name)
+ , m_Descriptor(descriptor)
+ , m_Weights(weights)
+ , m_Biases(biases)
+ {}
- virtual ~TestFullyConnectedLayerVistor() {};
+ virtual ~TestFullyConnectedLayerVistor() {}
void VisitFullyConnectedLayer(const IConnectableLayer* layer,
const FullyConnectedDescriptor& fullyConnectedDescriptor,
@@ -123,12 +129,15 @@ public:
const ConstTensor& variance,
const ConstTensor& beta,
const ConstTensor& gamma,
- const char* name = nullptr) : TestLayerVisitor(name),
- m_Descriptor(descriptor),
- m_Mean(mean),
- m_Variance(variance),
- m_Beta(beta),
- m_Gamma(gamma) {};
+ const char* name = nullptr)
+ : TestLayerVisitor(name)
+ , m_Descriptor(descriptor)
+ , m_Mean(mean)
+ , m_Variance(variance)
+ , m_Beta(beta)
+ , m_Gamma(gamma)
+ {}
+
void VisitBatchNormalizationLayer(const IConnectableLayer* layer,
const BatchNormalizationDescriptor& descriptor,
const ConstTensor& mean,
@@ -148,6 +157,7 @@ public:
protected:
void CheckDescriptor(const BatchNormalizationDescriptor& descriptor);
+
private:
BatchNormalizationDescriptor m_Descriptor;
ConstTensor m_Mean;
@@ -159,8 +169,11 @@ private:
class TestConstantLayerVisitor : public TestLayerVisitor
{
public:
- explicit TestConstantLayerVisitor(const ConstTensor& input, const char* name = nullptr) :
- TestLayerVisitor(name), m_Input(input) {};
+ explicit TestConstantLayerVisitor(const ConstTensor& input,
+ const char* name = nullptr)
+ : TestLayerVisitor(name)
+ , m_Input(input)
+ {}
void VisitConstantLayer(const IConnectableLayer* layer,
const ConstTensor& input,
@@ -180,8 +193,11 @@ class TestLstmLayerVisitor : public TestLayerVisitor
public:
explicit TestLstmLayerVisitor(const LstmDescriptor& descriptor,
const LstmInputParams& params,
- const char* name = nullptr) :
- TestLayerVisitor(name), m_Descriptor(descriptor), m_InputParams(params) {};
+ const char* name = nullptr)
+ : TestLayerVisitor(name)
+ , m_Descriptor(descriptor)
+ , m_InputParams(params)
+ {}
void VisitLstmLayer(const IConnectableLayer* layer,
const LstmDescriptor& descriptor,
@@ -204,4 +220,4 @@ private:
LstmInputParams m_InputParams;
};
-} // namespace armnn \ No newline at end of file
+} // namespace armnn
diff --git a/src/armnn/test/QuantizerTest.cpp b/src/armnn/test/QuantizerTest.cpp
index 5fcfc5d12e..6820e14f16 100644
--- a/src/armnn/test/QuantizerTest.cpp
+++ b/src/armnn/test/QuantizerTest.cpp
@@ -25,14 +25,17 @@ using MinMaxRange = std::pair<float, float>;
using MinMaxRanges = std::vector<MinMaxRange>;
using MinMaxRangeMap = std::unordered_map<LayerGuid, MinMaxRanges>;
+const float g_QuantizationBase = 255.0f;
+const float g_TestTolerance = 0.000001f;
+
BOOST_AUTO_TEST_SUITE(Quantizer)
class TestQuantization : public LayerVisitorBase<VisitorThrowingPolicy>
{
public:
- virtual void VisitInputLayer(const IConnectableLayer* layer,
- LayerBindingId id,
- const char* name = nullptr)
+ void VisitInputLayer(const IConnectableLayer* layer,
+ LayerBindingId id,
+ const char* name = nullptr) override
{
TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
@@ -41,12 +44,12 @@ public:
BOOST_TEST((info.GetQuantizationOffset() == 128));
// Based off current default [-15.0f, 15.0f]
- BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 30.0f/255.0f, 0.000001f);
+ BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 30.0f / g_QuantizationBase, g_TestTolerance);
}
- virtual void VisitOutputLayer(const IConnectableLayer* layer,
- LayerBindingId id,
- const char* name = nullptr)
+ void VisitOutputLayer(const IConnectableLayer* layer,
+ LayerBindingId id,
+ const char* name = nullptr) override
{}
};
@@ -58,25 +61,25 @@ void VisitLayersTopologically(const INetwork* inputNetwork, ILayerVisitor& visit
VisitLayers(graph, visitor);
}
-BOOST_AUTO_TEST_CASE(QuantizeAddition)
+class TestAdditionQuantization : public TestQuantization
{
- class TestAdditionQuantization : public TestQuantization
+public:
+ void VisitAdditionLayer(const IConnectableLayer* layer,
+ const char* name = nullptr) override
{
- public:
- virtual void VisitAdditionLayer(const IConnectableLayer* layer,
- const char* name = nullptr)
- {
- TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
+ TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
- BOOST_TEST((info.GetDataType() == DataType::QuantisedAsymm8));
+ BOOST_TEST((info.GetDataType() == DataType::QuantisedAsymm8));
- BOOST_TEST((info.GetQuantizationOffset() == 128));
+ BOOST_TEST((info.GetQuantizationOffset() == 128));
- // Based off current static value [-20.0f, 20.0f]
- BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 40.0f/255.0f, 0.000001f);
- }
- };
+ // Based off current static value [-20.0f, 20.0f]
+ BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 40.0f / g_QuantizationBase, g_TestTolerance);
+ }
+};
+BOOST_AUTO_TEST_CASE(QuantizeAddition)
+{
auto network = INetwork::Create();
// Add the layers
@@ -90,7 +93,7 @@ BOOST_AUTO_TEST_CASE(QuantizeAddition)
input1->GetOutputSlot(0).Connect(addition->GetInputSlot(1));
addition->GetOutputSlot(0).Connect(output->GetInputSlot(0));
- //Set TensorInfo
+ // Set TensorInfo
TensorShape shape{1U};
TensorInfo info(shape, DataType::Float32);
input0->GetOutputSlot(0).SetTensorInfo(info);
@@ -105,9 +108,9 @@ BOOST_AUTO_TEST_CASE(QuantizeAddition)
class TestActivationQuantization : public TestQuantization
{
public:
- virtual void VisitActivationLayer(const IConnectableLayer* layer,
- const ActivationDescriptor& descriptor,
- const char* name = nullptr)
+ void VisitActivationLayer(const IConnectableLayer* layer,
+ const ActivationDescriptor& descriptor,
+ const char* name = nullptr) override
{
TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
@@ -116,13 +119,14 @@ public:
BOOST_TEST((info.GetQuantizationOffset() == 0));
// Based off current static value [-20.0f, 20.0f]
- BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 15.0f/255.0f, 0.000001f);
+ BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 15.0f / g_QuantizationBase, g_TestTolerance);
}
};
INetworkPtr CreateNetworkWithActivationLayer(const ActivationDescriptor& descriptor)
{
auto network = INetwork::Create();
+
// Add the layers
IConnectableLayer* input0 = network->AddInputLayer(0);
IConnectableLayer* activation = network->AddActivationLayer(descriptor);
@@ -132,7 +136,7 @@ INetworkPtr CreateNetworkWithActivationLayer(const ActivationDescriptor& descrip
input0->GetOutputSlot(0).Connect(activation->GetInputSlot(0));
activation->GetOutputSlot(0).Connect(output->GetInputSlot(0));
- //Set TensorInfo
+ // Set TensorInfo
TensorShape shape{1U};
TensorInfo info(shape, DataType::Float32);
input0->GetOutputSlot(0).SetTensorInfo(info);
@@ -197,26 +201,26 @@ BOOST_AUTO_TEST_CASE(QuantizeSoftReLuActivation)
VisitLayersTopologically(quantizedNetwork.get(), validator);
}
-BOOST_AUTO_TEST_CASE(QuantizeBoundedReluActivation)
+class TestBoundedReluActivationQuantization : public TestQuantization
{
- class TestBoundedReluActivationQuantization : public TestQuantization
+public:
+ void VisitActivationLayer(const IConnectableLayer* layer,
+ const ActivationDescriptor& descriptor,
+ const char* name = nullptr) override
{
- public:
- virtual void VisitActivationLayer(const IConnectableLayer* layer,
- const ActivationDescriptor& descriptor,
- const char* name = nullptr)
- {
- TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
+ TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
- BOOST_TEST((info.GetDataType() == DataType::QuantisedAsymm8));
+ BOOST_TEST((info.GetDataType() == DataType::QuantisedAsymm8));
- BOOST_TEST((info.GetQuantizationOffset() == 0));
+ BOOST_TEST((info.GetQuantizationOffset() == 0));
- // Based off current static value [0.0f, 3.5f(<-layer upper bound)]
- BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 3.5f/255.0f, 0.000001f);
- }
- };
+ // Based off current static value [0.0f, 3.5f(<-layer upper bound)]
+ BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 3.5f / g_QuantizationBase, g_TestTolerance);
+ }
+};
+BOOST_AUTO_TEST_CASE(QuantizeBoundedReluActivation)
+{
ActivationDescriptor descriptor;
descriptor.m_Function = ActivationFunction::BoundedReLu;
descriptor.m_A = 3.5f;
@@ -229,26 +233,26 @@ BOOST_AUTO_TEST_CASE(QuantizeBoundedReluActivation)
VisitLayersTopologically(quantizedNetwork.get(), validator);
}
-BOOST_AUTO_TEST_CASE(QuantizeTanHActivation)
+class TestTanHActivationQuantization : public TestQuantization
{
- class TestTanHActivationQuantization : public TestQuantization
+public:
+ void VisitActivationLayer(const IConnectableLayer* layer,
+ const ActivationDescriptor& descriptor,
+ const char* name = nullptr) override
{
- public:
- virtual void VisitActivationLayer(const IConnectableLayer* layer,
- const ActivationDescriptor& descriptor,
- const char* name = nullptr)
- {
- TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
+ TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
- BOOST_TEST((info.GetDataType() == DataType::QuantisedAsymm8));
+ BOOST_TEST((info.GetDataType() == DataType::QuantisedAsymm8));
- BOOST_TEST((info.GetQuantizationOffset() == 128));
+ BOOST_TEST((info.GetQuantizationOffset() == 128));
- // Based off current static value [-1.0f, 1.0f]
- BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 2.0f/255.0f, 0.000001f);
- }
- };
+ // Based off current static value [-1.0f, 1.0f]
+ BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 2.0f / g_QuantizationBase, g_TestTolerance);
+ }
+};
+BOOST_AUTO_TEST_CASE(QuantizeTanHActivation)
+{
ActivationDescriptor descriptor;
descriptor.m_Function = ActivationFunction::TanH;
descriptor.m_A = 3.5f;
@@ -264,9 +268,9 @@ BOOST_AUTO_TEST_CASE(QuantizeTanHActivation)
class TestLeakyReLuActivationQuantization : public TestQuantization
{
public:
- virtual void VisitActivationLayer(const IConnectableLayer* layer,
- const ActivationDescriptor& descriptor,
- const char* name = nullptr)
+ void VisitActivationLayer(const IConnectableLayer* layer,
+ const ActivationDescriptor& descriptor,
+ const char* name = nullptr) override
{
TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
@@ -275,7 +279,7 @@ public:
BOOST_TEST((info.GetQuantizationOffset() == 64));
// Based off current static value [-5.0f, 15.0f]
- BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 20.0f/255.0f, 0.000001f);
+ BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 20.0f / g_QuantizationBase, g_TestTolerance);
}
protected:
// used by the descendant classes which test layers
@@ -307,54 +311,44 @@ BOOST_AUTO_TEST_CASE(QuantizeLeakyReLuActivation)
VisitLayersTopologically(quantizedNetwork.get(), validator);
}
-BOOST_AUTO_TEST_CASE(QuantizeBatchNorm)
+class TestBatchNormalizationQuantization : public TestQuantization
{
-
- class TestQuantization : public LayerVisitorBase<VisitorThrowingPolicy>
+public:
+ void VisitBatchNormalizationLayer(const IConnectableLayer* layer,
+ const BatchNormalizationDescriptor& desc,
+ const ConstTensor& mean,
+ const ConstTensor& variance,
+ const ConstTensor& beta,
+ const ConstTensor& gamma,
+ const char* name = nullptr) override
{
- public:
- virtual void VisitBatchNormalizationLayer(const IConnectableLayer* layer,
- const BatchNormalizationDescriptor& desc,
- const ConstTensor& mean,
- const ConstTensor& variance,
- const ConstTensor& beta,
- const ConstTensor& gamma,
- const char* name = nullptr)
- {
- TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
-
- BOOST_TEST((info.GetDataType() == DataType::QuantisedAsymm8));
-
- BOOST_TEST((info.GetQuantizationOffset() == 128));
+ TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
- // Based off current static value [-15.0f, 15.0f]
- BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 30.0f/255.0f, 0.000001f);
+ BOOST_TEST((info.GetDataType() == DataType::QuantisedAsymm8));
- //Test constants
- BOOST_TEST((mean.GetInfo().GetDataType() == DataType::QuantisedAsymm8));
- BOOST_TEST((variance.GetInfo().GetDataType() == DataType::QuantisedAsymm8));
- BOOST_TEST((beta.GetInfo().GetDataType() == DataType::QuantisedAsymm8));
- BOOST_TEST((gamma.GetInfo().GetDataType() == DataType::QuantisedAsymm8));
+ BOOST_TEST((info.GetQuantizationOffset() == 128));
- BOOST_CHECK_CLOSE(mean.GetInfo().GetQuantizationScale(), 3.0f/255.0f, 0.000001f);
- BOOST_CHECK_CLOSE(variance.GetInfo().GetQuantizationScale(), 3.0f/255.0f, 0.000001f);
- BOOST_CHECK_CLOSE(beta.GetInfo().GetQuantizationScale(), 3.0f/255.0f, 0.000001f);
- BOOST_CHECK_CLOSE(gamma.GetInfo().GetQuantizationScale(), 3.0f/255.0f, 0.000001f);
+ // Based off current static value [-15.0f, 15.0f]
+ BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 30.0f / g_QuantizationBase, g_TestTolerance);
- BOOST_TEST((mean.GetInfo().GetQuantizationOffset() == 85));
- }
+ // Test constants
+ BOOST_TEST((mean.GetInfo().GetDataType() == DataType::QuantisedAsymm8));
+ BOOST_TEST((variance.GetInfo().GetDataType() == DataType::QuantisedAsymm8));
+ BOOST_TEST((beta.GetInfo().GetDataType() == DataType::QuantisedAsymm8));
+ BOOST_TEST((gamma.GetInfo().GetDataType() == DataType::QuantisedAsymm8));
- virtual void VisitInputLayer(const IConnectableLayer* layer,
- LayerBindingId id,
- const char* name = nullptr)
- {}
+ float expectedQuantizationScale = 3.0f / g_QuantizationBase;
+ BOOST_CHECK_CLOSE(mean.GetInfo().GetQuantizationScale(), expectedQuantizationScale, g_TestTolerance);
+ BOOST_CHECK_CLOSE(variance.GetInfo().GetQuantizationScale(), expectedQuantizationScale, g_TestTolerance);
+ BOOST_CHECK_CLOSE(beta.GetInfo().GetQuantizationScale(), expectedQuantizationScale, g_TestTolerance);
+ BOOST_CHECK_CLOSE(gamma.GetInfo().GetQuantizationScale(), expectedQuantizationScale, g_TestTolerance);
- virtual void VisitOutputLayer(const IConnectableLayer* layer,
- LayerBindingId id,
- const char* name = nullptr)
- {}
- };
+ BOOST_TEST((mean.GetInfo().GetQuantizationOffset() == 85));
+ }
+};
+BOOST_AUTO_TEST_CASE(QuantizeBatchNorm)
+{
auto network = INetwork::Create();
TensorShape shape{3U};
@@ -381,12 +375,12 @@ BOOST_AUTO_TEST_CASE(QuantizeBatchNorm)
input0->GetOutputSlot(0).Connect(batchNorm->GetInputSlot(0));
batchNorm->GetOutputSlot(0).Connect(output->GetInputSlot(0));
- //Set TensorInfo
+ // Set TensorInfo
input0->GetOutputSlot(0).SetTensorInfo(info);
batchNorm->GetOutputSlot(0).SetTensorInfo(info);
auto quantizedNetwork = INetworkQuantizer::Create(network.get())->ExportNetwork();
- TestQuantization validator;
+ TestBatchNormalizationQuantization validator;
VisitLayersTopologically(quantizedNetwork.get(), validator);
}
@@ -501,7 +495,7 @@ INetworkPtr CreateNetworkWithFullyConnectedLayer(const bool biasEnabled)
input0->GetOutputSlot(0).Connect(fullyConnected->GetInputSlot(0));
fullyConnected->GetOutputSlot(0).Connect(output->GetInputSlot(0));
- //Set TensorInfo
+ // Set TensorInfo
input0->GetOutputSlot(0).SetTensorInfo(info);
fullyConnected->GetOutputSlot(0).SetTensorInfo(info);
@@ -524,18 +518,20 @@ public:
BOOST_TEST((info.GetQuantizationOffset() == 128));
// Based off current static value [-15.0f, 15.0f]
- BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 30.0f/255.0f, 0.000001f );
+ BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 30.0f / g_QuantizationBase, g_TestTolerance );
- //Test weights
+ // Test weights
BOOST_TEST((weights.GetInfo().GetDataType() == DataType::QuantisedAsymm8));
- BOOST_CHECK_CLOSE(weights.GetInfo().GetQuantizationScale(), 3.0f/255.0f, 0.000001f);
+ BOOST_CHECK_CLOSE(weights.GetInfo().GetQuantizationScale(), 3.0f / g_QuantizationBase, g_TestTolerance);
BOOST_TEST((weights.GetInfo().GetQuantizationOffset() == 85));
// Test biases
if (biases.has_value())
{
BOOST_TEST((biases.value().GetInfo().GetDataType() == DataType::QuantisedAsymm8));
- BOOST_CHECK_CLOSE(biases.value().GetInfo().GetQuantizationScale(), 30.0f/255.0f, 0.000001f);
+ BOOST_CHECK_CLOSE(biases.value().GetInfo().GetQuantizationScale(),
+ 30.0f / g_QuantizationBase,
+ g_TestTolerance);
}
}
};
@@ -561,23 +557,23 @@ BOOST_AUTO_TEST_CASE(QuantizeFullyConnectedBiasEnabled)
class TestConv2dQuantization : public TestQuantization
{
public:
- virtual void VisitConvolution2dLayer(const IConnectableLayer *layer,
- const Convolution2dDescriptor& convolution2dDescriptor,
- const ConstTensor& weights,
- const Optional<ConstTensor>& biases,
- const char *name = nullptr)
+ void VisitConvolution2dLayer(const IConnectableLayer *layer,
+ const Convolution2dDescriptor& convolution2dDescriptor,
+ const ConstTensor& weights,
+ const Optional<ConstTensor>& biases,
+ const char *name = nullptr) override
{
TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
BOOST_TEST((info.GetDataType() == DataType::QuantisedAsymm8));
BOOST_TEST((info.GetQuantizationOffset() == 128));
// Based off current static value [-15.0f, 15.0f]
- BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 30.0f / 255.0f, 0.000001f);
+ BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 30.0f / g_QuantizationBase, g_TestTolerance);
// Test weights
// Instantiate expected values
- const float quantizationScale = 3.0f / 255.0f;
- const float tolerance = 3.0f / 255.0f;
+ const float quantizationScale = 3.0f / g_QuantizationBase;
+ const float tolerance = 3.0f / g_QuantizationBase;
const int quantizationOffset = 85;
BOOST_TEST((weights.GetInfo().GetDataType() == DataType::QuantisedAsymm8));
BOOST_CHECK_CLOSE(weights.GetInfo().GetQuantizationScale(), quantizationScale, tolerance);
@@ -625,7 +621,7 @@ void TestQuantizeConvolution2d(bool useBiases)
input0->GetOutputSlot(0).Connect(conv2d->GetInputSlot(0));
conv2d->GetOutputSlot(0).Connect(output->GetInputSlot(0));
- //Set TensorInfo
+ // Set TensorInfo
input0->GetOutputSlot(0).SetTensorInfo(info);
conv2d->GetOutputSlot(0).SetTensorInfo(info);
@@ -647,23 +643,23 @@ BOOST_AUTO_TEST_CASE(QuantizeConvolution2dWithBiases)
class TestDepthwiseConv2dQuantization : public TestQuantization
{
public:
- virtual void VisitDepthwiseConvolution2dLayer(const IConnectableLayer *layer,
- const DepthwiseConvolution2dDescriptor& desc,
- const ConstTensor& weights,
- const Optional<ConstTensor>& biases,
- const char *name = nullptr)
+ void VisitDepthwiseConvolution2dLayer(const IConnectableLayer *layer,
+ const DepthwiseConvolution2dDescriptor& desc,
+ const ConstTensor& weights,
+ const Optional<ConstTensor>& biases,
+ const char *name = nullptr) override
{
TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
BOOST_TEST((info.GetDataType() == DataType::QuantisedAsymm8));
BOOST_TEST((info.GetQuantizationOffset() == 128));
// Based off current static value [-15.0f, 15.0f]
- BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 30.0f / 255.0f, 0.000001f);
+ BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 30.0f / g_QuantizationBase, g_TestTolerance);
// Test weights
// Instantiate expected values
- const float quantizationScale = 3.0f / 255.0f;
- const float tolerance = 3.0f / 255.0f;
+ const float quantizationScale = 3.0f / g_QuantizationBase;
+ const float tolerance = 3.0f / g_QuantizationBase;
const int quantizationOffset = 85;
BOOST_TEST((weights.GetInfo().GetDataType() == DataType::QuantisedAsymm8));
BOOST_CHECK_CLOSE(weights.GetInfo().GetQuantizationScale(), quantizationScale, tolerance);
@@ -733,9 +729,9 @@ BOOST_AUTO_TEST_CASE(QuantizeDepthwiseConvolution2dWithBiases)
class TestSoftmaxQuantization : public TestQuantization
{
public:
- virtual void VisitSoftmaxLayer(const IConnectableLayer* layer,
- const SoftmaxDescriptor& descriptor,
- const char* name = nullptr)
+ void VisitSoftmaxLayer(const IConnectableLayer* layer,
+ const SoftmaxDescriptor& descriptor,
+ const char* name = nullptr) override
{
TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
@@ -743,13 +739,14 @@ public:
BOOST_TEST((info.GetQuantizationOffset() == 0));
- BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 1.0f/255.0f, 0.000001f );
+ BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 1.0f / g_QuantizationBase, g_TestTolerance );
}
};
INetworkPtr CreateNetworkWithSoftmaxLayer(const SoftmaxDescriptor& descriptor)
{
auto network = INetwork::Create();
+
// Add the layers
IConnectableLayer* input0 = network->AddInputLayer(0);
IConnectableLayer* softmax = network->AddSoftmaxLayer(descriptor);
@@ -759,7 +756,7 @@ INetworkPtr CreateNetworkWithSoftmaxLayer(const SoftmaxDescriptor& descriptor)
input0->GetOutputSlot(0).Connect(softmax->GetInputSlot(0));
softmax->GetOutputSlot(0).Connect(output->GetInputSlot(0));
- //Set TensorInfo
+ // Set TensorInfo
TensorShape shape{1U};
TensorInfo info(shape, DataType::Float32);
input0->GetOutputSlot(0).SetTensorInfo(info);
@@ -822,9 +819,9 @@ BOOST_AUTO_TEST_CASE(QuantizePermute)
class TestPermuteQuantization : public TestLeakyReLuActivationQuantization
{
public:
- virtual void VisitPermuteLayer(const IConnectableLayer* layer,
- const PermuteDescriptor& desc,
- const char* name = nullptr)
+ void VisitPermuteLayer(const IConnectableLayer* layer,
+ const PermuteDescriptor& desc,
+ const char* name = nullptr) override
{
CheckForwardedQuantizationSettings(layer);
}
@@ -853,9 +850,9 @@ BOOST_AUTO_TEST_CASE(QuantizeSpaceToBatch)
class TestSpaceToBatchQuantization : public TestLeakyReLuActivationQuantization
{
public:
- virtual void VisitSpaceToBatchNdLayer(const IConnectableLayer* layer,
- const SpaceToBatchNdDescriptor& spaceToBatchNdDescriptor,
- const char* name = nullptr) override
+ void VisitSpaceToBatchNdLayer(const IConnectableLayer* layer,
+ const SpaceToBatchNdDescriptor& spaceToBatchNdDescriptor,
+ const char* name = nullptr) override
{
CheckForwardedQuantizationSettings(layer);
}
@@ -882,9 +879,9 @@ BOOST_AUTO_TEST_CASE(QuantizeSpaceToBatch)
class TestPooling2dQuantization : public TestLeakyReLuActivationQuantization
{
public:
- virtual void VisitPooling2dLayer(const IConnectableLayer* layer,
- const Pooling2dDescriptor& desc,
- const char* name = nullptr)
+ void VisitPooling2dLayer(const IConnectableLayer* layer,
+ const Pooling2dDescriptor& desc,
+ const char* name = nullptr) override
{
TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
@@ -893,7 +890,7 @@ public:
BOOST_TEST((info.GetQuantizationOffset() == 64));
// Based off parent LeakyReLu [-5.f, 15.f]
- BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 20.0f/255.0f, 0.000001f);
+ BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 20.0f / g_QuantizationBase, g_TestTolerance);
}
};
@@ -931,5 +928,54 @@ BOOST_AUTO_TEST_CASE(QuantizePooling2d)
VisitLayersTopologically(quantizedNetwork.get(), validator);
}
+class TestConstantQuantization : public TestAdditionQuantization
+{
+public:
+ void VisitConstantLayer(const IConnectableLayer* layer,
+ const ConstTensor& input,
+ const char* name = nullptr) override
+ {
+ BOOST_CHECK(std::string(name) == "ConstantLayer");
+
+ TensorInfo info = layer->GetOutputSlot(0).GetTensorInfo();
+ BOOST_CHECK(info.GetDataType() == DataType::QuantisedAsymm8);
+ BOOST_CHECK(info.GetQuantizationOffset() == 64);
+
+ // Based off the range of values in the const tensor used for the test: [-2.0f, 6.0f]
+ BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 8.0f / g_QuantizationBase, g_TestTolerance);
+ }
+};
+
+BOOST_AUTO_TEST_CASE(QuantizeConstant)
+{
+ auto network = INetwork::Create();
+
+ // Constant layer data
+ const char* name = "ConstantLayer";
+ std::vector<float> data = {-2.0f, -1.0f, 0.0f, 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 6.0f};
+ std::vector<unsigned int> dimensions = {1, 1, 3, 3};
+ TensorInfo tensorInfo(4, dimensions.data(), DataType::Float32);
+ ConstTensor constantTensor(tensorInfo, data);
+
+ // Add the layers
+ IConnectableLayer* input = network->AddInputLayer(0);
+ IConnectableLayer* constant = network->AddConstantLayer(constantTensor, name);
+ IConnectableLayer* addition = network->AddAdditionLayer();
+ IConnectableLayer* output = network->AddOutputLayer(1);
+
+ // Establish connections
+ input->GetOutputSlot(0).Connect(addition->GetInputSlot(0));
+ constant->GetOutputSlot(0).Connect(addition->GetInputSlot(1));
+ addition->GetOutputSlot(0).Connect(output->GetInputSlot(0));
+
+ // Set TensorInfo in the remaining layers
+ input->GetOutputSlot(0).SetTensorInfo(tensorInfo);
+ addition->GetOutputSlot(0).SetTensorInfo(tensorInfo);
+
+ auto quantizedNetwork = INetworkQuantizer::Create(network.get())->ExportNetwork();
+ TestConstantQuantization validator;
+ VisitLayersTopologically(quantizedNetwork.get(), validator);
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace armnn
diff --git a/src/armnn/test/TestLayerVisitor.cpp b/src/armnn/test/TestLayerVisitor.cpp
index 4c028b3709..ba30dbc666 100644
--- a/src/armnn/test/TestLayerVisitor.cpp
+++ b/src/armnn/test/TestLayerVisitor.cpp
@@ -23,7 +23,7 @@ void TestLayerVisitor::CheckLayerName(const char* name)
{
BOOST_CHECK_EQUAL(m_LayerName, name);
}
-};
+}
void TestLayerVisitor::CheckLayerPointer(const IConnectableLayer* layer)
{