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
diff --git a/delegate/src/Convolution.hpp b/delegate/src/Convolution.hpp
index 3b23d6d..679f4db 100644
--- a/delegate/src/Convolution.hpp
+++ b/delegate/src/Convolution.hpp
@@ -160,29 +160,29 @@
         return isSupported ? kTfLiteOk : kTfLiteError;
     }
 
-    armnn::IConnectableLayer* layer = nullptr;
-
     // Set up filter and biases
+    armnn::IConnectableLayer* layer = delegateData.m_Network->AddConvolution2dLayer(descriptor);
+
     auto filter =
         CreateConstTensor(&tfLiteContext->tensors[tfLiteNode->inputs->data[1]],
                           filterTensorInfo,
                           armnn::Optional<armnn::PermutationVector&>());
 
-    if(biasEnabled)
+    armnn::IConnectableLayer* weightsLayer = delegateData.m_Network->AddConstantLayer(filter);
+    weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1u));
+    weightsLayer->GetOutputSlot(0).SetTensorInfo(filterTensorInfo);
+
+    if (biasEnabled)
     {
-        auto biases =
-            CreateConstTensor(&tfLiteContext->tensors[tfLiteNode->inputs->data[2]],
-                              biasTensorInfo,
-                              armnn::Optional<armnn::PermutationVector&>());
-        layer = delegateData.m_Network->AddConvolution2dLayer(descriptor,
-                                                              filter,
-                                                              armnn::Optional<armnn::ConstTensor>(biases));
-    }
-    else
-    {
-        layer = delegateData.m_Network->AddConvolution2dLayer(descriptor,
-                                                              filter,
-                                                              armnn::EmptyOptional());
+        const TfLiteTensor& tfLiteBiasTensor = tfLiteTensors[tfLiteNode->inputs->data[2]];
+        if(tflite::IsConstantTensor(&tfLiteBiasTensor))
+        {
+            auto biasTensor = CreateConstTensor(&tfLiteBiasTensor, biasTensorInfo);
+            armnn::IConnectableLayer* biasLayer = delegateData.m_Network->AddConstantLayer(biasTensor);
+            ARMNN_ASSERT(biasLayer != nullptr);
+            biasLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(2u));
+            biasLayer->GetOutputSlot(0).SetTensorInfo(biasTensorInfo);
+        }
     }
 
     ARMNN_ASSERT(layer != nullptr);
diff --git a/include/armnn/Descriptors.hpp b/include/armnn/Descriptors.hpp
index 4aa23a4..7f46c6a 100644
--- a/include/armnn/Descriptors.hpp
+++ b/include/armnn/Descriptors.hpp
@@ -524,6 +524,8 @@
                m_BiasEnabled == rhs.m_BiasEnabled &&
                m_DataLayout  == rhs.m_DataLayout;
     }
+    uint32_t GetNumInputs() const;
+
 
     /// Padding left value in the width dimension.
     uint32_t             m_PadLeft;
diff --git a/include/armnn/ILayerVisitor.hpp b/include/armnn/ILayerVisitor.hpp
index d5e3d11..a0c782e 100644
--- a/include/armnn/ILayerVisitor.hpp
+++ b/include/armnn/ILayerVisitor.hpp
@@ -102,9 +102,19 @@
     /// function is invoked.
     /// @param layer - pointer to the layer which is calling back to this visit function.
     /// @param convolution2dDescriptor - Description of the 2D convolution layer.
+    /// @param name - Optional name for the layer.
+    virtual void VisitConvolution2dLayer(const IConnectableLayer* layer,
+                                         const Convolution2dDescriptor& convolution2dDescriptor,
+                                         const char* name = nullptr) = 0;
+
+    /// Function that a 2D convolution layer should call back to when its Accept(ILayerVisitor&)
+    /// function is invoked.
+    /// @param layer - pointer to the layer which is calling back to this visit function.
+    /// @param convolution2dDescriptor - Description of the 2D convolution layer.
     /// @param weights - Tensor for the weights data.
     /// @param biases - Optional tensor for the bias data. If specified, must match the output tensor shape.
     /// @param name - Optional name for the layer.
+    ARMNN_DEPRECATED_MSG("Use VisitConvolution2dLayer without ConstTensors")
     virtual void VisitConvolution2dLayer(const IConnectableLayer* layer,
                                          const Convolution2dDescriptor& convolution2dDescriptor,
                                          const ConstTensor& weights,
diff --git a/include/armnn/INetwork.hpp b/include/armnn/INetwork.hpp
index 1d6276b..89b4776 100644
--- a/include/armnn/INetwork.hpp
+++ b/include/armnn/INetwork.hpp
@@ -42,7 +42,7 @@
 public:
     virtual unsigned int GetNumConnections() const = 0;
     virtual const IInputSlot* GetConnection(unsigned int index) const = 0;
-    virtual IInputSlot* GetConnection(unsigned int index) = 0;
+    virtual IInputSlot* GetConnection(unsigned int outputindex) = 0;
 
     virtual void SetTensorInfo(const TensorInfo& tensorInfo) = 0;
     virtual const TensorInfo& GetTensorInfo() const = 0;
@@ -293,10 +293,18 @@
 
     /// Adds a 2D convolution layer to the network.
     /// @param convolution2dDescriptor - Description of the 2D convolution layer.
+    /// @param name - Optional name for the layer.
+    /// @return - Interface for configuring the layer.
+    IConnectableLayer* AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor,
+                                             const char* name = nullptr);
+
+    /// Adds a 2D convolution layer to the network.
+    /// @param convolution2dDescriptor - Description of the 2D convolution layer.
     /// @param weights - Tensor for the weights data.
     /// @param biases - Optional tensor for the bias data. If specified, must match the output tensor shape.
     /// @param name - Optional name for the layer.
     /// @return - Interface for configuring the layer.
+    ARMNN_DEPRECATED_MSG_REMOVAL_DATE("This AddConvolution2dLayer overload is deprecated", "22.08")
     IConnectableLayer* AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor,
                                              const ConstTensor& weights,
                                              const Optional<ConstTensor>& biases,
@@ -331,9 +339,8 @@
     /// @param convolution2dDescriptor - Description of the 2D depthwise convolution layer.
     /// @param name - Optional name for the layer.
     /// @return - Interface for configuring the layer.
-    IConnectableLayer* AddDepthwiseConvolution2dLayer(
-        const DepthwiseConvolution2dDescriptor& convolution2dDescriptor,
-        const char* name = nullptr);
+    IConnectableLayer* AddDepthwiseConvolution2dLayer(const DepthwiseConvolution2dDescriptor& convolution2dDescriptor,
+                                                      const char* name = nullptr);
 
     /// Adds a 2D depthwise convolution layer to the network.
     /// @param convolution2dDescriptor - Description of the 2D depthwise convolution layer.
diff --git a/include/armnn/LayerVisitorBase.hpp b/include/armnn/LayerVisitorBase.hpp
index acc8aa0..025fca7 100644
--- a/include/armnn/LayerVisitorBase.hpp
+++ b/include/armnn/LayerVisitorBase.hpp
@@ -72,6 +72,10 @@
                                  const Optional<ConstTensor>&,
                                  const char*) override { DefaultPolicy::Apply(__func__); }
 
+    void VisitConvolution2dLayer(const IConnectableLayer*,
+                                 const Convolution2dDescriptor&,
+                                 const char*) override { DefaultPolicy::Apply(__func__); }
+
     void VisitDepthToSpaceLayer(const IConnectableLayer*,
                                 const DepthToSpaceDescriptor&,
                                 const char*) override { DefaultPolicy::Apply(__func__); }
diff --git a/src/armnn/BackendHelper.cpp b/src/armnn/BackendHelper.cpp
index 03f32ac..9f97c26 100644
--- a/src/armnn/BackendHelper.cpp
+++ b/src/armnn/BackendHelper.cpp
@@ -373,6 +373,31 @@
     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 d67d440..4eb875e 100644
--- a/src/armnn/Descriptors.cpp
+++ b/src/armnn/Descriptors.cpp
@@ -425,16 +425,10 @@
 
 }
 
-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 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 c1cec48..8500e52 100644
--- a/src/armnn/Graph.cpp
+++ b/src/armnn/Graph.cpp
@@ -603,16 +603,19 @@
     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 @@
         {
             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 @@
     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 a31119b..3241b50 100644
--- a/src/armnn/Layer.cpp
+++ b/src/armnn/Layer.cpp
@@ -23,16 +23,23 @@
 // 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 @@
         // 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 a88fa5a..228927d 100644
--- a/src/armnn/LoadedNetwork.cpp
+++ b/src/armnn/LoadedNetwork.cpp
@@ -330,10 +330,10 @@
 
                         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 @@
             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 d2ebd4c..479e57f 100644
--- a/src/armnn/Network.cpp
+++ b/src/armnn/Network.cpp
@@ -83,35 +83,23 @@
 
 
 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);
 }
 
-
+ARMNN_NO_DEPRECATE_WARN_BEGIN
 IConnectableLayer* INetwork::AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor,
-                                                   const ConstTensor& weights,
-                                                   const char* name)
+                                                    const ConstTensor& weights,
+                                                    const Optional<ConstTensor>& biases,
+                                                    const char* name)
 {
-    Optional<ConstTensor> biases;
-    return pNetworkImpl->AddConvolution2dLayer(convolution2dDescriptor, weights, biases, name);
-}
-
-
-IConnectableLayer* INetwork::AddConvolution2dLayer(const Convolution2dDescriptor& convolution2dDescriptor,
-                                                   const ConstTensor& weights,
-                                                   const 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 @@
     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");
-    }
+    return m_Graph->AddLayer<Convolution2dLayer>(convolution2dDescriptor, name);
+}
 
-    const auto layer = 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 @@
     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 c5ed8de..c2be600 100644
--- a/src/armnn/Network.hpp
+++ b/src/armnn/Network.hpp
@@ -71,6 +71,10 @@
                                       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 @@
     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 666ce3d..7597798 100644
--- a/src/armnn/NetworkUtils.cpp
+++ b/src/armnn/NetworkUtils.cpp
@@ -98,6 +98,15 @@
     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 6a4dbf8..ab4ecc9 100644
--- a/src/armnn/Tensor.cpp
+++ b/src/armnn/Tensor.cpp
@@ -362,9 +362,7 @@
                        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 ef5db8e..7b3382b 100644
--- a/src/armnn/layers/Convolution2dLayer.cpp
+++ b/src/armnn/layers/Convolution2dLayer.cpp
@@ -21,7 +21,7 @@
 {
 
 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 @@
     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 @@
 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)
     {
-        ARMNN_ASSERT_MSG(m_Bias != nullptr, "Convolution2dLayer: Bias data should not be null.");
+        descriptor.m_Weight = m_Weight.get();
+    }
+    if (m_Param.m_BiasEnabled && m_Bias)
+    {
         descriptor.m_Bias = m_Bias.get();
     }
 
@@ -120,18 +119,18 @@
 
 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 @@
 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 8447478..6bb86da 100644
--- a/src/armnn/layers/Convolution2dLayer.hpp
+++ b/src/armnn/layers/Convolution2dLayer.hpp
@@ -17,8 +17,10 @@
 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 @@
     /// 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 bbaabb8..eb6bc90 100644
--- a/src/armnn/optimizations/FoldPadIntoLayer2d.hpp
+++ b/src/armnn/optimizations/FoldPadIntoLayer2d.hpp
@@ -146,8 +146,22 @@
     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 @@
         {
             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 @@
 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 6a50fc4..bca0c7d 100644
--- a/src/armnn/optimizations/FuseBatchNorm.hpp
+++ b/src/armnn/optimizations/FuseBatchNorm.hpp
@@ -14,8 +14,8 @@
 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 @@
     /// 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 @@
         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 @@
             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 @@
             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 @@
             {
                 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 @@
             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 @@
             // 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 cb97a0f..4833774 100644
--- a/src/armnn/optimizations/RedirectMembersToConstantInputs.hpp
+++ b/src/armnn/optimizations/RedirectMembersToConstantInputs.hpp
@@ -29,6 +29,7 @@
             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 af0581c..701327b 100644
--- a/src/armnn/test/ConstTensorLayerVisitor.cpp
+++ b/src/armnn/test/ConstTensorLayerVisitor.cpp
@@ -119,16 +119,22 @@
     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 @@
     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 @@
     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 @@
     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 00d17b4..1f1b3f5 100644
--- a/src/armnn/test/ConstTensorLayerVisitor.hpp
+++ b/src/armnn/test/ConstTensorLayerVisitor.hpp
@@ -21,22 +21,18 @@
 {
 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 @@
                 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 @@
 
 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 c64c0a0..7756f40 100644
--- a/src/armnn/test/NetworkTests.cpp
+++ b/src/armnn/test/NetworkTests.cpp
@@ -77,18 +77,18 @@
     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 @@
     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 @@
     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 @@
     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 6a13dc6..3dd5527 100644
--- a/src/armnn/test/OptimizerTests.cpp
+++ b/src/armnn/test/OptimizerTests.cpp
@@ -441,6 +441,11 @@
     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 @@
     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 @@
     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 @@
                (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 d45c990..a3800ad 100644
--- a/src/armnn/test/ShapeInferenceTests.cpp
+++ b/src/armnn/test/ShapeInferenceTests.cpp
@@ -275,8 +275,6 @@
 {
     const TensorShape inputShape{1, 1, 10, 10};
 
-    Graph graph;
-
     Convolution2dDescriptor descriptor;
 
     descriptor.m_PadLeft = 0;
@@ -288,16 +286,9 @@
     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 048c4f5..d7465c8 100644
--- a/src/armnn/test/SubgraphViewTests.cpp
+++ b/src/armnn/test/SubgraphViewTests.cpp
@@ -42,28 +42,44 @@
 //
 // 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 @@
 
     // 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 @@
     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 @@
     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 @@
     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 @@
 
     // Construct sub-graph
     SubgraphViewSelector::SubgraphViewPtr subgraph =
-            CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
+            CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}, {1}),
                                    CreateOutputsFrom({convLayer2}),
                                    {});
 
@@ -519,7 +538,7 @@
     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 @@
 
     // Construct sub-graph
     SubgraphViewSelector::SubgraphViewPtr subgraph =
-            CreateSubgraphViewFrom(CreateInputsFrom({convLayer1, convLayer2}),
+            CreateSubgraphViewFrom(CreateInputsFrom({convLayer1, convLayer2}, {1}),
                                    CreateOutputsFrom({convLayer1, convLayer2}),
                                    {});
 
@@ -942,7 +961,8 @@
     // 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 @@
 
     // 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 @@
                                                     "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 @@
     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 @@
     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 @@
     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 9919c6d..027b103 100644
--- a/src/armnn/test/optimizations/FoldPadTests.cpp
+++ b/src/armnn/test/optimizations/FoldPadTests.cpp
@@ -47,6 +47,12 @@
     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 @@
     // 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 @@
     };
 
     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 @@
     };
 
     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 @@
         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 e5f5420..0cca86f 100644
--- a/src/armnn/test/optimizations/FuseActivationTests.cpp
+++ b/src/armnn/test/optimizations/FuseActivationTests.cpp
@@ -42,7 +42,7 @@
 {
     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 @@
         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 b28bb17..4a94f78 100644
--- a/src/armnn/test/optimizations/FuseBatchNormTests.cpp
+++ b/src/armnn/test/optimizations/FuseBatchNormTests.cpp
@@ -24,7 +24,6 @@
 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 @@
                                              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 @@
 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 @@
         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 @@
                (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 @@
 
     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 @@
     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 @@
     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);
diff --git a/src/armnnDeserializer/Deserializer.cpp b/src/armnnDeserializer/Deserializer.cpp
index 704b6c3..04dde73 100644
--- a/src/armnnDeserializer/Deserializer.cpp
+++ b/src/armnnDeserializer/Deserializer.cpp
@@ -1423,44 +1423,69 @@
     CHECK_LAYERS(graph, 0, layerIndex);
     auto inputs = GetInputs(graph, layerIndex);
     CHECK_LOCATION();
-    CHECK_VALID_SIZE(inputs.size(), 1);
 
     auto outputs = GetOutputs(graph, layerIndex);
     CHECK_VALID_SIZE(outputs.size(), 1);
 
-    auto serializerLayer = graph->layers()->Get(layerIndex)->layer_as_Convolution2dLayer();
+    auto flatBufferLayer = graph->layers()->Get(layerIndex)->layer_as_Convolution2dLayer();
+
     auto layerName = GetLayerName(graph, layerIndex);
-    auto serializerDescriptor = serializerLayer->descriptor();
+    auto flatbufferDescriptor = flatBufferLayer->descriptor();
 
     armnn::Convolution2dDescriptor descriptor;
-    descriptor.m_PadLeft = serializerDescriptor->padLeft();
-    descriptor.m_PadRight = serializerDescriptor->padRight();
-    descriptor.m_PadTop = serializerDescriptor->padTop();
-    descriptor.m_PadBottom = serializerDescriptor->padBottom();
-    descriptor.m_StrideX = serializerDescriptor->strideX();
-    descriptor.m_StrideY = serializerDescriptor->strideY();;
-    descriptor.m_DilationX = serializerDescriptor->dilationX();
-    descriptor.m_DilationY = serializerDescriptor->dilationY();;
-    descriptor.m_BiasEnabled = serializerDescriptor->biasEnabled();;
-    descriptor.m_DataLayout = ToDataLayout(serializerDescriptor->dataLayout());
+    descriptor.m_PadLeft = flatbufferDescriptor->padLeft();
+    descriptor.m_PadRight = flatbufferDescriptor->padRight();
+    descriptor.m_PadTop = flatbufferDescriptor->padTop();
+    descriptor.m_PadBottom = flatbufferDescriptor->padBottom();
+    descriptor.m_StrideX = flatbufferDescriptor->strideX();
+    descriptor.m_StrideY = flatbufferDescriptor->strideY();;
+    descriptor.m_DilationX = flatbufferDescriptor->dilationX();
+    descriptor.m_DilationY = flatbufferDescriptor->dilationY();;
+    descriptor.m_BiasEnabled = flatbufferDescriptor->biasEnabled();;
+    descriptor.m_DataLayout = ToDataLayout(flatbufferDescriptor->dataLayout());
 
-    armnn::ConstTensor weights = ToConstTensor(serializerLayer->weights());
-    armnn::ConstTensor biases;
+    armnn::IConnectableLayer* layer;
+    std::vector<unsigned int> ignoreSlots {};
 
-    armnn::Optional<armnn::ConstTensor> optionalBiases = armnn::EmptyOptional();
-    if (descriptor.m_BiasEnabled)
+    armnn::ConstTensor biasTensor;
+    // Weights and biases used to be always constant and were stored as members of the layer. This has changed and
+    // they are now passed as inputs. If they are constant then they will be stored in a ConstantLayer.
+    if (this->GetFeatureVersions(graph).m_ConstTensorsAsInputs <= 0)
     {
-        biases = ToConstTensor(serializerLayer->biases());
-        optionalBiases = armnn::Optional<armnn::ConstTensor>(biases);
+        // If the model stores weights and biases as members of the layer we have to read them from there
+        // but add them to their own ConstantLayer for compatibility
+        CHECK_VALID_SIZE(inputs.size(), 1);
+
+        layer = m_Network->AddConvolution2dLayer(descriptor,
+                                                 layerName.c_str());
+
+        armnn::ConstTensor weightsTensor = ToConstTensor(flatBufferLayer->weights());
+        auto weightsLayer = m_Network->AddConstantLayer(weightsTensor);
+        weightsLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(1u));
+        weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsTensor.GetInfo());
+        ignoreSlots.emplace_back(1u);
+
+        if (descriptor.m_BiasEnabled)
+        {
+            biasTensor = ToConstTensor(flatBufferLayer->biases());
+            auto biasLayer = m_Network->AddConstantLayer(biasTensor);
+            biasLayer->GetOutputSlot(0).Connect(layer->GetInputSlot(2u));
+            biasLayer->GetOutputSlot(0).SetTensorInfo(biasTensor.GetInfo());
+            ignoreSlots.emplace_back(2u);
+        }
     }
-    IConnectableLayer* layer = m_Network->AddConvolution2dLayer(descriptor,
-                                                                weights,
-                                                                optionalBiases,
-                                                                layerName.c_str());
+    else
+    {
+        layer = m_Network->AddConvolution2dLayer(descriptor,
+                                                 layerName.c_str());
+        uint32_t numInputs = descriptor.GetNumInputs();
+        CHECK_VALID_SIZE(inputs.size(), numInputs);
+    }
+
     armnn::TensorInfo outputTensorInfo = ToTensorInfo(outputs[0]);
     layer->GetOutputSlot(0).SetTensorInfo(outputTensorInfo);
 
-    RegisterInputSlots(graph, layerIndex, layer);
+    RegisterInputSlots(graph, layerIndex, layer, ignoreSlots);
     RegisterOutputSlots(graph, layerIndex, layer);
 }
 
diff --git a/src/armnnDeserializer/test/DeserializeConvolution2d.cpp b/src/armnnDeserializer/test/DeserializeConvolution2d.cpp
index 6461250..e099597 100644
--- a/src/armnnDeserializer/test/DeserializeConvolution2d.cpp
+++ b/src/armnnDeserializer/test/DeserializeConvolution2d.cpp
@@ -121,6 +121,171 @@
     }
 };
 
+struct Convolution2dFixtureConstantAsInput : public ParserFlatbuffersSerializeFixture
+{
+    explicit Convolution2dFixtureConstantAsInput(const std::string & inputShape1,
+                                  const std::string & outputShape,
+                                  const std::string & weightsShape,
+                                  const std::string & dataType)
+    {
+        m_JsonString = R"(
+        {
+            inputIds: [0],
+            outputIds: [3],
+            layers: [{
+                layer_type: "InputLayer",
+                layer: {
+                    base: {
+                        layerBindingId: 0,
+                        base: {
+                            index: 0,
+                            layerName: "InputLayer",
+                            layerType: "Input",
+                            inputSlots: [{
+                                index: 0,
+                                connection: {sourceLayerIndex:0, outputSlotIndex:0 },
+                                }],
+                            outputSlots: [{
+                                index: 0,
+                                tensorInfo: {
+                                    dimensions: )" + inputShape1 + R"(,
+                                    dataType: )" + dataType + R"(,
+                                    quantizationScale: 0.5,
+                                    quantizationOffset: 0
+                                    },
+                                }]
+                            },
+                        }
+                    },
+                },
+            {
+            layer_type: "Convolution2dLayer",
+            layer : {
+                base: {
+                    index:1,
+                    layerName: "Convolution2dLayer",
+                    layerType: "Convolution2d",
+                    inputSlots: [
+                     {
+                            index: 0,
+                            connection: {sourceLayerIndex:0, outputSlotIndex:0 },
+                     },
+                     {
+                      index: 1,
+                      connection: {
+                        sourceLayerIndex: 2,
+                        outputSlotIndex: 0
+                      }
+                     }
+                    ],
+                    outputSlots: [
+                    {
+                        index: 0,
+                        tensorInfo: {
+                            dimensions: )" + outputShape + R"(,
+                            dataType: )" + dataType + R"(
+                        },
+                    }
+                    ],
+                },
+                descriptor: {
+                    padLeft: 1,
+                    padRight: 1,
+                    padTop: 1,
+                    padBottom: 1,
+                    strideX: 2,
+                    strideY: 2,
+                    biasEnabled: false,
+                    dataLayout: NHWC
+                }
+                }
+            },
+            {
+            layer_type: "ConstantLayer",
+            layer: {
+                base: {
+                    index: 2,
+                    layerName: "Weights",
+                    layerType: "Constant",
+                    inputSlots: [
+
+                    ],
+                    outputSlots: [
+                    {
+                      index: 0,
+                      tensorInfo: {
+                        dimensions: )" + weightsShape + R"(,
+                        dataType: )" + dataType + R"(,
+                        quantizationScale: 0.1,
+                        dimensionSpecificity: [
+                          true,
+                          true,
+                          true,
+                          true
+                        ]
+                      }
+                    }
+                  ]
+            },
+            input: {
+                  info: {
+                    dimensions: )" + weightsShape + R"(,
+                    dataType: )" + dataType + R"(,
+                    quantizationScale: 0.1,
+                    dimensionSpecificity: [
+                      true,
+                      true,
+                      true,
+                      true
+                    ]
+                  },
+                  data_type: "IntData",
+                  data: {
+                    data: [
+                        1082130432, 1084227584, 1086324736,
+                        0 ,0 ,0 ,
+                        1077936128, 1073741824, 1065353216
+                    ]
+                  }
+                }
+              }
+            },
+            {
+            layer_type: "OutputLayer",
+            layer: {
+                base:{
+                    layerBindingId: 0,
+                    base: {
+                        index: 3,
+                        layerName: "OutputLayer",
+                        layerType: "Output",
+                        inputSlots: [{
+                            index: 0,
+                            "connection": {
+                              "sourceLayerIndex": 1,
+                              "outputSlotIndex": 0
+                            }
+                        }],
+                        outputSlots: [ {
+                            index: 0,
+                            tensorInfo: {
+                                dimensions: )" + outputShape + R"(,
+                                dataType: )" + dataType + R"(
+                            },
+                        }],
+                    }
+                }},
+            }],
+            "featureVersions": {
+                "constantTensorsAsInputs": 1,
+                "weightsLayoutScheme": 1
+            }
+        }
+        )";
+        Setup();
+    }
+};
+
 struct SimpleConvolution2dFixture : Convolution2dFixture
 {
     SimpleConvolution2dFixture() : Convolution2dFixture("[ 1, 5, 5, 1 ]",
@@ -137,4 +302,21 @@
             {{"OutputLayer", {23, 33, 24, 91, 99, 48, 26, 50, 19}}});
 }
 
+
+struct SimpleConvolution2dFixtureConstantAsInput : Convolution2dFixtureConstantAsInput
+{
+    SimpleConvolution2dFixtureConstantAsInput() : Convolution2dFixtureConstantAsInput("[ 1, 5, 5, 1 ]",
+                                     "[ 1, 3, 3, 1 ]",
+                                     "[ 1, 3, 3, 1 ]",
+                                     "Float32") {}
+};
+
+TEST_CASE_FIXTURE(SimpleConvolution2dFixtureConstantAsInput, "Convolution2dFloat32ConstAsInput")
+{
+    RunTest<4, armnn::DataType::Float32>(
+            0,
+            {{"InputLayer", {1, 5, 2, 3, 5, 8, 7, 3, 6, 3, 3, 3, 9, 1, 9, 4, 1, 8, 1, 3, 6, 8, 1, 9, 2}}},
+            {{"OutputLayer", {23, 33, 24, 91, 99, 48, 26, 50, 19}}});
+}
+
 }
diff --git a/src/armnnOnnxParser/OnnxParser.cpp b/src/armnnOnnxParser/OnnxParser.cpp
index dd6a06f..4eaf636 100644
--- a/src/armnnOnnxParser/OnnxParser.cpp
+++ b/src/armnnOnnxParser/OnnxParser.cpp
@@ -1754,6 +1754,8 @@
     }
 
     armnn::IConnectableLayer* layer;
+    std::vector<std::string> tensorIndexes= {node.input(0), node.input(1)};
+
     auto weightTensor = CreateConstTensor(node.input(1));
 
     if (node.input_size() == 3)
@@ -1766,7 +1768,9 @@
                                              CHECK_LOCATION().AsString()));
         }
         desc.m_BiasEnabled = true;
+        tensorIndexes.emplace_back(node.input(2));
         auto biasTensor = CreateConstTensor(node.input(2));
+        ARMNN_NO_DEPRECATE_WARN_BEGIN
         layer = m_Network->AddConvolution2dLayer(desc,
                                                  weightTensor.first,
                                                  Optional<ConstTensor>(biasTensor.first),
@@ -1778,6 +1782,7 @@
                                                  weightTensor.first,
                                                  EmptyOptional(),
                                                  node.name().c_str());
+        ARMNN_NO_DEPRECATE_WARN_END
     }
     ARMNN_ASSERT(layer != nullptr);
 
@@ -1788,7 +1793,7 @@
 
     // register the input connection slots for the layer, connections are made after all layers have been created
     // only the tensors for the inputs are relevant, exclude the const tensors
-    RegisterInputSlots(layer, {node.input(0)});
+    RegisterInputSlots(layer, tensorIndexes);
 
     // register the output connection slots for the layer, connections are made after all layers have been created
     RegisterOutputSlots(layer, {node.output(0)});
diff --git a/src/armnnSerializer/Serializer.cpp b/src/armnnSerializer/Serializer.cpp
index 99d1c2b..488dac6 100644
--- a/src/armnnSerializer/Serializer.cpp
+++ b/src/armnnSerializer/Serializer.cpp
@@ -347,13 +347,10 @@
 // Build FlatBuffer for Convolution2dLayer
 void SerializerStrategy::SerializeConvolution2dLayer(const armnn::IConnectableLayer* layer,
                                                      const armnn::Convolution2dDescriptor& descriptor,
-                                                     const std::vector<armnn::ConstTensor>& constants,
                                                      const char* name)
 {
     IgnoreUnused(name);
 
-    const armnn::ConstTensor weights = constants[0];
-
     // Create FlatBuffer BaseLayer
     auto flatBufferBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_Convolution2d);
 
@@ -368,21 +365,11 @@
                                                               descriptor.m_DilationY,
                                                               descriptor.m_BiasEnabled,
                                                               GetFlatBufferDataLayout(descriptor.m_DataLayout));
-    auto flatBufferWeightsConstTensorInfo = CreateConstTensorInfo(weights);
-    flatbuffers::Offset<serializer::ConstTensor> flatBufferBiasesConstTensorInfo;
-
-    if (constants.size() > 1)
-    {
-        const armnn::ConstTensor biases = constants[1];
-        flatBufferBiasesConstTensorInfo = CreateConstTensorInfo(biases);
-    }
 
     // Create the FlatBuffer Convolution2dLayer
     auto flatBufferLayer = CreateConvolution2dLayer(m_flatBufferBuilder,
                                                     flatBufferBaseLayer,
-                                                    flatBufferDescriptor,
-                                                    flatBufferWeightsConstTensorInfo,
-                                                    flatBufferBiasesConstTensorInfo);
+                                                    flatBufferDescriptor);
 
     // Add the AnyLayer to the FlatBufferLayers
     CreateAnyLayer(flatBufferLayer.o, serializer::Layer::Layer_Convolution2dLayer);
@@ -2048,7 +2035,6 @@
                     static_cast<const armnn::Convolution2dDescriptor&>(descriptor);
             SerializeConvolution2dLayer(layer,
                                         layerDescriptor,
-                                        constants,
                                         name);
             break;
         }
diff --git a/src/armnnSerializer/Serializer.hpp b/src/armnnSerializer/Serializer.hpp
index afde778..1a0978f 100644
--- a/src/armnnSerializer/Serializer.hpp
+++ b/src/armnnSerializer/Serializer.hpp
@@ -145,7 +145,6 @@
 
     void SerializeConvolution2dLayer(const armnn::IConnectableLayer* layer,
                                      const armnn::Convolution2dDescriptor& descriptor,
-                                     const std::vector<armnn::ConstTensor>& constants,
                                      const char* name = nullptr);
 
     void SerializeConvolution3dLayer(const armnn::IConnectableLayer* layer,
diff --git a/src/armnnSerializer/test/SerializerTestUtils.cpp b/src/armnnSerializer/test/SerializerTestUtils.cpp
index cf2cb15..1873847 100644
--- a/src/armnnSerializer/test/SerializerTestUtils.cpp
+++ b/src/armnnSerializer/test/SerializerTestUtils.cpp
@@ -51,17 +51,17 @@
 
         const armnn::TensorInfo& connectedInfo = connectedOutput->GetTensorInfo();
         CHECK(connectedInfo.GetShape() == m_InputTensorInfos[i].GetShape());
-        CHECK(
-            GetDataTypeName(connectedInfo.GetDataType()) == GetDataTypeName(m_InputTensorInfos[i].GetDataType()));
+        CHECK(GetDataTypeName(connectedInfo.GetDataType()) == GetDataTypeName(m_InputTensorInfos[i].GetDataType()));
 
-        // If weights and bias are connected to DepthwiseConvolution2d via Constant Layer we do not check.
-        // Constant Layer already disabled in SerializerTestUtils.hpp from entering function.
-        if (layer->GetType() == armnn::LayerType::DepthwiseConvolution2d &&
-            connectedOutput->GetOwningIConnectableLayer().GetType() != armnn::LayerType::Constant)
+        if (connectedInfo.HasMultipleQuantizationScales())
+        {
+            CHECK(connectedInfo.GetQuantizationScales() == m_InputTensorInfos[i].GetQuantizationScales());
+        }
+        else
         {
             CHECK(connectedInfo.GetQuantizationScale() == m_InputTensorInfos[i].GetQuantizationScale());
-            CHECK(connectedInfo.GetQuantizationOffset() == m_InputTensorInfos[i].GetQuantizationOffset());
         }
+        CHECK(connectedInfo.GetQuantizationOffset() == m_InputTensorInfos[i].GetQuantizationOffset());
     }
 
     for (unsigned int i = 0; i < m_OutputTensorInfos.size(); i++)
diff --git a/src/armnnSerializer/test/SerializerTests.cpp b/src/armnnSerializer/test/SerializerTests.cpp
index 278715b..a042939 100644
--- a/src/armnnSerializer/test/SerializerTests.cpp
+++ b/src/armnnSerializer/test/SerializerTests.cpp
@@ -333,6 +333,39 @@
     deserializedNetwork->ExecuteStrategy(verifier);
 }
 
+using Convolution2dDescriptor = armnn::Convolution2dDescriptor;
+class Convolution2dLayerVerifier : public LayerVerifierBaseWithDescriptor<Convolution2dDescriptor>
+{
+public:
+    Convolution2dLayerVerifier(const std::string& layerName,
+                        const std::vector<armnn::TensorInfo>& inputInfos,
+                        const std::vector<armnn::TensorInfo>& outputInfos,
+                        const Convolution2dDescriptor& descriptor)
+        : LayerVerifierBaseWithDescriptor<Convolution2dDescriptor>(layerName, inputInfos, outputInfos, descriptor) {}
+
+    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
+    {
+        armnn::IgnoreUnused(constants, id);
+        switch (layer->GetType())
+        {
+            case armnn::LayerType::Input: break;
+            case armnn::LayerType::Output: break;
+            case armnn::LayerType::Constant: break;
+            default:
+            {
+                VerifyNameAndConnections(layer, name);
+                const Convolution2dDescriptor& layerDescriptor =
+                        static_cast<const Convolution2dDescriptor&>(descriptor);
+                CHECK(layerDescriptor.m_BiasEnabled == m_Descriptor.m_BiasEnabled);
+            }
+        }
+    }
+};
+
 TEST_CASE("SerializeConvolution2d")
 {
     const std::string layerName("convolution2d");
@@ -362,11 +395,13 @@
 
     armnn::INetworkPtr network = armnn::INetwork::Create();
     armnn::IConnectableLayer* const inputLayer  = network->AddInputLayer(0);
+    ARMNN_NO_DEPRECATE_WARN_BEGIN
     armnn::IConnectableLayer* const convLayer   =
             network->AddConvolution2dLayer(descriptor,
                                            weights,
                                            armnn::Optional<armnn::ConstTensor>(biases),
                                            layerName.c_str());
+    ARMNN_NO_DEPRECATE_WARN_END
     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
 
     inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
@@ -378,9 +413,7 @@
     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
     CHECK(deserializedNetwork);
 
-    const std::vector<armnn::ConstTensor>& constants {weights, biases};
-    LayerVerifierBaseWithDescriptorAndConstants<armnn::Convolution2dDescriptor> verifier(
-            layerName, {inputInfo}, {outputInfo}, descriptor, constants);
+    Convolution2dLayerVerifier verifier(layerName, {inputInfo, weightsInfo, biasesInfo}, {outputInfo}, descriptor);
     deserializedNetwork->ExecuteStrategy(verifier);
 }
 
@@ -417,11 +450,13 @@
 
     armnn::INetworkPtr network = armnn::INetwork::Create();
     armnn::IConnectableLayer* const inputLayer  = network->AddInputLayer(0);
+    ARMNN_NO_DEPRECATE_WARN_BEGIN
     armnn::IConnectableLayer* const convLayer   =
         network->AddConvolution2dLayer(descriptor,
                                        weights,
                                        armnn::Optional<armnn::ConstTensor>(biases),
                                        layerName.c_str());
+    ARMNN_NO_DEPRECATE_WARN_END
     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
 
     inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
@@ -433,9 +468,116 @@
     armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
     CHECK(deserializedNetwork);
 
+    Convolution2dLayerVerifier verifier(layerName, {inputInfo, kernelInfo, biasInfo}, {outputInfo}, descriptor);
+
+    deserializedNetwork->ExecuteStrategy(verifier);
+}
+
+TEST_CASE("SerializeConvolution2dWeightsAndBiasesAsConstantLayers")
+{
+    const std::string layerName("convolution2d");
+    const armnn::TensorInfo inputInfo ({ 1, 5, 5, 1 }, armnn::DataType::Float32);
+    const armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
+
+    const armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32, 0.0f, 0, true);
+    const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32, 0.0f, 0, true);
+
+    std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
+    armnn::ConstTensor weights(weightsInfo, weightsData);
+
+    std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
+    armnn::ConstTensor biases(biasesInfo, biasesData);
+
+    armnn::Convolution2dDescriptor descriptor;
+    descriptor.m_PadLeft     = 1;
+    descriptor.m_PadRight    = 1;
+    descriptor.m_PadTop      = 1;
+    descriptor.m_PadBottom   = 1;
+    descriptor.m_StrideX     = 2;
+    descriptor.m_StrideY     = 2;
+    descriptor.m_DilationX   = 2;
+    descriptor.m_DilationY   = 2;
+    descriptor.m_BiasEnabled = true;
+    descriptor.m_DataLayout  = armnn::DataLayout::NHWC;
+
+    armnn::INetworkPtr network = armnn::INetwork::Create();
+    armnn::IConnectableLayer* const inputLayer  = network->AddInputLayer(0);
+    armnn::IConnectableLayer* const weightsLayer = network->AddConstantLayer(weights, "Weights");
+    armnn::IConnectableLayer* const biasesLayer = network->AddConstantLayer(biases, "Biases");
+    armnn::IConnectableLayer* const convLayer   = network->AddConvolution2dLayer(descriptor,
+                                           layerName.c_str());
+    armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
+
+    inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
+    weightsLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(1));
+    biasesLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(2));
+    convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
+
+    inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
+    weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsInfo);
+    biasesLayer->GetOutputSlot(0).SetTensorInfo(biasesInfo);
+    convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
+
+    armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
+    CHECK(deserializedNetwork);
+
+    Convolution2dLayerVerifier verifier(layerName, {inputInfo, weightsInfo, biasesInfo}, {outputInfo}, descriptor);
+
+    deserializedNetwork->ExecuteStrategy(verifier);
+}
+
+TEST_CASE("SerializeConvolution2dWeightsAndBiasesAsConstantLayers")
+{
+    const std::string layerName("convolution2d");
+    const armnn::TensorInfo inputInfo ({ 1, 5, 5, 1 }, armnn::DataType::Float32);
+    const armnn::TensorInfo outputInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32);
+
+    const armnn::TensorInfo weightsInfo({ 1, 3, 3, 1 }, armnn::DataType::Float32, 0.0f, 0, true);
+    const armnn::TensorInfo biasesInfo ({ 1 }, armnn::DataType::Float32, 0.0f, 0, true);
+
+    std::vector<float> weightsData = GenerateRandomData<float>(weightsInfo.GetNumElements());
+    armnn::ConstTensor weights(weightsInfo, weightsData);
+
+    std::vector<float> biasesData = GenerateRandomData<float>(biasesInfo.GetNumElements());
+    armnn::ConstTensor biases(biasesInfo, biasesData);
+
+    armnn::Convolution2dDescriptor descriptor;
+    descriptor.m_PadLeft     = 1;
+    descriptor.m_PadRight    = 1;
+    descriptor.m_PadTop      = 1;
+    descriptor.m_PadBottom   = 1;
+    descriptor.m_StrideX     = 2;
+    descriptor.m_StrideY     = 2;
+    descriptor.m_DilationX   = 2;
+    descriptor.m_DilationY   = 2;
+    descriptor.m_BiasEnabled = true;
+    descriptor.m_DataLayout  = armnn::DataLayout::NHWC;
+
+    armnn::INetworkPtr network = armnn::INetwork::Create();
+    armnn::IConnectableLayer* const inputLayer  = network->AddInputLayer(0);
+    armnn::IConnectableLayer* const weightsLayer = network->AddConstantLayer(weights, "Weights");
+    armnn::IConnectableLayer* const biasesLayer = network->AddConstantLayer(biases, "Biases");
+    armnn::IConnectableLayer* const convLayer   = network->AddConvolution2dLayer(descriptor,
+                                           layerName.c_str());
+    armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
+
+    inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
+    weightsLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(1));
+    biasesLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(2));
+    convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
+
+    inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
+    weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsInfo);
+    biasesLayer->GetOutputSlot(0).SetTensorInfo(biasesInfo);
+    convLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
+
+    armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
+    CHECK(deserializedNetwork);
+
     const std::vector<armnn::ConstTensor>& constants {weights, biases};
-    LayerVerifierBaseWithDescriptorAndConstants<Convolution2dDescriptor> verifier(
-            layerName, {inputInfo}, {outputInfo}, descriptor, constants);
+    LayerVerifierBaseWithDescriptorAndConstants<armnn::Convolution2dDescriptor> verifier(
+            layerName, {inputInfo, weightsInfo, biasesInfo}, {outputInfo}, descriptor, constants);
+
     deserializedNetwork->ExecuteStrategy(verifier);
 }
 
diff --git a/src/armnnTestUtils/CommonTestUtils.cpp b/src/armnnTestUtils/CommonTestUtils.cpp
index c853305..472716c 100644
--- a/src/armnnTestUtils/CommonTestUtils.cpp
+++ b/src/armnnTestUtils/CommonTestUtils.cpp
@@ -9,14 +9,41 @@
 
 using namespace armnn;
 
-SubgraphView::InputSlots CreateInputsFrom(const std::vector<Layer*>& layers)
+SubgraphView::InputSlots CreateInputsFrom(Layer* layer,
+                                          std::vector<unsigned int> ignoreSlots)
 {
     SubgraphView::InputSlots result;
-    for (auto&& layer : layers)
+    for (auto&& it = layer->BeginInputSlots(); it != layer->EndInputSlots(); ++it)
+    {
+        if (std::find(ignoreSlots.begin(), ignoreSlots.end(), it->GetSlotIndex()) != ignoreSlots.end())
+        {
+            continue;
+        }
+        else
+        {
+            result.push_back(&(*it));
+        }
+    }
+        return result;
+}
+
+// ignoreSlots assumes you want to ignore the same slots all on layers within the vector
+SubgraphView::InputSlots CreateInputsFrom(const std::vector<Layer*>& layers,
+                                          std::vector<unsigned 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;
diff --git a/src/armnnTestUtils/CommonTestUtils.hpp b/src/armnnTestUtils/CommonTestUtils.hpp
index b75a32b..5b4b356 100644
--- a/src/armnnTestUtils/CommonTestUtils.hpp
+++ b/src/armnnTestUtils/CommonTestUtils.hpp
@@ -79,8 +79,11 @@
     layer->m_Weight->Allocate();
     layer->m_Bias->Allocate();
 }
+armnn::SubgraphView::InputSlots CreateInputsFrom(armnn::Layer* layer,
+                                                 std::vector<unsigned int> ignoreSlots = {});
 
-armnn::SubgraphView::InputSlots CreateInputsFrom(const std::vector<armnn::Layer*>& layers);
+armnn::SubgraphView::InputSlots CreateInputsFrom(const std::vector<armnn::Layer*>& layers,
+                                                 std::vector<unsigned int> ignoreSlots = {});
 
 armnn::SubgraphView::OutputSlots CreateOutputsFrom(const std::vector<armnn::Layer*>& layers);
 
diff --git a/src/armnnTestUtils/CreateWorkload.hpp b/src/armnnTestUtils/CreateWorkload.hpp
index 2590ae8..7700a55 100644
--- a/src/armnnTestUtils/CreateWorkload.hpp
+++ b/src/armnnTestUtils/CreateWorkload.hpp
@@ -483,28 +483,37 @@
     layerDesc.m_PadBottom = 1;
     layerDesc.m_StrideX = 2;
     layerDesc.m_StrideY = 4;
-    layerDesc.m_BiasEnabled = true;
+    layerDesc.m_BiasEnabled = false;
     layerDesc.m_DataLayout = dataLayout;
 
+    float inputsQScale = DataType == armnn::DataType::QAsymmU8 ? 1.0f : 0.0;
+    float outputQScale = DataType == armnn::DataType::QAsymmU8 ? 2.0f : 0.0;
+
     Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
 
     TensorShape weightShape = (dataLayout == DataLayout::NCHW) ? TensorShape{2, 3, 5, 3} : TensorShape{2, 5, 3, 3};
     TensorShape inputShape  = (dataLayout == DataLayout::NCHW) ? TensorShape{2, 3, 8, 16} : TensorShape{2, 8, 16, 3};
     TensorShape outputShape = (dataLayout == DataLayout::NCHW) ? TensorShape{2, 2, 2, 10} : TensorShape{2, 2, 10, 2};
 
+    // As optimization isn't run member variables need to be updated.
     layer->m_Weight = std::make_unique<ScopedTensorHandle>(TensorInfo(weightShape, DataType));
-    layer->m_Bias   = std::make_unique<ScopedTensorHandle>(TensorInfo({2}, GetBiasDataType(DataType)));
-
     layer->m_Weight->Allocate();
-    layer->m_Bias->Allocate();
+
+    armnn::TensorInfo weightsTensorInfo(weightShape, DataType, inputsQScale);
+    weightsTensorInfo.SetConstant();
 
     // Creates extra layers.
     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
+    auto const weights = graph.AddLayer<ConstantLayer>("weights");
     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
 
+    weights->m_LayerOutput = std::make_unique<ScopedTensorHandle>(weightsTensorInfo);
+    weights->m_LayerOutput->Allocate();
+
     // Connects up.
-    Connect(input, layer, TensorInfo(inputShape, DataType));
-    Connect(layer, output, TensorInfo(outputShape, DataType));
+    Connect(input, layer, TensorInfo(inputShape, DataType, inputsQScale));
+    Connect(weights, layer, weightsTensorInfo, 0, 1);
+    Connect(layer, output, TensorInfo(outputShape, DataType, outputQScale));
     CreateTensorHandles(graph, factory);
 
     // Makes the workload and checks it.
@@ -517,14 +526,11 @@
     CHECK(queueDescriptor.m_Parameters.m_PadRight == 3);
     CHECK(queueDescriptor.m_Parameters.m_PadTop == 1);
     CHECK(queueDescriptor.m_Parameters.m_PadBottom == 1);
-    CHECK(queueDescriptor.m_Parameters.m_BiasEnabled);
+    CHECK(!queueDescriptor.m_Parameters.m_BiasEnabled);
     CHECK((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
 
-    CHECK(queueDescriptor.m_Inputs.size() == 1);
+    CHECK(queueDescriptor.m_Inputs.size() == 2);
     CHECK(queueDescriptor.m_Outputs.size() == 1);
-    CHECK((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo(weightShape, DataType)));
-    CHECK((queueDescriptor.m_Bias->GetTensorInfo() ==
-        TensorInfo({2}, GetBiasDataType(DataType))));
 
     // Returns so we can do extra, backend-specific tests.
     return workload;
@@ -548,19 +554,26 @@
     layerDesc.m_BiasEnabled = true;
     layerDesc.m_DataLayout = dataLayout;
 
+    float inputsQScale = DataType == armnn::DataType::QAsymmU8 ? 1.0f : 0.0;
+    float outputQScale = DataType == armnn::DataType::QAsymmU8 ? 2.0f : 0.0;
 
     Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
 
     TensorShape weightShape = (dataLayout == DataLayout::NCHW) ? TensorShape{2, 3, 5, 3} : TensorShape{2, 5, 3, 3};
     TensorShape inputShape  = (dataLayout == DataLayout::NCHW) ? TensorShape{2, 3, 8, 16} : TensorShape{2, 8, 16, 3};
     TensorShape outputShape = (dataLayout == DataLayout::NCHW) ? TensorShape{2, 2, 2, 10} : TensorShape{2, 2, 10, 2};
-
+    // As optimization isn't run member variables need to be updated.
     layer->m_Weight = std::make_unique<ScopedTensorHandle>(TensorInfo(weightShape, DataType));
     layer->m_Bias   = std::make_unique<ScopedTensorHandle>(TensorInfo({2}, GetBiasDataType(DataType)));
 
     layer->m_Weight->Allocate();
     layer->m_Bias->Allocate();
 
+    armnn::TensorInfo weightsTensorInfo(weightShape, DataType, inputsQScale);
+    weightsTensorInfo.SetConstant();
+    armnn::TensorInfo biasTensorInfo({2}, DataType, inputsQScale);
+    biasTensorInfo.SetConstant();
+
     auto activationDesc = std::make_shared<ActivationDescriptor>();
     activationDesc->m_A        = 10.0f;
     activationDesc->m_B        = 5.0f;
@@ -579,11 +592,20 @@
 
     // Creates extra layers.
     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
+    auto const weights = graph.AddLayer<ConstantLayer>("weights");
+    auto const bias = graph.AddLayer<ConstantLayer>("bias");
     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
 
+    weights->m_LayerOutput = std::make_unique<ScopedTensorHandle>(weightsTensorInfo);
+    weights->m_LayerOutput->Allocate();
+    bias->m_LayerOutput = std::make_unique<ScopedTensorHandle>(biasTensorInfo);
+    bias->m_LayerOutput->Allocate();
+
     // Connects up.
-    Connect(input, layer, TensorInfo(inputShape, DataType));
-    Connect(layer, output, TensorInfo(outputShape, DataType));
+    Connect(input, layer, TensorInfo(inputShape, DataType, inputsQScale));
+    Connect(weights, layer, weightsTensorInfo, 0, 1);
+    Connect(bias, layer, biasTensorInfo, 0, 2);
+    Connect(layer, output, TensorInfo(outputShape, DataType, outputQScale));
     CreateTensorHandles(graph, factory);
 
     // Makes the workload and checks it.
@@ -606,11 +628,9 @@
     CHECK(queueDescriptor.m_Parameters.m_PadBottom == 1);
     CHECK(queueDescriptor.m_Parameters.m_BiasEnabled);
     CHECK((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
+
     CHECK(queueDescriptor.m_Outputs.size() == 1);
-    CHECK((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo(weightShape, DataType)));
-    CHECK((queueDescriptor.m_Bias->GetTensorInfo() ==
-        TensorInfo({2}, GetBiasDataType(DataType))));
-    CHECK(queueDescriptor.m_Inputs.size() == 1);
+    CHECK(queueDescriptor.m_Inputs.size() == 3);
 
     // Returns so we can do extra, backend-specific tests.
     return workload;
@@ -630,28 +650,41 @@
     layerDesc.m_PadBottom = 0;
     layerDesc.m_StrideX = 1;
     layerDesc.m_StrideY = 1;
-    layerDesc.m_BiasEnabled = false;
+    layerDesc.m_BiasEnabled = true;
     layerDesc.m_DataLayout = dataLayout;
 
+    float inputsQScale = DataType == armnn::DataType::QAsymmU8 ? 1.0f : 0.0;
+    float outputQScale = DataType == armnn::DataType::QAsymmU8 ? 2.0f : 0.0;
+
     Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
 
-    TensorShape weightShape = TensorShape{32, 32, 3, 3};
-    TensorShape inputShape  = TensorShape{1, 32, 149, 149};
-    TensorShape outputShape = TensorShape{1, 32, 147, 147};
-
+    TensorShape weightShape = TensorShape{ 32, 32, 3, 3 };
+    TensorShape biasShape = TensorShape{ 32 };
+    TensorShape inputShape = TensorShape{ 1, 32, 149, 149 };
+    TensorShape outputShape = TensorShape{ 1, 32, 147, 147 };
+    // As optimization isn't run member variables need to be updated.
     layer->m_Weight = std::make_unique<ScopedTensorHandle>(TensorInfo(weightShape, DataType));
-    layer->m_Bias   = std::make_unique<ScopedTensorHandle>(TensorInfo({2}, GetBiasDataType(DataType)));
+    layer->m_Bias   = std::make_unique<ScopedTensorHandle>(TensorInfo(biasShape, GetBiasDataType(DataType)));
 
     layer->m_Weight->Allocate();
     layer->m_Bias->Allocate();
 
+    armnn::TensorInfo weightsTensorInfo(weightShape, DataType, inputsQScale);
+    weightsTensorInfo.SetConstant();
+    armnn::TensorInfo biasTensorInfo(biasShape, DataType, inputsQScale);
+    biasTensorInfo.SetConstant();
+
     // Creates extra layers.
     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
+    auto const weights = graph.AddLayer<ConstantLayer>("weights");
+    auto const bias = graph.AddLayer<ConstantLayer>("bias");
     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
 
     // Connects up.
     Connect(input, layer, TensorInfo(inputShape, DataType));
-    Connect(layer, output, TensorInfo(outputShape, DataType));
+    Connect(weights, layer, weightsTensorInfo, 0, 1);
+    Connect(bias, layer, biasTensorInfo, 0, 2);
+    Connect(layer, output, TensorInfo(outputShape, DataType, outputQScale));
     CreateTensorHandles(graph, factory);
 
     // Makes the workload and checks it.
@@ -666,9 +699,8 @@
     CHECK(queueDescriptor.m_Parameters.m_PadBottom == 0);
     CHECK((queueDescriptor.m_Parameters.m_DataLayout == dataLayout));
 
-    CHECK(queueDescriptor.m_Inputs.size() == 1);
+    CHECK(queueDescriptor.m_Inputs.size() == 3);
     CHECK(queueDescriptor.m_Outputs.size() == 1);
-    CHECK((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo(weightShape, DataType)));
 
     // Returns so we can do extra, backend-specific tests.
     return workload;
@@ -1074,9 +1106,9 @@
     return workload;
 }
 
-template <typename Convolution2dWorkload, armnn::DataType DataType>
+template<typename Convolution2dWorkload, armnn::DataType DataType>
 std::unique_ptr<Convolution2dWorkload> CreateDirectConvolution2dWorkloadTest(armnn::IWorkloadFactory& factory,
-                                                                       armnn::Graph&            graph)
+                                                                             armnn::Graph& graph)
 {
     // Creates the layer we're testing.
     Convolution2dDescriptor layerDesc;
@@ -1093,18 +1125,34 @@
     float inputsQScale = DataType == armnn::DataType::QAsymmU8 ? 1.0f : 0.0;
     float outputQScale = DataType == armnn::DataType::QAsymmU8 ? 2.0f : 0.0;
 
-    layer->m_Weight = std::make_unique<ScopedTensorHandle>(TensorInfo({ 2, 3, 3, 3 }, DataType, inputsQScale));
-    layer->m_Bias   = std::make_unique<ScopedTensorHandle>
-        (TensorInfo({2},  GetBiasDataType(DataType), inputsQScale));
+    TensorShape biasShape = TensorShape{ 2 };
+    TensorShape weightShape = TensorShape{ 2, 3, 3, 3 };
+    armnn::TensorInfo weightsTensorInfo(weightShape, DataType, inputsQScale);
+    weightsTensorInfo.SetConstant();
+    armnn::TensorInfo biasTensorInfo(biasShape, GetBiasDataType(DataType), inputsQScale);
+    biasTensorInfo.SetConstant();
+
+    layer->m_Weight = std::make_unique<ScopedTensorHandle>(weightsTensorInfo);
+    layer->m_Bias   = std::make_unique<ScopedTensorHandle>(biasTensorInfo);
+
     layer->m_Weight->Allocate();
     layer->m_Bias->Allocate();
 
     // Creates extra layers.
     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
+    auto const weights = graph.AddLayer<ConstantLayer>("weights");
+    auto const bias = graph.AddLayer<ConstantLayer>("bias");
     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
 
+    weights->m_LayerOutput = std::make_unique<ScopedTensorHandle>(weightsTensorInfo);
+    weights->m_LayerOutput->Allocate();
+    bias->m_LayerOutput = std::make_unique<ScopedTensorHandle>(biasTensorInfo);
+    bias->m_LayerOutput->Allocate();
+
     // Connects up.
     Connect(input, layer, TensorInfo({2, 3, 6, 6}, DataType, inputsQScale));
+    Connect(weights, layer, weightsTensorInfo, 0, 1);
+    Connect(bias, layer, biasTensorInfo, 0, 2);
     Connect(layer, output, TensorInfo({2, 2, 6, 6}, DataType, outputQScale));
     CreateTensorHandles(graph, factory);
 
@@ -1120,12 +1168,10 @@
     CHECK(queueDescriptor.m_Parameters.m_PadBottom == 1);
     CHECK(queueDescriptor.m_Parameters.m_BiasEnabled == true);
 
-    CHECK(queueDescriptor.m_Inputs.size() == 1);
+    CHECK(queueDescriptor.m_Inputs.size() == 3);
     CHECK(queueDescriptor.m_Outputs.size() == 1);
-    CHECK((queueDescriptor.m_Weight->GetTensorInfo() == TensorInfo({2, 3, 3, 3},
-        DataType, inputsQScale)));
-    CHECK((queueDescriptor.m_Bias->GetTensorInfo()
-                == TensorInfo({2},  GetBiasDataType(DataType), inputsQScale)));
+    CHECK((queueDescriptor.m_Weight->GetTensorInfo() == weightsTensorInfo));
+    CHECK((queueDescriptor.m_Bias->GetTensorInfo() == biasTensorInfo));
 
     // Returns so we can do extra, backend-specific tests.
     return workload;
@@ -2094,18 +2140,22 @@
         armnn::ConstTensor biases(biasTensorInfo, biasData);
 
         // Create convolution layer with biases
+        ARMNN_NO_DEPRECATE_WARN_BEGIN
         convLayer = net->AddConvolution2dLayer(convDesc2d,
                                               weights,
                                               Optional<ConstTensor>(biases),
                                               convLayerName.c_str());
+        ARMNN_NO_DEPRECATE_WARN_END
     }
     else
     {
         // Create convolution layer without biases
+        ARMNN_NO_DEPRECATE_WARN_BEGIN
         convLayer = net->AddConvolution2dLayer(convDesc2d,
                                               weights,
                                               EmptyOptional(),
                                               convLayerName.c_str());
+        ARMNN_NO_DEPRECATE_WARN_END
     }
 
     CHECK(convLayer);
diff --git a/src/armnnTestUtils/MockBackend.cpp b/src/armnnTestUtils/MockBackend.cpp
index ac7f7c7..5dfe9a3 100644
--- a/src/armnnTestUtils/MockBackend.cpp
+++ b/src/armnnTestUtils/MockBackend.cpp
@@ -66,6 +66,7 @@
     {
         case armnn::LayerType::Input:
         case armnn::LayerType::Output:
+        case armnn::LayerType::Constant:
         case armnn::LayerType::Addition:
         case armnn::LayerType::Convolution2d:
             // Layer supported
diff --git a/src/armnnTfLiteParser/TfLiteParser.cpp b/src/armnnTfLiteParser/TfLiteParser.cpp
index 7cb9f6a..aa07f7b 100644
--- a/src/armnnTfLiteParser/TfLiteParser.cpp
+++ b/src/armnnTfLiteParser/TfLiteParser.cpp
@@ -417,6 +417,9 @@
         case tflite::TensorType_FLOAT32:
             type = armnn::DataType::Float32;
             break;
+        case tflite::TensorType_FLOAT16:
+            type = armnn::DataType::Float16;
+            break;
         case tflite::TensorType_INT8:
             if (tensorPtr->quantization->zero_point.size() == 1)
             {
@@ -1067,58 +1070,64 @@
 
     CHECK_SUPPORTED_FUSED_ACTIVATION(options, subgraphIndex, operatorIndex);
 
+    auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
+    auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
+    CHECK_VALID_SIZE(outputs.size(), 1);
+
     Convolution2dDescriptor desc;
-    desc.m_BiasEnabled = false;
+    inputs.size() == 3 ?
+        desc.m_BiasEnabled = true : desc.m_BiasEnabled = false;
     desc.m_StrideX = CHECKED_NON_NEGATIVE(options->stride_w);
     desc.m_StrideY = CHECKED_NON_NEGATIVE(options->stride_h);
     desc.m_DataLayout = armnn::DataLayout::NHWC;
     desc.m_DilationX = CHECKED_NON_NEGATIVE(options->dilation_w_factor);
     desc.m_DilationY = CHECKED_NON_NEGATIVE(options->dilation_h_factor);
 
-    auto inputs = GetInputs(m_Model, subgraphIndex, operatorIndex);
-    CHECK_VALID_SIZE(inputs.size(), 2, 3);
-
-    auto outputs = GetOutputs(m_Model, subgraphIndex, operatorIndex);
-    CHECK_VALID_SIZE(outputs.size(), 1);
-
-    armnn::TensorInfo inputTensorInfo  = ToTensorInfo(inputs[0]);
+    armnn::TensorInfo inputTensorInfo = ToTensorInfo(inputs[0]);
     armnn::TensorInfo filterTensorInfo = ToTensorInfo(inputs[1]);
 
     // assuming input is NHWC
     unsigned int inputHeight = inputTensorInfo.GetShape()[1];
-    unsigned int inputWidth  = inputTensorInfo.GetShape()[2];
+    unsigned int inputWidth = inputTensorInfo.GetShape()[2];
 
     // assuming the filter is OHWI : Output, H, W, Input
     // which is essentially the same as NHWC
     unsigned int filterHeight = filterTensorInfo.GetShape()[1];
-    unsigned int filterWidth  = filterTensorInfo.GetShape()[2];
+    unsigned int filterWidth = filterTensorInfo.GetShape()[2];
 
     CalcPadding(inputHeight, filterHeight, desc.m_StrideY,
                 desc.m_DilationY, desc.m_PadTop, desc.m_PadBottom, options->padding);
     CalcPadding(inputWidth, filterWidth, desc.m_StrideX,
                 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
 
-    auto filterTensorAndData = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo, inputTensorInfo.GetDataType());
-    armnn::IConnectableLayer* layer = nullptr;
+    // Add the first input and weights tensor to the registration list.
+    // The constant weights will be added by SetupConstantLayers.
+    auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
+    std::vector<unsigned int> tensorIndexesToRegister = { inputTensorIndexes[0], inputTensorIndexes[1] };
 
     auto layerName = fmt::format("Conv2D:{}:{}", subgraphIndex, operatorIndex);
+    armnn::IConnectableLayer* layer = m_Network->AddConvolution2dLayer(desc, layerName.c_str());
 
-    if (inputs.size() == 3)
+    if (IsConstTensor(inputs[1]) && inputTensorInfo.GetDataType() == DataType::Float32 &&
+        (filterTensorInfo.GetDataType() == DataType::QAsymmU8 ||
+            filterTensorInfo.GetDataType() == DataType::QAsymmS8))
     {
-        desc.m_BiasEnabled = true;
-        armnn::TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
-        auto biasTensorAndData = CreateConstTensorNonPermuted(inputs[2], biasTensorInfo, inputTensorInfo.GetDataType());
-        layer = m_Network->AddConvolution2dLayer(desc,
-                                                 filterTensorAndData.first,
-                                                 Optional<ConstTensor>(biasTensorAndData.first),
-                                                 layerName.c_str());
+        m_ConstantsToDequantize.emplace_back(inputs[1]->buffer);
     }
-    else
+
+    if (desc.m_BiasEnabled)
     {
-        layer = m_Network->AddConvolution2dLayer(desc,
-                                                 filterTensorAndData.first,
-                                                 EmptyOptional(),
-                                                 layerName.c_str());
+        armnn::TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
+
+        // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
+        tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
+
+        if (IsConstTensor(inputs[2]) && inputTensorInfo.GetDataType() == DataType::Float32 &&
+            (filterTensorInfo.GetDataType() == DataType::QAsymmU8 ||
+                filterTensorInfo.GetDataType() == DataType::QAsymmS8))
+        {
+            m_ConstantsToDequantize.emplace_back(inputs[2]->buffer);
+        }
     }
 
     ARMNN_ASSERT(layer != nullptr);
@@ -1128,13 +1137,12 @@
 
     // register the input connection slots for the layer, connections are made after all layers have been created
     // only the tensors for the inputs are relevant, exclude the const tensors
-    auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
-    RegisterInputSlots(subgraphIndex, operatorIndex, layer, {inputTensorIndexes[0]});
+    RegisterInputSlots(subgraphIndex, operatorIndex, layer, tensorIndexesToRegister);
 
     layer = AddFusedActivationLayer(layer, 0, options->fused_activation_function);
     // register the output connection slots for the layer, connections are made after all layers have been created
     auto outputTensorIndexes = AsUnsignedVector(GetOutputTensorIds(m_Model, subgraphIndex, operatorIndex));
-    RegisterOutputSlots(subgraphIndex, operatorIndex, layer, {outputTensorIndexes[0]});
+    RegisterOutputSlots(subgraphIndex, operatorIndex, layer, { outputTensorIndexes[0] });
 }
 
 // Conv3D support was added in TF 2.5, so for backwards compatibility a hash define is needed.
@@ -1261,7 +1269,6 @@
                 desc.m_DilationX, desc.m_PadLeft, desc.m_PadRight, options->padding);
 
     // ArmNN uses the same filter tensor layout at TfLite [1, H, W, O] no need for any permutation
-    auto filterTensor = CreateConstTensorNonPermuted(inputs[1], filterTensorInfo);
     auto layerName = fmt::format("DepthwiseConv2D:{}:{}", subgraphIndex, operatorIndex);
 
     auto inputTensorIndexes = AsUnsignedVector(GetInputTensorIds(m_Model, subgraphIndex, operatorIndex));
@@ -1275,7 +1282,6 @@
     {
         desc.m_BiasEnabled = true;
         TensorInfo biasTensorInfo = ToTensorInfo(inputs[2]);
-        auto biasTensorAndData = CreateConstTensorNonPermuted(inputs[2], biasTensorInfo);
 
         // Add the biases input to the registration list, a constant layer will be added by SetupConstantLayers.
         tensorIndexesToRegister.emplace_back(inputTensorIndexes[2]);
diff --git a/src/backends/aclCommon/ArmComputeSubgraphUtils.hpp b/src/backends/aclCommon/ArmComputeSubgraphUtils.hpp
index de3a34e..a26442c 100644
--- a/src/backends/aclCommon/ArmComputeSubgraphUtils.hpp
+++ b/src/backends/aclCommon/ArmComputeSubgraphUtils.hpp
@@ -225,28 +225,14 @@
                                   ActivationDescriptor& activationDesc,
                                   std::string name)
 {
-    std::shared_ptr<ConstTensorHandle> weightHandle = baseLayer->m_Weight;
-    TensorInfo weightInfo = weightHandle->GetTensorInfo();
+    IConnectableLayer* replacement = optimizationViews.GetINetwork()
+                                                      ->AddConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
 
-    std::shared_ptr<ConstTensorHandle> biasHandle = baseLayer->m_Bias;
-    ConstTensor biasTensor;
-    if (!biasHandle)
-    {
-        biasTensor = ConstTensor();
-    }
-    else
-    {
-        biasTensor = ConstTensor(biasHandle->GetTensorInfo(), biasHandle->Map(true));
-    }
-
-    IConnectableLayer* replacement =
-        optimizationViews.GetINetwork()->
-            AddConvolution2dLayer(baseLayer->GetParameters(),
-                                  ConstTensor(weightInfo, weightHandle->Map(true)),
-                                  Optional<ConstTensor>(biasTensor),
-                                  name.c_str());
     LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
 
+    replacementLayer->m_Weight = std::move(baseLayer->m_Weight);
+    replacementLayer->m_Bias = std::move(baseLayer->m_Bias);
+
     FuseLayer(optimizationViews,
               baseLayer,
               replacementLayer,
@@ -263,8 +249,9 @@
                                            ActivationDescriptor& activationDesc,
                                            std::string name)
 {
-    IConnectableLayer* replacement = optimizationViews.GetINetwork()->
-        AddDepthwiseConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
+    IConnectableLayer* replacement =
+        optimizationViews.GetINetwork()->AddDepthwiseConvolution2dLayer(baseLayer->GetParameters(), name.c_str());
+
     LayerType* replacementLayer = PolymorphicDowncast<LayerType*>(replacement);
 
     replacementLayer->m_Weight = std::move(baseLayer->m_Weight);
diff --git a/src/backends/backendsCommon/WorkloadData.cpp b/src/backends/backendsCommon/WorkloadData.cpp
index 289f780..37fda3e 100644
--- a/src/backends/backendsCommon/WorkloadData.cpp
+++ b/src/backends/backendsCommon/WorkloadData.cpp
@@ -1246,7 +1246,13 @@
 {
     const std::string descriptorName{"Convolution2dQueueDescriptor"};
 
-    ValidateNumInputs(workloadInfo,  descriptorName, 1);
+    uint32_t numInputs = 2;
+    if (m_Parameters.m_BiasEnabled)
+    {
+        numInputs = 3;
+    }
+
+    ValidateNumInputs(workloadInfo,  descriptorName, numInputs);
     ValidateNumOutputs(workloadInfo, descriptorName, 1);
 
     const TensorInfo& inputTensorInfo  = workloadInfo.m_InputTensorInfos[0];
@@ -1255,9 +1261,8 @@
     ValidateTensorNumDimensions(inputTensorInfo,  descriptorName, 4, "input");
     ValidateTensorNumDimensions(outputTensorInfo, descriptorName, 4, "output");
 
-    ValidatePointer(m_Weight, descriptorName, "weight");
+    const TensorInfo& weightTensorInfo = workloadInfo.m_InputTensorInfos[1];
 
-    const TensorInfo& weightTensorInfo = m_Weight->GetTensorInfo();
     ValidateTensorNumDimensions(weightTensorInfo, descriptorName, 4, "weight");
 
     ValidateWeightDataType(inputTensorInfo, weightTensorInfo, descriptorName);
@@ -1265,9 +1270,7 @@
     Optional<TensorInfo> optionalBiasTensorInfo;
     if (m_Parameters.m_BiasEnabled)
     {
-        ValidatePointer(m_Bias, descriptorName, "bias");
-
-        optionalBiasTensorInfo = MakeOptional<TensorInfo>(m_Bias->GetTensorInfo());
+        optionalBiasTensorInfo = MakeOptional<TensorInfo>(workloadInfo.m_InputTensorInfos[2]);
         const TensorInfo& biasTensorInfo = optionalBiasTensorInfo.value();
 
         ValidateTensorDataType(biasTensorInfo, GetBiasDataType(inputTensorInfo.GetDataType()), descriptorName, "bias");
diff --git a/src/backends/backendsCommon/WorkloadFactory.cpp b/src/backends/backendsCommon/WorkloadFactory.cpp
index f624ee6..3660e6e 100644
--- a/src/backends/backendsCommon/WorkloadFactory.cpp
+++ b/src/backends/backendsCommon/WorkloadFactory.cpp
@@ -246,7 +246,10 @@
             const TensorInfo input  = OverrideDataType(layer.GetInputSlot(0).GetConnection()->GetTensorInfo(),
                                                        dataType);
             const TensorInfo output = OverrideDataType(layer.GetOutputSlot(0).GetTensorInfo(), dataType);
-            ARMNN_ASSERT(cLayer->m_Weight.get() != nullptr);
+            ARMNN_ASSERT_MSG(layer.GetInputSlot(1).GetConnection(),
+                             "Convolution2dLayer: Weights should be connected as a Constant Layer.");
+            const TensorInfo weights = OverrideDataType(layer.GetInputSlot(1).GetConnection()->GetTensorInfo(),
+                                                        dataType);
 
             const Convolution2dDescriptor& descriptor = cLayer->GetParameters();
 
@@ -254,14 +257,17 @@
             Optional<TensorInfo> biases;
             if (descriptor.m_BiasEnabled)
             {
-                biases = OverrideDataType(cLayer->m_Bias->GetTensorInfo(), GetBiasTypeFromWeightsType(dataType));
+                ARMNN_ASSERT_MSG(layer.GetInputSlot(2).GetConnection(),
+                                 "Convolution2dLayer: Bias should be connected as a Constant Layer.");
+                biases = OverrideDataType(layer.GetInputSlot(2).GetConnection()->GetTensorInfo(),
+                                          GetBiasTypeFromWeightsType(dataType));
             }
 
             result = layerSupportObject.IsConvolution2dSupported(
                                               input,
                                               output,
                                               descriptor,
-                                              OverrideDataType(cLayer->m_Weight->GetTensorInfo(), dataType),
+                                              weights,
                                               biases,
                                               reason);
             break;
diff --git a/src/backends/backendsCommon/test/DynamicBackendTests.hpp b/src/backends/backendsCommon/test/DynamicBackendTests.hpp
index f53bd83..0d98804 100644
--- a/src/backends/backendsCommon/test/DynamicBackendTests.hpp
+++ b/src/backends/backendsCommon/test/DynamicBackendTests.hpp
@@ -1465,7 +1465,7 @@
     Convolution2dQueueDescriptor convolution2dQueueDescriptor;
     WorkloadInfo workloadInfo
     {
-        { inputInfo },
+        { inputInfo, weightInfo },
         { outputInfo }
     };
     convolution2dQueueDescriptor.m_Inputs.push_back(nullptr);
diff --git a/src/backends/backendsCommon/test/FullyConnectedEndToEndTestImpl.hpp b/src/backends/backendsCommon/test/FullyConnectedEndToEndTestImpl.hpp
index 1076aa6..0d2d2cb 100644
--- a/src/backends/backendsCommon/test/FullyConnectedEndToEndTestImpl.hpp
+++ b/src/backends/backendsCommon/test/FullyConnectedEndToEndTestImpl.hpp
@@ -110,8 +110,11 @@
 {
     armnn::INetworkPtr network(armnn::INetwork::Create());
 
+
+    ConstTensor biases;
+
     armnn::IConnectableLayer* inputLayer  = network->AddInputLayer(0, "Input");
-    armnn::IConnectableLayer* biasLayer   = network->AddInputLayer(2, "Bias_Input");
+    armnn::IConnectableLayer* biasLayer   = network->AddConstantLayer(biases, "Bias_Input");
     armnn::IConnectableLayer* fullyConnectedLayer = network->AddFullyConnectedLayer(descriptor, "Fully_Connected");
     armnn::IConnectableLayer* outputLayer = network->AddOutputLayer(0, "Output");
 
@@ -402,16 +405,7 @@
             IRuntime::CreationOptions options;
             IRuntimePtr               runtime(IRuntime::Create(options));
 
-            try
-            {
-                Optimize(*network, backends, runtime->GetDeviceSpec());
-                FAIL("LayerValidationException should have been thrown");
-            }
-            catch (const LayerValidationException& exc)
-            {
-                CHECK(strcmp(exc.what(), "Fully_Connected layer weights not set: Input slot(s) 1 not connected "
-                                         "to an output slot on FullyConnected layer \"Fully_Connected\"") == 0);
-            }
+            CHECK_THROWS_AS(Optimize(*network, backends, runtime->GetDeviceSpec()), LayerValidationException);
         }
         else if (!connectedBias)
         {
@@ -429,16 +423,7 @@
             IRuntime::CreationOptions options;
             IRuntimePtr               runtime(IRuntime::Create(options));
 
-            try
-            {
-                Optimize(*network, backends, runtime->GetDeviceSpec());
-                FAIL("LayerValidationException should have been thrown");
-            }
-            catch (const LayerValidationException& exc)
-            {
-                CHECK(strcmp(exc.what(), "Fully_Connected layer bias not set: Input slot(s) 2 not connected "
-                                         "to an output slot on FullyConnected layer \"Fully_Connected\"") == 0);
-            }
+            CHECK_THROWS_AS(Optimize(*network, backends, runtime->GetDeviceSpec()), LayerValidationException);
         }
     }
     else if(!connectedWeights && !connectedBias)
@@ -452,17 +437,7 @@
         IRuntime::CreationOptions options;
         IRuntimePtr               runtime(IRuntime::Create(options));
 
-        try
-        {
-            Optimize(*network, backends, runtime->GetDeviceSpec());
-            FAIL("LayerValidationException should have been thrown");
-        }
-        catch (const LayerValidationException& exc)
-        {
-            CHECK(strcmp(exc.what(), "Fully_Connected layer weights and bias not set: Input slot(s) 1 & 2 not "
-                                     "connected to an output slot on FullyConnected layer \"Fully_Connected\"") == 0);
-        }
-
+        CHECK_THROWS_AS(Optimize(*network, backends, runtime->GetDeviceSpec()), LayerValidationException);
     }
     else if(!tensorInfoSet)
     {
diff --git a/src/backends/backendsCommon/test/LayerReleaseConstantDataTest.cpp b/src/backends/backendsCommon/test/LayerReleaseConstantDataTest.cpp
index 56f15a5..5ceb8ae 100644
--- a/src/backends/backendsCommon/test/LayerReleaseConstantDataTest.cpp
+++ b/src/backends/backendsCommon/test/LayerReleaseConstantDataTest.cpp
@@ -70,49 +70,68 @@
 
  }
 
+TEST_CASE("ReleaseConvolution2dLayerConstantDataTest")
+{
+    Graph graph;
 
- TEST_CASE("ReleaseConvolution2dLayerConstantDataTest")
- {
-     Graph graph;
+    // create the layer we're testing
+    Convolution2dDescriptor layerDesc;
+    layerDesc.m_PadLeft = 3;
+    layerDesc.m_PadRight = 3;
+    layerDesc.m_PadTop = 1;
+    layerDesc.m_PadBottom = 1;
+    layerDesc.m_StrideX = 2;
+    layerDesc.m_StrideY = 4;
+    layerDesc.m_BiasEnabled = true;
 
-     // create the layer we're testing
-     Convolution2dDescriptor layerDesc;
-     layerDesc.m_PadLeft = 3;
-     layerDesc.m_PadRight = 3;
-     layerDesc.m_PadTop = 1;
-     layerDesc.m_PadBottom = 1;
-     layerDesc.m_StrideX = 2;
-     layerDesc.m_StrideY = 4;
-     layerDesc.m_BiasEnabled = true;
+    Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
 
-     Convolution2dLayer* const layer = graph.AddLayer<Convolution2dLayer>(layerDesc, "layer");
+    layer->m_Weight = std::make_unique<ScopedTensorHandle>(TensorInfo({ 2, 3, 5, 3 },
+                                                                      armnn::DataType::Float32));
+    layer->m_Bias = std::make_unique<ScopedTensorHandle>
+        (TensorInfo({ 2 }, GetBiasDataType(armnn::DataType::Float32)));
 
-     layer->m_Weight = std::make_unique<ScopedTensorHandle>(TensorInfo({2, 3, 5, 3},
-                                                                          armnn::DataType::Float32));
-     layer->m_Bias   = std::make_unique<ScopedTensorHandle>
-             (TensorInfo({2}, GetBiasDataType(armnn::DataType::Float32)));
+    layer->m_Weight->Allocate();
+    layer->m_Bias->Allocate();
 
-     layer->m_Weight->Allocate();
-     layer->m_Bias->Allocate();
+    ConstantLayer* weightsLayer = graph.AddLayer<ConstantLayer>("Weights");
+    ConstantLayer* biasLayer = graph.AddLayer<ConstantLayer>("Bias");
 
-     // create extra layers
-     Layer* const input = graph.AddLayer<InputLayer>(0, "input");
-     Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
+    weightsLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(TensorInfo({ 2, 3, 5, 3 },
+                                                                      armnn::DataType::Float32));
 
-     // connect up
-     Connect(input, layer, TensorInfo({2, 3, 8, 16}, armnn::DataType::Float32));
-     Connect(layer, output, TensorInfo({2, 2, 2, 10}, armnn::DataType::Float32));
+    biasLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(
+        TensorInfo({2}, GetBiasDataType(armnn::DataType::Float32)));
 
-     // check the constants that they are not NULL
-     CHECK(layer->m_Weight != nullptr);
-     CHECK(layer->m_Bias != nullptr);
+    TensorInfo weightsInfo = weightsLayer->m_LayerOutput->GetTensorInfo();
+    weightsInfo.SetConstant();
+    TensorInfo biasInfo = biasLayer->m_LayerOutput->GetTensorInfo();
+    biasInfo.SetConstant();
 
-     // free up the constants..
-     layer->ReleaseConstantData();
 
-     // check the constants that they are NULL now
-     CHECK(layer->m_Weight == nullptr);
-     CHECK(layer->m_Bias == nullptr);
+    weightsLayer->GetOutputSlot(0).SetTensorInfo(weightsInfo);
+    biasLayer->GetOutputSlot(0).SetTensorInfo(biasInfo);
+
+    // create extra layers
+    Layer* const input = graph.AddLayer<InputLayer>(0, "input");
+    Layer* const output = graph.AddLayer<OutputLayer>(0, "output");
+
+    // connect up
+    Connect(input, layer, TensorInfo({ 2, 3, 8, 16 }, armnn::DataType::Float32));
+    weightsLayer->GetOutputSlot().Connect(layer->GetInputSlot(1));
+    biasLayer->GetOutputSlot().Connect(layer->GetInputSlot(2));
+    Connect(layer, output, TensorInfo({ 2, 2, 2, 10 }, armnn::DataType::Float32));
+
+    // check the constants that they are not NULL
+    CHECK(layer->m_Weight != nullptr);
+    CHECK(layer->m_Bias != nullptr);
+
+    // free up the constants..
+    layer->ReleaseConstantData();
+
+    // check the constants that they are NULL now
+    CHECK(layer->m_Weight == nullptr);
+    CHECK(layer->m_Bias == nullptr);
 }
 
 TEST_CASE("ReleaseDepthwiseConvolution2dLayerConstantDataTest")
@@ -131,8 +150,10 @@
 
     DepthwiseConvolution2dLayer* const layer = graph.AddLayer<DepthwiseConvolution2dLayer>(layerDesc, "layer");
 
-    layer->m_Weight = std::make_unique<ScopedTensorHandle>(TensorInfo({3, 3, 5, 3}, DataType::Float32));
-    layer->m_Bias   = std::make_unique<ScopedTensorHandle>(TensorInfo({9}, DataType::Float32));
+    layer->m_Weight = std::make_unique<ScopedTensorHandle>(
+        TensorInfo({3, 3, 5, 3}, DataType::Float32));
+    layer->m_Bias = std::make_unique<ScopedTensorHandle>(
+        TensorInfo({9}, DataType::Float32));
     layer->m_Weight->Allocate();
     layer->m_Bias->Allocate();
 
@@ -170,10 +191,10 @@
     float inputsQScale = 1.0f;
     float outputQScale = 2.0f;
 
-    layer->m_Weight = std::make_unique<ScopedTensorHandle>(TensorInfo({7, 20},
-                                                          DataType::QAsymmU8, inputsQScale, 0));
-    layer->m_Bias   = std::make_unique<ScopedTensorHandle>(TensorInfo({7},
-                                                          GetBiasDataType(DataType::QAsymmU8), inputsQScale));
+    layer->m_Weight = std::make_unique<ScopedTensorHandle>(
+        TensorInfo({7, 20}, DataType::QAsymmU8, inputsQScale, 0));
+    layer->m_Bias = std::make_unique<ScopedTensorHandle>(
+        TensorInfo({7}, GetBiasDataType(DataType::QAsymmU8), inputsQScale));
     layer->m_Weight->Allocate();
     layer->m_Bias->Allocate();
 
diff --git a/src/backends/backendsCommon/test/OptimizationViewsTests.cpp b/src/backends/backendsCommon/test/OptimizationViewsTests.cpp
index 1219ac5..9b86784 100644
--- a/src/backends/backendsCommon/test/OptimizationViewsTests.cpp
+++ b/src/backends/backendsCommon/test/OptimizationViewsTests.cpp
@@ -61,31 +61,35 @@
     Layer* const inputLayer = baseGraph.AddLayer<InputLayer>(0, "input");
 
     Convolution2dDescriptor convDescriptor;
-    PreCompiledDescriptor substitutionLayerDescriptor(1, 1);
+    PreCompiledDescriptor substitutionLayerDescriptor(2, 1);
     Layer* const convLayer1 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
     Layer* const convLayer2 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
+    Layer* const weightsLayer1 = baseGraph.AddLayer<ConstantLayer>("weights1");
+    Layer* const weightsLayer2 = baseGraph.AddLayer<ConstantLayer>("weights2");
     Layer* const substitutableCompiledLayer =
             baseGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
 
     Layer* const outputLayer = baseGraph.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));
 
     // Subgraph for a failed layer
     SubgraphViewSelector::SubgraphViewPtr failedSubgraph =
-        CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
+        CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
                                CreateOutputsFrom({convLayer1}),
                                {convLayer1});
     // Subgraph for an untouched layer
     SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph =
-            CreateSubgraphViewFrom(CreateInputsFrom({convLayer2}),
+            CreateSubgraphViewFrom(CreateInputsFrom(convLayer2),
                                    CreateOutputsFrom({convLayer2}),
                                    {convLayer2});
     // Subgraph for a substitutable layer
     SubgraphViewSelector::SubgraphViewPtr substitutableSubgraph =
-            CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
+            CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
                                    CreateOutputsFrom({convLayer2}),
                                    {substitutableCompiledLayer});
     // Create a Graph containing a layer to substitute in
@@ -95,7 +99,7 @@
 
     // Subgraph for a substitution layer
     SubgraphViewSelector::SubgraphViewPtr substitutionSubgraph =
-            CreateSubgraphViewFrom(CreateInputsFrom({substitutionpreCompiledLayer}),
+            CreateSubgraphViewFrom(CreateInputsFrom(substitutionpreCompiledLayer),
                                    CreateOutputsFrom({substitutionpreCompiledLayer}),
                                    {substitutionpreCompiledLayer});
 
@@ -106,14 +110,14 @@
     view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
 
     SubgraphViewSelector::SubgraphViewPtr baseSubgraph =
-            CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
+            CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
                                    CreateOutputsFrom({convLayer2}),
                                    {substitutionpreCompiledLayer});
     view.AddSubstitution({*baseSubgraph, *substitutionSubgraph});
 
     // Construct original subgraph to compare against
     SubgraphViewSelector::SubgraphViewPtr originalSubgraph =
-            CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
+            CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
             CreateOutputsFrom({convLayer2}),
             {convLayer1, convLayer2, substitutionpreCompiledLayer});
 
@@ -147,11 +151,11 @@
     convLayer2->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
 
     // Subgraph for a failed layer
-    SubgraphViewSelector::SubgraphViewPtr failedSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
+    SubgraphViewSelector::SubgraphViewPtr failedSubgraph = CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
                                                                                   CreateOutputsFrom({convLayer1}),
                                                                                   {convLayer1});
     // Subgraph for an untouched layer
-    SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer2}),
+    SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph = CreateSubgraphViewFrom(CreateInputsFrom(convLayer2),
                                                                                      CreateOutputsFrom({convLayer2}),
                                                                                      {convLayer2});
 
@@ -162,21 +166,21 @@
 
     // Subgraph for a substitution layer
     SubgraphViewSelector::SubgraphViewPtr substitutionSubgraph =
-        CreateSubgraphViewFrom(CreateInputsFrom({substitutionpreCompiledLayer}),
+        CreateSubgraphViewFrom(CreateInputsFrom(substitutionpreCompiledLayer),
                                                 CreateOutputsFrom({substitutionpreCompiledLayer}),
                                                 {substitutionpreCompiledLayer});
 
     view.AddFailedSubgraph(SubgraphView(*failedSubgraph));
     view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
 
-    SubgraphViewSelector::SubgraphViewPtr baseSubgraph = CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
+    SubgraphViewSelector::SubgraphViewPtr baseSubgraph = CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
                                                                                 CreateOutputsFrom({convLayer2}),
                                                                                 {substitutionpreCompiledLayer});
     view.AddSubstitution({*baseSubgraph, *substitutionSubgraph});
 
     // Construct original subgraph to compare against
     SubgraphViewSelector::SubgraphViewPtr originalSubgraph =
-        CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
+        CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
                                                 CreateOutputsFrom({convLayer2}),
                                                 {convLayer1, convLayer2, substitutionpreCompiledLayer});
 
@@ -192,26 +196,31 @@
     Layer* const inputLayer = baseGraph.AddLayer<InputLayer>(0, "input");
 
     Convolution2dDescriptor convDescriptor;
-    PreCompiledDescriptor substitutionLayerDescriptor(1, 1);
+    PreCompiledDescriptor substitutionLayerDescriptor(2, 1);
     Layer* const convLayer1 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv1");
     Layer* const convLayer2 = baseGraph.AddLayer<Convolution2dLayer>(convDescriptor, "conv2");
+    Layer* const weightsLayer1 = baseGraph.AddLayer<ConstantLayer>("weights1");
+    Layer* const weightsLayer2 = baseGraph.AddLayer<ConstantLayer>("weights2");
     Layer* const substitutableCompiledLayer =
             baseGraph.AddLayer<PreCompiledLayer>(substitutionLayerDescriptor, "pre-compiled");
 
     Layer* const outputLayer = baseGraph.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));
 
     // Subgraph for an untouched layer
     SubgraphViewSelector::SubgraphViewPtr untouchedSubgraph =
-            CreateSubgraphViewFrom(CreateInputsFrom({convLayer2}),
+            CreateSubgraphViewFrom(CreateInputsFrom(convLayer2),
                                    CreateOutputsFrom({convLayer2}),
                                    {convLayer2});
     // Subgraph for a substitutable layer
     SubgraphViewSelector::SubgraphViewPtr substitutableSubgraph =
-            CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
+            CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
                                    CreateOutputsFrom({convLayer2}),
                                    {substitutableCompiledLayer});
     // Create a Graph containing a layer to substitute in
@@ -221,7 +230,7 @@
 
     // Subgraph for a substitution layer
     SubgraphViewSelector::SubgraphViewPtr substitutionSubgraph =
-            CreateSubgraphViewFrom(CreateInputsFrom({substitutionpreCompiledLayer}),
+            CreateSubgraphViewFrom(CreateInputsFrom(substitutionpreCompiledLayer),
                                    CreateOutputsFrom({substitutionpreCompiledLayer}),
                                    {substitutionpreCompiledLayer});
 
@@ -231,14 +240,14 @@
     view.AddUntouchedSubgraph(SubgraphView(*untouchedSubgraph));
 
     SubgraphViewSelector::SubgraphViewPtr baseSubgraph =
-            CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
+            CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
                                    CreateOutputsFrom({convLayer2}),
                                    {substitutionpreCompiledLayer});
     view.AddSubstitution({*baseSubgraph, *substitutionSubgraph});
 
     // Construct original subgraph to compare against
     SubgraphViewSelector::SubgraphViewPtr originalSubgraph =
-            CreateSubgraphViewFrom(CreateInputsFrom({convLayer1}),
+            CreateSubgraphViewFrom(CreateInputsFrom(convLayer1),
                                    CreateOutputsFrom({convLayer2}),
                                    {convLayer1, convLayer2, substitutionpreCompiledLayer});
 
diff --git a/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp b/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp
index ad59704..45fcf19 100644
--- a/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp
+++ b/src/backends/backendsCommon/test/OptimizeSubgraphViewTests.cpp
@@ -106,6 +106,21 @@
     return convLayer;
 }
 
+// Convenience function to add a constant layer to a graph
+ConstantLayer* AddConstantLayer(Graph& graph,
+                                LayerNameToLayerMap& layersInGraph,
+                                const std::string& layerName,
+                                const ConstTensor& constTensor,
+                                const TensorInfo& outputInfo)
+{
+    ConstantLayer* const constantLayer = graph.AddLayer<ConstantLayer>(layerName.c_str());
+    CHECK(constantLayer);
+    constantLayer->m_LayerOutput = std::make_shared<ScopedTensorHandle>(constTensor);
+    constantLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
+    layersInGraph.insert(std::make_pair(constantLayer->GetName(), constantLayer));
+    return constantLayer;
+}
+
 // Convenience function to add a pooling layer to a graph
 Pooling2dLayer* AddPoolingLayer(Graph& graph,
                                 LayerNameToLayerMap& layersInGraph,
@@ -246,7 +261,7 @@
     poolingLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
 
     // Create the subgraph view for the whole network
-    return CreateSubgraphViewFrom(CreateInputsFrom({poolingLayer}),
+    return CreateSubgraphViewFrom(CreateInputsFrom(poolingLayer),
                                   CreateOutputsFrom({poolingLayer}),
                                   {poolingLayer});
 }
@@ -287,7 +302,7 @@
     pooling3Layer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
 
     // Create the subgraph view for the whole network
-    return CreateSubgraphViewFrom(CreateInputsFrom({pooling1Layer}),
+    return CreateSubgraphViewFrom(CreateInputsFrom(pooling1Layer),
                                   CreateOutputsFrom({pooling3Layer}),
                                   {pooling1Layer,
                                    pooling2Layer,
@@ -299,8 +314,11 @@
 {
     const TensorInfo inputInfo ({  1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
     const TensorInfo outputInfo({  1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
-    const TensorInfo weightInfo({ 16,  1,  1, 16 }, DataType::QAsymmU8, 0.9f, 0);
-    const TensorInfo biasInfo  ({  1,  1,  1, 16 }, DataType::Signed32,        0.9f, 0);
+    TensorInfo weightInfo({ 16,  1,  1, 16 }, DataType::QAsymmU8, 0.9f, 0);
+    TensorInfo biasInfo  ({  1,  1,  1, 16 }, DataType::Signed32,        0.9f, 0);
+
+    weightInfo.SetConstant(true);
+    biasInfo.SetConstant(true);
 
     Convolution2dDescriptor convolutionDescriptor;
     convolutionDescriptor.m_StrideX     = 1;
@@ -308,20 +326,34 @@
     convolutionDescriptor.m_BiasEnabled = true;
     convolutionDescriptor.m_DataLayout  = DataLayout::NHWC;
 
+    std::vector<float> weightsVector(64);
+    ConstTensor constWeightsTensor(weightInfo, weightsVector);
+
+    std::vector<float> biasVector(16);
+    ConstTensor constBiasTensor(biasInfo, biasVector);
+
     // Construct the graph
     Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo);
     Convolution2dLayer* const convLayer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
                                                               "conv layer", weightInfo, biasInfo, outputInfo);
+
+  ConstantLayer* const weightsLayer =
+      AddConstantLayer(graph, layersInGraph, "Weights Layer", constWeightsTensor, outputInfo);
+  ConstantLayer* const biasLayer = AddConstantLayer(graph, layersInGraph, "Bias Layer", constBiasTensor, outputInfo);
+
     Layer* const outputLayer = AddOutputLayer(graph, "output layer");
 
     // Connect the network
     inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
+    weightsLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(1));
+    biasLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(2));
     convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
 
+    std::vector<unsigned int> ignoreSlots = {1, 2};
     // Create the subgraph view for the whole network
-    return CreateSubgraphViewFrom(CreateInputsFrom({convLayer}),
+    return CreateSubgraphViewFrom(CreateInputsFrom(convLayer, ignoreSlots),
                                   CreateOutputsFrom({convLayer}),
-                                  {convLayer});
+                                  {convLayer, weightsLayer, biasLayer});
 }
 
 // Creates a subgraph with five convolutions layers, all supported by the mock backend
@@ -329,8 +361,18 @@
 {
     const TensorInfo inputInfo ({  1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
     const TensorInfo outputInfo({  1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
-    const TensorInfo weightInfo({ 16,  1,  1, 16 }, DataType::QAsymmU8, 0.9f, 0);
-    const TensorInfo biasInfo  ({  1,  1,  1, 16 }, DataType::Signed32,        0.9f, 0);
+    TensorInfo weightInfo({ 16,  1,  1, 16 }, DataType::QAsymmU8, 0.9f, 0);
+    TensorInfo biasInfo  ({  1,  1,  1, 16 }, DataType::Signed32,        0.9f, 0);
+
+    weightInfo.SetConstant(true);
+    biasInfo.SetConstant(true);
+
+    std::vector<float> weightsVector(64);
+    ConstTensor constWeightsTensor(weightInfo, weightsVector);
+
+    std::vector<float> biasVector(16);
+    ConstTensor constBiasTensor(biasInfo, biasVector);
+
 
     Convolution2dDescriptor convolutionDescriptor;
     convolutionDescriptor.m_StrideX     = 1;
@@ -342,32 +384,84 @@
     Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo);
     Convolution2dLayer* const conv1Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
                                                                "conv1 layer", weightInfo, biasInfo, outputInfo);
+    ConstantLayer* const weightsLayer1 =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer 1", constWeightsTensor, outputInfo);
+    ConstantLayer* const biasLayer1 =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer 1", constBiasTensor, outputInfo);
+
     Convolution2dLayer* const conv2Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
                                                                "conv2 layer", weightInfo, biasInfo, outputInfo);
+    ConstantLayer* const weightsLayer2 =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer 2", constWeightsTensor, outputInfo);
+    ConstantLayer* const biasLayer2 =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer 2", constBiasTensor, outputInfo);
+
+
     Convolution2dLayer* const conv3Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
                                                                "conv3 layer", weightInfo, biasInfo, outputInfo);
+    ConstantLayer* const weightsLayer3 =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer 3", constWeightsTensor, outputInfo);
+    ConstantLayer* const biasLayer3 =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer 3", constBiasTensor, outputInfo);
+
     Convolution2dLayer* const conv4Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
                                                                "conv4 layer", weightInfo, biasInfo, outputInfo);
+    ConstantLayer* const weightsLayer4 =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer 4", constWeightsTensor, outputInfo);
+    ConstantLayer* const biasLayer4 =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer 4", constBiasTensor, outputInfo);
+
     Convolution2dLayer* const conv5Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
                                                                "conv5 layer", weightInfo, biasInfo, outputInfo);
+    ConstantLayer* const weightsLayer5 =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer 5", constWeightsTensor, outputInfo);
+    ConstantLayer* const biasLayer5 =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer 5", constBiasTensor, outputInfo);
+
+
     Layer* const outputLayer = AddOutputLayer(graph, "output layer");
 
     // Connect the network
     inputLayer->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(0));
-    conv1Layer->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(0));
-    conv2Layer->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(0));
-    conv3Layer->GetOutputSlot(0).Connect(conv4Layer->GetInputSlot(0));
-    conv4Layer->GetOutputSlot(0).Connect(conv5Layer->GetInputSlot(0));
-    conv5Layer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
+    weightsLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(1));
+    biasLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(2));
 
+    conv1Layer->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(0));
+    weightsLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(1));
+    biasLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(2));
+
+    conv2Layer->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(0));
+    weightsLayer3->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(1));
+    biasLayer3->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(2));
+
+    conv3Layer->GetOutputSlot(0).Connect(conv4Layer->GetInputSlot(0));
+    weightsLayer4->GetOutputSlot(0).Connect(conv4Layer->GetInputSlot(1));
+    biasLayer4->GetOutputSlot(0).Connect(conv4Layer->GetInputSlot(2));
+
+    conv4Layer->GetOutputSlot(0).Connect(conv5Layer->GetInputSlot(0));
+    weightsLayer5->GetOutputSlot(0).Connect(conv5Layer->GetInputSlot(1));
+    biasLayer5->GetOutputSlot(0).Connect(conv5Layer->GetInputSlot(2));
+
+    conv5Layer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
+    std::vector<unsigned int> ignoreSlots = {1, 2};
     // Create the subgraph view for the whole network
-    return CreateSubgraphViewFrom(CreateInputsFrom({conv1Layer}),
-                                  CreateOutputsFrom({conv5Layer}),
-                                  {conv1Layer,
-                                   conv2Layer,
-                                   conv3Layer,
-                                   conv4Layer,
-                                   conv5Layer});
+    return CreateSubgraphViewFrom(CreateInputsFrom(conv1Layer, ignoreSlots),
+                                  CreateOutputsFrom({ conv5Layer }),
+                                  { weightsLayer1,
+                                    biasLayer1,
+                                    conv1Layer,
+                                    weightsLayer2,
+                                    biasLayer2,
+                                    conv2Layer,
+                                    weightsLayer3,
+                                    biasLayer3,
+                                    conv3Layer,
+                                    weightsLayer4,
+                                    biasLayer4,
+                                    conv4Layer,
+                                    weightsLayer5,
+                                    biasLayer5,
+                                    conv5Layer });
 }
 
 // Creates a subgraph with both supported and unsupported layers
@@ -376,8 +470,17 @@
 {
     const TensorInfo inputInfo ({  1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
     const TensorInfo outputInfo({  1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
-    const TensorInfo weightInfo({ 16,  1,  1, 16 }, DataType::QAsymmU8, 0.9f, 0);
-    const TensorInfo biasInfo  ({  1,  1,  1, 16 }, DataType::Signed32,        0.9f, 0);
+    TensorInfo weightInfo({ 16,  1,  1, 16 }, DataType::QAsymmU8, 0.9f, 0);
+    TensorInfo biasInfo  ({  1,  1,  1, 16 }, DataType::Signed32,        0.9f, 0);
+
+    weightInfo.SetConstant(true);
+    biasInfo.SetConstant(true);
+
+    std::vector<float> weightsVector(64);
+    ConstTensor constWeightsTensor(weightInfo, weightsVector);
+
+    std::vector<float> biasVector(16);
+    ConstTensor constBiasTensor(biasInfo, biasVector);
 
     Convolution2dDescriptor convolutionDescriptor;
     convolutionDescriptor.m_StrideX     = 1;
@@ -400,12 +503,25 @@
 
     // Construct the graph
     Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo);
+    ConstantLayer* const weightsLayer1 =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer 1", constWeightsTensor, outputInfo);
+
+    ConstantLayer* const biasLayer1 =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer 1", constBiasTensor, outputInfo);
+
     Convolution2dLayer* const conv1Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
                                                                "conv1 layer", weightInfo, biasInfo, outputInfo);
     Pooling2dLayer* const pooling1Layer = AddPoolingLayer(graph, layersInGraph, poolingDescriptor,
                                                           "pooling1 layer", outputInfo);
     Pooling2dLayer* const pooling2Layer = AddPoolingLayer(graph, layersInGraph, poolingDescriptor,
                                                           "pooling2 layer", outputInfo);
+
+    ConstantLayer* const weightsLayer2 =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer 2", constWeightsTensor, outputInfo);
+
+    ConstantLayer* const biasLayer2 =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer 2", constBiasTensor, outputInfo);
+
     Convolution2dLayer* const conv2Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
                                                                "conv2 layer", weightInfo, biasInfo, outputInfo);
     Pooling2dLayer* const pooling3Layer = AddPoolingLayer(graph, layersInGraph, poolingDescriptor,
@@ -414,18 +530,27 @@
 
     // Connect the network
     inputLayer->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(0));
+    weightsLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(1));
+    biasLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(2));
     conv1Layer->GetOutputSlot(0).Connect(pooling1Layer->GetInputSlot(0));
     pooling1Layer->GetOutputSlot(0).Connect(pooling2Layer->GetInputSlot(0));
     pooling2Layer->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(0));
+    weightsLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(1));
+    biasLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(2));
     conv2Layer->GetOutputSlot(0).Connect(pooling3Layer->GetInputSlot(0));
     pooling3Layer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
 
+    std::vector<unsigned int> ignoreSlots = {1, 2};
     // Create the subgraph view for the whole network
-    return CreateSubgraphViewFrom(CreateInputsFrom({conv1Layer}),
+    return CreateSubgraphViewFrom(CreateInputsFrom(conv1Layer, ignoreSlots),
                                   CreateOutputsFrom({pooling3Layer}),
-                                  {conv1Layer,
+                                  {weightsLayer1,
+                                   biasLayer1,
+                                   conv1Layer,
                                    pooling1Layer,
                                    pooling2Layer,
+                                   weightsLayer2,
+                                   biasLayer2,
                                    conv2Layer,
                                    pooling3Layer});
 }
@@ -435,9 +560,17 @@
 {
     const TensorInfo inputInfo ({  1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
     const TensorInfo outputInfo({  1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
-    const TensorInfo weightInfo({ 16,  1,  1, 16 }, DataType::QAsymmU8, 0.9f, 0);
-    const TensorInfo biasInfo  ({  1,  1,  1, 16 }, DataType::Signed32,        0.9f, 0);
+    TensorInfo weightInfo({ 16,  1,  1, 16 }, DataType::QAsymmU8, 0.9f, 0);
+    TensorInfo biasInfo  ({  1,  1,  1, 16 }, DataType::Signed32,        0.9f, 0);
 
+    weightInfo.SetConstant(true);
+    biasInfo.SetConstant(true);
+
+    std::vector<float> weightsVector(64);
+    ConstTensor constWeightsTensor(weightInfo, weightsVector);
+
+    std::vector<float> biasVector(16);
+    ConstTensor constBiasTensor(biasInfo, biasVector);
     Convolution2dDescriptor convolutionDescriptor;
     convolutionDescriptor.m_StrideX     = 1;
     convolutionDescriptor.m_StrideY     = 1;
@@ -446,6 +579,13 @@
 
     // Construct the graph
     Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo);
+
+    ConstantLayer* const weightsLayer =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer unoptimizable", constWeightsTensor, outputInfo);
+
+    ConstantLayer* const biasLayer =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer unoptimizable", constBiasTensor, outputInfo);
+
     Convolution2dLayer* const convLayer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
                                                                "conv layer unoptimizable", weightInfo, biasInfo,
                                                                outputInfo);
@@ -453,12 +593,15 @@
 
     // Connect the network
     inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
+    weightsLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(1));
+    biasLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(2));
     convLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
 
+    std::vector<unsigned int> ignoreSlots = {1, 2};
     // Create the subgraph view for the whole network
-    return CreateSubgraphViewFrom(CreateInputsFrom({convLayer}),
+    return CreateSubgraphViewFrom(CreateInputsFrom(convLayer, ignoreSlots),
                                   CreateOutputsFrom({convLayer}),
-                                  {convLayer});
+                                  {convLayer, weightsLayer, biasLayer});
 }
 
 // Creates a subgraph with some unoptimizable layers ("unoptimizable" is added to the layer's name)
@@ -466,8 +609,17 @@
 {
     const TensorInfo inputInfo ({  1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
     const TensorInfo outputInfo({  1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
-    const TensorInfo weightInfo({ 16,  1,  1, 16 }, DataType::QAsymmU8, 0.9f, 0);
-    const TensorInfo biasInfo  ({  1,  1,  1, 16 }, DataType::Signed32,        0.9f, 0);
+    TensorInfo weightInfo({ 16,  1,  1, 16 }, DataType::QAsymmU8, 0.9f, 0);
+    TensorInfo biasInfo  ({  1,  1,  1, 16 }, DataType::Signed32,        0.9f, 0);
+
+    weightInfo.SetConstant(true);
+    biasInfo.SetConstant(true);
+
+    std::vector<float> weightsVector(64);
+    ConstTensor constWeightsTensor(weightInfo, weightsVector);
+
+    std::vector<float> biasVector(16);
+    ConstTensor constBiasTensor(biasInfo, biasVector);
 
     Convolution2dDescriptor convolutionDescriptor;
     convolutionDescriptor.m_StrideX     = 1;
@@ -477,36 +629,93 @@
 
     // Construct the graph
     Layer* const inputLayer = AddInputLayer(graph, "input layer", inputInfo);
-    Convolution2dLayer* const conv1Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
-                                                               "conv1 layer", weightInfo, biasInfo, outputInfo);
-    Convolution2dLayer* const conv2Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
-                                                               "conv2 layer unoptimizable", weightInfo, biasInfo,
-                                                               outputInfo);
-    Convolution2dLayer* const conv3Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
-                                                               "conv3 layer", weightInfo, biasInfo, outputInfo);
-    Convolution2dLayer* const conv4Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
-                                                               "conv4 layer unoptimizable", weightInfo, biasInfo,
-                                                               outputInfo);
-    Convolution2dLayer* const conv5Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
-                                                               "conv5 layer", weightInfo, biasInfo, outputInfo);
-    Layer* const outputLayer = AddOutputLayer(graph, "output layer");
+
+    ConstantLayer* const weightsLayer1 =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer 1", constWeightsTensor, outputInfo);
+    ConstantLayer* const biasLayer1 =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer 1", constBiasTensor, outputInfo);
+    ConstantLayer* const weightsLayer2 =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer 2 unoptimizable", constWeightsTensor, outputInfo);
+    ConstantLayer* const biasLayer2 =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer 2 unoptimizable", constBiasTensor, outputInfo);
+    ConstantLayer* const weightsLayer3 =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer 3", constWeightsTensor, outputInfo);
+    ConstantLayer* const biasLayer3 =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer 3", constBiasTensor, outputInfo);
+    ConstantLayer* const weightsLayer4 =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer 4 unoptimizable", constWeightsTensor, outputInfo);
+    ConstantLayer* const biasLayer4 =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer 4 unoptimizable", constBiasTensor, outputInfo);
+    ConstantLayer* const weightsLayer5 =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer 5", constWeightsTensor, outputInfo);
+    ConstantLayer* const biasLayer5 =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer 5", constBiasTensor, outputInfo);
+
+  Convolution2dLayer* const conv1Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
+                                                             "conv1 layer", weightInfo, biasInfo, outputInfo);
+  Convolution2dLayer* const conv2Layer = AddConvolutionLayer(graph,
+                                                             layersInGraph,
+                                                             convolutionDescriptor,
+                                                             "conv2 layer unoptimizable",
+                                                             weightInfo,
+                                                             biasInfo,
+                                                             outputInfo);
+  Convolution2dLayer* const conv3Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
+                                                             "conv3 layer", weightInfo, biasInfo, outputInfo);
+  Convolution2dLayer* const conv4Layer = AddConvolutionLayer(graph,
+                                                             layersInGraph,
+                                                             convolutionDescriptor,
+                                                             "conv4 layer unoptimizable",
+                                                             weightInfo,
+                                                             biasInfo,
+                                                             outputInfo);
+  Convolution2dLayer* const conv5Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
+                                                             "conv5 layer", weightInfo, biasInfo, outputInfo);
+
+  Layer* const outputLayer = AddOutputLayer(graph, "output layer");
 
     // Connect the network
     inputLayer->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(0));
+    weightsLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(1));
+    biasLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(2));
+
     conv1Layer->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(0));
+    weightsLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(1));
+    biasLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(2));
+
     conv2Layer->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(0));
+    weightsLayer3->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(1));
+    biasLayer3->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(2));
+
     conv3Layer->GetOutputSlot(0).Connect(conv4Layer->GetInputSlot(0));
+    weightsLayer4->GetOutputSlot(0).Connect(conv4Layer->GetInputSlot(1));
+    biasLayer4->GetOutputSlot(0).Connect(conv4Layer->GetInputSlot(2));
+
     conv4Layer->GetOutputSlot(0).Connect(conv5Layer->GetInputSlot(0));
+    weightsLayer5->GetOutputSlot(0).Connect(conv5Layer->GetInputSlot(1));
+    biasLayer5->GetOutputSlot(0).Connect(conv5Layer->GetInputSlot(2));
+
     conv5Layer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
 
+    std::vector<unsigned int> ignoreSlots = {1, 2};
     // Create the subgraph view for the whole network
-    return CreateSubgraphViewFrom(CreateInputsFrom({conv1Layer}),
+    return CreateSubgraphViewFrom(CreateInputsFrom(conv1Layer, ignoreSlots),
                                   CreateOutputsFrom({conv5Layer}),
-                                  {conv1Layer,
-                                   conv2Layer,
-                                   conv3Layer,
-                                   conv4Layer,
-                                   conv5Layer});
+                                  {weightsLayer1,
+                                    biasLayer1,
+                                    conv1Layer,
+                                    weightsLayer2,
+                                    biasLayer2,
+                                    conv2Layer,
+                                    weightsLayer3,
+                                    biasLayer3,
+                                    conv3Layer,
+                                    weightsLayer4,
+                                    biasLayer4,
+                                    conv4Layer,
+                                    weightsLayer5,
+                                    biasLayer5,
+                                    conv5Layer});
 }
 
 // Creates a subgraph with some input unoptimizable layers ("unoptimizable" is added to the layer's name),
@@ -515,8 +724,17 @@
 {
     const TensorInfo inputInfo ({  1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
     const TensorInfo outputInfo({  1, 16, 16, 16 }, DataType::QAsymmU8, 1.0f, 0);
-    const TensorInfo weightInfo({ 16,  1,  1, 16 }, DataType::QAsymmU8, 0.9f, 0);
-    const TensorInfo biasInfo  ({  1,  1,  1, 16 }, DataType::Signed32,        0.9f, 0);
+    TensorInfo weightInfo({ 16,  1,  1, 16 }, DataType::QAsymmU8, 0.9f, 0);
+    TensorInfo biasInfo  ({  1,  1,  1, 16 }, DataType::Signed32,        0.9f, 0);
+
+    weightInfo.SetConstant(true);
+    biasInfo.SetConstant(true);
+
+    std::vector<float> weightsVector(64);
+    ConstTensor constWeightsTensor(weightInfo, weightsVector);
+
+    std::vector<float> biasVector(16);
+    ConstTensor constBiasTensor(biasInfo, biasVector);
 
     Convolution2dDescriptor convolutionDescriptor;
     convolutionDescriptor.m_StrideX     = 1;
@@ -527,6 +745,20 @@
     // Construct the graph
     Layer* const input1Layer = AddInputLayer(graph, "input1 layer", inputInfo, 0);
     Layer* const input2Layer = AddInputLayer(graph, "input2 layer", inputInfo, 1);
+
+    ConstantLayer* const weightsLayer1 =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer 1", constWeightsTensor, outputInfo);
+    ConstantLayer* const biasLayer1 =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer 1", constBiasTensor, outputInfo);
+    ConstantLayer* const weightsLayer2 =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer 2 unoptimizable", constWeightsTensor, outputInfo);
+    ConstantLayer* const biasLayer2 =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer 2 unoptimizable", constBiasTensor, outputInfo);
+    ConstantLayer* const weightsLayer3 =
+        AddConstantLayer(graph, layersInGraph, "Weights Layer 3", constWeightsTensor, outputInfo);
+    ConstantLayer* const biasLayer3 =
+        AddConstantLayer(graph, layersInGraph, "Bias Layer 3", constBiasTensor, outputInfo);
+
     Convolution2dLayer* const conv1Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
                                                                "conv1 layer", weightInfo, biasInfo, outputInfo);
     Convolution2dLayer* const conv2Layer = AddConvolutionLayer(graph, layersInGraph, convolutionDescriptor,
@@ -539,20 +771,35 @@
 
     // Connect the network
     input1Layer->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(0));
-    input2Layer->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(0));
+    weightsLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(1));
+    biasLayer1->GetOutputSlot(0).Connect(conv1Layer->GetInputSlot(2));
     conv1Layer->GetOutputSlot(0).Connect(addLayer->GetInputSlot(0));
+
+    input2Layer->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(0));
+    weightsLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(1));
+    biasLayer2->GetOutputSlot(0).Connect(conv2Layer->GetInputSlot(2));
     conv2Layer->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(0));
+    weightsLayer3->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(1));
+    biasLayer3->GetOutputSlot(0).Connect(conv3Layer->GetInputSlot(2));
     conv3Layer->GetOutputSlot(0).Connect(addLayer->GetInputSlot(1));
+
     addLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
 
     // Create the subgraph view for the whole network
+    std::vector<unsigned int> ignoreSlots = {1, 2};
     return CreateSubgraphViewFrom(CreateInputsFrom({conv1Layer,
-                                                    conv2Layer}),
+                                                    conv2Layer}, ignoreSlots),
                                   CreateOutputsFrom({addLayer}),
-                                  {conv1Layer,
-                                   conv2Layer,
-                                   conv3Layer,
-                                   addLayer});
+                                  { weightsLayer1,
+                                    biasLayer1,
+                                    weightsLayer2,
+                                    biasLayer2,
+                                    weightsLayer3,
+                                    biasLayer3,
+                                    conv1Layer,
+                                    conv2Layer,
+                                    conv3Layer,
+                                    addLayer });
 }
 
 // The input subgraph contains only a single unsupported layer (only convolutions are unsupported by the mock backend)
@@ -713,9 +960,11 @@
 
     CHECK(subgraphInputSlots.size()  == 1);
     CHECK(subgraphOutputSlots.size() == 1);
-    CHECK(subgraphLayers.size()      == 1);
+    CHECK(subgraphLayers.size()      == 3);
 
     CHECK(Contains(layersInGraph, "conv layer"));
+    CHECK(Contains(layersInGraph, "Weights Layer"));
+    CHECK(Contains(layersInGraph, "Bias Layer"));
 
     // Create a mock backend object
     MockBackendInitialiser initialiser; // Register the Mock Backend
@@ -776,15 +1025,25 @@
     const SubgraphView::IOutputSlots& subgraphOutputSlots = subgraphPtr->GetIOutputSlots();
     const SubgraphView::IConnectableLayers& subgraphLayers = subgraphPtr->GetIConnectableLayers();
 
-    CHECK(subgraphPtr->GetIInputSlots().size()  == 1);
-    CHECK(subgraphPtr->GetIOutputSlots().size() == 1);
-    CHECK(subgraphPtr->GetIConnectableLayers().size() == 5);
+    CHECK(subgraphInputSlots.size()  == 1);
+    CHECK(subgraphOutputSlots.size() == 1);
+    CHECK(subgraphPtr->GetIConnectableLayers().size() == 15);
 
     CHECK(Contains(layersInGraph, "conv1 layer"));
     CHECK(Contains(layersInGraph, "conv2 layer"));
     CHECK(Contains(layersInGraph, "conv3 layer"));
     CHECK(Contains(layersInGraph, "conv4 layer"));
     CHECK(Contains(layersInGraph, "conv5 layer"));
+    CHECK(Contains(layersInGraph, "Weights Layer 1"));
+    CHECK(Contains(layersInGraph, "Weights Layer 2"));
+    CHECK(Contains(layersInGraph, "Weights Layer 3"));
+    CHECK(Contains(layersInGraph, "Weights Layer 4"));
+    CHECK(Contains(layersInGraph, "Weights Layer 5"));
+    CHECK(Contains(layersInGraph, "Bias Layer 1"));
+    CHECK(Contains(layersInGraph, "Bias Layer 2"));
+    CHECK(Contains(layersInGraph, "Bias Layer 3"));
+    CHECK(Contains(layersInGraph, "Bias Layer 4"));
+    CHECK(Contains(layersInGraph, "Bias Layer 5"));
 
     // Create a mock backend object
     MockBackendInitialiser initialiser; // Register the Mock Backend
@@ -811,20 +1070,31 @@
     const OptimizationViews::Substitutions& substitutions = optimizationViews.GetSubstitutions();
     CHECK(substitutions.size() == 1);
 
-    std::list<IConnectableLayer*> expectedSubstitutableLayers{ layersInGraph.at("conv1 layer"),
+    std::list<IConnectableLayer*> expectedSubstitutableLayers{
+                                                   layersInGraph.at("Weights Layer 1"),
+                                                   layersInGraph.at("Weights Layer 2"),
+                                                   layersInGraph.at("Weights Layer 3"),
+                                                   layersInGraph.at("Weights Layer 4"),
+                                                   layersInGraph.at("Weights Layer 5"),
+                                                   layersInGraph.at("Bias Layer 1"),
+                                                   layersInGraph.at("Bias Layer 2"),
+                                                   layersInGraph.at("Bias Layer 3"),
+                                                   layersInGraph.at("Bias Layer 4"),
+                                                   layersInGraph.at("Bias Layer 5"),
+                                                   layersInGraph.at("conv1 layer"),
                                                    layersInGraph.at("conv2 layer"),
                                                    layersInGraph.at("conv3 layer"),
                                                    layersInGraph.at("conv4 layer"),
-                                                   layersInGraph.at("conv5 layer") };
+                                                   layersInGraph.at("conv5 layer")};
 
     const OptimizationViews::SubstitutionPair& substitution = substitutions.at(0);
 
-    CheckSubstitution(substitution,
-                      { subgraphInputSlots.size(), subgraphOutputSlots.size(), subgraphLayers.size() },
-                      { subgraphInputSlots.size(), subgraphOutputSlots.size(), 1 },
-                      subgraphInputSlots,
-                      subgraphOutputSlots,
-                      expectedSubstitutableLayers);
+    CheckSubstitution(
+        substitution,
+        {subgraphInputSlots.size(), subgraphOutputSlots.size(),
+         subgraphLayers.size()},
+        {subgraphInputSlots.size(), subgraphOutputSlots.size(), 1},
+        subgraphInputSlots, subgraphOutputSlots, expectedSubstitutableLayers);
 
     const SubgraphView::IConnectableLayers& substitutableSubgraphLayers =
             substitution.m_SubstitutableSubgraph.GetIConnectableLayers();
@@ -865,11 +1135,15 @@
 
     CHECK(subgraphInputSlots.size()  == 1);
     CHECK(subgraphOutputSlots.size() == 1);
-    CHECK(subgraphLayers.size()      == 5);
+    CHECK(subgraphLayers.size()      == 9);
 
+    CHECK(Contains(layersInGraph, "Weights Layer 1"));
+    CHECK(Contains(layersInGraph, "Bias Layer 1"));
     CHECK(Contains(layersInGraph, "conv1 layer"));
     CHECK(Contains(layersInGraph, "pooling1 layer"));
     CHECK(Contains(layersInGraph, "pooling2 layer"));
+    CHECK(Contains(layersInGraph, "Weights Layer 2"));
+    CHECK(Contains(layersInGraph, "Bias Layer 2"));
     CHECK(Contains(layersInGraph, "conv2 layer"));
     CHECK(Contains(layersInGraph, "pooling3 layer"));
 
@@ -903,16 +1177,16 @@
                       s2.m_SubstitutableSubgraph.GetIConnectableLayers().front()->GetName()) < 0;
     });
 
-    std::vector<ExpectedSubgraphSize> expectedSubstitutableSubgraphSizes{ { 1, 1, 1 },
-                                                                          { 1, 1, 1 } };
+    std::vector<ExpectedSubgraphSize> expectedSubstitutableSubgraphSizes{ { 1, 1, 3 },
+                                                                          { 1, 1, 3 } };
     std::vector<ExpectedSubgraphSize> expectedReplacementSubgraphSizes{ { 1, 1, 1 },
                                                                         { 1, 1, 1 } };
     std::vector<SubgraphView::IInputSlots> expectedSubstitutableInputSlots
     {
             ConvertSlotsToISlots<InputSlot, IInputSlot>(
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlots())),
+                {ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlot(0))}),
             ConvertSlotsToISlots<InputSlot, IInputSlot>(
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer")->GetInputSlots()))
+                {ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer")->GetInputSlot(0))})
     };
 
     std::vector<SubgraphView::IOutputSlots> expectedSubstitutableOutputSlots
@@ -924,8 +1198,8 @@
     };
     std::vector<SubgraphView::IConnectableLayers> expectedSubstitutableLayers
     {
-        { layersInGraph.at("conv1 layer") },
-        { layersInGraph.at("conv2 layer") }
+        { layersInGraph.at("Weights Layer 1"), layersInGraph.at("Bias Layer 1"), layersInGraph.at("conv1 layer") },
+        { layersInGraph.at("Weights Layer 2"), layersInGraph.at("Bias Layer 2"), layersInGraph.at("conv2 layer") }
     };
 
     for (size_t substitutionIndex = 0; substitutionIndex < substitutions.size(); substitutionIndex++)
@@ -1005,7 +1279,7 @@
 
     CHECK(subgraphInputSlots.size()  == 1);
     CHECK(subgraphOutputSlots.size() == 1);
-    CHECK(subgraphLayers.size()      == 1);
+    CHECK(subgraphLayers.size()      == 3);
 
     CHECK(Contains(layersInGraph, "conv layer unoptimizable"));
 
@@ -1047,9 +1321,9 @@
     CHECK(untouchedSubgraphs.size() == 1);
 
     CheckUntouchedSubgraph(untouchedSubgraphs.at(0),
-                           { subgraphInputSlots.size(), subgraphOutputSlots.size(), subgraphLayers.size() },
-                           subgraphInputSlots,
-                           subgraphOutputSlots,
+                           {subgraphInputSlots.size(),
+                            subgraphOutputSlots.size(), subgraphLayers.size()},
+                           subgraphInputSlots, subgraphOutputSlots,
                            subgraphLayers);
 }
 
@@ -1069,7 +1343,7 @@
 
     CHECK(subgraphInputSlots.size()  == 1);
     CHECK(subgraphOutputSlots.size() == 1);
-    CHECK(subgraphLayers.size()      == 5);
+    CHECK(subgraphLayers.size()      == 15);
 
     CHECK(Contains(layersInGraph, "conv1 layer"));
     CHECK(Contains(layersInGraph, "conv2 layer unoptimizable"));
@@ -1107,20 +1381,20 @@
         { return strcmp(s1.m_SubstitutableSubgraph.GetIConnectableLayers().front()->GetName(),
                         s2.m_SubstitutableSubgraph.GetIConnectableLayers().front()->GetName()) < 0; });
 
-    std::vector<ExpectedSubgraphSize> expectedSubstitutableSubgraphSizes{ { 1, 1, 1 },
-                                                                          { 1, 1, 1 },
-                                                                          { 1, 1, 1 } };
+    std::vector<ExpectedSubgraphSize> expectedSubstitutableSubgraphSizes{ { 1, 1, 3 },
+                                                                          { 1, 1, 3 },
+                                                                          { 1, 1, 3 } };
     std::vector<ExpectedSubgraphSize> expectedReplacementSubgraphSizes{ { 1, 1, 1 },
                                                                         { 1, 1, 1 },
                                                                         { 1, 1, 1 } };
     std::vector<SubgraphView::IInputSlots> expectedSubstitutableInputSlots
     {
         ConvertSlotsToISlots<InputSlot, IInputSlot>(
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlots())),
+            {ConvertReferenceTypeToPointerType(layersInGraph.at("conv1 layer")->GetInputSlot(0))}),
         ConvertSlotsToISlots<InputSlot, IInputSlot>(
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv3 layer")->GetInputSlots())),
+        {ConvertReferenceTypeToPointerType(layersInGraph.at("conv3 layer")->GetInputSlot(0))}),
         ConvertSlotsToISlots<InputSlot, IInputSlot>(
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv5 layer")->GetInputSlots()))
+        {ConvertReferenceTypeToPointerType(layersInGraph.at("conv5 layer")->GetInputSlot(0))})
     };
     std::vector<SubgraphView::IOutputSlots> expectedSubstitutableOutputSlots
     {
@@ -1133,9 +1407,9 @@
     };
     std::vector<SubgraphView::IConnectableLayers> expectedSubstitutableLayers
     {
-        { layersInGraph.at("conv1 layer") },
-        { layersInGraph.at("conv3 layer") },
-        { layersInGraph.at("conv5 layer") }
+        { layersInGraph.at("Weights Layer 1"), layersInGraph.at("Bias Layer 1"), layersInGraph.at("conv1 layer") },
+        { layersInGraph.at("Weights Layer 3"), layersInGraph.at("Bias Layer 3"), layersInGraph.at("conv3 layer") },
+        { layersInGraph.at("Weights Layer 5"), layersInGraph.at("Bias Layer 5"), layersInGraph.at("conv5 layer") }
     };
 
     for (size_t substitutionIndex = 0; substitutionIndex < substitutions.size(); substitutionIndex++)
@@ -1166,27 +1440,33 @@
                       s2.GetIConnectableLayers().front()->GetName()) < 0;
     });
 
-    std::vector<ExpectedSubgraphSize> expectedUntouchedSubgraphSizes{ { 1, 1, 1 },
-                                                                      { 1, 1, 1 } };
-    std::vector<SubgraphView::IInputSlots> expectedUntouchedInputSlots
-    {
-            ConvertSlotsToISlots<InputSlot, IInputSlot>(
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetInputSlots())),
-            ConvertSlotsToISlots<InputSlot, IInputSlot>(
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv4 layer unoptimizable")->GetInputSlots()))
-    };
+    std::vector<ExpectedSubgraphSize> expectedUntouchedSubgraphSizes{ { 1, 1, 3 },
+                                                                      { 1, 1, 3 } };
+    std::vector<SubgraphView::IInputSlots> expectedUntouchedInputSlots{
+        ConvertSlotsToISlots<InputSlot,
+                             IInputSlot>({ConvertReferenceTypeToPointerType(
+            layersInGraph.at("conv2 layer unoptimizable")->GetInputSlot(0))}),
+        ConvertSlotsToISlots<InputSlot,
+                             IInputSlot>({ConvertReferenceTypeToPointerType(
+            layersInGraph.at("conv4 layer unoptimizable")->GetInputSlot(0))})};
+
     std::vector<SubgraphView::IOutputSlots> expectedUntouchedOutputSlots
-    {
+        {
             ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetOutputSlots())),
+                ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetOutputSlots())),
             ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv4 layer unoptimizable")->GetOutputSlots()))
-    };
+                ConvertReferenceTypeToPointerType(layersInGraph.at("conv4 layer unoptimizable")->GetOutputSlots()))
+        };
+
     std::vector<SubgraphView::IConnectableLayers> expectedUntouchedLayers
-    {
-        { layersInGraph.at("conv2 layer unoptimizable") },
-        { layersInGraph.at("conv4 layer unoptimizable") }
-    };
+        {
+            { layersInGraph.at("Weights Layer 2 unoptimizable"),
+              layersInGraph.at("Bias Layer 2 unoptimizable"),
+              layersInGraph.at("conv2 layer unoptimizable") },
+            { layersInGraph.at("Weights Layer 4 unoptimizable"),
+              layersInGraph.at("Bias Layer 4 unoptimizable"),
+              layersInGraph.at("conv4 layer unoptimizable") }
+        };
 
     for (size_t untouchedIndex = 0; untouchedIndex < untouchedSubgraphs.size(); untouchedIndex++)
     {
@@ -1215,7 +1495,7 @@
 
     CHECK(subgraphInputSlots.size()  == 2);
     CHECK(subgraphOutputSlots.size() == 1);
-    CHECK(subgraphLayers.size()      == 4);
+    CHECK(subgraphLayers.size()      == 10);
 
     CHECK(Contains(layersInGraph, "conv1 layer"));
     CHECK(Contains(layersInGraph, "conv2 layer unoptimizable"));
@@ -1247,7 +1527,7 @@
     const OptimizationViews::Substitutions& substitutions = optimizationViews.GetSubstitutions();
     CHECK(substitutions.size() == 1);
 
-    ExpectedSubgraphSize expectedSubstitutableSubgraphSizes{ 2, 1, 3 };
+    ExpectedSubgraphSize expectedSubstitutableSubgraphSizes{ 2, 1, 7 };
     ExpectedSubgraphSize expectedReplacementSubgraphSizes{ 2, 1, 1 };
 
     SubgraphView::IInputSlots expectedSubstitutableInputSlots
@@ -1266,6 +1546,10 @@
 
     SubgraphView::IConnectableLayers expectedSubstitutableLayers
     {
+        layersInGraph.at("Weights Layer 1"),
+        layersInGraph.at("Weights Layer 3"),
+        layersInGraph.at("Bias Layer 1"),
+        layersInGraph.at("Bias Layer 3"),
         layersInGraph.at("conv1 layer"),
         layersInGraph.at("conv3 layer"),
         layersInGraph.at("add layer")
@@ -1291,12 +1575,12 @@
     const OptimizationViews::Subgraphs& untouchedSubgraphs = optimizationViews.GetUntouchedSubgraphs();
     CHECK(untouchedSubgraphs.size() == 1);
 
-    std::vector<ExpectedSubgraphSize> expectedUntouchedSubgraphSizes{ { 1, 1, 1 } };
+    std::vector<ExpectedSubgraphSize> expectedUntouchedSubgraphSizes{ { 1, 1, 3 } };
     std::vector<SubgraphView::IInputSlots> expectedUntouchedInputSlots
     {
-            ConvertSlotsToISlots<InputSlot, IInputSlot>(
-        ConvertReferenceTypeToPointerType(layersInGraph.at("conv2 layer unoptimizable")->GetInputSlots()))
-    };
+        ConvertSlotsToISlots<InputSlot,
+                             IInputSlot>({ConvertReferenceTypeToPointerType(
+            layersInGraph.at("conv2 layer unoptimizable")->GetInputSlot(0))})};
     std::vector<SubgraphView::IOutputSlots> expectedUntouchedOutputSlots
     {
             ConvertSlotsToISlots<OutputSlot, IOutputSlot>(
@@ -1304,7 +1588,8 @@
     };
     std::vector<SubgraphView::IConnectableLayers> expectedUntouchedLayers
     {
-        { layersInGraph.at("conv2 layer unoptimizable") }
+        { layersInGraph.at("conv2 layer unoptimizable"), layersInGraph.at("Weights Layer 2 unoptimizable"),
+        layersInGraph.at("Bias Layer 2 unoptimizable") }
     };
 
     for (size_t untouchedIndex = 0; untouchedIndex < untouchedSubgraphs.size(); untouchedIndex++)
diff --git a/src/backends/backendsCommon/test/OptimizedNetworkTests.cpp b/src/backends/backendsCommon/test/OptimizedNetworkTests.cpp
index cc79741..8e3b275 100644
--- a/src/backends/backendsCommon/test/OptimizedNetworkTests.cpp
+++ b/src/backends/backendsCommon/test/OptimizedNetworkTests.cpp
@@ -401,11 +401,14 @@
 
     armnn::INetworkPtr network = armnn::INetwork::Create();
     armnn::IConnectableLayer* const inputLayer  = network->AddInputLayer(0);
+
+    ARMNN_NO_DEPRECATE_WARN_BEGIN
     armnn::IConnectableLayer* const convLayer   =
             network->AddConvolution2dLayer(descriptor,
                                            weights,
                                            armnn::Optional<armnn::ConstTensor>(biases),
                                            layerName.c_str());
+    ARMNN_NO_DEPRECATE_WARN_END
     armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
 
     inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
diff --git a/src/backends/backendsCommon/test/WorkloadDataValidation.cpp b/src/backends/backendsCommon/test/WorkloadDataValidation.cpp
index c715d28..fed21eb 100644
--- a/src/backends/backendsCommon/test/WorkloadDataValidation.cpp
+++ b/src/backends/backendsCommon/test/WorkloadDataValidation.cpp
@@ -642,7 +642,7 @@
     CHECK_NOTHROW(data.Validate(info));
 }
 
-TEST_CASE("BiasPerAxisQuantization_Validate")
+TEST_CASE("BiasPerAxisQuantization_ValidateCorrectValues")
 {
     constexpr unsigned int nInput  = 1u;
     constexpr unsigned int cInput  = 3u;
@@ -675,6 +675,7 @@
 
     WorkloadInfo workloadInfo;
     AddInputToWorkload(queueDescriptor, workloadInfo, inputInfo, nullptr);
+    AddInputToWorkload(queueDescriptor, workloadInfo, weightInfo, nullptr);
     AddOutputToWorkload(queueDescriptor, workloadInfo, outputInfo, nullptr);
 
     ScopedTensorHandle weightTensor(weightInfo);
@@ -687,17 +688,102 @@
     ScopedTensorHandle biasHandle1(biasInfo1);
     queueDescriptor.m_Bias = &biasHandle1;
 
-    CHECK_NOTHROW(queueDescriptor.Validate(workloadInfo));
+    AddInputToWorkload(queueDescriptor, workloadInfo, biasInfo1, nullptr);
 
-    // Test 2: wrong per-axis quantization values
+    CHECK_NOTHROW(queueDescriptor.Validate(workloadInfo));
+}
+
+TEST_CASE("BiasPerAxisQuantization_ValidateIncorrectValues")
+{
+    constexpr unsigned int nInput  = 1u;
+    constexpr unsigned int cInput  = 3u;
+    constexpr unsigned int hInput  = 3u;
+    constexpr unsigned int wInput  = 3u;
+
+    constexpr unsigned int nOutput = nInput;
+    constexpr unsigned int cOutput = cInput;
+    constexpr unsigned int hOutput = 1u;
+    constexpr unsigned int wOutput = 1u;
+
+    const TensorShape inputShape { nInput,  cInput,  hInput,  wInput  };
+    const TensorShape outputShape{ nOutput, cOutput, hOutput, wOutput };
+    const TensorShape weightShape{ cOutput, cInput,  hInput,  wInput  };
+    const TensorShape biasShape  { cOutput                            };
+
+    constexpr DataType inputType  = DataType::QAsymmU8;
+    constexpr DataType weightType = DataType::QSymmS8;
+    constexpr DataType biasType   = DataType::Signed32;
+
+    constexpr float perTensorScale = 1.5f;
+    const TensorInfo inputInfo (inputShape,  inputType, perTensorScale);
+    const TensorInfo outputInfo(outputShape, inputType, perTensorScale);
+
+    const std::vector<float> weightPerAxisScales = { 2.50f, 3.50f };
+    const TensorInfo weightInfo(weightShape, weightType, weightPerAxisScales, 0);
+
+    Convolution2dQueueDescriptor queueDescriptor;
+    queueDescriptor.m_Parameters.m_BiasEnabled = true;
+
+    WorkloadInfo workloadInfo;
+    AddInputToWorkload(queueDescriptor, workloadInfo, inputInfo, nullptr);
+    AddInputToWorkload(queueDescriptor, workloadInfo, weightInfo, nullptr);
+    AddOutputToWorkload(queueDescriptor, workloadInfo, outputInfo, nullptr);
+
+    ScopedTensorHandle weightTensor(weightInfo);
+    queueDescriptor.m_Weight = &weightTensor;
+
+   // Test 2: wrong per-axis quantization values
     const std::vector<float> biasPerAxisScales2 = { 4.00f, 5.00f };
     const TensorInfo biasInfo2(biasShape, biasType, biasPerAxisScales2, 0);
 
     ScopedTensorHandle biasHandle2(biasInfo2);
     queueDescriptor.m_Bias = &biasHandle2;
 
+    AddInputToWorkload(queueDescriptor, workloadInfo, biasInfo2, nullptr);
+
     CHECK_NOTHROW(queueDescriptor.Validate(workloadInfo));
 
+}
+
+TEST_CASE("BiasPerAxisQuantization_ValidateInvalidArgumentException")
+{
+    constexpr unsigned int nInput  = 1u;
+    constexpr unsigned int cInput  = 3u;
+    constexpr unsigned int hInput  = 3u;
+    constexpr unsigned int wInput  = 3u;
+
+    constexpr unsigned int nOutput = nInput;
+    constexpr unsigned int cOutput = cInput;
+    constexpr unsigned int hOutput = 1u;
+    constexpr unsigned int wOutput = 1u;
+
+    const TensorShape inputShape { nInput,  cInput,  hInput,  wInput  };
+    const TensorShape outputShape{ nOutput, cOutput, hOutput, wOutput };
+    const TensorShape weightShape{ cOutput, cInput,  hInput,  wInput  };
+    const TensorShape biasShape  { cOutput                            };
+
+    constexpr DataType inputType  = DataType::QAsymmU8;
+    constexpr DataType weightType = DataType::QSymmS8;
+    constexpr DataType biasType   = DataType::Signed32;
+
+    constexpr float perTensorScale = 1.5f;
+    const TensorInfo inputInfo (inputShape,  inputType, perTensorScale);
+    const TensorInfo outputInfo(outputShape, inputType, perTensorScale);
+
+    const std::vector<float> weightPerAxisScales = { 2.50f, 3.50f };
+    const TensorInfo weightInfo(weightShape, weightType, weightPerAxisScales, 0);
+
+    Convolution2dQueueDescriptor queueDescriptor;
+    queueDescriptor.m_Parameters.m_BiasEnabled = true;
+
+    WorkloadInfo workloadInfo;
+    AddInputToWorkload(queueDescriptor, workloadInfo, inputInfo, nullptr);
+    AddInputToWorkload(queueDescriptor, workloadInfo, weightInfo, nullptr);
+    AddOutputToWorkload(queueDescriptor, workloadInfo, outputInfo, nullptr);
+
+    ScopedTensorHandle weightTensor(weightInfo);
+    queueDescriptor.m_Weight = &weightTensor;
+
     // Test 3: mismatched number of quantization scales
     const std::vector<float> biasPerAxisScales3 = { 3.75f, 5.25f, 5.25f };
     const TensorInfo biasInfo3(biasShape, biasType, biasPerAxisScales3, 0);
@@ -705,7 +791,10 @@
     ScopedTensorHandle biasHandle3(biasInfo3);
     queueDescriptor.m_Bias = &biasHandle3;
 
+    AddInputToWorkload(queueDescriptor, workloadInfo, biasInfo3, nullptr);
+
     CHECK_THROWS_AS(queueDescriptor.Validate(workloadInfo), InvalidArgumentException);
 }
 
+
 }
diff --git a/src/backends/backendsCommon/test/layerTests/Conv2dTestImpl.cpp b/src/backends/backendsCommon/test/layerTests/Conv2dTestImpl.cpp
index 74c65e2..1e0adc1 100644
--- a/src/backends/backendsCommon/test/layerTests/Conv2dTestImpl.cpp
+++ b/src/backends/backendsCommon/test/layerTests/Conv2dTestImpl.cpp
@@ -309,6 +309,7 @@
 
     std::unique_ptr<armnn::ITensorHandle> inputHandle = tensorHandleFactory.CreateTensorHandle(inputTensorInfo);
     std::unique_ptr<armnn::ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo);
+    std::unique_ptr<armnn::ITensorHandle> weightsHandle = tensorHandleFactory.CreateTensorHandle(kernelDesc);
 
     armnn::Convolution2dQueueDescriptor data;
     armnn::WorkloadInfo info;
@@ -329,8 +330,15 @@
     }
 
     AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
+    AddInputToWorkload(data, info, kernelDesc, weightsHandle.get());
     AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
 
+    std::unique_ptr<armnn::ITensorHandle> biasHandle = nullptr;
+    if (biasEnabled)
+    {
+        biasHandle = tensorHandleFactory.CreateTensorHandle(biasDesc);
+        AddInputToWorkload(data, info, biasDesc, biasHandle.get());
+    }
     data.m_Weight = &weightsTensor;
     data.m_Bias = &biasTensor; // Still set this whether or not bias is enabled - can be a source of bugs.
     data.m_Parameters.m_StrideX = strideX;
@@ -349,8 +357,16 @@
                                                                                 info);
     inputHandle->Allocate();
     outputHandle->Allocate();
+    weightsHandle->Allocate();
+
+    if (biasEnabled)
+    {
+        biasHandle->Allocate();
+        CopyDataToITensorHandle(biasHandle.get(), bias.data());
+    }
 
     CopyDataToITensorHandle(inputHandle.get(), inputData.data());
+    CopyDataToITensorHandle(weightsHandle.get(), kernel.data());
 
     ExecuteWorkload(*workload, memoryManager);
 
@@ -423,6 +439,8 @@
 
     std::unique_ptr<armnn::ITensorHandle> inputHandle = tensorHandleFactory.CreateTensorHandle(inputTensorInfo);
     std::unique_ptr<armnn::ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo);
+    std::unique_ptr<armnn::ITensorHandle> weightsHandle = tensorHandleFactory.CreateTensorHandle(kernelDesc);
+    std::unique_ptr<armnn::ITensorHandle> biasHandle = nullptr;
 
     armnn::ScopedTensorHandle weightsTensor(kernelDesc);
     AllocateAndCopyDataToITensorHandle(&weightsTensor, kernel.data());
@@ -444,15 +462,30 @@
 
     armnn::WorkloadInfo info;
     AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
+    AddInputToWorkload(data, info, kernelDesc, weightsHandle.get());
     AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
 
+    if (biasEnabled)
+    {
+        biasHandle = tensorHandleFactory.CreateTensorHandle(biasDesc);
+        AddInputToWorkload(data, info, biasDesc, biasHandle.get());
+    }
+
     std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateWorkload(armnn::LayerType::Convolution2d,
                                                                                 data,
                                                                                 info);
     inputHandle->Allocate();
     outputHandle->Allocate();
+    weightsHandle->Allocate();
+
+    if (biasEnabled)
+    {
+        biasHandle->Allocate();
+        CopyDataToITensorHandle(biasHandle.get(), bias.data());
+    }
 
     CopyDataToITensorHandle(inputHandle.get(), inputData.data());
+    CopyDataToITensorHandle(weightsHandle.get(), kernel.data());
 
     ExecuteWorkload(*workload, memoryManager);
 
@@ -552,35 +585,52 @@
 
     std::unique_ptr<armnn::ITensorHandle> inputHandle  = tensorHandleFactory.CreateTensorHandle(inputInfo);
     std::unique_ptr<armnn::ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputInfo);
+    std::unique_ptr<armnn::ITensorHandle> weightsHandle = tensorHandleFactory.CreateTensorHandle(kernelInfo);
+    std::unique_ptr<armnn::ITensorHandle> biasHandle = nullptr;
 
     armnn::Convolution2dQueueDescriptor data;
     armnn::WorkloadInfo info;
-    armnn::ScopedTensorHandle         weightsTensor(kernelInfo);
-    armnn::ScopedTensorHandle         biasTensor(biasInfo);
+    armnn::ScopedTensorHandle weightsTensor(kernelInfo);
+    armnn::ScopedTensorHandle biasTensor(biasInfo);
 
     AllocateAndCopyDataToITensorHandle(&weightsTensor, kernelData.data());
     AllocateAndCopyDataToITensorHandle(&biasTensor, biasData.data());
 
     AddInputToWorkload(data, info, inputInfo, inputHandle.get());
+    AddInputToWorkload(data, info, kernelInfo, weightsHandle.get());
     AddOutputToWorkload(data, info, outputInfo, outputHandle.get());
 
-    data.m_Weight         = &weightsTensor;
-    data.m_Bias           = &biasTensor;
-    data.m_Parameters.m_StrideX        = 1;
-    data.m_Parameters.m_StrideY        = stride;
-    data.m_Parameters.m_PadLeft        = 0;
-    data.m_Parameters.m_PadRight       = 0;
-    data.m_Parameters.m_PadTop         = padSize;
-    data.m_Parameters.m_PadBottom      = padSize;
-    data.m_Parameters.m_BiasEnabled    = biasEnabled;
+    data.m_Weight = &weightsTensor;
+    data.m_Bias = &biasTensor;
+    data.m_Parameters.m_StrideX = 1;
+    data.m_Parameters.m_StrideY = stride;
+    data.m_Parameters.m_PadLeft = 0;
+    data.m_Parameters.m_PadRight = 0;
+    data.m_Parameters.m_PadTop = padSize;
+    data.m_Parameters.m_PadBottom = padSize;
+    data.m_Parameters.m_BiasEnabled = biasEnabled;
+
+    if (biasEnabled)
+    {
+        biasHandle = tensorHandleFactory.CreateTensorHandle(biasInfo);
+        AddInputToWorkload(data, info, biasInfo, biasHandle.get());
+    }
 
     std::unique_ptr<armnn::IWorkload> workload = workloadFactory.CreateWorkload(armnn::LayerType::Convolution2d,
                                                                                 data,
                                                                                 info);
     inputHandle->Allocate();
     outputHandle->Allocate();
+    weightsHandle->Allocate();
+
+    if (biasEnabled)
+    {
+        biasHandle->Allocate();
+        CopyDataToITensorHandle(biasHandle.get(), biasData.data());
+    }
 
     CopyDataToITensorHandle(inputHandle.get(), inputData.data());
+    CopyDataToITensorHandle(weightsHandle.get(), kernelData.data());
 
     ExecuteWorkload(*workload, memoryManager);
 
@@ -1364,18 +1414,30 @@
     std::vector<T> expectedOutput(outputTensorInfo.GetNumElements());
 
     std::unique_ptr<armnn::ITensorHandle> inputHandle = tensorHandleFactory.CreateTensorHandle(inputTensorInfo);
+    std::unique_ptr<armnn::ITensorHandle> biasHandle = tensorHandleFactory.CreateTensorHandle(biasDesc);
+    std::unique_ptr<armnn::ITensorHandle> weightsHandle = tensorHandleFactory.CreateTensorHandle(kernelDesc);
     std::unique_ptr<armnn::ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputTensorInfo);
 
     armnn::Convolution2dQueueDescriptor data;
     armnn::WorkloadInfo info;
+
     armnn::ScopedTensorHandle weightsTensor(kernelDesc);
     armnn::ScopedTensorHandle biasTensor(biasDesc);
 
+    AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
+    AddInputToWorkload(data, info, kernelDesc, weightsHandle.get());
+    AddInputToWorkload(data, info, biasDesc, biasHandle.get());
+    AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
+
+    // AllocateAndCopyDataToITensorHandle() is required twice for the weights AND biases:
+    // See comment in DepthwiseConvolution2dAsymmetricTestImpl() for reasons.
+    // 1) ScopedTensorHandle (weightsTensor) required for QueueDescriptor (data.m_Weight).
+    // 2) ITensorHandle (converts to Backend TensorHandle) required in RefWorkload for GetTensorInfo() method.
+    AllocateAndCopyDataToITensorHandle(weightsHandle.get(), kernel.data());
     AllocateAndCopyDataToITensorHandle(&weightsTensor, kernel.data());
+    AllocateAndCopyDataToITensorHandle(biasHandle.get(), bias.data());
     AllocateAndCopyDataToITensorHandle(&biasTensor, bias.data());
 
-    AddInputToWorkload(data, info, inputTensorInfo, inputHandle.get());
-    AddOutputToWorkload(data, info, outputTensorInfo, outputHandle.get());
     data.m_Weight = &weightsTensor;
     data.m_Bias = &biasTensor;
     data.m_Parameters.m_StrideX = strideX;
@@ -1387,11 +1449,15 @@
     data.m_Parameters.m_BiasEnabled = true;
 
     std::unique_ptr<armnn::ITensorHandle> outputHandleRef = refTensorHandleFactory.CreateTensorHandle(outputTensorInfo);
+    std::unique_ptr<armnn::ITensorHandle> weightsHandleRef = refTensorHandleFactory.CreateTensorHandle(kernelDesc);
+    std::unique_ptr<armnn::ITensorHandle> biasHandleRef = refTensorHandleFactory.CreateTensorHandle(biasDesc);
     std::unique_ptr<armnn::ITensorHandle> inputHandleRef = refTensorHandleFactory.CreateTensorHandle(inputTensorInfo);
 
     armnn::Convolution2dQueueDescriptor refData = data;
     armnn::WorkloadInfo                 refInfo = info;
     SetWorkloadInput(refData, refInfo, 0, inputTensorInfo, inputHandleRef.get());
+    SetWorkloadInput(refData, refInfo, 1, kernelDesc, weightsHandleRef.get());
+    SetWorkloadInput(refData, refInfo, 2, biasDesc, biasHandleRef.get());
     SetWorkloadOutput(refData, refInfo, 0, outputTensorInfo, outputHandleRef.get());
 
     std::unique_ptr<armnn::IWorkload> workload
@@ -1401,12 +1467,16 @@
 
     outputHandleRef->Allocate();
     inputHandleRef->Allocate();
+    weightsHandleRef->Allocate();
+    biasHandleRef->Allocate();
 
     inputHandle->Allocate();
     outputHandle->Allocate();
 
     CopyDataToITensorHandle(inputHandle.get(), input.data());
     CopyDataToITensorHandle(inputHandleRef.get(), input.data());
+    CopyDataToITensorHandle(weightsHandleRef.get(), kernel.data());
+    CopyDataToITensorHandle(biasHandleRef.get(), bias.data());
 
     ExecuteWorkload(*workload, memoryManager);
 
@@ -3622,6 +3692,8 @@
 
     std::unique_ptr<ITensorHandle> inputHandle  = tensorHandleFactory.CreateTensorHandle(inputInfo);
     std::unique_ptr<ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputInfo);
+    std::unique_ptr<armnn::ITensorHandle> weightsHandle = tensorHandleFactory.CreateTensorHandle(kernelInfo);
+    std::unique_ptr<armnn::ITensorHandle> biasHandle = nullptr;
 
     WorkloadInfo workloadInfo;
     ScopedTensorHandle weightTensor(kernelInfo);
@@ -3636,6 +3708,14 @@
     queueDescriptor.m_Bias       = &biasTensor;
 
     AddInputToWorkload(queueDescriptor, workloadInfo, inputInfo, inputHandle.get());
+    AddInputToWorkload(queueDescriptor, workloadInfo, kernelInfo, weightsHandle.get());
+
+    if (descriptor.m_BiasEnabled)
+    {
+        biasHandle = tensorHandleFactory.CreateTensorHandle(biasInfo);
+        AddInputToWorkload(queueDescriptor, workloadInfo, biasInfo, biasHandle.get());
+    }
+
     AddOutputToWorkload(queueDescriptor, workloadInfo, outputInfo, outputHandle.get());
 
     std::unique_ptr<IWorkload> workload= workloadFactory.CreateWorkload(armnn::LayerType::Convolution2d,
@@ -3643,8 +3723,16 @@
                                                                         workloadInfo);
     inputHandle->Allocate();
     outputHandle->Allocate();
+    weightsHandle->Allocate();
 
+    if (descriptor.m_BiasEnabled)
+    {
+        biasHandle->Allocate();
+        CopyDataToITensorHandle(biasHandle.get(), biasData.data());
+    }
     CopyDataToITensorHandle(inputHandle.get(), inputData.data());
+    CopyDataToITensorHandle(weightsHandle.get(), kernelData.data());
+
 
     ExecuteWorkload(*workload, memoryManager);
 
diff --git a/src/backends/cl/ClBackend.cpp b/src/backends/cl/ClBackend.cpp
index 47990d8..bd1b94e 100644
--- a/src/backends/cl/ClBackend.cpp
+++ b/src/backends/cl/ClBackend.cpp
@@ -341,14 +341,14 @@
 
                                 if (baseLayer->GetParameters().m_BiasEnabled)
                                 {
-                                    biases = baseLayer->m_Bias->GetTensorInfo();
+                                    biases = baseLayer->GetInputSlot(2).GetConnectedOutputSlot()->GetTensorInfo();
                                 }
 
                                 arm_compute::Status status = ClConvolution2dWorkloadValidate(
                                         baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
                                         activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
                                         baseLayer->GetParameters(),
-                                        baseLayer->m_Weight->GetTensorInfo(),
+                                        baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
                                         biases,
                                         isFastMathEnabled,
                                         &activationDesc);
diff --git a/src/backends/cl/test/ClCreateWorkloadTests.cpp b/src/backends/cl/test/ClCreateWorkloadTests.cpp
index 4f53b92..3a757f8 100644
--- a/src/backends/cl/test/ClCreateWorkloadTests.cpp
+++ b/src/backends/cl/test/ClCreateWorkloadTests.cpp
@@ -471,6 +471,8 @@
     auto tensorHandleFactory = ClWorkloadFactoryHelper::GetTensorHandleFactory(memoryManager);
 
     std::unique_ptr<ITensorHandle> inputHandle  = tensorHandleFactory.CreateTensorHandle(inputInfo);
+    std::unique_ptr<armnn::ITensorHandle> weightsHandle = tensorHandleFactory.CreateTensorHandle(kernelInfo);
+    std::unique_ptr<armnn::ITensorHandle> biasHandle = tensorHandleFactory.CreateTensorHandle(biasInfo);
     std::unique_ptr<ITensorHandle> outputHandle = tensorHandleFactory.CreateTensorHandle(outputInfo);
 
 
@@ -487,6 +489,8 @@
     queueDescriptor.m_Bias       = &biasTensor;
 
     AddInputToWorkload(queueDescriptor, workloadInfo, inputInfo, inputHandle.get());
+    AddInputToWorkload(queueDescriptor, workloadInfo, kernelInfo, weightsHandle.get());
+    AddInputToWorkload(queueDescriptor, workloadInfo, biasInfo, biasHandle.get());
     AddOutputToWorkload(queueDescriptor, workloadInfo, outputInfo, outputHandle.get());
 
     // Initialize our m_CLCompileContext using default device and context
diff --git a/src/backends/cl/test/ClImportTensorHandleTests.cpp b/src/backends/cl/test/ClImportTensorHandleTests.cpp
index e10e81a..9bfd1fb 100644
--- a/src/backends/cl/test/ClImportTensorHandleTests.cpp
+++ b/src/backends/cl/test/ClImportTensorHandleTests.cpp
@@ -11,7 +11,6 @@
 
 #include <doctest/doctest.h>
 
-
 #include <armnn/IRuntime.hpp>
 #include <armnn/INetwork.hpp>
 #include "Network.hpp"
@@ -320,10 +319,13 @@
     convDesc2d.m_PadTop = 1;
     convDesc2d.m_PadBottom = 1;
     convDesc2d.m_DataLayout = DataLayout::NHWC;
+
+    ARMNN_NO_DEPRECATE_WARN_BEGIN
     armnn::IConnectableLayer* const convLayer = network->AddConvolution2dLayer(convDesc2d,
                                                                           weights,
                                                                           armnn::EmptyOptional(),
                                                                           "conv");
+    ARMNN_NO_DEPRECATE_WARN_END
     ARMNN_ASSERT(convLayer);
 
     inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
@@ -876,10 +878,12 @@
     convDesc2d.m_PadTop = 1;
     convDesc2d.m_PadBottom = 1;
     convDesc2d.m_DataLayout = DataLayout::NHWC;
+    ARMNN_NO_DEPRECATE_WARN_BEGIN
     armnn::IConnectableLayer* const convLayer = network->AddConvolution2dLayer(convDesc2d,
                                                                           weights,
                                                                           armnn::EmptyOptional(),
                                                                           "conv");
+    ARMNN_NO_DEPRECATE_WARN_END
     ARMNN_ASSERT(convLayer);
 
     inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
@@ -1094,10 +1098,12 @@
     convDesc2d.m_PadTop = 1;
     convDesc2d.m_PadBottom = 1;
     convDesc2d.m_DataLayout = DataLayout::NHWC;
+    ARMNN_NO_DEPRECATE_WARN_BEGIN
     armnn::IConnectableLayer* const convLayer = network->AddConvolution2dLayer(convDesc2d,
                                                                           weights,
                                                                           armnn::EmptyOptional(),
                                                                           "conv");
+    ARMNN_NO_DEPRECATE_WARN_END
     ARMNN_ASSERT(convLayer);
 
     inputLayer->GetOutputSlot(0).Connect(convLayer->GetInputSlot(0));
diff --git a/src/backends/cl/workloads/ClConvolution2dWorkload.cpp b/src/backends/cl/workloads/ClConvolution2dWorkload.cpp
index bf82fbf..e3d679a 100644
--- a/src/backends/cl/workloads/ClConvolution2dWorkload.cpp
+++ b/src/backends/cl/workloads/ClConvolution2dWorkload.cpp
@@ -28,6 +28,15 @@
                                                     bool isFastMathEnabled,
                                                     const ActivationDescriptor* activationDescriptor)
 {
+    // The implemented workload does support both const and non const
+    // weights. However, in the case of non const weights we'd have to call
+    // prepare or configure for each inference which we're not setup to do just yet.
+    if (!weights.IsConstant())
+    {
+        return arm_compute::Status{arm_compute::ErrorCode::RUNTIME_ERROR,
+                                   "ArmNN ClConvolution2dWorkload does not support non constant weights."};
+    }
+
     const arm_compute::TensorInfo aclInputInfo = BuildArmComputeTensorInfo(input, descriptor.m_DataLayout);
     const arm_compute::TensorInfo aclOutputInfo = BuildArmComputeTensorInfo(output, descriptor.m_DataLayout);
     const arm_compute::TensorInfo aclWeightsInfo = BuildArmComputeTensorInfo(weights, descriptor.m_DataLayout);
@@ -41,7 +50,12 @@
     if (descriptor.m_BiasEnabled)
     {
         ARMNN_ASSERT(biases.has_value());
-
+        // Same for bias as weights. We don't currently support non const.
+        if (!biases.value().IsConstant())
+        {
+            return arm_compute::Status{arm_compute::ErrorCode::RUNTIME_ERROR,
+                                       "ArmNN ClConvolution2dWorkload does not support non constant bias."};
+        }
         aclBiasesInfo = BuildArmComputeTensorInfo(biases.value(), descriptor.m_DataLayout);
         optionalAclBiasesInfo = &aclBiasesInfo;
     }
@@ -72,6 +86,7 @@
 {
     ARMNN_SCOPED_PROFILING_EVENT(Compute::Undefined, "ClConvolution2dWorkload");
     const TensorInfo& weightInfo = m_Data.m_Weight->GetTensorInfo();
+    m_Data.ValidateInputsOutputs("ClConvolution2dWorkload", 1, 1);
 
     m_KernelTensor = std::make_unique<arm_compute::CLTensor>();
     BuildArmComputeTensor(*m_KernelTensor, weightInfo, m_Data.m_Parameters.m_DataLayout);
@@ -85,8 +100,6 @@
         BuildArmComputeTensor(*m_BiasTensor, m_Data.m_Bias->GetTensorInfo(), m_Data.m_Parameters.m_DataLayout);
     }
 
-    m_Data.ValidateInputsOutputs("ClConvolution2dWorkload", 1, 1);
-
     arm_compute::ICLTensor& input  = static_cast<IClTensorHandle*>(m_Data.m_Inputs[0])->GetTensor();
     arm_compute::ICLTensor& output = static_cast<IClTensorHandle*>(m_Data.m_Outputs[0])->GetTensor();
 
diff --git a/src/backends/neon/NeonBackend.cpp b/src/backends/neon/NeonBackend.cpp
index 39ad4b9..2433642 100644
--- a/src/backends/neon/NeonBackend.cpp
+++ b/src/backends/neon/NeonBackend.cpp
@@ -193,14 +193,14 @@
 
                                 if (baseLayer->GetParameters().m_BiasEnabled)
                                 {
-                                    biases = baseLayer->m_Bias->GetTensorInfo();
+                                    biases = baseLayer->GetInputSlot(2).GetConnectedOutputSlot()->GetTensorInfo();
                                 }
 
                                 arm_compute::Status status = NeonConvolution2dWorkloadValidate(
                                         baseLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
                                         activationLayer->GetInputSlot(0).GetConnectedOutputSlot()->GetTensorInfo(),
                                         baseLayer->GetParameters(),
-                                        baseLayer->m_Weight->GetTensorInfo(),
+                                        baseLayer->GetInputSlot(1).GetConnectedOutputSlot()->GetTensorInfo(),
                                         biases,
                                         false,
                                         &activationDesc);
diff --git a/src/backends/neon/workloads/NeonConvolution2dWorkload.cpp b/src/backends/neon/workloads/NeonConvolution2dWorkload.cpp
index fce57e6..d5716c8 100644
--- a/src/backends/neon/workloads/NeonConvolution2dWorkload.cpp
+++ b/src/backends/neon/workloads/NeonConvolution2dWorkload.cpp
@@ -29,6 +29,15 @@
                                                       bool isFastMathEnabled,
                                                       const ActivationDescriptor* activationDescriptor)
 {
+    // The implemented workload does support both const and non const
+    // weights. However, in the case of non const weights we'd have to call
+    // prepare or configure for each inference which we're not setup to do just yet.
+    if (!weights.IsConstant())
+    {
+        return arm_compute::Status{arm_compute::ErrorCode::RUNTIME_ERROR,
+                                   "ArmNN NeonConvolution2dWorkload does not support non constant weights."};
+    }
+
     const arm_compute::TensorInfo aclInputInfo = BuildArmComputeTensorInfo(input, descriptor.m_DataLayout);
     const arm_compute::TensorInfo aclOutputInfo = BuildArmComputeTensorInfo(output, descriptor.m_DataLayout);
     const arm_compute::TensorInfo aclWeightsInfo = BuildArmComputeTensorInfo(weights, descriptor.m_DataLayout);
@@ -42,7 +51,12 @@
     if (descriptor.m_BiasEnabled)
     {
         ARMNN_ASSERT(biases.has_value());
-
+        // Same for bias as weights. We don't currently support non const.
+        if (!biases.value().IsConstant())
+        {
+            return arm_compute::Status{arm_compute::ErrorCode::RUNTIME_ERROR,
+                                       "ArmNN NeonConvolution2dWorkload does not support non constant bias."};
+        }
         aclBiasesInfo = BuildArmComputeTensorInfo(biases.value(), descriptor.m_DataLayout);
         optionalAclBiasesInfo = &aclBiasesInfo;
     }
diff --git a/src/backends/reference/RefLayerSupport.cpp b/src/backends/reference/RefLayerSupport.cpp
index f921383..8051dcf 100644
--- a/src/backends/reference/RefLayerSupport.cpp
+++ b/src/backends/reference/RefLayerSupport.cpp
@@ -1246,11 +1246,12 @@
 {
    bool supported = true;
 
-    std::array<DataType,4> supportedInputTypes = {
+    std::array<DataType,5> supportedInputTypes = {
         DataType::QAsymmS8,
         DataType::QAsymmU8,
         DataType::QSymmS8,
-        DataType::QSymmS16
+        DataType::QSymmS16,
+        DataType::Float16
     };
 
     supported &= CheckSupportRule(TypeAnyOf(input, supportedInputTypes), reasonIfUnsupported,
diff --git a/src/backends/reference/workloads/RefConvolution2dWorkload.cpp b/src/backends/reference/workloads/RefConvolution2dWorkload.cpp
index d57040e..fe97cb1 100644
--- a/src/backends/reference/workloads/RefConvolution2dWorkload.cpp
+++ b/src/backends/reference/workloads/RefConvolution2dWorkload.cpp
@@ -12,37 +12,46 @@
 
 namespace armnn
 {
-RefConvolution2dWorkload::RefConvolution2dWorkload(
-    const Convolution2dQueueDescriptor& descriptor, const WorkloadInfo& info)
+RefConvolution2dWorkload::RefConvolution2dWorkload(const Convolution2dQueueDescriptor& descriptor,
+                                                   const WorkloadInfo& info)
     : RefBaseWorkload<Convolution2dQueueDescriptor>(descriptor, info)
 {
     WorkloadInfo detailsInfo;
     detailsInfo.m_InputTensorInfos = info.m_InputTensorInfos;
     detailsInfo.m_OutputTensorInfos = info.m_OutputTensorInfos;
-    detailsInfo.m_WeightsTensorInfo = armnn::Optional<armnn::TensorInfo>(descriptor.m_Weight->GetTensorInfo());
-    if (descriptor.m_Parameters.m_BiasEnabled)
-    {
-        detailsInfo.m_BiasTensorInfo = armnn::Optional<armnn::TensorInfo>(descriptor.m_Bias->GetTensorInfo());
-    }
 
     // Report Profiling Details
     ARMNN_REPORT_PROFILING_WORKLOAD_DESC("RefConvolution2dWorkload_Construct",
                                          descriptor.m_Parameters,
                                          detailsInfo,
                                          this->GetGuid());
+}
 
-    m_Weight = std::make_unique<ScopedTensorHandle>(*( descriptor.m_Weight ));
-    const TensorInfo& rFilterInfo = m_Weight->GetTensorInfo();
+void RefConvolution2dWorkload::PostAllocationConfigure()
+{
+    PostAllocationConfigure(m_Data.m_Inputs, m_Data.m_Outputs);
+}
 
+void RefConvolution2dWorkload::PostAllocationConfigure(std::vector<ITensorHandle*> inputs,
+                                                        std::vector<ITensorHandle*> outputs)
+{
+    const TensorInfo& inputInfo = GetTensorInfo(inputs[0]);
+    ARMNN_ASSERT(inputInfo.GetNumDimensions() > 1);
+    m_InputShape = inputInfo.GetShape();
+
+    const TensorInfo& rFilterInfo = GetTensorInfo(inputs[1]);
+    ARMNN_ASSERT(inputInfo.GetNumDimensions() > 1);
     m_FilterShape = rFilterInfo.GetShape();
-    m_FilterDecoder = MakeDecoder<float>(rFilterInfo, m_Weight.get()->Map(true));
+    m_FilterDecoder = MakeDecoder<float>(rFilterInfo);
 
-    if ( descriptor.m_Parameters.m_BiasEnabled )
+    if (m_Data.m_Parameters.m_BiasEnabled)
     {
-        m_Bias = std::make_unique<ScopedTensorHandle>(*( descriptor.m_Bias ));
-        const TensorInfo& biasInfo = m_Bias->GetTensorInfo();
-        m_BiasDecoder = MakeDecoder<float>(biasInfo, m_Bias->Map(true));
+        const TensorInfo& biasInfo = GetTensorInfo(inputs[2]);
+        m_BiasDecoder = MakeDecoder<float>(biasInfo);
     }
+
+    const TensorInfo& outputInfo = GetTensorInfo(outputs[0]);
+    m_OutputShape = outputInfo.GetShape();
 }
 
 void RefConvolution2dWorkload::Execute() const
@@ -52,6 +61,8 @@
 
 void RefConvolution2dWorkload::ExecuteAsync(WorkingMemDescriptor& workingMemDescriptor)
 {
+    PostAllocationConfigure(workingMemDescriptor.m_Inputs, workingMemDescriptor.m_Outputs);
+
     Execute(workingMemDescriptor.m_Inputs, workingMemDescriptor.m_Outputs);
 }
 
@@ -62,14 +73,17 @@
     std::unique_ptr<Decoder<float>> inputDecoder = MakeDecoder<float>(GetTensorInfo(inputs[0]), inputs[0]->Map());
     std::unique_ptr<Encoder<float>> outputEncoder = MakeEncoder<float>(GetTensorInfo(outputs[0]), outputs[0]->Map());
 
-    const TensorShape& inputShape = GetTensorInfo(inputs[0]).GetShape();
-    const TensorShape& outputShape = GetTensorInfo(outputs[0]).GetShape();
+    m_FilterDecoder->Reset(inputs[1]->Map());
+    if (m_Data.m_Parameters.m_BiasEnabled)
+    {
+        m_BiasDecoder->Reset(inputs[2]->Map());
+    }
 
-    Convolve(inputShape, *inputDecoder, outputShape, *outputEncoder, m_FilterShape,
+    Convolve(m_InputShape, *inputDecoder, m_OutputShape, *outputEncoder, m_FilterShape,
              *m_FilterDecoder, m_Data.m_Parameters.m_BiasEnabled, m_BiasDecoder.get(),
              m_Data.m_Parameters.m_DataLayout, m_Data.m_Parameters.m_PadTop, m_Data.m_Parameters.m_PadLeft,
              m_Data.m_Parameters.m_StrideX, m_Data.m_Parameters.m_StrideY,
              m_Data.m_Parameters.m_DilationX, m_Data.m_Parameters.m_DilationY);
 }
 
-} //namespace armnn
+} //namespace armnn
\ No newline at end of file
diff --git a/src/backends/reference/workloads/RefConvolution2dWorkload.hpp b/src/backends/reference/workloads/RefConvolution2dWorkload.hpp
index 3335782..1cb30b6 100644
--- a/src/backends/reference/workloads/RefConvolution2dWorkload.hpp
+++ b/src/backends/reference/workloads/RefConvolution2dWorkload.hpp
@@ -19,20 +19,21 @@
     explicit RefConvolution2dWorkload(const Convolution2dQueueDescriptor& descriptor,
                                       const WorkloadInfo& info);
 
+    void PostAllocationConfigure() override;
 
     void Execute() const override;
     void ExecuteAsync(WorkingMemDescriptor& workingMemDescriptor)  override;
 
 private:
+    void PostAllocationConfigure(std::vector<ITensorHandle*> inputs, std::vector<ITensorHandle*> outputs);
     void Execute(std::vector<ITensorHandle*> inputs, std::vector<ITensorHandle*> outputs) const;
-    std::unique_ptr<ScopedTensorHandle> m_Weight;
-    std::unique_ptr<ScopedTensorHandle> m_Bias;
 
     std::unique_ptr<Decoder<float>> m_FilterDecoder;
     std::unique_ptr<Decoder<float>> m_BiasDecoder;
 
+    TensorShape m_InputShape;
+    TensorShape m_OutputShape;
     TensorShape m_FilterShape;
 };
 
-} //namespace armnn
-
+} //namespace armnn
\ No newline at end of file
diff --git a/src/backends/reference/workloads/RefDepthwiseConvolution2dWorkload.hpp b/src/backends/reference/workloads/RefDepthwiseConvolution2dWorkload.hpp
index ef0b16d..30ee6d8 100644
--- a/src/backends/reference/workloads/RefDepthwiseConvolution2dWorkload.hpp
+++ b/src/backends/reference/workloads/RefDepthwiseConvolution2dWorkload.hpp
@@ -22,13 +22,6 @@
 private:
     void Execute(std::vector<ITensorHandle*> inputs, std::vector<ITensorHandle*> outputs) const;
 
-    std::unique_ptr <ScopedTensorHandle> m_Weight;
-    std::unique_ptr <ScopedTensorHandle> m_Bias;
-
-    std::unique_ptr <Decoder<float>> m_FilterDecoder;
-    std::unique_ptr <Decoder<float>> m_BiasDecoder;
-
-    TensorShape m_FilterShape;
 };
 
 } //namespace armnn
diff --git a/src/profiling/test/ProfilingTestUtils.cpp b/src/profiling/test/ProfilingTestUtils.cpp
index 0159f61..58708ca 100644
--- a/src/profiling/test/ProfilingTestUtils.cpp
+++ b/src/profiling/test/ProfilingTestUtils.cpp
@@ -424,8 +424,9 @@
     conv2dDesc.m_PadTop = 2;
     conv2dDesc.m_PadBottom = 2;
     conv2dDesc.m_BiasEnabled = true;
+    ARMNN_NO_DEPRECATE_WARN_BEGIN
     IConnectableLayer* conv2d = net->AddConvolution2dLayer(conv2dDesc, weights, optionalBiases);
-
+    ARMNN_NO_DEPRECATE_WARN_END
     // Abs layer
     armnn::ElementwiseUnaryDescriptor absDesc;
     armnn::IConnectableLayer* const abs = net->AddElementwiseUnaryLayer(absDesc, "abs");
@@ -515,7 +516,6 @@
     // Input layer
     // Input layer entity
     VerifyTimelineEntityBinaryPacketData(input->GetGuid(), readableData, offset);
-
     // Name Entity
     ProfilingGuid inputLabelGuid = VerifyTimelineLabelBinaryPacketData(
         arm::pipe::EmptyOptional(), "input", readableData, offset);
@@ -547,6 +547,159 @@
                                                readableData,
                                                offset);
 
+    // Weights layer
+    //  We will not check the GUID from the packets since we haven't direct access to the layer
+    //  The GUID will change depending on the number of tests ran since we do are not explicitly resetting the
+    //  ProfilingGuid counter at the beginning of this test
+
+
+    // Weights layer entity
+    VerifyTimelineEntityBinaryPacketData( arm::pipe::EmptyOptional(), readableData, offset);
+
+    // Name entity
+    ProfilingGuid weightsNameLabelGuid = VerifyTimelineLabelBinaryPacketData(
+        arm::pipe::EmptyOptional(), "Weights", readableData, offset);
+
+    // Entity - Name relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::LabelLink,
+                                               arm::pipe::EmptyOptional(),
+                                               arm::pipe::EmptyOptional(),
+                                               weightsNameLabelGuid,
+                                               LabelsAndEventClasses::NAME_GUID,
+                                               readableData,
+                                               offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::LabelLink,
+                                               arm::pipe::EmptyOptional(),
+                                               arm::pipe::EmptyOptional(),
+                                               LabelsAndEventClasses::LAYER_GUID,
+                                               LabelsAndEventClasses::TYPE_GUID,
+                                               readableData,
+                                               offset);
+
+    // Network - Weights layer relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::RetentionLink,
+                                               arm::pipe::EmptyOptional(),
+                                               optNetGuid,
+                                               arm::pipe::EmptyOptional(),
+                                               LabelsAndEventClasses::CHILD_GUID,
+                                               readableData,
+                                               offset);
+
+    // Weights workload
+    // Weights workload entity
+    ProfilingGuid weightsWorkloadGuid = VerifyTimelineEntityBinaryPacketData(
+        arm::pipe::EmptyOptional(), readableData, offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::LabelLink,
+                                               arm::pipe::EmptyOptional(),
+                                               weightsWorkloadGuid,
+                                               LabelsAndEventClasses::WORKLOAD_GUID,
+                                               LabelsAndEventClasses::TYPE_GUID,
+                                               readableData,
+                                               offset);
+
+    // BackendId entity
+    ProfilingGuid backendIdLabelGuid = VerifyTimelineLabelBinaryPacketData(
+        arm::pipe::EmptyOptional(), backendId.Get(), readableData, offset);
+
+    // Entity - BackendId relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::LabelLink,
+                                               arm::pipe::EmptyOptional(),
+                                               weightsWorkloadGuid,
+                                               backendIdLabelGuid,
+                                               LabelsAndEventClasses::BACKENDID_GUID,
+                                               readableData,
+                                               offset);
+
+
+    // Weights layer - Weights workload relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::RetentionLink,
+                                               arm::pipe::EmptyOptional(),
+                                               arm::pipe::EmptyOptional(),
+                                               weightsWorkloadGuid,
+                                               LabelsAndEventClasses::CHILD_GUID,
+                                               readableData,
+                                               offset);
+
+    // Bias layer
+    //  We will not check the GUID from the packets since we haven't direct access to the layer
+    //  The GUID will change depending on the number of tests ran since we do are not explicitly resetting the
+    //  ProfilingGuid counter at the beginning of this test
+
+    // Bias layer entity
+    VerifyTimelineEntityBinaryPacketData(arm::pipe::EmptyOptional(), readableData, offset);
+
+    // Name entity
+    ProfilingGuid biasNameLabelGuid = VerifyTimelineLabelBinaryPacketData(
+        arm::pipe::EmptyOptional(), "Bias", readableData, offset);
+
+    // Entity - Name relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::LabelLink,
+                                               arm::pipe::EmptyOptional(),
+                                               arm::pipe::EmptyOptional(),
+                                               biasNameLabelGuid,
+                                               LabelsAndEventClasses::NAME_GUID,
+                                               readableData,
+                                               offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::LabelLink,
+                                               arm::pipe::EmptyOptional(),
+                                               arm::pipe::EmptyOptional(),
+                                               LabelsAndEventClasses::LAYER_GUID,
+                                               LabelsAndEventClasses::TYPE_GUID,
+                                               readableData,
+                                               offset);
+
+    // Network - Bias layer relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::RetentionLink,
+                                               arm::pipe::EmptyOptional(),
+                                               optNetGuid,
+                                               arm::pipe::EmptyOptional(),
+                                               LabelsAndEventClasses::CHILD_GUID,
+                                               readableData,
+                                               offset);
+
+    // Bias workload
+    // Bias workload entity
+    ProfilingGuid biasWorkloadGuid = VerifyTimelineEntityBinaryPacketData(
+        arm::pipe::EmptyOptional(), readableData, offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::LabelLink,
+                                               arm::pipe::EmptyOptional(),
+                                               biasWorkloadGuid,
+                                               LabelsAndEventClasses::WORKLOAD_GUID,
+                                               LabelsAndEventClasses::TYPE_GUID,
+                                               readableData,
+                                               offset);
+
+    // BackendId entity
+    backendIdLabelGuid = VerifyTimelineLabelBinaryPacketData(
+        arm::pipe::EmptyOptional(), backendId.Get(), readableData, offset);
+
+    // Entity - BackendId relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::LabelLink,
+                                               arm::pipe::EmptyOptional(),
+                                               biasWorkloadGuid,
+                                               backendIdLabelGuid,
+                                               LabelsAndEventClasses::BACKENDID_GUID,
+                                               readableData,
+                                               offset);
+
+
+    // Bias layer - Bias workload relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::RetentionLink,
+                                               arm::pipe::EmptyOptional(),
+                                               arm::pipe::EmptyOptional(),
+                                               biasWorkloadGuid,
+                                               LabelsAndEventClasses::CHILD_GUID,
+                                               readableData,
+                                               offset);
+
     // Conv2d layer
     // Conv2d layer entity
     VerifyTimelineEntityBinaryPacketData(conv2d->GetGuid(), readableData, offset);
@@ -591,6 +744,24 @@
                                                readableData,
                                                offset);
 
+    // Weights layer - Conv2d layer relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::RetentionLink,
+                                               arm::pipe::EmptyOptional(),
+                                               arm::pipe::EmptyOptional(),
+                                               conv2d->GetGuid(),
+                                               LabelsAndEventClasses::CONNECTION_GUID,
+                                               readableData,
+                                               offset);
+
+    // Bias layer - Conv2d layer relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::RetentionLink,
+                                               arm::pipe::EmptyOptional(),
+                                               arm::pipe::EmptyOptional(),
+                                               conv2d->GetGuid(),
+                                               LabelsAndEventClasses::CONNECTION_GUID,
+                                               readableData,
+                                               offset);
+
     // Conv2d workload
     // Conv2d workload entity
     ProfilingGuid conv2DWorkloadGuid = VerifyTimelineEntityBinaryPacketData(
@@ -606,7 +777,7 @@
                                                offset);
 
     // BackendId entity
-    ProfilingGuid backendIdLabelGuid = VerifyTimelineLabelBinaryPacketData(
+    backendIdLabelGuid = VerifyTimelineLabelBinaryPacketData(
         arm::pipe::EmptyOptional(), backendId.Get(), readableData, offset);
 
     // Entity - BackendId relationship
@@ -884,7 +1055,7 @@
     // Validate inference data
     size = inferenceReadableBuffer->GetSize();
 
-    CHECK(size == 1228 + 10 * ThreadIdSize);
+    CHECK(size == 1748 + 10 * ThreadIdSize);
 
     readableData = inferenceReadableBuffer->GetReadableData();
     CHECK(readableData != nullptr);
@@ -892,7 +1063,7 @@
     offset = 0;
 
     // Verify Header
-    VerifyTimelineHeaderBinary(readableData, offset, 1220 + 10 * ThreadIdSize);
+    VerifyTimelineHeaderBinary(readableData, offset, 1740 + 10 * ThreadIdSize);
 
     // Inference timeline trace
     // Inference entity
@@ -992,6 +1163,126 @@
                                                readableData,
                                                offset);
 
+   // Weights workload execution
+    // Weights workload execution entity
+    ProfilingGuid weightsWorkloadExecutionGuid = VerifyTimelineEntityBinaryPacketData(
+        arm::pipe::EmptyOptional(), readableData, offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::LabelLink,
+                                               arm::pipe::EmptyOptional(),
+                                               weightsWorkloadExecutionGuid,
+                                               LabelsAndEventClasses::WORKLOAD_EXECUTION_GUID,
+                                               LabelsAndEventClasses::TYPE_GUID,
+                                               readableData,
+                                               offset);
+
+    // Inference - Workload execution relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::RetentionLink,
+                                               arm::pipe::EmptyOptional(),
+                                               inferenceGuid,
+                                               weightsWorkloadExecutionGuid,
+                                               LabelsAndEventClasses::CHILD_GUID,
+                                               readableData,
+                                               offset);
+
+    // Workload - Workload execution relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::RetentionLink,
+                                               arm::pipe::EmptyOptional(),
+                                               weightsWorkloadGuid,
+                                               weightsWorkloadExecutionGuid,
+                                               LabelsAndEventClasses::EXECUTION_OF_GUID,
+                                               readableData,
+                                               offset);
+
+    // Start Weights workload execution life
+    // Event packet - timeline, threadId, eventGuid
+    ProfilingGuid weightsWorkloadExecutionSOLEventGuid = VerifyTimelineEventBinaryPacket(
+        arm::pipe::EmptyOptional(), arm::pipe::EmptyOptional(), arm::pipe::EmptyOptional(), readableData, offset);
+
+    // Weights workload execution - event relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::ExecutionLink,
+                                               arm::pipe::EmptyOptional(),
+                                               weightsWorkloadExecutionGuid,
+                                               weightsWorkloadExecutionSOLEventGuid,
+                                               LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS,
+                                               readableData,
+                                               offset);
+
+    // End of Weights workload execution life
+    // Event packet - timeline, threadId, eventGuid
+    ProfilingGuid weightsWorkloadExecutionEOLEventGuid = VerifyTimelineEventBinaryPacket(
+        arm::pipe::EmptyOptional(), arm::pipe::EmptyOptional(), arm::pipe::EmptyOptional(), readableData, offset);
+
+    // Weights workload execution - event relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::ExecutionLink,
+                                               arm::pipe::EmptyOptional(),
+                                               weightsWorkloadExecutionGuid,
+                                               weightsWorkloadExecutionEOLEventGuid,
+                                               LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS,
+                                               readableData,
+                                               offset);
+
+   // Bias workload execution
+    // Bias workload execution entity
+    ProfilingGuid biasWorkloadExecutionGuid = VerifyTimelineEntityBinaryPacketData(
+        arm::pipe::EmptyOptional(), readableData, offset);
+
+    // Entity - Type relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::LabelLink,
+                                               arm::pipe::EmptyOptional(),
+                                               biasWorkloadExecutionGuid,
+                                               LabelsAndEventClasses::WORKLOAD_EXECUTION_GUID,
+                                               LabelsAndEventClasses::TYPE_GUID,
+                                               readableData,
+                                               offset);
+
+    // Inference - Workload execution relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::RetentionLink,
+                                               arm::pipe::EmptyOptional(),
+                                               inferenceGuid,
+                                               biasWorkloadExecutionGuid,
+                                               LabelsAndEventClasses::CHILD_GUID,
+                                               readableData,
+                                               offset);
+
+    // Workload - Workload execution relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::RetentionLink,
+                                               arm::pipe::EmptyOptional(),
+                                               biasWorkloadGuid,
+                                               biasWorkloadExecutionGuid,
+                                               LabelsAndEventClasses::EXECUTION_OF_GUID,
+                                               readableData,
+                                               offset);
+
+    // Start Bias workload execution life
+    // Event packet - timeline, threadId, eventGuid
+    ProfilingGuid biasWorkloadExecutionSOLEventGuid = VerifyTimelineEventBinaryPacket(
+        arm::pipe::EmptyOptional(), arm::pipe::EmptyOptional(), arm::pipe::EmptyOptional(), readableData, offset);
+
+    // Bias workload execution - event relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::ExecutionLink,
+                                               arm::pipe::EmptyOptional(),
+                                               biasWorkloadExecutionGuid,
+                                               biasWorkloadExecutionSOLEventGuid,
+                                               LabelsAndEventClasses::ARMNN_PROFILING_SOL_EVENT_CLASS,
+                                               readableData,
+                                               offset);
+
+    // End of Bias workload execution life
+    // Event packet - timeline, threadId, eventGuid
+    ProfilingGuid biasWorkloadExecutionEOLEventGuid = VerifyTimelineEventBinaryPacket(
+        arm::pipe::EmptyOptional(), arm::pipe::EmptyOptional(), arm::pipe::EmptyOptional(), readableData, offset);
+
+    // Bias workload execution - event relationship
+    VerifyTimelineRelationshipBinaryPacketData(ProfilingRelationshipType::ExecutionLink,
+                                               arm::pipe::EmptyOptional(),
+                                               biasWorkloadExecutionGuid,
+                                               biasWorkloadExecutionEOLEventGuid,
+                                               LabelsAndEventClasses::ARMNN_PROFILING_EOL_EVENT_CLASS,
+                                               readableData,
+                                               offset);
+
     // Conv2d workload execution
     // Conv2d workload execution entity
     ProfilingGuid conv2DWorkloadExecutionGuid = VerifyTimelineEntityBinaryPacketData(