IVGCVSW-3974 Add serialization support for LOG_SOFTMAX

Signed-off-by: Sadik Armagan <sadik.armagan@arm.com>
Change-Id: I0777abc672dd7d5c9fadaed27b0e776ac591d2c7
diff --git a/src/armnnSerializer/ArmnnSchema.fbs b/src/armnnSerializer/ArmnnSchema.fbs
index 7588b9d..187a091 100644
--- a/src/armnnSerializer/ArmnnSchema.fbs
+++ b/src/armnnSerializer/ArmnnSchema.fbs
@@ -142,7 +142,8 @@
     ArgMinMax = 47,
     Slice = 48,
     DepthToSpace = 49,
-    InstanceNormalization = 50
+    InstanceNormalization = 50,
+    LogSoftmax = 51
 }
 
 // Base layer table to be used as part of other layers
@@ -273,6 +274,16 @@
     dataLayout:DataLayout;
 }
 
+table LogSoftmaxLayer {
+    base:LayerBase;
+    descriptor:LogSoftmaxDescriptor;
+}
+
+table LogSoftmaxDescriptor {
+    beta:float = 1;
+    axis:int = -1;
+}
+
 table L2NormalizationLayer {
     base:LayerBase;
     descriptor:L2NormalizationDescriptor;
@@ -748,7 +759,8 @@
     ArgMinMaxLayer,
     SliceLayer,
     DepthToSpaceLayer,
-    InstanceNormalizationLayer
+    InstanceNormalizationLayer,
+    LogSoftmaxLayer
 }
 
 table AnyLayer {
diff --git a/src/armnnSerializer/Serializer.cpp b/src/armnnSerializer/Serializer.cpp
index 0e8c894..11f833c 100644
--- a/src/armnnSerializer/Serializer.cpp
+++ b/src/armnnSerializer/Serializer.cpp
@@ -467,7 +467,22 @@
                                              const armnn::LogSoftmaxDescriptor& logSoftmaxDescriptor,
                                              const char* name)
 {
-    throw armnn::UnimplementedException("SerializerVisitor::VisitLogSoftmaxLayer() is not implemented");
+    // Create FlatBuffer BaseLayer
+    auto flatBufferLogSoftmaxBaseLayer = CreateLayerBase(layer, serializer::LayerType::LayerType_LogSoftmax);
+
+    // Create the FlatBuffer LogSoftmaxDescriptor
+    auto flatBufferLogSoftmaxDesc =
+        serializer::CreateLogSoftmaxDescriptor(m_flatBufferBuilder,
+                                               logSoftmaxDescriptor.m_Beta,
+                                               logSoftmaxDescriptor.m_Axis);
+
+    // Create the FlatBuffer LogSoftmaxLayer
+    auto flatBufferLogSoftmaxLayer =
+        serializer::CreateLogSoftmaxLayer(m_flatBufferBuilder,
+                                          flatBufferLogSoftmaxBaseLayer,
+                                          flatBufferLogSoftmaxDesc);
+
+    CreateAnyLayer(flatBufferLogSoftmaxLayer.o, serializer::Layer::Layer_LogSoftmaxLayer);
 }
 
 void SerializerVisitor::VisitLstmLayer(const armnn::IConnectableLayer* layer,
diff --git a/src/armnnSerializer/SerializerSupport.md b/src/armnnSerializer/SerializerSupport.md
index e628253..2def918 100644
--- a/src/armnnSerializer/SerializerSupport.md
+++ b/src/armnnSerializer/SerializerSupport.md
@@ -28,6 +28,7 @@
 * Input
 * InstanceNormalization
 * L2Normalization
+* LogSoftmax
 * Lstm
 * Maximum
 * Mean
diff --git a/src/armnnSerializer/test/SerializerTests.cpp b/src/armnnSerializer/test/SerializerTests.cpp
index 98893a5..a70c891 100644
--- a/src/armnnSerializer/test/SerializerTests.cpp
+++ b/src/armnnSerializer/test/SerializerTests.cpp
@@ -1437,6 +1437,61 @@
     deserializedNetwork->Accept(verifier);
 }
 
+BOOST_AUTO_TEST_CASE(SerializeLogSoftmax)
+{
+    class LogSoftmaxLayerVerifier : public LayerVerifierBase
+    {
+    public:
+        LogSoftmaxLayerVerifier(const std::string& layerName,
+                                const std::vector<armnn::TensorInfo>& inputInfos,
+                                const std::vector<armnn::TensorInfo>& outputInfos,
+                                const armnn::LogSoftmaxDescriptor& descriptor)
+            : LayerVerifierBase(layerName, inputInfos, outputInfos)
+            , m_Descriptor(descriptor) {}
+
+        void VisitLogSoftmaxLayer(const armnn::IConnectableLayer* layer,
+                                  const armnn::LogSoftmaxDescriptor& descriptor,
+                                  const char* name) override
+        {
+            VerifyNameAndConnections(layer, name);
+            VerifyDescriptor(descriptor);
+        }
+
+    private:
+        void VerifyDescriptor(const armnn::LogSoftmaxDescriptor& descriptor)
+        {
+            BOOST_TEST(descriptor.m_Beta == m_Descriptor.m_Beta);
+            BOOST_TEST(descriptor.m_Axis == m_Descriptor.m_Axis);
+        }
+
+        armnn::LogSoftmaxDescriptor m_Descriptor;
+    };
+
+    const std::string layerName("log_softmax");
+    const armnn::TensorInfo info({1, 10}, armnn::DataType::Float32);
+
+    armnn::LogSoftmaxDescriptor descriptor;
+    descriptor.m_Beta = 1.0f;
+    descriptor.m_Axis = -1;
+
+    armnn::INetworkPtr network = armnn::INetwork::Create();
+    armnn::IConnectableLayer* const inputLayer      = network->AddInputLayer(0);
+    armnn::IConnectableLayer* const logSoftmaxLayer = network->AddLogSoftmaxLayer(descriptor, layerName.c_str());
+    armnn::IConnectableLayer* const outputLayer     = network->AddOutputLayer(0);
+
+    inputLayer->GetOutputSlot(0).Connect(logSoftmaxLayer->GetInputSlot(0));
+    logSoftmaxLayer->GetOutputSlot(0).Connect(outputLayer->GetInputSlot(0));
+
+    inputLayer->GetOutputSlot(0).SetTensorInfo(info);
+    logSoftmaxLayer->GetOutputSlot(0).SetTensorInfo(info);
+
+    armnn::INetworkPtr deserializedNetwork = DeserializeNetwork(SerializeNetwork(*network));
+    BOOST_CHECK(deserializedNetwork);
+
+    LogSoftmaxLayerVerifier verifier(layerName, {info}, {info}, descriptor);
+    deserializedNetwork->Accept(verifier);
+}
+
 BOOST_AUTO_TEST_CASE(SerializeMaximum)
 {
     class MaximumLayerVerifier : public LayerVerifierBase