diff options
author | Matthew Sloyan <matthew.sloyan@arm.com> | 2021-07-13 19:46:11 +0100 |
---|---|---|
committer | Matthew Sloyan <matthew.sloyan@arm.com> | 2021-08-06 09:25:26 +0000 |
commit | 81beae3a870004795275e9266bc43d845b9f78db (patch) | |
tree | 70af86f3c36c8e330c72770e6f1419ca7b2a4bb8 /src/armnn/Network.cpp | |
parent | 95e9efc28ce70a8cda93e722f5ce90ebc96bdd95 (diff) | |
download | armnn-81beae3a870004795275e9266bc43d845b9f78db.tar.gz |
IVGCVSW-6119 ConstTensorsAsInput: FullyConnected
* Constant weights and biases are now stored as Constant layers.
* Updated Serializer, Deserializer and unit tests to reflect this.
* Updated TfLiteDelegate, TfLiteParser and OnnxParser.
* Updated Schema with IsConstant and ConstantTensorsAsInputs.
* Updated Ref backend to handle constant weights and
bias as inputs rather than reading from member variables.
* Added dynamic or constant input EndToEnd tests.
!android-nn-driver:5959
Signed-off-by: Matthew Sloyan <matthew.sloyan@arm.com>
Change-Id: Ibf3cf437df1100e4b322b0d303c575c6339f9696
Diffstat (limited to 'src/armnn/Network.cpp')
-rw-r--r-- | src/armnn/Network.cpp | 128 |
1 files changed, 66 insertions, 62 deletions
diff --git a/src/armnn/Network.cpp b/src/armnn/Network.cpp index 83eafe7993..a29ce83c5a 100644 --- a/src/armnn/Network.cpp +++ b/src/armnn/Network.cpp @@ -30,6 +30,8 @@ #include <common/include/ProfilingGuid.hpp> +#include <fmt/format.h> + #include <fcntl.h> #include <algorithm> #include <fstream> @@ -178,21 +180,16 @@ IConnectableLayer* INetwork::AddFillLayer(const FillDescriptor& fillDescriptor, } IConnectableLayer* INetwork::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, - const ConstTensor& weights, - const Optional<ConstTensor>& biases, const char* name) { - return pNetworkImpl->AddFullyConnectedLayer(fullyConnectedDescriptor, - armnn::Optional<ConstTensor>(weights), - biases, - name); + return pNetworkImpl->AddFullyConnectedLayer(fullyConnectedDescriptor, name); } IConnectableLayer* INetwork::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, const ConstTensor& weights, + const Optional<ConstTensor>& biases, const char* name) { - armnn::Optional<ConstTensor> biases; return pNetworkImpl->AddFullyConnectedLayer(fullyConnectedDescriptor, armnn::Optional<ConstTensor>(weights), biases, @@ -200,17 +197,6 @@ IConnectableLayer* INetwork::AddFullyConnectedLayer(const FullyConnectedDescript } IConnectableLayer* INetwork::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, - const ConstTensor& weights, - const ConstTensor& biases, - const char* name) -{ - return pNetworkImpl->AddFullyConnectedLayer(fullyConnectedDescriptor, - armnn::Optional<ConstTensor>(weights), - armnn::Optional<ConstTensor>(biases), - name); -} - -IConnectableLayer* INetwork::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, const Optional<ConstTensor>& weights, const Optional<ConstTensor>& biases, const char* name) @@ -1799,69 +1785,87 @@ IConnectableLayer* NetworkImpl::AddFillLayer(const FillDescriptor& fillDescripto return m_Graph->AddLayer<FillLayer>(fillDescriptor, name); } -IConnectableLayer* NetworkImpl::AddFullyConnectedLayerImpl(const FullyConnectedDescriptor& fullyConnectedDescriptor, - const Optional<ConstTensor>& weights, - const Optional<ConstTensor>& biases, - const char* name) +IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, + const char* name) +{ + return m_Graph->AddLayer<FullyConnectedLayer>(fullyConnectedDescriptor, name); +} + +IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, + const Optional<ConstTensor>& weights, + const Optional<ConstTensor>& biases, + const char* name) { - if (fullyConnectedDescriptor.m_ConstantWeights && !weights.has_value()) + ConstantLayer* weightsLayer = nullptr; + ConstantLayer* biasLayer = nullptr; + unsigned int numInputs = fullyConnectedDescriptor.GetNumInputs(); + + // Add a constant layer for weights + if (weights.has_value()) { - throw InvalidArgumentException("AddFullyConnectedLayer: weights cannot be empty"); + weightsLayer = m_Graph->AddLayer<ConstantLayer>("Weights"); + weightsLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(weights.value()); + weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsLayer->m_LayerOutput->GetTensorInfo()); + } + else if (fullyConnectedDescriptor.m_ConstantWeights) + { + throw InvalidArgumentException("AddFullyConnectedLayer: Constant weights tensor is empty."); + } - if (fullyConnectedDescriptor.m_BiasEnabled && !biases.has_value()) - { - throw InvalidArgumentException("AddFullyConnectedLayer: biases cannot be empty"); - } + // Add a constant layer for biases + if (biases.has_value() && fullyConnectedDescriptor.m_BiasEnabled) + { + biasLayer = m_Graph->AddLayer<ConstantLayer>("Biases"); + biasLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(biases.value()); + biasLayer->GetOutputSlot(0).SetTensorInfo(biasLayer->m_LayerOutput->GetTensorInfo()); } - const auto layer = m_Graph->AddLayer<FullyConnectedLayer>(fullyConnectedDescriptor, name); + if (numInputs < 2) + { + throw InvalidArgumentException("AddFullyConnectedLayer: Requires at least 2 input tensors: Input, Weights"); + } + + auto layer = m_Graph->AddLayer<FullyConnectedLayer>(fullyConnectedDescriptor, name); + + if (weightsLayer) + { + // Connect weights layer + weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1)); + } - if (fullyConnectedDescriptor.m_ConstantWeights) + if ( fullyConnectedDescriptor.m_BiasEnabled && numInputs == 3 ) { - layer->m_Weight = std::make_shared<ScopedTensorHandle>(weights.value()); - if (fullyConnectedDescriptor.m_BiasEnabled) + if (biasLayer) { - layer->m_Bias = std::make_shared<ScopedTensorHandle>(biases.value()); + // Connect bias layer + biasLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(2)); } } + else if ( !fullyConnectedDescriptor.m_BiasEnabled && numInputs == 2 ) + { + // Bias is disabled + layer->m_Bias = nullptr; + } + else + { + throw InvalidArgumentException(fmt::format( + "AddFullyConnectedLayer: Value mismatch. When bias is enabled in the " + "descriptor the number of inputs is expected to be 3 otherwise 2. " + "BiasEnabled={}, numInputs={}", + fullyConnectedDescriptor.m_BiasEnabled, + numInputs)); + } return layer; } IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, - const Optional<ConstTensor>& weights, + const ConstTensor& weights, const Optional<ConstTensor>& biases, const char* name) { - return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, weights, biases, name); -} - -IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, - const ConstTensor& weights, - const Optional<ConstTensor>& biases, - const char* name) -{ Optional<ConstTensor> optionalWeights(weights); - return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, optionalWeights, biases, name); -} - -IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, - const ConstTensor& weights, - const char* name) -{ - Optional<ConstTensor> optionalWeights(weights); - Optional<ConstTensor> biases; - return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, optionalWeights, biases, name); -} - -IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, - const ConstTensor& weights, - const ConstTensor& biases, - const char* name) -{ - Optional<ConstTensor> optionalWeights(weights); - Optional<ConstTensor> optionalBiases(biases); - return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, optionalWeights, optionalBiases, name); + return AddFullyConnectedLayer(fullyConnectedDescriptor, optionalWeights, biases, name); } IConnectableLayer* NetworkImpl::AddConcatLayer(const ConcatDescriptor& concatDescriptor, |