IVGCVSW-5736 and IVGCVSW-5743 'NonConstWeights: Update front-end and TfLiteDelegate support for FullyConnected Operator'

* Added front-end support for non-const weights for FULLY_CONNECTED operator
* Added FULLY_CONNECTED end-to-end test
* Updated FULLY_CONNECTED operator support in TfLite Arm NN Delegate for non-const weights
* Updated the version numbers

Signed-off-by: Sadik Armagan <sadik.armagan@arm.com>
Change-Id: Iffa5b9aa9297aca4c02d923cce4636c88ac21faa
diff --git a/src/armnnSerializer/ArmnnSchema.fbs b/src/armnnSerializer/ArmnnSchema.fbs
index e2b3a3c..88d66f7 100644
--- a/src/armnnSerializer/ArmnnSchema.fbs
+++ b/src/armnnSerializer/ArmnnSchema.fbs
@@ -321,6 +321,7 @@
 table FullyConnectedDescriptor {
     biasEnabled:bool = false;
     transposeWeightsMatrix:bool = false;
+    constantWeights:bool = true;
 }
 
 table GatherLayer {
diff --git a/src/armnnSerializer/ArmnnSchema_generated.h b/src/armnnSerializer/ArmnnSchema_generated.h
index 524ffb0..99ab0dc 100644
--- a/src/armnnSerializer/ArmnnSchema_generated.h
+++ b/src/armnnSerializer/ArmnnSchema_generated.h
@@ -3504,7 +3504,8 @@
   typedef FullyConnectedDescriptorBuilder Builder;
   enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
     VT_BIASENABLED = 4,
-    VT_TRANSPOSEWEIGHTSMATRIX = 6
+    VT_TRANSPOSEWEIGHTSMATRIX = 6,
+    VT_CONSTANTWEIGHTS = 8
   };
   bool biasEnabled() const {
     return GetField<uint8_t>(VT_BIASENABLED, 0) != 0;
@@ -3512,10 +3513,14 @@
   bool transposeWeightsMatrix() const {
     return GetField<uint8_t>(VT_TRANSPOSEWEIGHTSMATRIX, 0) != 0;
   }
+  bool constantWeights() const {
+    return GetField<uint8_t>(VT_CONSTANTWEIGHTS, 1) != 0;
+  }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
            VerifyField<uint8_t>(verifier, VT_BIASENABLED) &&
            VerifyField<uint8_t>(verifier, VT_TRANSPOSEWEIGHTSMATRIX) &&
+           VerifyField<uint8_t>(verifier, VT_CONSTANTWEIGHTS) &&
            verifier.EndTable();
   }
 };
@@ -3530,6 +3535,9 @@
   void add_transposeWeightsMatrix(bool transposeWeightsMatrix) {
     fbb_.AddElement<uint8_t>(FullyConnectedDescriptor::VT_TRANSPOSEWEIGHTSMATRIX, static_cast<uint8_t>(transposeWeightsMatrix), 0);
   }
+  void add_constantWeights(bool constantWeights) {
+    fbb_.AddElement<uint8_t>(FullyConnectedDescriptor::VT_CONSTANTWEIGHTS, static_cast<uint8_t>(constantWeights), 1);
+  }
   explicit FullyConnectedDescriptorBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
@@ -3545,8 +3553,10 @@
 inline flatbuffers::Offset<FullyConnectedDescriptor> CreateFullyConnectedDescriptor(
     flatbuffers::FlatBufferBuilder &_fbb,
     bool biasEnabled = false,
-    bool transposeWeightsMatrix = false) {
+    bool transposeWeightsMatrix = false,
+    bool constantWeights = true) {
   FullyConnectedDescriptorBuilder builder_(_fbb);
+  builder_.add_constantWeights(constantWeights);
   builder_.add_transposeWeightsMatrix(transposeWeightsMatrix);
   builder_.add_biasEnabled(biasEnabled);
   return builder_.Finish();
diff --git a/src/armnnSerializer/Serializer.cpp b/src/armnnSerializer/Serializer.cpp
index 0586700..ae9ddf2 100644
--- a/src/armnnSerializer/Serializer.cpp
+++ b/src/armnnSerializer/Serializer.cpp
@@ -1118,12 +1118,8 @@
 void SerializerStrategy::SerializeFullyConnectedLayer(const armnn::IConnectableLayer* layer,
                                                       const armnn::FullyConnectedDescriptor& fullyConnectedDescriptor,
                                                       const std::vector<armnn::ConstTensor>& constants,
-                                                      const char* name)
+                                                      const char*)
 {
-    IgnoreUnused(name);
-
-    const armnn::ConstTensor& weights = constants.at(0);
-
     // Create FlatBuffer BaseLayer
     auto flatBufferBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_FullyConnected);
 
@@ -1131,17 +1127,23 @@
     auto flatBufferDescriptor =
         serializer::CreateFullyConnectedDescriptor(m_flatBufferBuilder,
                                                    fullyConnectedDescriptor.m_BiasEnabled,
-                                                   fullyConnectedDescriptor.m_TransposeWeightMatrix);
+                                                   fullyConnectedDescriptor.m_TransposeWeightMatrix,
+                                                   fullyConnectedDescriptor.m_ConstantWeights);
 
     // Create FlatBuffer weights data
-    auto flatBufferWeights = CreateConstTensorInfo(weights);
-
+    flatbuffers::Offset<serializer::ConstTensor> flatBufferWeights;
     // Create FlatBuffer bias data
     flatbuffers::Offset<serializer::ConstTensor> flatBufferBiases;
-    if (fullyConnectedDescriptor.m_BiasEnabled)
+    if (fullyConnectedDescriptor.m_ConstantWeights && !constants.empty())
     {
-        armnn::ConstTensor biases = constants.at(1);
-        flatBufferBiases = CreateConstTensorInfo(biases);
+        armnn::ConstTensor weights = constants.at(0);
+        flatBufferWeights = CreateConstTensorInfo(weights);
+
+        if (fullyConnectedDescriptor.m_BiasEnabled)
+        {
+            armnn::ConstTensor biases = constants.at(1);
+            flatBufferBiases = CreateConstTensorInfo(biases);
+        }
     }
 
     // Create FlatBuffer FullyConnectedLayer
diff --git a/src/armnnSerializer/test/SerializerTests.cpp b/src/armnnSerializer/test/SerializerTests.cpp
index f261731..d7c10cb 100644
--- a/src/armnnSerializer/test/SerializerTests.cpp
+++ b/src/armnnSerializer/test/SerializerTests.cpp
@@ -748,6 +748,7 @@
     armnn::FullyConnectedDescriptor descriptor;
     descriptor.m_BiasEnabled = true;
     descriptor.m_TransposeWeightMatrix = false;
+    descriptor.m_ConstantWeights = true;
 
     armnn::INetworkPtr network = armnn::INetwork::Create();
     armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
@@ -773,6 +774,53 @@
     deserializedNetwork->ExecuteStrategy(verifier);
 }
 
+BOOST_AUTO_TEST_CASE(SerializeFullyConnectedWeightsAsInputs)
+{
+    const std::string layerName("fullyConnected_weights_as_inputs");
+    const armnn::TensorInfo inputInfo ({ 2, 5, 1, 1 }, armnn::DataType::Float32);
+    const armnn::TensorInfo outputInfo({ 2, 3 }, armnn::DataType::Float32);
+
+    const armnn::TensorInfo weightsInfo({ 5, 3 }, armnn::DataType::Float32);
+    const armnn::TensorInfo biasesInfo ({ 3 }, armnn::DataType::Float32);
+
+    armnn::Optional<armnn::ConstTensor> weights = armnn::EmptyOptional();
+    armnn::Optional<armnn::ConstTensor> bias = armnn::EmptyOptional();
+
+    armnn::FullyConnectedDescriptor descriptor;
+    descriptor.m_BiasEnabled = true;
+    descriptor.m_TransposeWeightMatrix = false;
+    descriptor.m_ConstantWeights = false;
+
+    armnn::INetworkPtr network = armnn::INetwork::Create();
+    armnn::IConnectableLayer* const inputLayer = network->AddInputLayer(0);
+    armnn::IConnectableLayer* const weightsInputLayer = network->AddInputLayer(1);
+    armnn::IConnectableLayer* const biasInputLayer = network->AddInputLayer(2);
+    armnn::IConnectableLayer* const fullyConnectedLayer =
+        network->AddFullyConnectedLayer(descriptor,
+                                        weights,
+                                        bias,
+                                        layerName.c_str());
+    armnn::IConnectableLayer* const outputLayer = network->AddOutputLayer(0);
+
+    inputLayer->GetOutputSlot(0).Connect(fullyConnectedLayer->GetInputSlot(0));
+    weightsInputLayer->GetOutputSlot(0).Connect(fullyConnectedLayer->GetInputSlot(1));
+    biasInputLayer->GetOutputSlot(0).Connect(fullyConnectedLayer->GetInputSlot(2));
+    fullyConnectedLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
+
+    inputLayer->GetOutputSlot(0).SetTensorInfo(inputInfo);
+    weightsInputLayer->GetOutputSlot(0).SetTensorInfo(weightsInfo);
+    biasInputLayer->GetOutputSlot(0).SetTensorInfo(biasesInfo);
+    fullyConnectedLayer->GetOutputSlot(0).SetTensorInfo(outputInfo);
+
+    armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
+    BOOST_CHECK(deserializedNetwork);
+
+    const std::vector<armnn::ConstTensor> constants {};
+    LayerVerifierBaseWithDescriptorAndConstants<armnn::FullyConnectedDescriptor> verifier(
+        layerName, {inputInfo, weightsInfo, biasesInfo}, {outputInfo}, descriptor, constants);
+    deserializedNetwork->ExecuteStrategy(verifier);
+}
+
 BOOST_AUTO_TEST_CASE(SerializeGather)
 {
     using GatherDescriptor = armnn::GatherDescriptor;