aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrancisMurtagh <francis.murtagh@arm.com>2019-02-11 11:06:33 +0000
committerFrancisMurtagh <francis.murtagh@arm.com>2019-02-11 11:06:33 +0000
commite604cde16fc16dc5fea9fc2c1c38ac8e8e2c4a59 (patch)
tree053d14bd78ab4a5dd1502dedaeef04f5e429eb3c
parent43a799ca3ab5ffb60a381172dba2536ebb87708a (diff)
downloadarmnn-e604cde16fc16dc5fea9fc2c1c38ac8e8e2c4a59.tar.gz
IVGCVSW-2624 Support static quantization of FullyConnected
Change-Id: Ib18085e7e4b2e9d55e29b14122410732e3bdd088 Signed-off-by: FrancisMurtagh <francis.murtagh@arm.com>
-rw-r--r--src/armnn/QuantizerVisitor.cpp32
-rw-r--r--src/armnn/QuantizerVisitor.hpp13
-rw-r--r--src/armnn/StaticRangeVisitor.cpp24
-rw-r--r--src/armnn/StaticRangeVisitor.hpp9
-rw-r--r--src/armnn/test/QuantizerTest.cpp107
5 files changed, 182 insertions, 3 deletions
diff --git a/src/armnn/QuantizerVisitor.cpp b/src/armnn/QuantizerVisitor.cpp
index b5085be0a2..97a8bc1ad2 100644
--- a/src/armnn/QuantizerVisitor.cpp
+++ b/src/armnn/QuantizerVisitor.cpp
@@ -79,7 +79,37 @@ void QuantizerVisitor::VisitActivationLayer(const IConnectableLayer* layer,
SetQuantizedInputConnections(layer, newLayer);
}
-void QuantizerVisitor::VisitInputLayer(const IConnectableLayer* layer, LayerBindingId id, const char* name)
+void QuantizerVisitor::VisitFullyConnectedLayer(const IConnectableLayer *layer,
+ const FullyConnectedDescriptor& desc,
+ const ConstTensor& weights,
+ const char *name)
+{
+ std::vector<uint8_t> weightsBacking;
+ ConstTensor qWeights = CreateQuantizedConst(weights, weightsBacking);
+
+ IConnectableLayer* newLayer = m_QuantizedNetwork->AddFullyConnectedLayer(desc, qWeights, name);
+ RecordLayer(layer, newLayer);
+ SetQuantizedInputConnections(layer, newLayer);
+}
+
+void QuantizerVisitor::VisitFullyConnectedLayer(const IConnectableLayer *layer,
+ const FullyConnectedDescriptor& desc,
+ const ConstTensor& weights,
+ const ConstTensor& bias,
+ const char *name)
+{
+ std::vector<uint8_t> weightsBacking;
+ ConstTensor qWeights = CreateQuantizedConst(weights, weightsBacking);
+
+ std::vector<uint8_t> biasBacking;
+ ConstTensor qBias = CreateQuantizedConst(bias, biasBacking);
+
+ IConnectableLayer* newLayer = m_QuantizedNetwork->AddFullyConnectedLayer(desc, qWeights, qBias, name);
+ RecordLayer(layer, newLayer);
+ SetQuantizedInputConnections(layer, newLayer);
+}
+
+void QuantizerVisitor::VisitInputLayer(const IConnectableLayer *layer, LayerBindingId id, const char *name)
{
IConnectableLayer* newLayer = m_QuantizedNetwork->AddInputLayer(id, name);
RecordLayer(layer, newLayer);
diff --git a/src/armnn/QuantizerVisitor.hpp b/src/armnn/QuantizerVisitor.hpp
index dcaccd4ac7..53b3edc3fd 100644
--- a/src/armnn/QuantizerVisitor.hpp
+++ b/src/armnn/QuantizerVisitor.hpp
@@ -41,8 +41,17 @@ public:
const ConstTensor& beta,
const ConstTensor& gamma,
const char* name = nullptr) override;
-
- /// Extract the quantized network
+ void VisitFullyConnectedLayer(const IConnectableLayer *layer,
+ const FullyConnectedDescriptor&,
+ const ConstTensor&,
+ const char *name = nullptr) override;
+ void VisitFullyConnectedLayer(const IConnectableLayer *layer,
+ const FullyConnectedDescriptor&,
+ const ConstTensor&,
+ const ConstTensor&,
+ const char *name = nullptr) override;
+
+ // Extract the quantized network
INetworkPtr RetrieveFinalNetwork() { return std::move(m_QuantizedNetwork); }
private:
diff --git a/src/armnn/StaticRangeVisitor.cpp b/src/armnn/StaticRangeVisitor.cpp
index 258d499279..eac434eecb 100644
--- a/src/armnn/StaticRangeVisitor.cpp
+++ b/src/armnn/StaticRangeVisitor.cpp
@@ -87,4 +87,28 @@ void StaticRangeVisitor::VisitActivationLayer(const IConnectableLayer* layer,
}
}
+void StaticRangeVisitor::VisitFullyConnectedLayer(const armnn::IConnectableLayer *layer,
+ const armnn::FullyConnectedDescriptor& desc,
+ const ConstTensor& weights,
+ const char *name)
+{
+ boost::ignore_unused(desc);
+ boost::ignore_unused(weights);
+ boost::ignore_unused(name);
+ SetRange(layer, 0, -15.0f, 15.0f);
+}
+
+void StaticRangeVisitor::VisitFullyConnectedLayer(const armnn::IConnectableLayer *layer,
+ const armnn::FullyConnectedDescriptor& desc,
+ const ConstTensor& weights,
+ const ConstTensor& bias,
+ const char *name)
+{
+ boost::ignore_unused(desc);
+ boost::ignore_unused(weights);
+ boost::ignore_unused(bias);
+ boost::ignore_unused(name);
+ SetRange(layer, 0, -15.0f, 15.0f);
+}
+
} //namespace armnn
diff --git a/src/armnn/StaticRangeVisitor.hpp b/src/armnn/StaticRangeVisitor.hpp
index ea27947e7a..94a6ea0e50 100644
--- a/src/armnn/StaticRangeVisitor.hpp
+++ b/src/armnn/StaticRangeVisitor.hpp
@@ -38,6 +38,15 @@ public:
void VisitActivationLayer(const IConnectableLayer* layer,
const ActivationDescriptor& activationDescriptor,
const char* name = nullptr) override;
+ void VisitFullyConnectedLayer(const armnn::IConnectableLayer *layer,
+ const armnn::FullyConnectedDescriptor& desc,
+ const ConstTensor& weights,
+ const char *name) override;
+ void VisitFullyConnectedLayer(const armnn::IConnectableLayer *layer,
+ const armnn::FullyConnectedDescriptor& desc,
+ const ConstTensor& weights,
+ const ConstTensor& bias,
+ const char *name) override;
/// Retrieve the default range
MinMaxRange DefaultRange() const { return std::make_pair(-15.0f, 15.0f); }
diff --git a/src/armnn/test/QuantizerTest.cpp b/src/armnn/test/QuantizerTest.cpp
index ba10fd8b79..dd90368524 100644
--- a/src/armnn/test/QuantizerTest.cpp
+++ b/src/armnn/test/QuantizerTest.cpp
@@ -459,5 +459,112 @@ BOOST_AUTO_TEST_CASE(OverrideInputRangeInputLayers)
BOOST_CHECK(guidToRangesMap[input1->GetGuid()].at(0).second == minMaxRange.second);
}
+INetworkPtr CreateNetworkWithFullyConnectedLayer(const bool biasEnabled)
+{
+ FullyConnectedDescriptor desc;
+ desc.m_BiasEnabled = biasEnabled;
+ auto network = INetwork::Create();
+
+ TensorShape shape{3U};
+ TensorInfo info(shape, DataType::Float32);
+
+ std::vector<float> weightsData{-1.0f, 1.5f, 2.0f};
+ ConstTensor weights(info, weightsData);
+
+ // Add the layers
+ IConnectableLayer* input0 = network->AddInputLayer(0);
+ IConnectableLayer* fullyConnected;
+ if (desc.m_BiasEnabled)
+ {
+ std::vector<float> biasData{10.0f, 20.0f, 30.0f};
+ ConstTensor bias(info, biasData);
+ fullyConnected = network->AddFullyConnectedLayer(desc, weights, bias);
+ }
+ else
+ {
+ fullyConnected = network->AddFullyConnectedLayer(desc, weights);
+ }
+ IConnectableLayer* output = network->AddOutputLayer(1);
+
+ // Establish connections
+ input0->GetOutputSlot(0).Connect(fullyConnected->GetInputSlot(0));
+ fullyConnected->GetOutputSlot(0).Connect(output->GetInputSlot(0));
+
+ //Set TensorInfo
+ input0->GetOutputSlot(0).SetTensorInfo(info);
+ fullyConnected->GetOutputSlot(0).SetTensorInfo(info);
+
+ return network;
+}
+
+class TestFullyConnectedQuantization : public TestQuantization
+{
+public:
+ virtual void VisitFullyConnectedLayer(const IConnectableLayer* layer,
+ const FullyConnectedDescriptor& desc,
+ const ConstTensor& weights,
+ const char* name = nullptr)
+ {
+ 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 );
+
+ //Test constants
+ BOOST_TEST((weights.GetInfo().GetDataType() == DataType::QuantisedAsymm8));
+
+ BOOST_CHECK_CLOSE(weights.GetInfo().GetQuantizationScale(), 3.0f/255.0f, 0.000001f);
+
+ BOOST_TEST((weights.GetInfo().GetQuantizationOffset() == 85));
+ }
+
+ virtual void VisitFullyConnectedLayer(const IConnectableLayer* layer,
+ const FullyConnectedDescriptor& desc,
+ const ConstTensor& weights,
+ const ConstTensor& bias,
+ const char* name = nullptr)
+ {
+ 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 );
+
+ //Test constants
+ BOOST_TEST((weights.GetInfo().GetDataType() == DataType::QuantisedAsymm8));
+ BOOST_TEST((bias.GetInfo().GetDataType() == DataType::QuantisedAsymm8));
+
+ BOOST_CHECK_CLOSE(weights.GetInfo().GetQuantizationScale(), 3.0f/255.0f, 0.000001f);
+ BOOST_CHECK_CLOSE(bias.GetInfo().GetQuantizationScale(), 30.0f/255.0f, 0.000001f);
+
+ BOOST_TEST((weights.GetInfo().GetQuantizationOffset() == 85));
+ }
+};
+
+void ValidateFullyConnectedLayer(const bool biasEnabled)
+{
+ auto network = CreateNetworkWithFullyConnectedLayer(biasEnabled);
+ auto quantizedNetwork = INetworkQuantizer::Create(network.get())->ExportNetwork();
+ TestFullyConnectedQuantization validator;
+ VisitLayersTopologically(quantizedNetwork.get(), validator);
+}
+
+BOOST_AUTO_TEST_CASE(QuantizeFullyConnected)
+{
+ ValidateFullyConnectedLayer(false);
+}
+
+BOOST_AUTO_TEST_CASE(QuantizeFullyConnectedBiasEnabled)
+{
+ ValidateFullyConnectedLayer(true);
+}
+
BOOST_AUTO_TEST_SUITE_END()
} // namespace armnn