diff --git a/hpvm/projects/onnx/frontend/graph_builder.py b/hpvm/projects/onnx/frontend/graph_builder.py index fd9a6ee9e1b4820f0c09b0c8faa64e0fef1760d4..7ffe32c53812b55d48eec4db6d6c14980a06dfbb 100644 --- a/hpvm/projects/onnx/frontend/graph_builder.py +++ b/hpvm/projects/onnx/frontend/graph_builder.py @@ -153,7 +153,7 @@ class GraphBuilder(object): for tensor in self.tensors.values(): if isinstance(tensor, WeightTensor): print("Dump weight: {0}".format(weight_tensor.name)) - tensor.dump_weight(self.weight_dir + "/" + tensor.get_mapped_name() + "_path.bin") + #tensor.dump_weight(self.weight_dir + "/" + tensor.get_mapped_name() + "_path.bin") return DFG(self.graph, self.tensors) class DFG(object): diff --git a/hpvm/projects/onnx/frontend/graph_codegen.py b/hpvm/projects/onnx/frontend/graph_codegen.py index cdd2425054fead1ac29b8d6961075d48f90f5591..f985ae810f9efa4744fa68760a4f0b490c7f55f0 100644 --- a/hpvm/projects/onnx/frontend/graph_codegen.py +++ b/hpvm/projects/onnx/frontend/graph_codegen.py @@ -138,7 +138,7 @@ class GraphCodeGen(object): return inst_str ################################################ - # Emit functions for code generation + # CodeGen functions ################################################ def emit_weights(self): @@ -215,7 +215,7 @@ class GraphCodeGen(object): self.program_str += end_main def emit_batch_loop(self, x_test=None): - # FIXME: Dimensions from test data + # FIXME: Dimensions from test data not available in ONNX N = 1#x_test.shape[0] C = 1#x_test.shape[1] H = 1#x_test.shape[2] diff --git a/hpvm/projects/onnx/frontend/graph_ir.py b/hpvm/projects/onnx/frontend/graph_ir.py index c25b1df4a5f2c7f3950d3484043389e98fda8cc9..2cfed0c78fc6cc8065fabf3e9f1427656d58c352 100644 --- a/hpvm/projects/onnx/frontend/graph_ir.py +++ b/hpvm/projects/onnx/frontend/graph_ir.py @@ -11,7 +11,10 @@ class DFGNode(object): self.inst_str = "" def codegen(self, tensors): - pass + return self.inst_str + + def hpvm_codegen(self, tensors): + return self.inst_str ''' @@ -20,8 +23,6 @@ e.g. HardSigmoid, LeakyRelu, PRelu, Pow, Reciprocal, Relu, Selu, Sigmoid, Softplus, Sqrt, ThresholdedRelu, Abs, Ceil, Elu, Floor, Neg ''' - - class ActivationNode(DFGNode): pass @@ -32,8 +33,6 @@ In other words, they are logical comparison operators e.g. And, Equal, Greater, GreaterOrEqual, Less, LessOrEqual, Or, Xor ''' - - class LogicalOpNode(DFGNode): pass @@ -222,45 +221,22 @@ class PadNode(DFGNode): def __init__(self, layer): DFGNode.__init__(self, layer) - def codegen(self, tensors): - return self.inst_str - - class IdentityNode(DFGNode): def __init__(self, layer): DFGNode.__init__(self, layer) - def codegen(self, tensors): - return self.inst_str - - class FlattenNode(DFGNode): def __init__(self, layer): DFGNode.__init__(self, layer) - def codegen(self, tensors): - return self.inst_str - - class ZeroPadding2DNode(DFGNode): def __init__(self, layer): DFGNode.__init__(self, layer) - def codegen(self, tensors): - return self.inst_str - - class DepthwiseConv2DNode(DFGNode): def __init__(self, layer): DFGNode.__init__(self, layer) - def codegen(self, tensors): - return self.inst_str - - class DenseNode(DFGNode): def __init__(self, layer): DFGNode.__init__(self, layer) - - def codegen(self, tensors): - return self.inst_str diff --git a/hpvm/projects/onnx/frontend/hpvm_codegen.py b/hpvm/projects/onnx/frontend/hpvm_codegen.py index f28abd5fc2479d48a73b1bdea9069e76791b3c7b..48cfaec36be5bb19b2216be85f5f51fe4c10e969 100644 --- a/hpvm/projects/onnx/frontend/hpvm_codegen.py +++ b/hpvm/projects/onnx/frontend/hpvm_codegen.py @@ -1,3 +1,7 @@ +from tensor import WeightTensor + +skip_layer = ["Identity", "Flatten", "Pad"] + class HpvmCodeGen: def __init__(self, DFG, weights_dir, test_data=None, test_labels=None): self.program_str = "" @@ -8,8 +12,25 @@ class HpvmCodeGen: self.weights_dir = weights_dir self.test_data = test_data self.test_labels = test_labels - self.filter_names = {} # essentially tensors + self.filter_names = dict() # essentially tensors + for tensor in self.tensors.values(): + if isinstance(tensor, WeightTensor): + self.filter_names[tensor.get_mapped_name()] = 1 + print(self.filter_names) + + ################################################ + # Aux functions + ################################################ + def get_last_var(self): + return "var_" + str(self.var_cnt) + + def get_new_var(self): + self.var_cnt = self.var_cnt + 1 + return "var_" + str(self.var_cnt) + ################################################ + # CodeGen functions + ################################################ def emit_header(self): headers = "\n#include <stdio.h> \n" headers += "#include <stdlib.h> \n" @@ -22,61 +43,70 @@ class HpvmCodeGen: headers += "#include <tensorUtils.h> \n\n" self.program_str += headers - def emit_root(self): - def emitRootNodeHeader(): - root_signature = "void root(" - index = 0 - for f_name in self.filter_names: - if index > 0: - root_signature += "\t " - self.filter_names[f_name] = index - root_signature += "void* " + f_name + ", " - root_signature += "size_t " + f_name + "_bytes" - if index < len(self.filter_names) - 1: - root_signature += ", \n" + def emit_root_node_header(self): + root_signature = "void root(" + index = 0 + for f_name in self.filter_names: + if index > 0: + root_signature += "\t " + self.filter_names[f_name] = index + root_signature += "void* " + f_name + ", " + root_signature += "size_t " + f_name + "_bytes" + if index < len(self.filter_names) - 1: + root_signature += ", \n" + index += 1 + root_signature += "){ \n\n" + root_signature += "\n __visc__hint(visc::CPU_TARGET); \n" + root_signature += " __visc__attributes(" + \ + str(len(self.filter_names)) + ", " + index = 0 + for f_name in self.filter_names: + root_signature += f_name + if index < len(self.filter_names) - 1: + root_signature += ", " index += 1 - root_signature += "){ \n\n" - root_signature += "\n __visc__hint(visc::CPU_TARGET); \n" - root_signature += " __visc__attributes(" + \ - str(len(self.filter_names)) + ", " - index = 0 - for f_name in self.filter_names: - root_signature += f_name - if index < len(self.filter_names) - 1: - root_signature += ", " - index += 1 - root_signature += ", 0); \n\n" - return root_signature + root_signature += ", 0); \n\n" + self.program_str += root_signature - def emitRootNodeFooter(self): - last_node = self.dfg.last_node - output_var = self.output_map[last_node.layer_name] - # Binding output of last DFG node to the Root Node output - root_footer_str = "\n __visc__bindOut(" + \ - output_var + ", 0, 0, 0); \n" - root_footer_str += " __visc__bindOut(" + \ - output_var + ", 1, 1, 0); \n" - root_footer_str += "\n}\n\n" - return root_footer_str + def emit_root_structure(self): + root_struct = "" + root_struct += "struct ret_t {\n" + root_struct += " void* tensor; \n" + root_struct += " size_t bytes; \n" + root_struct += "}; \n\n" + root_struct += "typedef struct __attribute__((__packed__)) {\n" + for f_name in self.filter_names: + root_struct += " void* " + f_name + "; \n" + root_struct += " size_t " + f_name + "_bytes; \n" + root_struct += "\n struct ret_t r; \n" + root_struct += "}\nRootIn;\n\n" + self.program_str += root_struct - def emitRootStructure(self): - root_struct = "" - root_struct += "struct ret_t {\n" - root_struct += " void* tensor; \n" - root_struct += " size_t bytes; \n" - root_struct += "}; \n\n" - root_struct += "typedef struct __attribute__((__packed__)) {\n" - for f_name in self.filter_names: - root_struct += " void* " + f_name + "; \n" - root_struct += " size_t " + f_name + "_bytes; \n" - root_struct += "\n struct ret_t r; \n" - root_struct += "}\nRootIn;\n\n" - return root_struct + def emit_hpvm_graph(self): + for node in self.nodes: + # check if all inputs of this node is mapped + cur_node = node.onnx_node + for i in cur_node.input: + self.tensors[i].get_mapped_name() + # set var name for output node + if len(cur_node.output) > 1: + raise ValueError("Output number for a single layer larger than 1!") + if cur_node.op_type in skip_layer: + mapped_output_name = self.get_last_var() + else: + mapped_output_name = self.get_new_var() + self.tensors[cur_node.output[0]].set_mapped_name(mapped_output_name) + self.program_str += node.hpvm_codegen(self.tensors) - self.program_str += emitRootNodeHeader() - self.program_str += emitRootStructure() - # self.codegen(self.dfg) - self.program_str += emitRootNodeFooter() + def emit_root_node_footer(self): + mapped_output_var = self.tensors[self.graph.output[0].name].get_mapped_name() + # Binding output of last DFG node to the Root Node output + root_footer_str = "\n __visc__bindOut(" + \ + mapped_output_var + ", 0, 0, 0); \n" + root_footer_str += " __visc__bindOut(" + \ + mapped_output_var + ", 1, 1, 0); \n" + root_footer_str += "\n}\n\n" + self.program_str += root_footer_str def emit_main(self, test_data): main_func_str = "int main(){ \n\n" @@ -99,13 +129,16 @@ class HpvmCodeGen: def emit_source(self, dir_prefix): print(self.program_str) - f = open(dir_prefix + "/approxhpvm_src.cc", "w+") + f = open(dir_prefix + "/hpvm_src.cc", "w+") f.write(self.program_str) f.close() def compile(self): self.emit_header() - # self.emitRoot() + self.emit_root_node_header() + self.emit_root_structure() + self.emit_hpvm_graph() + self.emit_root_node_footer() self.emit_main(self.test_data) # dump generated program string to source file self.emit_source(self.weights_dir) diff --git a/hpvm/projects/onnx/frontend/main.py b/hpvm/projects/onnx/frontend/main.py index 3a9344015b7082fd8e59f92fc6e4faf0e80a0b04..258e1d23a572902becc76982da305feff6e2c44b 100644 --- a/hpvm/projects/onnx/frontend/main.py +++ b/hpvm/projects/onnx/frontend/main.py @@ -7,6 +7,7 @@ import glob onnx_file_dir = "../models/keras/lenet.onnx" src_emit_dir = "./test_src" +opset_version_default = 11 def check_version(model, new_version): try: @@ -35,15 +36,17 @@ def compile(model): # TODO: make this in constant # make a cmd option, default value -> constant weights_dir = src_emit_dir - opset_version_default = 11 # test_data_dir = '../models/mnist/test_data_set_0' # converted_model = convert_version(model) # model = check_version(model, 11) from graph_builder import GraphBuilder from graph_codegen import GraphCodeGen + from hpvm_codegen import HpvmCodeGen gBuilder = GraphBuilder(model, None, "float32", weights_dir) - gCodegen = GraphCodeGen(gBuilder.build_graph(), weights_dir) - gCodegen.compile() + #gCodegen = GraphCodeGen(gBuilder.build_graph(), weights_dir) + hCodegen = HpvmCodeGen(gBuilder.build_graph(), weights_dir) + #gCodegen.compile() + hCodegen.compile() def main(): # TODO: Put it in args