diff options
author | Keith Davis <keith.davis@arm.com> | 2022-04-07 11:32:00 +0100 |
---|---|---|
committer | Keith Davis <keith.davis@arm.com> | 2022-05-16 16:08:54 +0100 |
commit | b4dd5cc86d4eb841de670f0f102ede599e0d9c40 (patch) | |
tree | 77857cf739baecaf63701b66c1a2646b7930a834 /src/armnn | |
parent | b86ec6641b4b06ccddad5eebbc21010d6184fe79 (diff) | |
download | armnn-b4dd5cc86d4eb841de670f0f102ede599e0d9c40.tar.gz |
IVGCVSW-6124 ConstTensorsAsInput: Conv2d - FrontEnd
* Update Front-end and Tools.
* Updated Serializer, Deserializer and unit tests to reflect this.
* Updated TfLiteDelegate, TfLiteParser and OnnxParser.
* Updated Ref.
* Fixed resulting Neon / CL tests
* Unified optimizers for conv2d ops
* Optimizer Fix - Fp32ToBf16
* Partial implementation for ACL backends to fix VTS failures
!android-nn-driver:7477
Signed-off-by: Keith Davis <keith.davis@arm.com>
Change-Id: I5fb18877f7ee32643e15a9818945356274bb401b
Diffstat (limited to 'src/armnn')
23 files changed, 415 insertions, 373 deletions
diff --git a/src/armnn/BackendHelper.cpp b/src/armnn/BackendHelper.cpp index 03f32ac191..9f97c26a75 100644 --- a/src/armnn/BackendHelper.cpp +++ b/src/armnn/BackendHelper.cpp @@ -373,6 +373,31 @@ bool LayerSupportHandle::IsConvolution2dSupported(const TensorInfo& input, TensorInfo biasesVal = biases.has_value() ? biases.value() : TensorInfo(); TensorInfos infos{input, output, weights, biasesVal}; + Optional<const BackendOptions::BackendOption> capability ; + if(!m_BackendId.IsUndefined()) + { + capability = GetCapability("ConstantTensorsAsInputs", m_BackendId); + if(!capability.has_value() || capability.value().GetValue().AsBool() == false) + { + if(!weights.IsConstant()) + { + return false; + } + if (descriptor.m_BiasEnabled && !biases.has_value()) + { + return false; + } + + + // At the first stage we will only print a warning. this is to give + // backend developers a chance to adopt and read weights from input slots. + ARMNN_LOG(warning) << "The backend makes use of a deprecated interface to read constant tensors. " + "If you are a backend developer please find more information in our " + "doxygen documentation on github https://github.com/ARM-software/armnn " + "under the keyword 'ConstTensorsAsInputs'."; + } + } + return m_LayerSupport->IsLayerSupported(LayerType::Convolution2d, infos, descriptor, diff --git a/src/armnn/Descriptors.cpp b/src/armnn/Descriptors.cpp index d67d4404e0..4eb875e03d 100644 --- a/src/armnn/Descriptors.cpp +++ b/src/armnn/Descriptors.cpp @@ -425,16 +425,10 @@ int StridedSliceDescriptor::GetStopForAxis(const TensorShape& inputShape, } -uint32_t FullyConnectedDescriptor::GetNumViews() const +uint32_t GetNumInputs(bool biasEnabled) { - return GetNumInputs(); -} - -uint32_t FullyConnectedDescriptor::GetNumInputs() const -{ - // Return 2 otherwise check if bias is enabled unsigned int numInputs = 2; - if (m_BiasEnabled) + if (biasEnabled) { numInputs = 3; } @@ -443,24 +437,27 @@ uint32_t FullyConnectedDescriptor::GetNumInputs() const uint32_t Convolution3dDescriptor::GetNumInputs() const { - // Return 2 otherwise check if bias is enabled - unsigned int numInputs = 2; - if (m_BiasEnabled) - { - numInputs = 3; - } - return numInputs; + return armnn::GetNumInputs(m_BiasEnabled); +} + +uint32_t Convolution2dDescriptor::GetNumInputs() const +{ + return armnn::GetNumInputs(m_BiasEnabled); +} + +uint32_t FullyConnectedDescriptor::GetNumInputs() const +{ + return armnn::GetNumInputs(m_BiasEnabled); +} + +uint32_t FullyConnectedDescriptor::GetNumViews() const +{ + return armnn::GetNumInputs(m_BiasEnabled); } uint32_t DepthwiseConvolution2dDescriptor::GetNumInputs() const { - // Return 2 otherwise check if bias is enabled - unsigned int numInputs = 2; - if (m_BiasEnabled) - { - numInputs = 3; - } - return numInputs; + return armnn::GetNumInputs(m_BiasEnabled); } } diff --git a/src/armnn/Graph.cpp b/src/armnn/Graph.cpp index c1cec482b6..8500e529b0 100644 --- a/src/armnn/Graph.cpp +++ b/src/armnn/Graph.cpp @@ -603,16 +603,19 @@ void Graph::ConstructErrorMessageForUnconnectedInputs(Layer* const layer, bool noWeightsAndBias = false; if ((layer->GetType() == armnn::LayerType::FullyConnected || + layer->GetType() == armnn::LayerType::Convolution2d || layer->GetType() == armnn::LayerType::Convolution3d || layer->GetType() == armnn::LayerType::DepthwiseConvolution2d) && slotIndex > 0) { + message << std::endl; + // If weights are not set and is bias enabled, also check if bias is set if (slotIndex == 1 && layer->GetNumInputSlots() == 3) { const IOutputSlot* biasSource = layer->GetInputSlot(2).GetConnectedOutputSlot(); if (biasSource == NULL) { - message << layer->GetName() << " layer weights and bias not set: "; + message << "Weights and bias layers not set." << std::endl; noWeightsAndBias = true; } } @@ -622,11 +625,11 @@ void Graph::ConstructErrorMessageForUnconnectedInputs(Layer* const layer, { if (slotIndex == 1) { - message << layer->GetName() << " layer weights not set: "; + message << "Weights layer not set." << std::endl; } else { - message << layer->GetName() << " layer bias not set: "; + message << "Bias layer not set." << std::endl; } } } @@ -634,9 +637,10 @@ void Graph::ConstructErrorMessageForUnconnectedInputs(Layer* const layer, std::string slotString = noWeightsAndBias ? "1 & 2" : std::to_string(slotIndex); message << "Input slot(s) " << slotString - << " not connected to an output slot on " + << " for " << GetLayerTypeAsCString(layer->GetType()) - << " layer " + << " not connected to an output slot. " << std::endl + << "Layer name: " << std::quoted(layer->GetName()); throw LayerValidationException(message.str()); } diff --git a/src/armnn/Layer.cpp b/src/armnn/Layer.cpp index a31119b395..3241b5024e 100644 --- a/src/armnn/Layer.cpp +++ b/src/armnn/Layer.cpp @@ -23,16 +23,23 @@ namespace armnn // Instantiate the static member variable NullDescriptor Layer::m_NullDescriptor; -template <typename LayerT> -void AssertMultipleInputSlots(Layer& layer) +void AssertNumberOfInputSlots(Layer& layer) { - if(PolymorphicDowncast<const LayerT*>(&(layer.GetParameters()))->m_BiasEnabled) + switch (layer.GetType()) { - ARMNN_ASSERT(layer.GetNumInputSlots() == 3); - } - else - { - ARMNN_ASSERT(layer.GetNumInputSlots() == 2); + case LayerType::Convolution2d: + case LayerType::DepthwiseConvolution2d: + case LayerType::FullyConnected: + { + ARMNN_ASSERT(layer.GetNumInputSlots() == 2 || + layer.GetNumInputSlots() == 3); + break; + } + default: + { + ARMNN_ASSERT(layer.GetNumInputSlots() == 1); + break; + } } } @@ -47,19 +54,7 @@ void InputSlot::Insert(Layer& layer) // Disconnects parent from this. prevSlot->Disconnect(*this); - switch (layer.GetType()) - { - case LayerType::DepthwiseConvolution2d: - { - AssertMultipleInputSlots<DepthwiseConvolution2dDescriptor>(layer); - break; - } - default: - { - ARMNN_ASSERT(layer.GetNumInputSlots() == 1); - break; - } - } + AssertNumberOfInputSlots(layer); // Connects inserted layer to parent. int idx = prevSlot->Connect(layer.GetInputSlot(0)); diff --git a/src/armnn/LoadedNetwork.cpp b/src/armnn/LoadedNetwork.cpp index a88fa5ab9c..228927db57 100644 --- a/src/armnn/LoadedNetwork.cpp +++ b/src/armnn/LoadedNetwork.cpp @@ -330,10 +330,10 @@ LoadedNetwork::LoadedNetwork(std::unique_ptr<IOptimizedNetwork> net, if (layer->GetType() == LayerType::Constant) { + // Place the Constant Workloads into a queue so that they can be executed first ConstWorkloads.push_back(m_WorkloadQueue.back().get()); } } - // release the constant data in the layer.. layer->ReleaseConstantData(); break; @@ -513,10 +513,7 @@ LoadedNetwork::LoadedNetwork(std::unique_ptr<IOptimizedNetwork> net, AllocateAndExecuteConstantWorkloadsAsync(); } } - - // If synchronous, execute all constant layer workloads as the FoldPad optimization - // may have created a new conv2d layer prior to the input constant layers which will - // cause a failure if constant workloads are not executed + // If synchronous, execute all constant layer workloads if (!networkProperties.m_AsyncEnabled) { for (auto workload: ConstWorkloads) diff --git a/src/armnn/Network.cpp b/src/armnn/Network.cpp index d2ebd4cde6..479e57fc56 100644 --- a/src/armnn/Network.cpp +++ b/src/armnn/Network.cpp @@ -83,35 +83,23 @@ IConnectableLayer* INetwork::AddConcatLayer(const ConcatDescriptor& concatDescri IConnectableLayer* INetwork::AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor, - const ConstTensor& weights, - const Optional<ConstTensor>& biases, const char* name) { - return pNetworkImpl->AddConvolution2dLayer(convolution2dDescriptor, weights, biases, name); + return pNetworkImpl->AddConvolution2dLayer(convolution2dDescriptor, name); } - -IConnectableLayer* INetwork::AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor, - const ConstTensor& weights, - const char* name) -{ - Optional<ConstTensor> biases; - return pNetworkImpl->AddConvolution2dLayer(convolution2dDescriptor, weights, biases, name); -} - - +ARMNN_NO_DEPRECATE_WARN_BEGIN IConnectableLayer* INetwork::AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor, - const ConstTensor& weights, - const ConstTensor& biases, - const char* name ) + const ConstTensor& weights, + const Optional<ConstTensor>& biases, + const char* name) { - return pNetworkImpl->AddConvolution2dLayer(convolution2dDescriptor, weights, armnn::Optional<ConstTensor>(biases), name); } - +ARMNN_NO_DEPRECATE_WARN_END IConnectableLayer* INetwork::AddConvolution3dLayer(const Convolution3dDescriptor& convolution3dDescriptor, const char* name) @@ -2012,25 +2000,33 @@ IConnectableLayer* NetworkImpl::AddConcatLayer(const ConcatDescriptor& concatDes return m_Graph->AddLayer<ConcatLayer>(concatDescriptor, name); } -IConnectableLayer* NetworkImpl::AddConvolution2dLayerImpl(const Convolution2dDescriptor& convolution2dDescriptor, - const ConstTensor& weights, - const Optional<ConstTensor>& biases, - const char* name) +IConnectableLayer* NetworkImpl::AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor, + const char* name) { - if (convolution2dDescriptor.m_BiasEnabled && !biases.has_value()) - { - throw InvalidArgumentException("AddConvolution2dLayer: biases cannot be empty"); - } - - const auto layer = m_Graph->AddLayer<Convolution2dLayer>(convolution2dDescriptor, name); + return m_Graph->AddLayer<Convolution2dLayer>(convolution2dDescriptor, name); +} +IConnectableLayer* NetworkImpl::AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor, + const ConstTensor& weights, + const Optional<ConstTensor>& biases, + const char* name) +{ + auto layer = m_Graph->AddLayer<Convolution2dLayer>(convolution2dDescriptor, name); + // Add a constant layer for weights + ConstantLayer* weightsLayer = m_Graph->AddLayer<ConstantLayer>("Weights"); + weightsLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(weights); layer->m_Weight = std::make_shared<ScopedTensorHandle>(weights); - - if (convolution2dDescriptor.m_BiasEnabled) + weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsLayer->m_LayerOutput->GetTensorInfo()); + weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1)); + // Add a constant layer for biases + if (biases.has_value() && convolution2dDescriptor.m_BiasEnabled) { + ConstantLayer* biasLayer = m_Graph->AddLayer<ConstantLayer>("Bias"); + biasLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(biases.value()); layer->m_Bias = std::make_shared<ScopedTensorHandle>(biases.value()); + biasLayer->GetOutputSlot(0).SetTensorInfo(biasLayer->m_LayerOutput->GetTensorInfo()); + biasLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(2)); } - return layer; } @@ -2044,31 +2040,6 @@ IConnectableLayer* NetworkImpl::AddConvertFp32ToFp16Layer(const char* name) return m_Graph->AddLayer<ConvertFp32ToFp16Layer>(name); } -IConnectableLayer* NetworkImpl::AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor, - const ConstTensor& weights, - const Optional<ConstTensor>& biases, - const char* name) -{ - return AddConvolution2dLayerImpl(convolution2dDescriptor, weights, biases, name); -} - -IConnectableLayer* NetworkImpl::AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor, - const ConstTensor& weights, - const char* name) -{ - Optional<ConstTensor> biases; - return AddConvolution2dLayerImpl(convolution2dDescriptor, weights, biases, name); -} - -IConnectableLayer* NetworkImpl::AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor, - const ConstTensor& weights, - const ConstTensor& biases, - const char* name) -{ - Optional<ConstTensor> optionalBiases(biases); - return AddConvolution2dLayerImpl(convolution2dDescriptor, weights, optionalBiases, name); -} - IConnectableLayer* NetworkImpl::AddConvolution3dLayer(const Convolution3dDescriptor& convolution3dDescriptor, const char* name) { diff --git a/src/armnn/Network.hpp b/src/armnn/Network.hpp index c5ed8de50d..c2be600d05 100644 --- a/src/armnn/Network.hpp +++ b/src/armnn/Network.hpp @@ -71,6 +71,10 @@ public: const char* name = nullptr); IConnectableLayer* AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor, + const char* name = nullptr); + + ARMNN_DEPRECATED_MSG_REMOVAL_DATE("This AddConvolution2dLayer overload is deprecated", "22.11") + IConnectableLayer* AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor, const ConstTensor& weights, const Optional<ConstTensor>& biases, const char* name = nullptr); @@ -256,10 +260,6 @@ public: void ExecuteStrategy(IStrategy& strategy) const; private: - IConnectableLayer* AddConvolution2dLayerImpl(const Convolution2dDescriptor& convolution2dDescriptor, - const ConstTensor& weights, - const Optional<ConstTensor>& biases, - const char* name); bool GetShapeInferenceMethod(); NetworkOptions m_NetworkOptions; diff --git a/src/armnn/NetworkUtils.cpp b/src/armnn/NetworkUtils.cpp index 666ce3d069..7597798fa4 100644 --- a/src/armnn/NetworkUtils.cpp +++ b/src/armnn/NetworkUtils.cpp @@ -98,6 +98,15 @@ std::vector<ConvertFp32ToBf16Layer*> InsertConvertFp32ToBf16LayersBefore(Graph& for (auto&& inputSlot = layer.BeginInputSlots(); inputSlot != layer.EndInputSlots(); ++inputSlot) { bool allowInsert = true; + + if ((layer.GetType() == LayerType::Convolution2d || + layer.GetType() == LayerType::FullyConnected || + layer.GetType() == LayerType::DepthwiseConvolution2d) + && inputSlot->GetSlotIndex() == 2) + { + // Refrain from reducing bias to Bf16 + continue; + } if (expectCorrectInputType) { // Only insert ConvertFp32ToBf16Layer before FP32 input slots diff --git a/src/armnn/Tensor.cpp b/src/armnn/Tensor.cpp index 6a4dbf8dae..ab4ecc9194 100644 --- a/src/armnn/Tensor.cpp +++ b/src/armnn/Tensor.cpp @@ -362,9 +362,7 @@ TensorInfo::TensorInfo(unsigned int numDimensions, float quantizationScale, int32_t quantizationOffset, bool isConstant) - : m_Shape(numDimensions, dimensionSizes) - , m_DataType(dataType) - , m_IsConstant(isConstant) + : m_Shape(numDimensions, dimensionSizes), m_DataType(dataType), m_IsConstant(isConstant) { SetQuantizationScale(quantizationScale); SetQuantizationOffset(quantizationOffset); diff --git a/src/armnn/layers/Convolution2dLayer.cpp b/src/armnn/layers/Convolution2dLayer.cpp index ef5db8e9b9..7b3382bf93 100644 --- a/src/armnn/layers/Convolution2dLayer.cpp +++ b/src/armnn/layers/Convolution2dLayer.cpp @@ -21,7 +21,7 @@ namespace armnn { Convolution2dLayer::Convolution2dLayer(const Convolution2dDescriptor& param, const char* name) - : LayerWithParameters(1, 1, LayerType::Convolution2d, param, name) + : LayerWithParameters(param.GetNumInputs(), 1, LayerType::Convolution2d, param, name) { } @@ -32,7 +32,7 @@ void Convolution2dLayer::SerializeLayerParameters(ParameterStringifyFunction& fn const std::vector<TensorShape>& inputShapes = { GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape(), - m_Weight->GetTensorInfo().GetShape() + GetInputSlot(1).GetConnection()->GetTensorInfo().GetShape() }; const TensorShape filterShape = inputShapes[1]; DataLayoutIndexed dataLayoutIndex(m_Param.m_DataLayout); @@ -49,15 +49,14 @@ void Convolution2dLayer::SerializeLayerParameters(ParameterStringifyFunction& fn std::unique_ptr<IWorkload> Convolution2dLayer::CreateWorkload(const IWorkloadFactory& factory) const { // on this level constant data should not be released.. - ARMNN_ASSERT_MSG(m_Weight != nullptr, "Convolution2dLayer: Weights data should not be null."); ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "Convolution2dLayer_CreateWorkload"); Convolution2dQueueDescriptor descriptor; - - descriptor.m_Weight = m_Weight.get(); - - if (m_Param.m_BiasEnabled) + if (m_Weight) + { + descriptor.m_Weight = m_Weight.get(); + } + if (m_Param.m_BiasEnabled && m_Bias) { - ARMNN_ASSERT_MSG(m_Bias != nullptr, "Convolution2dLayer: Bias data should not be null."); descriptor.m_Bias = m_Bias.get(); } @@ -120,18 +119,18 @@ std::vector<TensorShape> Convolution2dLayer::InferOutputShapes(const std::vector void Convolution2dLayer::ValidateTensorShapesFromInputs() { - VerifyLayerConnections(1, CHECK_LOCATION()); + VerifyLayerConnections(m_Param.GetNumInputs(), CHECK_LOCATION()); const TensorShape& outputShape = GetOutputSlot(0).GetTensorInfo().GetShape(); VerifyShapeInferenceType(outputShape, m_ShapeInferenceMethod); - // check if we m_Weight data is not nullptr - ARMNN_ASSERT_MSG(m_Weight != nullptr, "Convolution2dLayer: Weights data should not be null."); + ARMNN_ASSERT_MSG(GetInputSlot(1).GetConnection(), + "Convolution2dLayer: Weights should be connected to input slot 1."); - auto inferredShapes = InferOutputShapes({ - GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape(), - m_Weight->GetTensorInfo().GetShape() }); + std::vector<TensorShape> inferredShapes = InferOutputShapes({ + GetInputSlot(0).GetConnection()->GetTensorInfo().GetShape(), + GetInputSlot(1).GetConnection()->GetTensorInfo().GetShape() }); ARMNN_ASSERT(inferredShapes.size() == 1); @@ -147,33 +146,13 @@ Layer::ConstantTensors Convolution2dLayer::GetConstantTensorsByRef() ARMNN_NO_DEPRECATE_WARN_BEGIN void Convolution2dLayer::Accept(ILayerVisitor& visitor) const { - ManagedConstTensorHandle managedWeight(m_Weight); - ConstTensor weightsTensor(managedWeight.GetTensorInfo(), managedWeight.Map()); - - Optional<ConstTensor> optionalBiasTensor = EmptyOptional(); - ManagedConstTensorHandle managedBias(m_Bias); - if (GetParameters().m_BiasEnabled) - { - ConstTensor biasTensor(managedBias.GetTensorInfo(), managedBias.Map()); - optionalBiasTensor = Optional<ConstTensor>(biasTensor); - } - - visitor.VisitConvolution2dLayer(this, GetParameters(), weightsTensor, optionalBiasTensor, GetName()); + visitor.VisitConvolution2dLayer(this, GetParameters(), GetName()); } ARMNN_NO_DEPRECATE_WARN_END void Convolution2dLayer::ExecuteStrategy(IStrategy& strategy) const { - ManagedConstTensorHandle managedWeight(m_Weight); - std::vector<armnn::ConstTensor> constTensors { { managedWeight.GetTensorInfo(), managedWeight.Map() } }; - - ManagedConstTensorHandle managedBias(m_Bias); - if (GetParameters().m_BiasEnabled) - { - constTensors.emplace_back(ConstTensor(managedBias.GetTensorInfo(), managedBias.Map())); - } - - strategy.ExecuteStrategy(this, GetParameters(), constTensors, GetName()); + strategy.ExecuteStrategy(this, GetParameters(), { }, GetName()); } } // namespace armnn diff --git a/src/armnn/layers/Convolution2dLayer.hpp b/src/armnn/layers/Convolution2dLayer.hpp index 844747831c..6bb86da18e 100644 --- a/src/armnn/layers/Convolution2dLayer.hpp +++ b/src/armnn/layers/Convolution2dLayer.hpp @@ -17,8 +17,10 @@ class Convolution2dLayer : public LayerWithParameters<Convolution2dDescriptor> public: /// A unique pointer to store Weight values. + /// @Note: Deprecated. Removal date is 22.11. Weights are stored in ConstantLayers now. std::shared_ptr<ConstTensorHandle> m_Weight; /// A unique pointer to store Bias values. + /// @Note: Deprecated. Removal date is 22.11. Bias are stored in ConstantLayers now. std::shared_ptr<ConstTensorHandle> m_Bias; /// Makes a workload for the Convolution2d type. @@ -59,8 +61,8 @@ protected: /// Default destructor ~Convolution2dLayer() = default; - /// Retrieve the handles to the constant values stored by the layer. - /// @return A vector of the constant tensors stored by this layer. + /// @Note Deprecated. GetConstantTensorsByRef is deprecated. m_Weights and m_Bias + /// should be connected to layer as Constant Layers instead." ConstantTensors GetConstantTensorsByRef() override; }; diff --git a/src/armnn/optimizations/FoldPadIntoLayer2d.hpp b/src/armnn/optimizations/FoldPadIntoLayer2d.hpp index bbaabb815e..eb6bc90afd 100644 --- a/src/armnn/optimizations/FoldPadIntoLayer2d.hpp +++ b/src/armnn/optimizations/FoldPadIntoLayer2d.hpp @@ -146,8 +146,22 @@ Layer2dT* FoldPadIntoLayer2dImpl(Graph& graph, InputSlot& connection) const std::string name = std::string("folded-") + padLayer.GetName() + "-into-" + layer2d.GetName(); auto& newLayer2d = *graph.InsertNewLayer<Layer2dT>(padLayer.GetInputSlot(0), newLayer2dDescriptor, name.c_str()); - // Reconnect the pad layer with its original parent. newLayer2d.GetOutputSlot().MoveAllConnections(parentSlot); + // Start at 1 to connect only weights and bias + for (unsigned int i = 1; i < layer2d.GetNumInputSlots(); ++i) + { + if (layer2d.GetInputSlot(i).GetConnectedOutputSlot() != nullptr) + { + Layer& tgtLayer = layer2d.GetInputSlot(i).GetConnectedOutputSlot()->GetOwningLayer(); + // Ensure we are definitely connecting the necessary constant layers + if (tgtLayer.GetType() == armnn::LayerType::Constant) + { + // Remove old connection and connect to new layer2d + tgtLayer.GetOutputSlot(0).Disconnect(layer2d.GetInputSlot(i)); + tgtLayer.GetOutputSlot(0).Connect(newLayer2d.GetInputSlot(i)); + } + } + } // Moves connections in old layer2d layer output to new layer. // Old layer2d layer will be removed as it's left unconnected. @@ -168,14 +182,19 @@ public: { const auto conv2dLayer = PolymorphicDowncast<Convolution2dLayer*>(&connection.GetOwningLayer()); // Copy weights and bias to the new convolution layer - ARMNN_ASSERT_MSG(conv2dLayer->m_Weight != nullptr, - "FoldPadIntoConvolution2d: Weights data should not be null."); + ARMNN_ASSERT_MSG(newConv2dLayer->GetInputSlot(1).GetConnection() != nullptr, + "FoldPadIntoConvolution2d: New convolution layer is missing connection to weights layer"); + + // Deprecated 22.11 newConv2dLayer->m_Weight = std::move(conv2dLayer->m_Weight); if (conv2dLayer->GetParameters().m_BiasEnabled) { - ARMNN_ASSERT_MSG(conv2dLayer->m_Bias != nullptr, - "FoldPadIntoConvolution2d: Bias data should not be null if bias is enabled."); + ARMNN_ASSERT_MSG(newConv2dLayer->GetInputSlot(2).GetConnection() != nullptr, + "FoldPadIntoConvolution2d: New convolution layer is missing " + "connection to bias layer."); + + // Deprecated 22.11 newConv2dLayer->m_Bias = std::move(conv2dLayer->m_Bias); } } @@ -191,26 +210,25 @@ class FoldPadIntoDepthwiseConvolution2dImpl public: void Run(Graph& graph, InputSlot& connection) const { - const auto newLayer2d = FoldPadIntoLayer2dImpl<DepthwiseConvolution2dLayer>(graph, connection); + const auto newConv2dLayer = FoldPadIntoLayer2dImpl<DepthwiseConvolution2dLayer>(graph, connection); - if (newLayer2d != nullptr) + if (newConv2dLayer != nullptr) { - const auto layer2d = PolymorphicDowncast<DepthwiseConvolution2dLayer*>(&connection.GetOwningLayer()); + const auto conv2dLayer = PolymorphicDowncast<DepthwiseConvolution2dLayer*>(&connection.GetOwningLayer()); + // Copy weights and bias to the new convolution layer + ARMNN_ASSERT_MSG(newConv2dLayer->GetInputSlot(1).GetConnection() != nullptr, + "FoldPadIntoDepthwiseConvolution2d: New convolution layer is missing connection to weights layer"); - // Move weights and bias layer connections to the new convolution layer - ARMNN_ASSERT_MSG(layer2d->GetInputSlot(1).GetConnection() != nullptr, - "FoldPadIntoDepthwiseConvolution2d: Weights data should not be null."); - Layer& weightLayer = layer2d->GetInputSlot(1).GetConnectedOutputSlot()->GetOwningLayer(); - weightLayer.GetOutputSlot(0).Disconnect(layer2d->GetInputSlot(1)); - weightLayer.GetOutputSlot(0).Connect(newLayer2d->GetInputSlot(1)); + // Deprecated 22.11 + newConv2dLayer->m_Weight = std::move(conv2dLayer->m_Weight); - if (layer2d->GetParameters().m_BiasEnabled) + if (conv2dLayer->GetParameters().m_BiasEnabled) { - ARMNN_ASSERT_MSG(layer2d->GetInputSlot(2).GetConnection() != nullptr, - "FoldPadIntoDepthwiseConvolution2d: Bias data should not be null if bias is enabled."); - Layer& biasLayer = layer2d->GetInputSlot(2).GetConnectedOutputSlot()->GetOwningLayer(); - biasLayer.GetOutputSlot(0).Disconnect(layer2d->GetInputSlot(2)); - biasLayer.GetOutputSlot(0).Connect(newLayer2d->GetInputSlot(2)); + ARMNN_ASSERT_MSG(newConv2dLayer->GetInputSlot(2).GetConnection() != nullptr, + "FoldPadIntoConvolution2d: New convolution layer is missing " + "connection to bias layer."); + // Deprecated 22.11 + newConv2dLayer->m_Bias = std::move(conv2dLayer->m_Bias); } } } diff --git a/src/armnn/optimizations/FuseBatchNorm.hpp b/src/armnn/optimizations/FuseBatchNorm.hpp index 6a50fc4a0c..bca0c7d00a 100644 --- a/src/armnn/optimizations/FuseBatchNorm.hpp +++ b/src/armnn/optimizations/FuseBatchNorm.hpp @@ -14,8 +14,8 @@ namespace armnn namespace optimizations { -template <typename ConvLayer, armnn::DataType ArmnnType, - typename T = armnn::ResolveType<ArmnnType>> +template<typename ConvLayer, armnn::DataType ArmnnType, + typename T = armnn::ResolveType<ArmnnType>> class FuseBatchNorm { public: @@ -26,7 +26,7 @@ public: /// combined with the parameters of the child BatchNorm layer. void Run(Graph& graph, InputSlot& connection) const { - Layer& base = connection.GetConnectedOutputSlot()->GetOwningLayer(); + Layer& base = connection.GetConnectedOutputSlot()->GetOwningLayer(); Layer& child = connection.GetOwningLayer(); bool depthwise = (base.GetType() == LayerType::DepthwiseConvolution2d); @@ -37,7 +37,7 @@ public: if (base.GetDataType() == ArmnnType && child.GetDataType() == ArmnnType) { OutputSlot* parentOut = base.GetInputSlot(0).GetConnectedOutputSlot(); - auto convLayer = PolymorphicDowncast<ConvLayer*>(&base); + auto convLayer = PolymorphicDowncast<ConvLayer*>(&base); auto batchNormLayer = PolymorphicDowncast<BatchNormalizationLayer*>(&child); // Read convolution and batch norm parameters @@ -50,25 +50,16 @@ public: ConstTensor meanTensor(batchNormLayer->m_Mean->GetTensorInfo(), batchNormLayer->m_Mean->Map(true)); ConstTensor varTensor(batchNormLayer->m_Variance->GetTensorInfo(), batchNormLayer->m_Variance->Map(true)); - auto convDescriptor = convLayer->GetParameters(); + auto convDescriptor = convLayer->GetParameters(); ConstTensor weightsTensor; - if (convLayer->GetNumInputSlots() > 1) - { - ARMNN_ASSERT_MSG(convLayer->GetInputSlots()[1].GetConnection() != nullptr, - "FuseBatchNorm: Weight data should not be null."); - InputSlot & oldSlotWeights = const_cast<InputSlot&>(convLayer->GetInputSlots()[1]); - OutputSlot & constantSlotWeights = const_cast<OutputSlot&>(*oldSlotWeights.GetConnectedOutputSlot()); - ConstantLayer* weightLayer = PolymorphicDowncast<ConstantLayer*>( - &constantSlotWeights.GetOwningLayer()); - weightsTensor = ConstTensor(weightLayer->m_LayerOutput->GetTensorInfo(), - weightLayer->m_LayerOutput->Map(true)); - } - else - { - ARMNN_ASSERT_MSG(convLayer->m_Weight != nullptr, - "FuseBatchNorm: Bias data should not be null if bias is enabled."); - weightsTensor = ConstTensor(convLayer->m_Weight->GetTensorInfo(), convLayer->m_Weight->Map(true)); - } + ARMNN_ASSERT_MSG(convLayer->GetInputSlots()[1].GetConnection() != nullptr, + "FuseBatchNorm: Weight data should not be null."); + + ConstantLayer* weightLayer = PolymorphicDowncast<ConstantLayer*>( + &base.GetInputSlot(1).GetConnectedOutputSlot()->GetOwningLayer()); + + weightsTensor = ConstTensor(weightLayer->m_LayerOutput->GetTensorInfo(), + weightLayer->m_LayerOutput->Map(true)); armnnUtils::DataLayoutIndexed dataLayout(convDescriptor.m_DataLayout); auto weightsShape = weightsTensor.GetInfo().GetShape(); @@ -76,9 +67,9 @@ public: const unsigned int depthMultiplier = depthwise ? weightsShape[3] / inputChannels : 1; const unsigned int outputChannels = depthwise ? weightsShape[3] : weightsShape[0]; const unsigned int weightsHeight = depthwise ? weightsShape[1] : - weightsShape[dataLayout.GetHeightIndex()]; + weightsShape[dataLayout.GetHeightIndex()]; const unsigned int weightsWidth = depthwise ? weightsShape[2] : - weightsShape[dataLayout.GetWidthIndex()]; + weightsShape[dataLayout.GetWidthIndex()]; const auto* weightsBuffer = static_cast<const T*>(weightsTensor.GetMemoryArea()); const auto* betaBuffer = static_cast<const T*>(betaTensor.GetMemoryArea()); @@ -99,7 +90,7 @@ public: { for (unsigned int cOut = 0; cOut < outputChannels; ++cOut) { - T mult = gammaVector[cOut] / static_cast<T>(sqrtf (varianceVector[cOut] + epsilon)); + T mult = gammaVector[cOut] / static_cast<T>(sqrtf(varianceVector[cOut] + epsilon)); for (unsigned int h = 0; h < weightsHeight; ++h) { @@ -140,23 +131,14 @@ public: if (biasWasEnabledBeforeOpt) { ConstTensor biasTensor; - if (convLayer->GetNumInputSlots() > 1) - { - ARMNN_ASSERT_MSG(convLayer->GetInputSlots()[2].GetConnection() != nullptr, - "FuseBatchNorm: Bias data should not be null if bias is enabled."); - InputSlot & oldSlotBias = const_cast<InputSlot&>(convLayer->GetInputSlots()[2]); - OutputSlot & constantSlotBias = const_cast<OutputSlot&>(*oldSlotBias.GetConnectedOutputSlot()); - ConstantLayer* biasLayer = PolymorphicDowncast<ConstantLayer*>( - &constantSlotBias.GetOwningLayer()); - biasTensor = ConstTensor(biasLayer->m_LayerOutput->GetTensorInfo(), - biasLayer->m_LayerOutput->Map(true)); - } - else - { - ARMNN_ASSERT_MSG(convLayer->m_Bias != nullptr, - "FuseBatchNorm: Bias data should not be null if bias is enabled."); - biasTensor = ConstTensor(convLayer->m_Bias->GetTensorInfo(), convLayer->m_Bias->Map(true)); - } + ARMNN_ASSERT_MSG(convLayer->GetInputSlots()[2].GetConnection() != nullptr, + "FuseBatchNorm: Bias data should not be null if bias is enabled."); + + ConstantLayer* biasLayer = PolymorphicDowncast<ConstantLayer*>( + &base.GetInputSlot(2).GetConnectedOutputSlot()->GetOwningLayer()); + + biasTensor = ConstTensor(biasLayer->m_LayerOutput->GetTensorInfo(), + biasLayer->m_LayerOutput->Map(true)); const auto* biasBuffer = static_cast<const T*>(biasTensor.GetMemoryArea()); std::vector<T> biasVector(biasBuffer, biasBuffer + biasTensor.GetNumElements()); @@ -192,8 +174,6 @@ public: // This optimization will always have 3 input slots on the Conv2d base layer if (newConv2dLayer.GetNumInputSlots() > 1) { - ConstantLayer* weightLayer = PolymorphicDowncast<ConstantLayer*>( - &base.GetInputSlot(1).GetConnectedOutputSlot()->GetOwningLayer()); // Remove old connection and connect to new layer2d weightLayer->GetOutputSlot(0).Disconnect(base.GetInputSlot(1)); weightLayer->GetOutputSlot(0).Connect(newConv2dLayer.GetInputSlot(1)); diff --git a/src/armnn/optimizations/RedirectMembersToConstantInputs.hpp b/src/armnn/optimizations/RedirectMembersToConstantInputs.hpp index cb97a0fe32..483377452e 100644 --- a/src/armnn/optimizations/RedirectMembersToConstantInputs.hpp +++ b/src/armnn/optimizations/RedirectMembersToConstantInputs.hpp @@ -29,6 +29,7 @@ public: case LayerType::BatchNormalization: break; case LayerType::Convolution2d: + RedirectWeightsAndBiases<Convolution2dLayer>(&layer); break; case LayerType::DepthwiseConvolution2d: RedirectWeightsAndBiases<DepthwiseConvolution2dLayer>(&layer); diff --git a/src/armnn/test/ConstTensorLayerVisitor.cpp b/src/armnn/test/ConstTensorLayerVisitor.cpp index af0581ce4c..701327b120 100644 --- a/src/armnn/test/ConstTensorLayerVisitor.cpp +++ b/src/armnn/test/ConstTensorLayerVisitor.cpp @@ -119,16 +119,22 @@ TEST_CASE("CheckConvolution2dLayer") descriptor.m_StrideX = 2; descriptor.m_StrideY = 3; descriptor.m_DataLayout = DataLayout::NHWC; + descriptor.m_BiasEnabled = false; std::vector<float> data = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}; std::vector<unsigned int> dimensions = {1, 1, 3, 3}; ConstTensor weights(TensorInfo(4, dimensions.data(), DataType::Float32, 0.0f, 0, true), data); - TestConvolution2dLayerVisitor visitor(descriptor, weights, EmptyOptional()); + TestConstantLayerVisitor weightsVisitor(weights); + TestConvolution2dLayerVisitor visitor(descriptor); NetworkImpl net; - IConnectableLayer* const layer = net.AddConvolution2dLayer(descriptor, weights, EmptyOptional()); + IConnectableLayer* const weightsLayer = net.AddConstantLayer(weights); + IConnectableLayer* const layer = net.AddConvolution2dLayer(descriptor); + weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1)); + + weightsLayer->ExecuteStrategy(weightsVisitor); layer->ExecuteStrategy(visitor); } @@ -148,11 +154,17 @@ TEST_CASE("CheckNamedConvolution2dLayer") std::vector<unsigned int> dimensions = {1, 1, 3, 3}; ConstTensor weights(TensorInfo(4, dimensions.data(), DataType::Float32, 0.0f, 0, true), data); - TestConvolution2dLayerVisitor visitor(descriptor, weights, EmptyOptional(), layerName); + TestConstantLayerVisitor weightsVisitor(weights); + TestConvolution2dLayerVisitor visitor(descriptor, layerName); NetworkImpl net; - IConnectableLayer* const layer = net.AddConvolution2dLayer(descriptor, weights, EmptyOptional(), layerName); + IConnectableLayer* const weightsLayer = net.AddConstantLayer(weights); + IConnectableLayer* const layer = net.AddConvolution2dLayer(descriptor, layerName); + + weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1)); + + weightsLayer->ExecuteStrategy(weightsVisitor); layer->ExecuteStrategy(visitor); } @@ -175,13 +187,21 @@ TEST_CASE("CheckConvolution2dLayerWithBiases") std::vector<float> biasData = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}; std::vector<unsigned int> biasDimensions = {1, 1, 3, 3}; ConstTensor biases(TensorInfo(4, biasDimensions.data(), DataType::Float32, 0.0f, 0, true), biasData); - Optional<ConstTensor> optionalBiases(biases); - TestConvolution2dLayerVisitor visitor(descriptor, weights, optionalBiases); + TestConstantLayerVisitor weightsVisitor(weights); + TestConstantLayerVisitor biasVisitor(biases); + TestConvolution2dLayerVisitor visitor(descriptor); NetworkImpl net; + IConnectableLayer* const weightsLayer = net.AddConstantLayer(weights); + IConnectableLayer* const biasLayer = net.AddConstantLayer(biases); + IConnectableLayer* const layer = net.AddConvolution2dLayer(descriptor); - IConnectableLayer* const layer = net.AddConvolution2dLayer(descriptor, weights, optionalBiases); + weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1)); + biasLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(2)); + + biasLayer->ExecuteStrategy(biasVisitor); + weightsLayer->ExecuteStrategy(weightsVisitor); layer->ExecuteStrategy(visitor); } @@ -205,13 +225,21 @@ TEST_CASE("CheckNamedConvolution2dLayerWithBiases") std::vector<float> biasData = {1.0, 2.0, 3.0, 4.0, 5.0, 6.0, 7.0, 8.0, 9.0}; std::vector<unsigned int> biasDimensions = {1, 1, 3, 3}; ConstTensor biases(TensorInfo(4, biasDimensions.data(), DataType::Float32, 0.0f, 0, true), biasData); - Optional<ConstTensor> optionalBiases(biases); - TestConvolution2dLayerVisitor visitor(descriptor, weights, optionalBiases, layerName); + TestConstantLayerVisitor weightsVisitor(weights); + TestConstantLayerVisitor biasVisitor(biases); + TestConvolution2dLayerVisitor visitor(descriptor, layerName); NetworkImpl net; + IConnectableLayer* const weightsLayer = net.AddConstantLayer(weights); + IConnectableLayer* const biasLayer = net.AddConstantLayer(biases); + IConnectableLayer* const layer = net.AddConvolution2dLayer(descriptor, layerName); - IConnectableLayer* const layer = net.AddConvolution2dLayer(descriptor, weights, optionalBiases, layerName); + weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1)); + biasLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(2)); + + biasLayer->ExecuteStrategy(biasVisitor); + weightsLayer->ExecuteStrategy(weightsVisitor); layer->ExecuteStrategy(visitor); } diff --git a/src/armnn/test/ConstTensorLayerVisitor.hpp b/src/armnn/test/ConstTensorLayerVisitor.hpp index 00d17b4ae8..1f1b3f5262 100644 --- a/src/armnn/test/ConstTensorLayerVisitor.hpp +++ b/src/armnn/test/ConstTensorLayerVisitor.hpp @@ -21,22 +21,18 @@ class TestConvolution2dLayerVisitor : public TestLayerVisitor { 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) {} virtual ~TestConvolution2dLayerVisitor() {} void ExecuteStrategy(const armnn::IConnectableLayer* layer, - const armnn::BaseDescriptor& descriptor, - const std::vector<armnn::ConstTensor>& constants, - const char* name, - const armnn::LayerBindingId id = 0) override + const armnn::BaseDescriptor& descriptor, + const std::vector<armnn::ConstTensor>& constants, + const char* name, + const armnn::LayerBindingId id = 0) override { armnn::IgnoreUnused(descriptor, constants, id); switch (layer->GetType()) @@ -46,12 +42,6 @@ public: CheckLayerPointer(layer); CheckLayerName(name); CheckDescriptor(static_cast<const armnn::Convolution2dDescriptor&>(descriptor)); - CheckConstTensors(m_Weights, constants[0]); - if (m_Biases.has_value()) - { - CHECK(constants.size() == 2); - CheckConstTensors(m_Biases.value(), constants[1]); - } break; } default: @@ -66,8 +56,6 @@ protected: private: Convolution2dDescriptor m_Descriptor; - ConstTensor m_Weights; - Optional<ConstTensor> m_Biases; }; class TestDepthwiseConvolution2dLayerVisitor : public TestLayerVisitor diff --git a/src/armnn/test/NetworkTests.cpp b/src/armnn/test/NetworkTests.cpp index c64c0a0d40..7756f40623 100644 --- a/src/armnn/test/NetworkTests.cpp +++ b/src/armnn/test/NetworkTests.cpp @@ -77,18 +77,18 @@ TEST_CASE("NetworkModification") armnn::ConstTensor weights(armnn::TensorInfo(4, dims, armnn::DataType::Float32, 0.0f, 0, true), convWeightsData); armnn::Convolution2dDescriptor convDesc2d; - armnn::IConnectableLayer* const convLayer = net.AddConvolution2dLayer(convDesc2d, - weights, - armnn::EmptyOptional(), - "conv layer"); + armnn::IConnectableLayer* const weightsLayer = net.AddConstantLayer(weights, "conv const weights"); + armnn::IConnectableLayer* const convLayer = net.AddConvolution2dLayer(convDesc2d, "conv layer"); CHECK(convLayer); + CHECK(weightsLayer); inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0)); + weightsLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(1)); armnn::FullyConnectedDescriptor fullyConnectedDesc; // Constant layer that now holds weights data for FullyConnected - armnn::IConnectableLayer* const constantWeightsLayer = net.AddConstantLayer(weights, "const weights"); + armnn::IConnectableLayer* const constantWeightsLayer = net.AddConstantLayer(weights, "fc const weights"); armnn::IConnectableLayer* const fullyConnectedLayer = net.AddFullyConnectedLayer(fullyConnectedDesc, "fully connected"); CHECK(constantWeightsLayer); @@ -155,12 +155,13 @@ TEST_CASE("NetworkModification") multiplicationLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); //Tests that all layers are present in the graph. - CHECK(net.GetGraph().GetNumLayers() == 12); + CHECK(net.GetGraph().GetNumLayers() == 13); //Tests that the vertices exist and have correct names. CHECK(GraphHasNamedLayer(net.GetGraph(), "input layer")); CHECK(GraphHasNamedLayer(net.GetGraph(), "conv layer")); - CHECK(GraphHasNamedLayer(net.GetGraph(), "const weights")); + CHECK(GraphHasNamedLayer(net.GetGraph(), "conv const weights")); + CHECK(GraphHasNamedLayer(net.GetGraph(), "fc const weights")); CHECK(GraphHasNamedLayer(net.GetGraph(), "fully connected")); CHECK(GraphHasNamedLayer(net.GetGraph(), "pooling2d")); CHECK(GraphHasNamedLayer(net.GetGraph(), "activation")); @@ -239,8 +240,8 @@ TEST_CASE("NetworkModification") CHECK(AreAllLayerInputSlotsConnected(*outputLayer)); // Checks connectivity. - checkOneOutputToOneInputConnection(inputLayer, convLayer, 0); - checkOneOutputToTwoInputConnectionForTwoDifferentLayers(convLayer, constantWeightsLayer, fullyConnectedLayer, 1, 0); + checkOneOutputToTwoInputConnectionForTwoDifferentLayers(inputLayer, weightsLayer, convLayer, 0, 0); + checkOneOutputToTwoInputConnectionForTwoDifferentLayers(convLayer, constantWeightsLayer, fullyConnectedLayer, 2, 0); checkOneOutputToOneInputConnection(fullyConnectedLayer, poolingLayer, 2, 1); checkOneOutputToOneInputConnection(poolingLayer, activationLayer); checkOneOutputToOneInputConnection(activationLayer, normalizationLayer); @@ -619,10 +620,12 @@ TEST_CASE("ObtainConv2DDescriptorFromIConnectableLayer") convDesc2d.m_DilationY = 3; convDesc2d.m_BiasEnabled = false; convDesc2d.m_DataLayout = armnn::DataLayout::NCHW; + ARMNN_NO_DEPRECATE_WARN_BEGIN armnn::IConnectableLayer* const convLayer = net.AddConvolution2dLayer(convDesc2d, weights, armnn::EmptyOptional(), "conv layer"); + ARMNN_NO_DEPRECATE_WARN_END CHECK(convLayer); const armnn::BaseDescriptor& descriptor = convLayer->GetParameters(); diff --git a/src/armnn/test/OptimizerTests.cpp b/src/armnn/test/OptimizerTests.cpp index 6a13dc6456..3dd55279c6 100644 --- a/src/armnn/test/OptimizerTests.cpp +++ b/src/armnn/test/OptimizerTests.cpp @@ -441,6 +441,11 @@ void CreateConvolution2dGraph(Graph &graph, const unsigned int* inputShape, Layer* input = graph.AddLayer<InputLayer>(0, "input"); input->GetOutputSlot().SetTensorInfo(inputInfo); + ConstantLayer* weightsLayer = nullptr; + weightsLayer = graph.AddLayer<ConstantLayer>("Weights"); + weightsLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(weights); + weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsLayer->m_LayerOutput->GetTensorInfo()); + Convolution2dLayer* layer = graph.AddLayer<Convolution2dLayer>(desc, "conv2d"); layer->m_Weight = std::make_unique<armnn::ScopedTensorHandle>(weights); layer->GetOutputSlot().SetTensorInfo(outputInfo); @@ -448,6 +453,7 @@ void CreateConvolution2dGraph(Graph &graph, const unsigned int* inputShape, Layer* output = graph.AddLayer<OutputLayer>(0, "output"); input->GetOutputSlot().Connect(layer->GetInputSlot(0)); layer->GetOutputSlot().Connect(output->GetInputSlot(0)); + weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1)); } TEST_CASE("Conv2dValidateTensorShapesFromInputs") @@ -875,40 +881,70 @@ TEST_CASE("OptimizeForExclusiveConnectionsFuseTest") ConstTensor mean(TensorInfo(1, outputChannelSize, DataType::Float32, 0.0f, 0, true), meanVector); ConstTensor variance(TensorInfo(1, outputChannelSize, DataType::Float32, 0.0f, 0, true), varianceVector); + ConstantLayer* biasLayer = nullptr; + // Define the network Graph graph; auto input = graph.AddLayer<InputLayer>(0, "input"); + auto weightsLayer = graph.AddLayer<ConstantLayer>("Weights"); auto conv = graph.AddLayer<Convolution2dLayer>(convolution2dDescriptor, "convolution"); auto batchNorm = graph.AddLayer<BatchNormalizationLayer>(batchNormDescriptor, "batchNorm"); auto output = graph.AddLayer<OutputLayer>(0, "output"); // Set layer information input->GetOutputSlot().SetTensorInfo(inputInfo); + + weightsLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(weights); + weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsLayer->m_LayerOutput->GetTensorInfo()); conv->GetOutputSlot().SetTensorInfo(outputInfo); + batchNorm->GetOutputSlot().SetTensorInfo(outputInfo); - conv->m_Weight = std::make_unique<ScopedTensorHandle>(weights); batchNorm->m_Beta = std::make_unique<ScopedTensorHandle>(beta); batchNorm->m_Gamma = std::make_unique<ScopedTensorHandle>(gamma); batchNorm->m_Mean = std::make_unique<ScopedTensorHandle>(mean); batchNorm->m_Variance = std::make_unique<ScopedTensorHandle>(variance); + if (convolution2dDescriptor.m_BiasEnabled) { std::vector<float> biasVector = { 11 }; ConstTensor bias(TensorInfo(1, outputChannelSize, DataType::Float32, 0.0f, 0, true), biasVector); - conv->m_Bias = std::make_unique<ScopedTensorHandle>(bias); + biasLayer =graph.AddLayer<ConstantLayer>("Bias"); + biasLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(bias); + biasLayer->GetOutputSlot(0).SetTensorInfo(biasLayer->m_LayerOutput->GetTensorInfo()); + biasLayer->GetOutputSlot(0).Connect(conv->GetInputSlot(2)); + conv->m_Bias = biasLayer->m_LayerOutput; } // Connect layers input->GetOutputSlot(0).Connect(conv->GetInputSlot(0)); + weightsLayer->GetOutputSlot(0).Connect(conv->GetInputSlot(1)); conv->GetOutputSlot(0).Connect(batchNorm->GetInputSlot(0)); batchNorm->GetOutputSlot(0).Connect(output->GetInputSlot(0)); - CHECK(4 == graph.GetNumLayers()); - CHECK(CheckSequence(graph.cbegin(), graph.cend(), - &IsLayerOfType<InputLayer>, - &IsLayerOfType<Convolution2dLayer>, - &IsLayerOfType<BatchNormalizationLayer>, - &IsLayerOfType<OutputLayer>)); + // Temporary workaround to ensure the descriptor weights are populated + conv->m_Weight = weightsLayer->m_LayerOutput; + + if (convolution2dDescriptor.m_BiasEnabled) + { + CHECK(6 == graph.GetNumLayers()); + CHECK(CheckSequence(graph.cbegin(), graph.cend(), + &IsLayerOfType<InputLayer>, + &IsLayerOfType<ConstantLayer>, + &IsLayerOfType<ConstantLayer>, + &IsLayerOfType<Convolution2dLayer>, + &IsLayerOfType<BatchNormalizationLayer>, + &IsLayerOfType<OutputLayer>)); + } + else + { + CHECK(5 == graph.GetNumLayers()); + CHECK(CheckSequence(graph.cbegin(), graph.cend(), + &IsLayerOfType<InputLayer>, + &IsLayerOfType<ConstantLayer>, + &IsLayerOfType<Convolution2dLayer>, + &IsLayerOfType<BatchNormalizationLayer>, + &IsLayerOfType<OutputLayer>)); + } // Optimize graph armnn::Optimizer::Pass(graph, MakeOptimizations(FuseBatchNormIntoConvolution2DFloat32())); @@ -918,11 +954,13 @@ TEST_CASE("OptimizeForExclusiveConnectionsFuseTest") (layer->GetNameStr() == "fused-batchNorm-into-convolution"); }; - CHECK(3 == graph.GetNumLayers()); + CHECK(5 == graph.GetNumLayers()); CHECK(CheckSequence(graph.cbegin(), graph.cend(), - &IsLayerOfType<InputLayer>, - checkFusedConv2d, - &IsLayerOfType<OutputLayer>)); + &IsLayerOfType<InputLayer>, + &IsLayerOfType<ConstantLayer>, + &IsLayerOfType<ConstantLayer>, + checkFusedConv2d, + &IsLayerOfType<OutputLayer>)); } // Tests that OptimizeForExclusiveConnections works, not fusing when not needed, using BatchNorm fusing as example diff --git a/src/armnn/test/ShapeInferenceTests.cpp b/src/armnn/test/ShapeInferenceTests.cpp index d45c9900c0..a3800ade09 100644 --- a/src/armnn/test/ShapeInferenceTests.cpp +++ b/src/armnn/test/ShapeInferenceTests.cpp @@ -275,8 +275,6 @@ TEST_CASE("Convolution2dTest") { const TensorShape inputShape{1, 1, 10, 10}; - Graph graph; - Convolution2dDescriptor descriptor; descriptor.m_PadLeft = 0; @@ -288,16 +286,9 @@ TEST_CASE("Convolution2dTest") descriptor.m_DilationX = 3; descriptor.m_DilationY = 3; - auto layer = BuildGraph<Convolution2dLayer>(&graph, - {inputShape}, - descriptor, - "conv2d"); - - const float Datum = 0.0f; - ConstTensor weights({{1, 1, 3, 3}, DataType::Float32, 0.0f, 0, true}, &Datum); - layer->m_Weight = std::make_unique<ScopedTensorHandle>(weights); - - RunShapeInferenceTest<Convolution2dLayer>(layer, {{ 1, 1, 4, 4 }}); + CreateGraphAndRunTest<Convolution2dLayer>({ inputShape, { 1, 1, 3, 3 } }, + { { 1, 1, 4, 4 } }, descriptor, + "convd"); } TEST_CASE("DebugLayerTest") diff --git a/src/armnn/test/SubgraphViewTests.cpp b/src/armnn/test/SubgraphViewTests.cpp index 048c4f51fd..d7465c8361 100644 --- a/src/armnn/test/SubgraphViewTests.cpp +++ b/src/armnn/test/SubgraphViewTests.cpp @@ -42,28 +42,44 @@ bool AreAnySubgraphLayersPresentInGraph(const SubgraphView::IConnectableLayers & // // this helper only works if all layers where the inputs connect to are not selected // -SubgraphView::InputSlots CreateInputsFrom(const std::vector<Layer*>& layers) +SubgraphView::InputSlots CreateInputsFrom(const std::vector<Layer*>& layers, + std::vector<int> ignoreSlots = {}) { SubgraphView::InputSlots result; for (auto&& layer : layers) { for (auto&& it = layer->BeginInputSlots(); it != layer->EndInputSlots(); ++it) { - result.push_back(&(*it)); + if (std::find(ignoreSlots.begin(), ignoreSlots.end(), it->GetSlotIndex()) != ignoreSlots.end()) + { + continue; + } + else + { + result.push_back(&(*it)); + } } } return result; } /// Duplication for IConnectableLayer -SubgraphView::IInputSlots CreateIInputsFrom(const std::vector<armnn::IConnectableLayer*>& layers) +SubgraphView::IInputSlots CreateIInputsFrom(const std::vector<armnn::IConnectableLayer*>& layers, + std::vector<int> ignoreSlots = {}) { SubgraphView::IInputSlots result; - for (auto&& layer : layers) + for (auto&& layer: layers) { - for (unsigned int i = 0 ; i < layer->GetNumInputSlots(); ++i) + for (unsigned int i = 0; i < layer->GetNumInputSlots(); ++i) { - result.push_back(&(layer->GetInputSlot(i))); + if (std::find(ignoreSlots.begin(), ignoreSlots.end(), i) != ignoreSlots.end()) + { + continue; + } + else + { + result.push_back(&(layer->GetInputSlot(i))); + } } } return result; @@ -241,7 +257,7 @@ TEST_CASE("SubgraphViewSlots") // Construct sub-graph SubgraphViewSelector::SubgraphViewPtr subgraph = CreateSubgraphViewFrom({}, - CreateIInputsFrom({convLayer1}), + CreateIInputsFrom({convLayer1}, {1, 2}), CreateIOutputsFrom({convLayer2})); // Test that both old and new are initialized @@ -327,17 +343,20 @@ TEST_CASE("SingleInputSingleOutput") Convolution2dDescriptor convDescriptor; Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1"); Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2"); - + Layer* const weightsLayer1 = graph.AddLayer<ConstantLayer>("weights1"); + Layer* const weightsLayer2 = graph.AddLayer<ConstantLayer>("weights2"); Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, "output"); inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0)); + weightsLayer1->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(1)); convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0)); + weightsLayer2->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(1)); convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Construct sub-graph SubgraphViewSelector::SubgraphViewPtr subgraph = CreateSubgraphViewFrom({}, - CreateIInputsFrom({convLayer1}), + CreateIInputsFrom({convLayer1}, {1}), CreateIOutputsFrom({convLayer2})); // Save sub-graph connections for comparison after substitution @@ -377,7 +396,7 @@ TEST_CASE("SingleInputSingleOutputAddPrecompiledLayerSubstituteSubgraph1") convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Construct sub-graph - SubgraphViewSelector::SubgraphViewPtr subgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}), + SubgraphViewSelector::SubgraphViewPtr subgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}, {1}), CreateOutputsFrom({convLayer2}), {}); @@ -421,7 +440,7 @@ TEST_CASE("SingleInputSingleOutputAddPrecompiledLayerSubstituteSubgraph2") convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Construct sub-graph - SubgraphViewSelector::SubgraphViewPtr subgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}), + SubgraphViewSelector::SubgraphViewPtr subgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}, {1}), CreateOutputsFrom({convLayer2}), {}); @@ -467,7 +486,7 @@ TEST_CASE("SingleInputSingleOutputSubstituteGraph") // Construct sub-graph SubgraphViewSelector::SubgraphViewPtr subgraph = - CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}), + CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}, {1}), CreateOutputsFrom({convLayer2}), {}); @@ -519,7 +538,7 @@ TEST_CASE("MultiInputSingleOutput") concatLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // Construct sub-graph - auto subgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1, convLayer2}), + auto subgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1, convLayer2}, {1}), CreateOutputsFrom({concatLayer}), {}); @@ -621,7 +640,7 @@ TEST_CASE("MultiInputMultiOutput") // Construct sub-graph SubgraphViewSelector::SubgraphViewPtr subgraph = - CreateSubgraphViewFrom(CreateInputsFrom({convLayer1, convLayer2}), + CreateSubgraphViewFrom(CreateInputsFrom({convLayer1, convLayer2}, {1}), CreateOutputsFrom({convLayer1, convLayer2}), {}); @@ -942,7 +961,8 @@ TEST_CASE("MultipleSimpleSubgraphs") // This test case represents the scenario when we have two distinct subgraphs // in a simple linear network. The selected nodes are the M* and the // non-selected ones are the X* - // + // W2 ->-> + // | // X1 -> M1 -> M2 -> X2 -> M3 -> X3 // // The expected results is two subgraphs, one with {M1, M2} and another one @@ -952,12 +972,17 @@ TEST_CASE("MultipleSimpleSubgraphs") // the graph is constructed in reverse order auto x3 = graph.AddLayer<OutputLayer>(0, "output"); + auto m3 = graph.InsertNewLayer<ActivationLayer>(x3->GetInputSlot(0), ActivationDescriptor{}, "m3"); + auto x2 = graph.InsertNewLayer<Convolution2dLayer>(m3->GetInputSlot(0), - Convolution2dDescriptor{}, - "x2"); + Convolution2dDescriptor{}, + "x2"); + + auto w2 = graph.InsertNewLayer<ConstantLayer>(x2->GetInputSlot(1), "w2"); + auto m2 = graph.InsertNewLayer<ActivationLayer>(x2->GetInputSlot(0), ActivationDescriptor{}, "m2"); @@ -966,6 +991,7 @@ TEST_CASE("MultipleSimpleSubgraphs") "m1"); graph.InsertNewLayer<InputLayer>(m1->GetInputSlot(0), 0, "x1"); + IgnoreUnused(w2); // All selected 'M*' layers will be of Activation type SubgraphViewSelector::Subgraphs subgraphs = SubgraphViewSelector::SelectSubgraphs( @@ -1636,10 +1662,17 @@ TEST_CASE("SingleSubgraph") Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2"); convLayer2->SetBackendId(Compute::GpuAcc); + Layer* const weights1 = graph.AddLayer<ConstantLayer>("weights1"); + weights1->SetBackendId(Compute::GpuAcc); + Layer* const weights2 = graph.AddLayer<ConstantLayer>("weights2"); + weights2->SetBackendId(Compute::GpuAcc); + Layer* const outputLayer = graph.AddLayer<OutputLayer>(0, "output"); inputLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0)); + weights1->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(1)); convLayer1->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(0)); + weights2->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(1)); convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); // GpuAcc sub graph selector @@ -1702,6 +1735,9 @@ TEST_CASE("MultipleSubgraphs") Layer* const convLayer1 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1"); Layer* const convLayer2 = graph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2"); + Layer* const weights1 = graph.AddLayer<ConstantLayer>("weights1"); + Layer* const weights2 = graph.AddLayer<ConstantLayer>("weights2"); + OriginsDescriptor concatDescriptor(2); Layer* const pConcatLayer = graph.AddLayer<ConcatLayer>(concatDescriptor, "concat"); pConcatLayer->SetBackendId(Compute::CpuAcc); @@ -1711,7 +1747,9 @@ TEST_CASE("MultipleSubgraphs") inputLayer->GetOutputSlot(0).Connect(splitterLayer->GetInputSlot(0)); splitterLayer->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(0)); splitterLayer->GetOutputSlot(1).Connect(convLayer2->GetInputSlot(0)); + weights1->GetOutputSlot(0).Connect(convLayer1->GetInputSlot(1)); convLayer1->GetOutputSlot(0).Connect(pConcatLayer->GetInputSlot(0)); + weights2->GetOutputSlot(0).Connect(convLayer2->GetInputSlot(1)); convLayer2->GetOutputSlot(0).Connect(pConcatLayer->GetInputSlot(1)); pConcatLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0)); diff --git a/src/armnn/test/optimizations/FoldPadTests.cpp b/src/armnn/test/optimizations/FoldPadTests.cpp index 9919c6d0e6..027b10377d 100644 --- a/src/armnn/test/optimizations/FoldPadTests.cpp +++ b/src/armnn/test/optimizations/FoldPadTests.cpp @@ -47,6 +47,12 @@ TEST_CASE("FoldPadLayerIntoConvolution2dLayer") std::vector<float> weightsVector(18); ConstTensor weights(TensorInfo(4, weightsShape, DataType::Float32, 0.0f, 0, true), weightsVector); + ConstantLayer* weightsLayer = graph.AddLayer<ConstantLayer>("Weights"); + weightsLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(weights); + + TensorInfo weightsInfo = weightsLayer->m_LayerOutput->GetTensorInfo(); + weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsInfo); + Convolution2dLayer* conv2dLayer = graph.AddLayer<Convolution2dLayer>(convolution2dDescriptor, "conv2d"); conv2dLayer->m_Weight = std::make_unique<ScopedTensorHandle>(weights); conv2dLayer->GetOutputSlot().SetTensorInfo(outputInfo); @@ -56,6 +62,7 @@ TEST_CASE("FoldPadLayerIntoConvolution2dLayer") // Connect up layers - input -> pad -> conv2d -> output input->GetOutputSlot().Connect(padLayer->GetInputSlot(0)); padLayer->GetOutputSlot().Connect(conv2dLayer->GetInputSlot(0)); + weightsLayer->GetOutputSlot().Connect(conv2dLayer->GetInputSlot(1)); conv2dLayer->GetOutputSlot().Connect(output->GetInputSlot(0)); auto checkSimpleConv2d = [](const Layer* const layer)->bool { @@ -69,10 +76,11 @@ TEST_CASE("FoldPadLayerIntoConvolution2dLayer") }; CHECK(CheckSequence(graph.cbegin(), graph.cend(), - &IsLayerOfType<InputLayer>, - &IsLayerOfType<PadLayer>, - checkSimpleConv2d, - &IsLayerOfType<OutputLayer>)); + &IsLayerOfType<InputLayer>, + &IsLayerOfType<PadLayer>, + &IsLayerOfType<ConstantLayer>, + checkSimpleConv2d, + &IsLayerOfType<OutputLayer>)); armnn::Optimizer::Pass(graph, armnn::MakeOptimizations(FoldPadIntoConvolution2d())); @@ -87,9 +95,10 @@ TEST_CASE("FoldPadLayerIntoConvolution2dLayer") }; CHECK(CheckSequence(graph.cbegin(), graph.cend(), - &IsLayerOfType<InputLayer>, - checkPadFoldedIntoConv2d, - &IsLayerOfType<OutputLayer>)); + &IsLayerOfType<InputLayer>, + checkPadFoldedIntoConv2d, + &IsLayerOfType<ConstantLayer>, + &IsLayerOfType<OutputLayer>)); } TEST_CASE("FoldPadLayerIntoDepthwiseConvolution2dLayer") @@ -628,12 +637,12 @@ TEST_CASE("FoldPadLayerIntoConv2dLayer_ExecuteInferenceWithAndWithoutOptimizatio TensorInfo biasInfo({4}, DataType::Float32, 0.0f, 0, true); ConstTensor bias(biasInfo, biasVector); Optional<ConstTensor> optionalBias = Optional<ConstTensor>(bias); - + ARMNN_NO_DEPRECATE_WARN_BEGIN IConnectableLayer* conv2dLayer = network->AddConvolution2dLayer(convDescriptor, weights, optionalBias, "Conv2D"); - + ARMNN_NO_DEPRECATE_WARN_END TensorInfo outputInfo(4, outputShape, DataType::Float32); conv2dLayer->GetOutputSlot(0).SetTensorInfo(outputInfo); diff --git a/src/armnn/test/optimizations/FuseActivationTests.cpp b/src/armnn/test/optimizations/FuseActivationTests.cpp index e5f54208f0..0cca86f93b 100644 --- a/src/armnn/test/optimizations/FuseActivationTests.cpp +++ b/src/armnn/test/optimizations/FuseActivationTests.cpp @@ -42,7 +42,7 @@ struct Convolution2dTest { using LayerType = Convolution2dLayer; static const bool isElementWise = false; - static const bool isConstTensorAsInputSupported = false; + static const bool isConstTensorAsInputSupported = true; static TensorShape GetInputShape() { return TensorShape( {1, 4, 4, 3}); } // NHWCin static TensorShape GetOutputShape() { return TensorShape( {1, 3, 3, 4}); } // NHWCout @@ -69,8 +69,9 @@ struct Convolution2dTest TensorInfo weightsInfo(GetWeightsShape(), ArmnnType, scale, offset, true); ConstTensor weights(weightsInfo, weightsVector); Optional<ConstTensor> optionalBias; - + ARMNN_NO_DEPRECATE_WARN_BEGIN return network->AddConvolution2dLayer(descriptor, weights, optionalBias, name); + ARMNN_NO_DEPRECATE_WARN_END } static std::vector<IConnectableLayer*> AddConstantLayers(INetwork* network, diff --git a/src/armnn/test/optimizations/FuseBatchNormTests.cpp b/src/armnn/test/optimizations/FuseBatchNormTests.cpp index b28bb17773..4a94f7889b 100644 --- a/src/armnn/test/optimizations/FuseBatchNormTests.cpp +++ b/src/armnn/test/optimizations/FuseBatchNormTests.cpp @@ -24,7 +24,6 @@ class Conv2dTest public: using ConvDescriptorType = armnn::Convolution2dDescriptor; using ConvLayerType = armnn::Convolution2dLayer; - static const bool isConstTensorAsInputSupported = false; static IConnectableLayer *AddConvolution(INetwork *network, const Convolution2dDescriptor &descriptor, @@ -32,7 +31,9 @@ public: const Optional<ConstTensor> &biases, const char *name) { + ARMNN_NO_DEPRECATE_WARN_BEGIN return network->AddConvolution2dLayer(descriptor, weights, biases, name); + ARMNN_NO_DEPRECATE_WARN_END } static std::vector<IConnectableLayer*> AddConstantLayers(INetwork *network, @@ -54,13 +55,12 @@ class DepthwiseConv2dTest public: using ConvDescriptorType = armnn::DepthwiseConvolution2dDescriptor; using ConvLayerType = armnn::DepthwiseConvolution2dLayer; - static const bool isConstTensorAsInputSupported = true; - static IConnectableLayer *AddConvolution(INetwork *network, - const DepthwiseConvolution2dDescriptor &descriptor, - const ConstTensor &weights, - const Optional<ConstTensor> &biases, - const char *name) + static IConnectableLayer* AddConvolution(INetwork* network, + const DepthwiseConvolution2dDescriptor& descriptor, + const ConstTensor& weights, + const Optional<ConstTensor>& biases, + const char* name) { IgnoreUnused(weights); IgnoreUnused(biases); @@ -183,19 +183,15 @@ INetworkPtr CreateNetwork(bool depthwise, bool preventFusing) output2Layer = network->AddOutputLayer(1); } - // If ConstTensorAsInputs is supported weights and bias are stored as constant layers. - if (Conv2dTest::isConstTensorAsInputSupported) - { - std::vector<IConnectableLayer*> constantLayers = Conv2dTest::AddConstantLayers(network.get(), - convolution2dDescriptor, - weights, - Optional<ConstTensor>()); + std::vector<IConnectableLayer*> constantLayers = Conv2dTest::AddConstantLayers(network.get(), + convolution2dDescriptor, + weights, + Optional<ConstTensor>()); - // Connect constant layers to receiverLayer. - for (unsigned int i = 0; i < constantLayers.size(); ++i) - { - constantLayers[i]->GetOutputSlot(0).Connect(convLayer->GetInputSlot(i + 1)); - } + // Connect constant layers to receiverLayer. + for (unsigned int i = 0; i < constantLayers.size(); ++i) + { + constantLayers[i]->GetOutputSlot(0).Connect(convLayer->GetInputSlot(i + 1)); } // Set layer information @@ -241,26 +237,14 @@ void FuseBatchNormIntoConvTest(bool depthwise, float tolerance, armnn::Compute b (layer->GetNameStr() == "fused-batchNorm-into-convolution"); }; - if (Conv2dTest::isConstTensorAsInputSupported) - { - CHECK(5 == graphFused.GetNumLayers()); - CHECK(CheckSequence(graphFused.cbegin(), - graphFused.cend(), - &IsLayerOfType<InputLayer>, - &IsLayerOfType<ConstantLayer>, - &IsLayerOfType<ConstantLayer>, - checkFusedConv2d, - &IsLayerOfType<OutputLayer>)); - } - else - { - CHECK(3 == graphFused.GetNumLayers()); - CHECK(CheckSequence(graphFused.cbegin(), - graphFused.cend(), - &IsLayerOfType<InputLayer>, - checkFusedConv2d, - &IsLayerOfType<OutputLayer>)); - } + CHECK(5 == graphFused.GetNumLayers()); + CHECK(CheckSequence(graphFused.cbegin(), + graphFused.cend(), + &IsLayerOfType<InputLayer>, + &IsLayerOfType<ConstantLayer>, + &IsLayerOfType<ConstantLayer>, + checkFusedConv2d, + &IsLayerOfType<OutputLayer>)); // Load network into runtime NetworkId networkIdentifier; @@ -278,10 +262,10 @@ void FuseBatchNormIntoConvTest(bool depthwise, float tolerance, armnn::Compute b TensorInfo inputTensorInfo = run->GetInputTensorInfo(networkIdentifier, 0); inputTensorInfo.SetConstant(true); - InputTensors inputTensorsFused { + InputTensors inputTensorsFused { {0, ConstTensor(inputTensorInfo, inputDataFused.data())}}; OutputTensors outputTensorsFused{ - {0, Tensor(run->GetOutputTensorInfo(networkIdentifier, 0), outputDataFused.data())}}; + {0, Tensor(run->GetOutputTensorInfo(networkIdentifier, 0), outputDataFused.data())}}; // Execute network run->EnqueueWorkload(networkIdentifier, inputTensorsFused, outputTensorsFused); @@ -294,33 +278,19 @@ void FuseBatchNormIntoConvTest(bool depthwise, float tolerance, armnn::Compute b IRuntimePtr runNotFused = IRuntime::Create(IRuntime::CreationOptions()); // default options // Optimise ArmNN network - IOptimizedNetworkPtr optNetNotFused = Optimize(*networkNotFused, {backendId}, runNotFused->GetDeviceSpec()); + IOptimizedNetworkPtr optNetNotFused = Optimize(*networkNotFused, { backendId }, runNotFused->GetDeviceSpec()); Graph& graphNotFused = GetGraphForTesting(optNetNotFused.get()); - if (Conv2dTest::isConstTensorAsInputSupported) - { - CHECK(6 == graphNotFused.GetNumLayers()); - CHECK(CheckSequence(graphNotFused.cbegin(), - graphNotFused.cend(), - &IsLayerOfType<armnn::InputLayer>, - &IsLayerOfType<armnn::ConstantLayer>, - &IsLayerOfType<ConvLayerType>, - &IsLayerOfType<armnn::BatchNormalizationLayer>, - &IsLayerOfType<armnn::OutputLayer>, - &IsLayerOfType<armnn::OutputLayer>)); - } - else - { - CHECK(5 == graphNotFused.GetNumLayers()); - CHECK(CheckSequence(graphNotFused.cbegin(), - graphNotFused.cend(), - &IsLayerOfType<armnn::InputLayer>, - &IsLayerOfType<ConvLayerType>, - &IsLayerOfType<armnn::BatchNormalizationLayer>, - &IsLayerOfType<armnn::OutputLayer>, - &IsLayerOfType<armnn::OutputLayer>)); - } + CHECK(6 == graphNotFused.GetNumLayers()); + CHECK(CheckSequence(graphNotFused.cbegin(), + graphNotFused.cend(), + &IsLayerOfType<armnn::InputLayer>, + &IsLayerOfType<armnn::ConstantLayer>, + &IsLayerOfType<ConvLayerType>, + &IsLayerOfType<armnn::BatchNormalizationLayer>, + &IsLayerOfType<armnn::OutputLayer>, + &IsLayerOfType<armnn::OutputLayer>)); // Load network into runtime NetworkId networkIdentifierNotFused; @@ -341,10 +311,10 @@ void FuseBatchNormIntoConvTest(bool depthwise, float tolerance, armnn::Compute b TensorInfo inputTensorInfo2 = runNotFused->GetInputTensorInfo(networkIdentifierNotFused, 0); inputTensorInfo2.SetConstant(true); InputTensors inputTensorsNotFused{ - {0, ConstTensor(inputTensorInfo2, inputDataNotFused.data())}}; + { 0, ConstTensor(inputTensorInfo2, inputDataNotFused.data()) } }; OutputTensors outputTensorsNotFused{ - {0, Tensor(runNotFused->GetOutputTensorInfo(networkIdentifierNotFused, 0), outputDataNotFused.data())}, - {1, Tensor(runNotFused->GetOutputTensorInfo(networkIdentifierNotFused, 1), outputData2NotFused.data())}}; + { 0, Tensor(runNotFused->GetOutputTensorInfo(networkIdentifierNotFused, 0), outputDataNotFused.data()) }, + { 1, Tensor(runNotFused->GetOutputTensorInfo(networkIdentifierNotFused, 1), outputData2NotFused.data()) } }; // Execute network runNotFused->EnqueueWorkload(networkIdentifierNotFused, inputTensorsNotFused, outputTensorsNotFused); |