aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDerek Lamberti <derek.lamberti@arm.com>2019-02-07 11:14:11 +0000
committerDerek Lamberti <derek.lamberti@arm.com>2019-02-07 13:21:28 +0000
commit857aa45407df9dbe99a11d03a4be2b20bd0110ae (patch)
tree3e47a2aa1ac8787a00900eff0ba49246ef9a4bdc
parent49dbe0e9f6747583cff29ada68d6670796d4216c (diff)
downloadarmnn-857aa45407df9dbe99a11d03a4be2b20bd0110ae.tar.gz
IVGCVSW-2609 Quantize BatchNormalizationLayer
Change-Id: I7b847112a0322ffc8b88a0708d8439bfb97cfe2c Signed-off-by: Derek Lamberti <derek.lamberti@arm.com>
-rw-r--r--src/armnn/QuantizerVisitor.cpp83
-rw-r--r--src/armnn/QuantizerVisitor.hpp7
-rw-r--r--src/armnn/StaticRangeVisitor.cpp18
-rw-r--r--src/armnn/StaticRangeVisitor.hpp7
-rw-r--r--src/armnn/layers/BatchNormalizationLayer.cpp8
-rw-r--r--src/armnn/test/QuantizerTest.cpp83
6 files changed, 202 insertions, 4 deletions
diff --git a/src/armnn/QuantizerVisitor.cpp b/src/armnn/QuantizerVisitor.cpp
index fd08b2d2e5..afe3713036 100644
--- a/src/armnn/QuantizerVisitor.cpp
+++ b/src/armnn/QuantizerVisitor.cpp
@@ -7,6 +7,8 @@
#include "QuantizerVisitor.hpp"
#include "StaticRangeVisitor.hpp"
+#include "armnn/TypesUtils.hpp"
+
#include <cmath>
#include <stdint.h>
#include <limits>
@@ -34,6 +36,56 @@ std::pair<int, float> ComputeQAsymmParams(int numBits, double min, double max)
return std::make_pair(static_cast<int>(std::round(offset)), static_cast<float>(scale));
}
+template<typename srcType>
+void Quantize(const srcType* src, uint8_t* dst, size_t numElements, float &scale, int &offset)
+{
+ BOOST_ASSERT(src);
+ BOOST_ASSERT(dst);
+
+ float min = std::numeric_limits<srcType>::max();
+ float max = std::numeric_limits<srcType>::lowest();
+ for (size_t i = 0; i < numElements; ++i)
+ {
+ min = std::min(min, src[i]);
+ max = std::max(max, src[i]);
+ }
+
+ auto qParams = ComputeQAsymmParams(8, min, max);
+ offset = qParams.first;
+ scale = qParams.second;
+ for (size_t i = 0; i < numElements; ++i)
+ {
+ dst[i] = armnn::Quantize<uint8_t>(src[i], scale, offset);
+ }
+}
+
+ConstTensor CreateQuantizedConst(const ConstTensor& tensor, std::vector<uint8_t> &backing)
+{
+ float scale = 0.0f;
+ int offset = 0;
+ // Reserve the backing memory
+ backing.resize(tensor.GetInfo().GetNumElements());
+
+ DataType type = tensor.GetInfo().GetDataType();
+ switch(type)
+ {
+ case DataType::Float32:
+ {
+ Quantize(static_cast<const float*>( tensor.GetMemoryArea()),
+ backing.data(),
+ backing.size(),
+ scale,
+ offset);
+ }
+ break;
+ default:
+ BOOST_ASSERT_MSG(false, "Can't quantize unsupported data type");
+ }
+
+ TensorInfo qInfo(tensor.GetInfo().GetShape(), DataType::QuantisedAsymm8, scale, offset);
+ return ConstTensor(qInfo, backing);
+}
+
} // namespace
QuantizerVisitor::QuantizerVisitor(armnn::StaticRangeVisitor* ranges)
@@ -108,4 +160,35 @@ void QuantizerVisitor::VisitOutputLayer(const IConnectableLayer *layer, LayerBin
SetQuantizedInputConnections(layer, newLayer);
}
+void QuantizerVisitor::VisitBatchNormalizationLayer(const IConnectableLayer *layer,
+ const BatchNormalizationDescriptor& desc,
+ const ConstTensor& mean,
+ const ConstTensor& variance,
+ const ConstTensor& beta,
+ const ConstTensor& gamma,
+ const char *name)
+{
+ std::vector<uint8_t> meanBacking;
+ ConstTensor qMean = CreateQuantizedConst(mean, meanBacking);
+
+ std::vector<uint8_t> varianceBacking;
+ ConstTensor qVariance = CreateQuantizedConst(variance, varianceBacking);
+
+ std::vector<uint8_t> betaBacking;
+ ConstTensor qBeta = CreateQuantizedConst(beta, betaBacking);
+
+ std::vector<uint8_t> gammaBacking;
+ ConstTensor qGamma = CreateQuantizedConst(variance, gammaBacking);
+
+ IConnectableLayer* newLayer = m_QuantizedNetwork->AddBatchNormalizationLayer(desc,
+ qMean,
+ qVariance,
+ qBeta,
+ qGamma,
+ name);
+
+ RecordLayer(layer, newLayer);
+ SetQuantizedInputConnections(layer, newLayer);
+}
+
} //namespace armnn \ No newline at end of file
diff --git a/src/armnn/QuantizerVisitor.hpp b/src/armnn/QuantizerVisitor.hpp
index 5ff457ec33..d6aee6babf 100644
--- a/src/armnn/QuantizerVisitor.hpp
+++ b/src/armnn/QuantizerVisitor.hpp
@@ -28,6 +28,13 @@ public:
void VisitInputLayer(const IConnectableLayer *layer, LayerBindingId id, const char *name = nullptr) override;
void VisitAdditionLayer(const IConnectableLayer *layer, const char *name = nullptr) override;
void VisitOutputLayer(const IConnectableLayer *layer, LayerBindingId id, const char *name = nullptr) override;
+ 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;
// Extract the quantized network
INetworkPtr RetrieveFinalNetwork() { return std::move(m_QuantizedNetwork); }
diff --git a/src/armnn/StaticRangeVisitor.cpp b/src/armnn/StaticRangeVisitor.cpp
index 8e90ba8b51..cc8c26e778 100644
--- a/src/armnn/StaticRangeVisitor.cpp
+++ b/src/armnn/StaticRangeVisitor.cpp
@@ -5,6 +5,7 @@
#include "StaticRangeVisitor.hpp"
+#include <boost/core/ignore_unused.hpp>
namespace armnn
{
@@ -35,4 +36,21 @@ void StaticRangeVisitor::VisitAdditionLayer(const IConnectableLayer *layer, cons
SetRange(layer, 0, -20.f, 20.f);
};
+void StaticRangeVisitor::VisitBatchNormalizationLayer(const IConnectableLayer* layer,
+ const BatchNormalizationDescriptor& desc,
+ const ConstTensor& mean,
+ const ConstTensor& variance,
+ const ConstTensor& beta,
+ const ConstTensor& gamma,
+ const char* name)
+{
+ boost::ignore_unused(desc);
+ boost::ignore_unused(mean);
+ boost::ignore_unused(variance);
+ boost::ignore_unused(beta);
+ boost::ignore_unused(gamma);
+ boost::ignore_unused(name);
+ SetRange(layer, 0, -15.0f, 15.0f);
+}
+
} //namespace armnn \ No newline at end of file
diff --git a/src/armnn/StaticRangeVisitor.hpp b/src/armnn/StaticRangeVisitor.hpp
index af59dace9e..4276a178f3 100644
--- a/src/armnn/StaticRangeVisitor.hpp
+++ b/src/armnn/StaticRangeVisitor.hpp
@@ -27,6 +27,13 @@ public:
/// Functions to set the Range on a per-layer-type basis
void VisitAdditionLayer(const IConnectableLayer *layer, const char *name = nullptr) override;
+ 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;
/// Retreive the default range
MinMaxRange DefaultRange() const { return std::make_pair(-15.0f, 15.0f); }
diff --git a/src/armnn/layers/BatchNormalizationLayer.cpp b/src/armnn/layers/BatchNormalizationLayer.cpp
index 85132053fb..2212f47d3c 100644
--- a/src/armnn/layers/BatchNormalizationLayer.cpp
+++ b/src/armnn/layers/BatchNormalizationLayer.cpp
@@ -71,10 +71,10 @@ Layer::ConstantTensors BatchNormalizationLayer::GetConstantTensorsByRef()
void BatchNormalizationLayer::Accept(ILayerVisitor& visitor) const
{
- ConstTensor meanTensor(m_Mean->GetTensorInfo(), m_Mean->GetTensor<void*>()) ;
- ConstTensor varianceTensor(m_Variance->GetTensorInfo(), m_Variance->GetTensor<void*>()) ;
- ConstTensor betaTensor(m_Beta->GetTensorInfo(), m_Beta->GetTensor<void*>()) ;
- ConstTensor gammaTensor(m_Gamma->GetTensorInfo(), m_Gamma->GetTensor<void*>()) ;
+ ConstTensor meanTensor(m_Mean->GetTensorInfo(), m_Mean->Map(true));
+ ConstTensor varianceTensor(m_Variance->GetTensorInfo(), m_Variance->Map(true));
+ ConstTensor betaTensor(m_Beta->GetTensorInfo(), m_Beta->Map(true));
+ ConstTensor gammaTensor(m_Gamma->GetTensorInfo(), m_Gamma->Map(true));
visitor.VisitBatchNormalizationLayer(this, GetParameters(), meanTensor, varianceTensor, betaTensor, gammaTensor);
}
diff --git a/src/armnn/test/QuantizerTest.cpp b/src/armnn/test/QuantizerTest.cpp
index 56b1497967..fbafbd8f1e 100644
--- a/src/armnn/test/QuantizerTest.cpp
+++ b/src/armnn/test/QuantizerTest.cpp
@@ -92,5 +92,88 @@ BOOST_AUTO_TEST_CASE(QuantizeAddition)
VisitLayersTopologically(quantizedNetwork.get(), validator);
}
+BOOST_AUTO_TEST_CASE(QuantizeBatchNorm)
+{
+
+ class TestQuantization : public LayerVisitorBase<VisitorThrowingPolicy>
+ {
+ 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));
+
+ // Based off current static value [-15.0f, 15.0f]
+ BOOST_CHECK_CLOSE(info.GetQuantizationScale(), 30.0f/255.0f, 0.000001f );
+
+ //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_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);
+
+ BOOST_TEST((mean.GetInfo().GetQuantizationOffset() == 85));
+ }
+
+ virtual void VisitInputLayer(const IConnectableLayer* layer,
+ LayerBindingId id,
+ const char* name = nullptr)
+ {}
+
+ virtual void VisitOutputLayer(const IConnectableLayer* layer,
+ LayerBindingId id,
+ const char* name = nullptr)
+ {}
+ };
+
+ auto network = INetwork::Create();
+
+ TensorShape shape{3U};
+ TensorInfo info(shape, DataType::Float32);
+
+ std::vector<float> meanData{-1.0f, 1.5f, 2.0f};
+ std::vector<float> varData{-1.0f, 1.5f, 2.0f};
+ std::vector<float> betaData{-1.0f, 1.5f, 2.0f};
+ std::vector<float> gammaData{-1.0f, 1.5f, 2.0f};
+
+ ConstTensor mean(info, meanData);
+ ConstTensor var(info, varData);
+ ConstTensor beta(info, betaData);
+ ConstTensor gamma(info, gammaData);
+
+ BatchNormalizationDescriptor desc;
+
+ // Add the layers
+ IConnectableLayer* input0 = network->AddInputLayer(0);
+ IConnectableLayer* batchNorm = network->AddBatchNormalizationLayer(desc, mean, var, beta, gamma);
+ IConnectableLayer* output = network->AddOutputLayer(1);
+
+ // Establish connections
+ input0->GetOutputSlot(0).Connect(batchNorm->GetInputSlot(0));
+ batchNorm->GetOutputSlot(0).Connect(output->GetInputSlot(0));
+
+ //Set TensorInfo
+ input0->GetOutputSlot(0).SetTensorInfo(info);
+ batchNorm->GetOutputSlot(0).SetTensorInfo(info);
+
+ auto quantizedNetwork = INetworkQuantizer::Create(network.get())->ExportNetwork();
+ TestQuantization validator;
+ VisitLayersTopologically(quantizedNetwork.get(), validator);
+}
+
BOOST_AUTO_TEST_SUITE_END()
} //namespace armnn