From 2298a5dc261c23b5a32468c6db00f598f0bd3c64 Mon Sep 17 00:00:00 2001
From: auphelia <jakobapk@web.de>
Date: Tue, 10 Dec 2019 12:29:50 +0000
Subject: [PATCH] [Execution and Test] Added verification (and test) for
 xnorpopcountmatmul and streamingfclayer

---
 .../custom_op/verify_custom_op_construct.py   | 66 ++++++++++++++++---
 tests/test_verify_custom_ops.py               | 63 +++++++++++++++++-
 2 files changed, 117 insertions(+), 12 deletions(-)

diff --git a/src/finn/custom_op/verify_custom_op_construct.py b/src/finn/custom_op/verify_custom_op_construct.py
index c9ad0815c..07d47a959 100644
--- a/src/finn/custom_op/verify_custom_op_construct.py
+++ b/src/finn/custom_op/verify_custom_op_construct.py
@@ -3,27 +3,27 @@ from finn.core.utils import get_by_name
 
 class CustomOp_Construct(Enum):
     MultiThreshold = auto()
-    #XnorPopcountMatMul = auto()
+    XnorPopcountMatMul = auto()
     #StreamingMaxPool_Batch = auto()
-    #StreamingFCLayer_Batch = auto()
+    StreamingFCLayer_Batch = auto()
 
-    def verify_layout(self, node):
+    def verify_construct(self, node):
         assert self.verify_num_of_attr(node) == True, 'Number of attributes is not correct'
         assert self.verify_domain_is_finn(node) == True, 'Domain name is not "finn"'
         if self.name in ["StreamingMaxPool_Batch", "StreamingFCLayer_Batch"]:
             assert self.verify_backend_is_fpgadataflow(node) == True, 'Attribute backend has to be set to "fpgadataflow"'
         assert self.verify_all_attr(node) == True, 'The attributes are not correct'
         assert self.verify_num_of_inputs(node) == True, 'The number of inputs is wrong'
-          
+
     def verify_num_of_attr(self, node):
         if self.name == "MultiThreshold":
             num_of_attr = 3
-        #elif self.name == "XnorPopcountMatMul":
-            #num_of_attr =
+        elif self.name == "XnorPopcountMatMul":
+            num_of_attr = 0
         #elif self.name == "StreamingMaxPool_Batch":
             #num_of_attr =
-        #elif self.name == "StreamingFCLayer_Batch":
-            #num_of_attr =
+        elif self.name == "StreamingFCLayer_Batch":
+            num_of_attr = 14
         if len(node.attribute) == num_of_attr:
             return True
         else:
@@ -40,7 +40,7 @@ class CustomOp_Construct(Enum):
     def verify_backend_is_fpgadataflow(self, node):
         #only for HLS CustomOp
         backend_value = get_by_name(node.attribute, "backend")
-        if backend_value == "fpgadataflow":
+        if backend_value.s.decode("UTF-8") == "fpgadataflow":
             return True
         else:
             return False
@@ -54,6 +54,29 @@ class CustomOp_Construct(Enum):
                 return True
             except:
                 return False
+
+        elif self.name == "XnorPopcountMatMul":
+            return True
+        #elif self.name == "StreamingMaxPool_Batch":
+        elif self.name == "StreamingFCLayer_Batch":
+            try:
+                get_by_name(node.attribute, "code_gen_dir")
+                get_by_name(node.attribute, "executable_path")
+                get_by_name(node.attribute, "resType")
+                get_by_name(node.attribute, "MW")
+                get_by_name(node.attribute, "MH")
+                get_by_name(node.attribute, "SIMD")
+                get_by_name(node.attribute, "PE")
+                get_by_name(node.attribute, "inputDataType")
+                get_by_name(node.attribute, "weightDataType")
+                get_by_name(node.attribute, "outputDataType")
+                get_by_name(node.attribute, "ActVal")
+                get_by_name(node.attribute, "binaryXnorMode")
+                get_by_name(node.attribute, "noActivation")
+                return True
+            except:
+                return False
+
         
     def verify_num_of_inputs(self, node):
         if self.name == "MultiThreshold":
@@ -61,6 +84,31 @@ class CustomOp_Construct(Enum):
                 return True
             else:
                 return False
+        elif self.name == "XnorPopcountMatMul":
+            if len(node.input) == 2:
+                return True
+            else:
+                return False
+        #elif self.name == "StreamingMaxPool_Batch":
+        elif self.name == "StreamingFCLayer_Batch":
+            # check noActivation value to determine the number of inputs
+            no_act = get_by_name(node.attribute, "noActivation")
+            no_act = no_act.i
+           
+            if no_act == 1:
+                if len(node.input) == 2:
+                    return True
+                else:
+                    return False
+            elif no_act == 0:
+                if len(node.input) == 3:
+                    return True
+                else:
+                    return False
+            else:
+                Exception("noActivation attribute contains {} should be 0 or 1".format(no_act))
+        else:
+            Exception("CustomOp {} is not supported".format(node.op_type))
     
 
 
diff --git a/tests/test_verify_custom_ops.py b/tests/test_verify_custom_ops.py
index 5d49303b0..c05278b1d 100644
--- a/tests/test_verify_custom_ops.py
+++ b/tests/test_verify_custom_ops.py
@@ -1,8 +1,9 @@
-import onnx
+from onnx import helper
 from finn.custom_op.verify_custom_op_construct import CustomOp_Construct
 
 def test_verify_layout_custom_ops():
-    m_node = onnx.helper.make_node(
+    # MultiThreshold
+    m_node = helper.make_node(
         "MultiThreshold",
         ["v", "thresholds"],
         ["out"],
@@ -13,5 +14,61 @@ def test_verify_layout_custom_ops():
     ) 
 
     inst = CustomOp_Construct[m_node.op_type] 
-    inst.verify_layout(m_node) 
+    inst.verify_construct(m_node) 
+
+    # XnorPopcountMatMul
+    xnor_node = helper.make_node(
+        "XnorPopcountMatMul", ["x", "W"], ["out"], domain="finn"
+    )
+
+    inst = CustomOp_Construct[xnor_node.op_type]
+    inst.verify_construct(xnor_node)
+
+    # StreamingFCLayer_Batch - no activation
+    FCLayer_node = helper.make_node(
+        "StreamingFCLayer_Batch",
+        ["in", "weights"],
+        ["out"],
+        domain="finn",
+        backend="fpgadataflow",
+        code_gen_dir="",
+        executable_path="",
+        resType="ap_resource_lut()",
+        MW=8,
+        MH=8,
+        SIMD=4,
+        PE=4,
+        inputDataType="<FINN DataType>",
+        weightDataType="<FINN DataType>",
+        outputDataType="<FINN DataType>",
+        ActVal=0,
+        binaryXnorMode=1,
+        noActivation=1
+    
+    inst = CustomOp_Construct[FCLayer_node.op_type]
+    inst.verify_construct(FCLayer_node)
+
+    # StreamingFCLayer_Batch - with activation
+    FCLayer_node = helper.make_node(
+        "StreamingFCLayer_Batch",
+        ["in", "weights", "threshs"],
+        ["out"],
+        domain="finn",
+        backend="fpgadataflow",
+        code_gen_dir="",
+        executable_path="",
+        resType="ap_resource_lut()",
+        MW=8,
+        MH=8,
+        SIMD=4,
+        PE=4,
+        inputDataType="<FINN DataType>",
+        weightDataType="<FINN DataType>",
+        outputDataType="<FINN DataType>",
+        ActVal=0,
+        binaryXnorMode=1,
+        noActivation=0
+    )
+    inst = CustomOp_Construct[FCLayer_node.op_type]
+    inst.verify_construct(FCLayer_node)
 
-- 
GitLab