Repository: landerlini/scikinC (language: python)

Issue:
Added softmax and its test
Added softmax loss as a *layer*, still not supported as a string shortcut.


Discussion / hints:

Fix patch:
diff --git a/scikinC/layers/Softmax.py b/scikinC/layers/Softmax.py
new file mode 100644
index 0000000..2fcc3c9
--- /dev/null
+++ b/scikinC/layers/Softmax.py
@@ -0,0 +1,41 @@
+from scikinC.layers.BaseLayerConverter import BaseLayerConverter
+from scikinC._tools import array2c
+
+class Softmax (BaseLayerConverter):
+    """
+    Softmax activation function
+    """
+
+    def definition(self):
+        """Return the definition of the layer function"""
+        ret = []
+
+        nX = self.layer.output_shape[1]
+
+        ret += ["""
+        extern "C"
+        FLOAT_T* %(layername)s (FLOAT_T* ret, const FLOAT_T* input)
+        {
+            int i; 
+            FLOAT_T denom = 0;
+            
+            for (i=0; i < %(nX)d; ++i)
+                denom += exp(input[i]);
+            
+            for (i=0; i < %(nX)d; ++i)
+                ret[i] = exp(input[i])/denom;
+
+            return ret; 
+        }
+        """ % dict(
+            layername=self.name,
+            nX=nX
+        )]
+
+        return "\n".join(ret)
+
+    def call(self, obuffer, ibuffer):
+        """Return the call to the layer function"""
+        return "%(layername)s ( %(obuffer)s, %(ibuffer)s);" % dict (
+            layername=self.name, obuffer=obuffer, ibuffer=ibuffer )
+
diff --git a/scikinC/layers/__init__.py b/scikinC/layers/__init__.py
index cba01c5..f2b7193 100644
--- a/scikinC/layers/__init__.py
+++ b/scikinC/layers/__init__.py
@@ -3,3 +3,4 @@
 from scikinC.layers.PReLU import PReLU
 from scikinC.layers.LeakyReLU import LeakyReLU
 from scikinC.layers.Dropout import Dropout
+from scikinC.layers.Softmax import Softmax


Test patch:
diff --git a/test/test_keras.py b/test/test_keras.py
index a96b1b2..0538853 100644
--- a/test/test_keras.py
+++ b/test/test_keras.py
@@ -67,6 +67,23 @@ def test_prelu (classifier_prelu):
   deployed = deploy_keras("keras_prelu", classifier_prelu) 
   assert eval_error (classifier_prelu, deployed) < 1e-5
 
+
+################################################################################
+### Softmax layer
+@pytest.fixture
+def classifier_softmax():
+    return make_classifier([
+        tf.keras.layers.Dense(16, activation='linear'),
+        tf.keras.layers.Softmax(),
+        tf.keras.layers.Dense(1, activation='sigmoid')
+    ])
+
+
+def test_softmax(classifier_softmax):
+    deployed = deploy_keras("keras_softmax", classifier_softmax)
+    assert eval_error(classifier_softmax, deployed) < 1e-5
+
+
 ################################################################################
 ### LeakyReLU layer 
 @pytest.fixture
diff --git a/test/wrap.py b/test/wrap.py
index a5b6ee2..b925544 100644
--- a/test/wrap.py
+++ b/test/wrap.py
@@ -23,7 +23,7 @@ def __del__ (self):
 
     def compile (self):
       output = subprocess.check_output(
-          ["gcc", "-o", self.compiled, "--shared", "-lm", "-fPIC", self.filename]
+          ["gcc", self.filename, "-o", self.compiled, "--shared", "-fPIC", "-lm"]
           )
       if str(output, 'ASCII') not in ["", "\n"]:
         raise Exception("Compilation error %s" % str(output, 'ASCII'))