Add ConstTensorsAsInput support for Conv3d

 * Constant weights and biases are now stored as Constant layers.
 * Updated Serializer, Deserializer and unit tests to reflect this.
 * Updated TfLiteParser.
 * Updated Ref backend to handle constant weights and
   bias as inputs rather than reading from member variables.
 * Added Conv3d EndToEnd test.
 * Added NCDHW DataLayout and unit tests.

Signed-off-by: Matthew Sloyan <matthew.sloyan@arm.com>
Change-Id: I10cdd354ca5f1c748730f92ffdb36bf810f83c8e
diff --git a/src/armnnSerializer/ArmnnSchema.fbs b/src/armnnSerializer/ArmnnSchema.fbs
index 7798288..c577a11 100644
--- a/src/armnnSerializer/ArmnnSchema.fbs
+++ b/src/armnnSerializer/ArmnnSchema.fbs
@@ -46,7 +46,8 @@
 enum DataLayout : byte {
     NHWC = 0,
     NCHW = 1,
-    NDHWC = 2
+    NDHWC = 2,
+    NCDHW = 3
 }
 
 enum ReduceOperation: byte {
@@ -287,8 +288,6 @@
 table Convolution3dLayer {
     base:LayerBase;
     descriptor:Convolution3dDescriptor;
-    weights:ConstTensor;
-    biases:ConstTensor;
 }
 
 table Convolution3dDescriptor {
diff --git a/src/armnnSerializer/ArmnnSchema_generated.h b/src/armnnSerializer/ArmnnSchema_generated.h
index 8234aa9..712ad28 100644
--- a/src/armnnSerializer/ArmnnSchema_generated.h
+++ b/src/armnnSerializer/ArmnnSchema_generated.h
@@ -540,31 +540,34 @@
   DataLayout_NHWC = 0,
   DataLayout_NCHW = 1,
   DataLayout_NDHWC = 2,
+  DataLayout_NCDHW = 3,
   DataLayout_MIN = DataLayout_NHWC,
-  DataLayout_MAX = DataLayout_NDHWC
+  DataLayout_MAX = DataLayout_NCDHW
 };
 
-inline const DataLayout (&EnumValuesDataLayout())[3] {
+inline const DataLayout (&EnumValuesDataLayout())[4] {
   static const DataLayout values[] = {
     DataLayout_NHWC,
     DataLayout_NCHW,
-    DataLayout_NDHWC
+    DataLayout_NDHWC,
+    DataLayout_NCDHW
   };
   return values;
 }
 
 inline const char * const *EnumNamesDataLayout() {
-  static const char * const names[4] = {
+  static const char * const names[5] = {
     "NHWC",
     "NCHW",
     "NDHWC",
+    "NCDHW",
     nullptr
   };
   return names;
 }
 
 inline const char *EnumNameDataLayout(DataLayout e) {
-  if (flatbuffers::IsOutRange(e, DataLayout_NHWC, DataLayout_NDHWC)) return "";
+  if (flatbuffers::IsOutRange(e, DataLayout_NHWC, DataLayout_NCDHW)) return "";
   const size_t index = static_cast<size_t>(e);
   return EnumNamesDataLayout()[index];
 }
@@ -3250,9 +3253,7 @@
   typedef Convolution3dLayerBuilder Builder;
   enum FlatBuffersVTableOffset FLATBUFFERS_VTABLE_UNDERLYING_TYPE {
     VT_BASE = 4,
-    VT_DESCRIPTOR = 6,
-    VT_WEIGHTS = 8,
-    VT_BIASES = 10
+    VT_DESCRIPTOR = 6
   };
   const armnnSerializer::LayerBase *base() const {
     return GetPointer<const armnnSerializer::LayerBase *>(VT_BASE);
@@ -3260,22 +3261,12 @@
   const armnnSerializer::Convolution3dDescriptor *descriptor() const {
     return GetPointer<const armnnSerializer::Convolution3dDescriptor *>(VT_DESCRIPTOR);
   }
-  const armnnSerializer::ConstTensor *weights() const {
-    return GetPointer<const armnnSerializer::ConstTensor *>(VT_WEIGHTS);
-  }
-  const armnnSerializer::ConstTensor *biases() const {
-    return GetPointer<const armnnSerializer::ConstTensor *>(VT_BIASES);
-  }
   bool Verify(flatbuffers::Verifier &verifier) const {
     return VerifyTableStart(verifier) &&
            VerifyOffset(verifier, VT_BASE) &&
            verifier.VerifyTable(base()) &&
            VerifyOffset(verifier, VT_DESCRIPTOR) &&
            verifier.VerifyTable(descriptor()) &&
-           VerifyOffset(verifier, VT_WEIGHTS) &&
-           verifier.VerifyTable(weights()) &&
-           VerifyOffset(verifier, VT_BIASES) &&
-           verifier.VerifyTable(biases()) &&
            verifier.EndTable();
   }
 };
@@ -3290,12 +3281,6 @@
   void add_descriptor(flatbuffers::Offset<armnnSerializer::Convolution3dDescriptor> descriptor) {
     fbb_.AddOffset(Convolution3dLayer::VT_DESCRIPTOR, descriptor);
   }
-  void add_weights(flatbuffers::Offset<armnnSerializer::ConstTensor> weights) {
-    fbb_.AddOffset(Convolution3dLayer::VT_WEIGHTS, weights);
-  }
-  void add_biases(flatbuffers::Offset<armnnSerializer::ConstTensor> biases) {
-    fbb_.AddOffset(Convolution3dLayer::VT_BIASES, biases);
-  }
   explicit Convolution3dLayerBuilder(flatbuffers::FlatBufferBuilder &_fbb)
         : fbb_(_fbb) {
     start_ = fbb_.StartTable();
@@ -3311,12 +3296,8 @@
 inline flatbuffers::Offset<Convolution3dLayer> CreateConvolution3dLayer(
     flatbuffers::FlatBufferBuilder &_fbb,
     flatbuffers::Offset<armnnSerializer::LayerBase> base = 0,
-    flatbuffers::Offset<armnnSerializer::Convolution3dDescriptor> descriptor = 0,
-    flatbuffers::Offset<armnnSerializer::ConstTensor> weights = 0,
-    flatbuffers::Offset<armnnSerializer::ConstTensor> biases = 0) {
+    flatbuffers::Offset<armnnSerializer::Convolution3dDescriptor> descriptor = 0) {
   Convolution3dLayerBuilder builder_(_fbb);
-  builder_.add_biases(biases);
-  builder_.add_weights(weights);
   builder_.add_descriptor(descriptor);
   builder_.add_base(base);
   return builder_.Finish();
diff --git a/src/armnnSerializer/Serializer.cpp b/src/armnnSerializer/Serializer.cpp
index 7e1b74e..84a9d53 100644
--- a/src/armnnSerializer/Serializer.cpp
+++ b/src/armnnSerializer/Serializer.cpp
@@ -388,18 +388,15 @@
     CreateAnyLayer(flatBufferLayer.o, serializer::Layer::Layer_Convolution2dLayer);
 }
 
-// Build FlatBuffer for Convolution2dLayer
+// Build FlatBuffer for Convolution3dLayer
 void SerializerStrategy::SerializeConvolution3dLayer(const armnn::IConnectableLayer* layer,
                                                      const armnn::Convolution3dDescriptor& 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);
+    auto flatBufferBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_Convolution3d);
 
     auto flatBufferDescriptor = CreateConvolution3dDescriptor(m_flatBufferBuilder,
                                                               descriptor.m_PadLeft,
@@ -416,21 +413,11 @@
                                                               descriptor.m_DilationZ,
                                                               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
+    // Create the FlatBuffer Convolution3dLayer
     auto flatBufferLayer = CreateConvolution3dLayer(m_flatBufferBuilder,
                                                     flatBufferBaseLayer,
-                                                    flatBufferDescriptor,
-                                                    flatBufferWeightsConstTensorInfo,
-                                                    flatBufferBiasesConstTensorInfo);
+                                                    flatBufferDescriptor);
 
     // Add the AnyLayer to the FlatBufferLayers
     CreateAnyLayer(flatBufferLayer.o, serializer::Layer::Layer_Convolution3dLayer);
@@ -2038,7 +2025,6 @@
                     static_cast<const armnn::Convolution3dDescriptor&>(descriptor);
             SerializeConvolution3dLayer(layer,
                                         layerDescriptor,
-                                        constants,
                                         name);
             break;
         }
diff --git a/src/armnnSerializer/Serializer.hpp b/src/armnnSerializer/Serializer.hpp
index 2f827ac..1c0a9a6 100644
--- a/src/armnnSerializer/Serializer.hpp
+++ b/src/armnnSerializer/Serializer.hpp
@@ -150,7 +150,6 @@
 
     void SerializeConvolution3dLayer(const armnn::IConnectableLayer* layer,
                                      const armnn::Convolution3dDescriptor& descriptor,
-                                     const std::vector<armnn::ConstTensor>& constants,
                                      const char* name = nullptr);
 
     void SerializeDepthToSpaceLayer(const armnn::IConnectableLayer* layer,
diff --git a/src/armnnSerializer/SerializerUtils.cpp b/src/armnnSerializer/SerializerUtils.cpp
index fca6db8..5ad2771 100644
--- a/src/armnnSerializer/SerializerUtils.cpp
+++ b/src/armnnSerializer/SerializerUtils.cpp
@@ -99,6 +99,8 @@
             return armnnSerializer::DataLayout::DataLayout_NHWC;
         case armnn::DataLayout::NDHWC:
             return armnnSerializer::DataLayout::DataLayout_NDHWC;
+        case armnn::DataLayout::NCDHW:
+            return armnnSerializer::DataLayout::DataLayout_NCDHW;
         case armnn::DataLayout::NCHW:
         default:
             return armnnSerializer::DataLayout::DataLayout_NCHW;
diff --git a/src/armnnSerializer/test/SerializerTestUtils.hpp b/src/armnnSerializer/test/SerializerTestUtils.hpp
index c6f148b..ce4d2cc 100644
--- a/src/armnnSerializer/test/SerializerTestUtils.hpp
+++ b/src/armnnSerializer/test/SerializerTestUtils.hpp
@@ -69,6 +69,7 @@
         {
             case armnn::LayerType::Input: break;
             case armnn::LayerType::Output: break;
+            case armnn::LayerType::Constant: break;
             default:
             {
                 VerifyNameAndConnections(layer, name);
diff --git a/src/armnnSerializer/test/SerializerTests.cpp b/src/armnnSerializer/test/SerializerTests.cpp
index f2c9852..2bffe0b 100644
--- a/src/armnnSerializer/test/SerializerTests.cpp
+++ b/src/armnnSerializer/test/SerializerTests.cpp
@@ -472,25 +472,26 @@
 
     armnn::INetworkPtr network = armnn::INetwork::Create();
     armnn::IConnectableLayer* const inputLayer  = network->AddInputLayer(0);
-    armnn::IConnectableLayer* const convLayer   =
-            network->AddConvolution3dLayer(descriptor,
-                                           weights,
-                                           armnn::Optional<armnn::ConstTensor>(biases),
-                                           layerName.c_str());
+    armnn::IConnectableLayer* const weightsLayer = network->AddConstantLayer(weights, "Weights");
+    armnn::IConnectableLayer* const biasesLayer = network->AddConstantLayer(biases, "Biases");
+    armnn::IConnectableLayer* const convLayer   = network->AddConvolution3dLayer(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<armnn::Convolution3dDescriptor> verifier(
-            layerName, {inputInfo}, {outputInfo}, descriptor, constants);
+    LayerVerifierBaseWithDescriptor<armnn::Convolution3dDescriptor> verifier(
+            layerName, {inputInfo, weightsInfo, biasesInfo}, {outputInfo}, descriptor);
     deserializedNetwork->ExecuteStrategy(verifier);
 }