From 81beae3a870004795275e9266bc43d845b9f78db Mon Sep 17 00:00:00 2001 From: Matthew Sloyan Date: Tue, 13 Jul 2021 19:46:11 +0100 Subject: 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 Change-Id: Ibf3cf437df1100e4b322b0d303c575c6339f9696 --- src/armnn/Network.cpp | 128 ++++++++++++++++++++++++++------------------------ 1 file changed, 66 insertions(+), 62 deletions(-) (limited to 'src/armnn/Network.cpp') 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 +#include + #include #include #include @@ -178,38 +180,22 @@ IConnectableLayer* INetwork::AddFillLayer(const FillDescriptor& fillDescriptor, } IConnectableLayer* INetwork::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, - const ConstTensor& weights, - const Optional& biases, const char* name) { - return pNetworkImpl->AddFullyConnectedLayer(fullyConnectedDescriptor, - armnn::Optional(weights), - biases, - name); + return pNetworkImpl->AddFullyConnectedLayer(fullyConnectedDescriptor, name); } IConnectableLayer* INetwork::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, const ConstTensor& weights, + const Optional& biases, const char* name) { - armnn::Optional biases; return pNetworkImpl->AddFullyConnectedLayer(fullyConnectedDescriptor, armnn::Optional(weights), biases, name); } -IConnectableLayer* INetwork::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, - const ConstTensor& weights, - const ConstTensor& biases, - const char* name) -{ - return pNetworkImpl->AddFullyConnectedLayer(fullyConnectedDescriptor, - armnn::Optional(weights), - armnn::Optional(biases), - name); -} - IConnectableLayer* INetwork::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, const Optional& weights, const Optional& biases, @@ -1799,69 +1785,87 @@ IConnectableLayer* NetworkImpl::AddFillLayer(const FillDescriptor& fillDescripto return m_Graph->AddLayer(fillDescriptor, name); } -IConnectableLayer* NetworkImpl::AddFullyConnectedLayerImpl(const FullyConnectedDescriptor& fullyConnectedDescriptor, - const Optional& weights, - const Optional& biases, - const char* name) +IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, + const char* name) +{ + return m_Graph->AddLayer(fullyConnectedDescriptor, name); +} + +IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, + const Optional& weights, + const Optional& 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("Weights"); + weightsLayer->m_LayerOutput = std::make_shared(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("Biases"); + biasLayer->m_LayerOutput = std::make_shared(biases.value()); + biasLayer->GetOutputSlot(0).SetTensorInfo(biasLayer->m_LayerOutput->GetTensorInfo()); } - const auto layer = m_Graph->AddLayer(fullyConnectedDescriptor, name); + if (numInputs < 2) + { + throw InvalidArgumentException("AddFullyConnectedLayer: Requires at least 2 input tensors: Input, Weights"); + } + + auto layer = m_Graph->AddLayer(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(weights.value()); - if (fullyConnectedDescriptor.m_BiasEnabled) + if (biasLayer) { - layer->m_Bias = std::make_shared(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& weights, + const ConstTensor& weights, const Optional& biases, const char* name) -{ - return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, weights, biases, name); -} - -IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, - const ConstTensor& weights, - const Optional& biases, - const char* name) { Optional optionalWeights(weights); - return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, optionalWeights, biases, name); -} - -IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, - const ConstTensor& weights, - const char* name) -{ - Optional optionalWeights(weights); - Optional biases; - return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, optionalWeights, biases, name); -} - -IConnectableLayer* NetworkImpl::AddFullyConnectedLayer(const FullyConnectedDescriptor& fullyConnectedDescriptor, - const ConstTensor& weights, - const ConstTensor& biases, - const char* name) -{ - Optional optionalWeights(weights); - Optional optionalBiases(biases); - return AddFullyConnectedLayerImpl(fullyConnectedDescriptor, optionalWeights, optionalBiases, name); + return AddFullyConnectedLayer(fullyConnectedDescriptor, optionalWeights, biases, name); } IConnectableLayer* NetworkImpl::AddConcatLayer(const ConcatDescriptor& concatDescriptor, -- cgit v1.2.1