diff --git a/hpvm/projects/onnx/frontend/config.py b/hpvm/projects/onnx/frontend/config.py index 8f42dafa4ee5591f095f410f1bfb390c6e12ace4..8eac060c2838aca3820a83c05bf7633d6ecb9146 100644 --- a/hpvm/projects/onnx/frontend/config.py +++ b/hpvm/projects/onnx/frontend/config.py @@ -1,4 +1,4 @@ -model_name = "alexnet" +model_name = "lenet" compile_type = 1 # 0 for HPVM Tensor Runtime, 1 for HPVM C Interface input_size = [1,2,3,4] onnx_file_dir = "../models/keras/lenet.onnx" diff --git a/hpvm/projects/onnx/frontend/graph_builder.py b/hpvm/projects/onnx/frontend/graph_builder.py index 737eb1d3e178267a76bbccdf13f29c9739007453..fb5d97f4ac03b830d057bbd636a2f9e23263a4fd 100644 --- a/hpvm/projects/onnx/frontend/graph_builder.py +++ b/hpvm/projects/onnx/frontend/graph_builder.py @@ -153,33 +153,36 @@ class DFG(object): def build_dfg(self): print("\n\n ****** Traversing and Printing DFG ******* \n\n") for node in self.graph.node: - self.nodes.append(self.emit_node(node)) + self.nodes.extend(self.emit_node(node)) # This should be the place where partial evaluation happens def emit_node(self, onnx_node): if onnx_node.op_type == "Conv": - return Conv2DNode(onnx_node) + if len(onnx_node.input) == 2: + return [Conv2DNode(onnx_node)] + else: + return [Conv2DNode(onnx_node), BiasAddNode(onnx_node)] elif onnx_node.op_type == "MaxPool": - return MaxPool2DNode(onnx_node) + return [MaxPool2DNode(onnx_node)] elif onnx_node.op_type == "AveragePool": - return AveragePool2DNode(onnx_node) + return [AveragePool2DNode(onnx_node)] elif onnx_node.op_type == "MatMul": - return MatMulNode(onnx_node) + return [MatMulNode(onnx_node)] elif onnx_node.op_type == "Add": - return AddNode(onnx_node) + return [AddNode(onnx_node)] elif onnx_node.op_type == "Softmax": - return SoftMaxNode(onnx_node) + return [SoftMaxNode(onnx_node)] elif onnx_node.op_type == "Relu": - return ReluNode(onnx_node) + return [ReluNode(onnx_node)] elif onnx_node.op_type == "Tanh": - return TanhNode(onnx_node) + return [TanhNode(onnx_node)] elif onnx_node.op_type == "BatchNormalization": - return BatchNormalizationNode(onnx_node) + return [BatchNormalizationNode(onnx_node)] elif onnx_node.op_type == "Pad": - return PadNode(onnx_node) + return [PadNode(onnx_node)] elif onnx_node.op_type == "Identity": - return IdentityNode(onnx_node) + return [IdentityNode(onnx_node)] elif onnx_node.op_type == "Flatten": - return FlattenNode(onnx_node) + return [FlattenNode(onnx_node)] else: raise ValueError("Unsupported operator type: {}!".format(onnx_node.op_type)) diff --git a/hpvm/projects/onnx/frontend/graph_codegen.py b/hpvm/projects/onnx/frontend/graph_codegen.py index df02685386817133a8dba3012132b99b5636238b..a9db0ad92b40e541afcc9b71d13cb0da233b2c9e 100644 --- a/hpvm/projects/onnx/frontend/graph_codegen.py +++ b/hpvm/projects/onnx/frontend/graph_codegen.py @@ -11,7 +11,7 @@ class GraphCodeGen(object): self.graph = dfg.graph self.tensors = dfg.tensors self.nodes = dfg.nodes - self.var_cnt = 0 + self.var_cnt = -1 self.weights_dir = weights_dir self.test_data_shape = test_data_shape @@ -56,17 +56,16 @@ class GraphCodeGen(object): def emit_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: + for i in node.input: self.tensors[i].get_mapped_name() # set var name for output node - if len(cur_node.output) > 1: + if len(node.output) > 1: raise ValueError("Output number for a single layer larger than 1!") - if cur_node.op_type in skip_layer: + if node.op_type in skip_layer or node.op_type == "BiasAdd": 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.tensors[node.output[0]].set_mapped_name(mapped_output_name) self.program_str += node.codegen(self.tensors) def emit_header(self): diff --git a/hpvm/projects/onnx/frontend/graph_ir.py b/hpvm/projects/onnx/frontend/graph_ir.py index b14de79439b3a7f6c28cf8a88594af94dc773fe7..a221baf34fb1b9ad9a579ec68018c556918f193b 100644 --- a/hpvm/projects/onnx/frontend/graph_ir.py +++ b/hpvm/projects/onnx/frontend/graph_ir.py @@ -8,13 +8,14 @@ class DFGNode(object): self.onnx_node = onnx_node self.name = onnx_node.name self.op_type = onnx_node.op_type - self.inst_str = "" + self.input = onnx_node.input + self.output = onnx_node.output def codegen(self, tensors): - return self.inst_str + return "Not Implemented." def hpvm_codegen(self, tensors): - return self.inst_str + return "Not Implemented." ''' @@ -44,30 +45,49 @@ class LogicalOpNode(DFGNode): class AddNode(DFGNode): def codegen(self, tensors): - cur_node = self.onnx_node - left_input = tensors[cur_node.input[0]].get_mapped_name() - right_input = tensors[cur_node.input[1]].get_mapped_name() - mapped_output_name = tensors[cur_node.output[0]].get_mapped_name() - self.inst_str += "void* " + mapped_output_name + " = " - self.inst_str += "tensorAdd(" + left_input + ", " + right_input + "); \n" - return self.inst_str + inst_str = "" + left_input = tensors[self.input[0]].get_mapped_name() + right_input = tensors[self.input[1]].get_mapped_name() + mapped_output_name = tensors[self.output[0]].get_mapped_name() + inst_str += "void* " + mapped_output_name + " = " + inst_str += "tensorAdd(" + left_input + ", " + right_input + "); \n" + return inst_str def hpvm_codegen(self, tensors): return " void *r = __visc__tensor_add(t1, t2); \n" +class BiasAddNode(DFGNode): + + def __init__(self, onnx_conv_node): + super().__init__(onnx_conv_node) + self.op_type = "BiasAdd" + self.input = list() + self.input.append(self.output[0]) + self.input.append(onnx_conv_node.input[2]) + + def codegen(self, tensors): + inst_str = "" + left_input = tensors[self.input[0]].get_mapped_name() + right_input = tensors[self.input[1]].get_mapped_name() + mapped_output_name = tensors[self.output[0]].get_mapped_name() + inst_str += mapped_output_name + " = " + inst_str += "tensorAdd(" + left_input + ", " + right_input + "); \n" + return inst_str + def hpvm_codegen(self, tensors): + return " void *r = __visc__tensor_add(t1, t2); \n" class MatMulNode(DFGNode): def codegen(self, tensors): - cur_node = self.onnx_node - left_input = tensors[cur_node.input[0]].get_mapped_name() - right_input = tensors[cur_node.input[1]].get_mapped_name() - mapped_output_name = tensors[cur_node.output[0]].get_mapped_name() - self.inst_str += "void* " + mapped_output_name + " = " - self.inst_str += "tensorGemmGPU(" + left_input + \ + inst_str = "" + left_input = tensors[self.input[0]].get_mapped_name() + right_input = tensors[self.input[1]].get_mapped_name() + mapped_output_name = tensors[self.output[0]].get_mapped_name() + inst_str += "void* " + mapped_output_name + " = " + inst_str += "tensorGemmGPU(" + left_input + \ ", " + right_input + "); \n" - return self.inst_str + return inst_str def hpvm_codegen(self, tensors): return " void *r = __visc__tensor_mul(t1, t2); \n" @@ -76,12 +96,12 @@ class MatMulNode(DFGNode): class SoftMaxNode(DFGNode): def codegen(self, tensors): - cur_node = self.onnx_node - mapped_input_name = tensors[cur_node.input[0]].get_mapped_name() - mapped_output_name = tensors[cur_node.output[0]].get_mapped_name() - self.inst_str += "void* " + mapped_output_name + " = " - self.inst_str += "tensorSoftmax(" + mapped_input_name + "); \n" - return self.inst_str + inst_str = "" + mapped_input_name = tensors[self.input[0]].get_mapped_name() + mapped_output_name = tensors[self.output[0]].get_mapped_name() + inst_str += "void* " + mapped_output_name + " = " + inst_str += "tensorSoftmax(" + mapped_input_name + "); \n" + return inst_str def hpvm_codegen(self, tensors): return " void* r = __visc__tensor_softmax(t1); \n" @@ -89,159 +109,128 @@ class SoftMaxNode(DFGNode): class Conv2DNode(DFGNode): - def codegen(self, tensors): - cur_node = self.onnx_node - mapped_input_name = tensors[cur_node.input[0]].get_mapped_name() - mapped_output_name = tensors[cur_node.output[0]].get_mapped_name() - weight = cur_node.input[1] - strides = list() - padding = 0 - for attr in cur_node.attribute: + def __init__(self, onnx_node): + super().__init__(onnx_node) + if len(self.input) == 3: + tmp_input = list() + for i in self.input: + tmp_input.append(i) + self.input = tmp_input + self.input.pop() # remove the last index for bias add + self.padding = 0 + self.strides = list() + for attr in onnx_node.attribute: if attr.name == "pads": - padding = attr.ints[0] + self.padding = attr.ints[0] elif attr.name == "strides": for stride in attr.ints: - strides.append(stride) - - self.inst_str += "void* " + mapped_output_name + " = " - self.inst_str += "tensorConvolution(" + mapped_input_name + ", " - self.inst_str += tensors[cur_node.input[1]].get_mapped_name() + ", " - self.inst_str += str(padding) + ", " - self.inst_str += str(padding) + ", " - self.inst_str += str(strides[0]) + ", " - self.inst_str += str(strides[1]) + ", " - self.inst_str += "1, 1); \n" - - # check if has bias add (Optional) - # in ONNX it is only in Conv - # in Keras bias add could exist in Dense - if len(cur_node.input) == 3: - self.inst_str += mapped_output_name + " = " - self.inst_str += "tensorAdd(" + mapped_output_name + ", " - self.inst_str += tensors[cur_node.input[2]].get_mapped_name() + "" - self.inst_str += "); \n" - return self.inst_str + self.strides.append(stride) + + def codegen(self, tensors): + inst_str = "" + mapped_input_name = tensors[self.input[0]].get_mapped_name() + mapped_output_name = tensors[self.output[0]].get_mapped_name() + + inst_str += "void* " + mapped_output_name + " = " + inst_str += "tensorConvolution(" + mapped_input_name + ", " + inst_str += tensors[self.input[1]].get_mapped_name() + ", " + inst_str += str(self.padding) + ", " + inst_str += str(self.padding) + ", " + inst_str += str(self.strides[0]) + ", " + inst_str += str(self.strides[1]) + ", " + inst_str += "1, 1); \n" + return inst_str def hpvm_codegen(self, tensors): - strides = list() - padding = 0 - cur_node = self.onnx_node - for attr in cur_node.attribute: - if attr.name == "pads": - padding = attr.ints[0] - elif attr.name == "strides": - for stride in attr.ints: - strides.append(stride) inst_str = " void *r = __visc__tensor_convolution(t1, t2, " - inst_str += str(padding) + ", " - inst_str += str(padding) + ", " - inst_str += str(strides[0]) + ", " - inst_str += str(strides[1]) + inst_str += str(self.padding) + ", " + inst_str += str(self.padding) + ", " + inst_str += str(self.strides[0]) + ", " + inst_str += str(self.strides[1]) inst_str += "); \n" return inst_str class MaxPool2DNode(DFGNode): - def codegen(self, tensors): - cur_node = self.onnx_node - mapped_input_name = tensors[cur_node.input[0]].get_mapped_name() - mapped_output_name = tensors[cur_node.output[0]].get_mapped_name() - strides = list() - pool_size = list() - for attr in cur_node.attribute: + def __init__(self, onnx_node): + super().__init__(onnx_node) + self.strides = list() + self.pool_size = list() + self.padding = 0 + self.pool_type = "0" + for attr in onnx_node.attribute: if attr.name == "kernel_shape": for pool in attr.ints: - pool_size.append(pool) + self.pool_size.append(pool) elif attr.name == "strides": for stride in attr.ints: - strides.append(stride) - # FIXME: Non-same padding is *NOT* currently supported - padding = 0 - pool_type = "0" + self.strides.append(stride) + + + def codegen(self, tensors): + mapped_input_name = tensors[self.input[0]].get_mapped_name() + mapped_output_name = tensors[self.output[0]].get_mapped_name() # tensorPooling(input, pool_type, pool_h, pool_w, v_pad, h_pad, v_stride, h_stride) - self.inst_str += "void* " + mapped_output_name + " = " - self.inst_str += "tensorPooling(" + mapped_input_name + "," + \ - pool_type + "," + str(pool_size[0]) + "," + str(pool_size[1]) - self.inst_str += "," + str(padding) + "," + str(padding) + \ - "," + str(strides[0]) + "," + str(strides[1]) - self.inst_str += "); \n" - return self.inst_str + inst_str = "void* " + mapped_output_name + " = " + inst_str += "tensorPooling(" + mapped_input_name + "," + \ + self.pool_type + "," + str(self.pool_size[0]) + "," + str(self.pool_size[1]) + inst_str += "," + str(self.padding) + "," + str(self.padding) + \ + "," + str(self.strides[0]) + "," + str(self.strides[1]) + inst_str += "); \n" + return inst_str def hpvm_codegen(self, tensors): - cur_node = self.onnx_node - padding = 0 - strides = list() - pool_size = list() - for attr in cur_node.attribute: - if attr.name == "kernel_shape": - for pool in attr.ints: - pool_size.append(pool) - elif attr.name == "strides": - for stride in attr.ints: - strides.append(stride) inst_str = " void* r = __visc__tensor_pool_max(t1, " - inst_str += str(pool_size[0]) + ", " + str(pool_size[1]) + ", " - inst_str += str(padding) + ", " + str(padding) + ", " - inst_str += str(strides[0]) + ", " + str(strides[1]) + "); \n" + inst_str += str(self.pool_size[0]) + ", " + str(self.pool_size[1]) + ", " + inst_str += str(self.padding) + ", " + str(self.padding) + ", " + inst_str += str(self.strides[0]) + ", " + str(self.strides[1]) + "); \n" return inst_str class AveragePool2DNode(DFGNode): - def codegen(self, tensors): - cur_node = self.onnx_node - mapped_input_name = tensors[cur_node.input[0]].get_mapped_name() - mapped_output_name = tensors[cur_node.output[0]].get_mapped_name() - strides = list() - pool_size = list() - for attr in cur_node.attribute: + def __init__(self, onnx_node): + super().__init__(onnx_node) + self.strides = list() + self.pool_size = list() + self.padding = 0 + self.pool_type = "1" + for attr in onnx_node.attribute: if attr.name == "kernel_shape": for pool in attr.ints: - pool_size.append(pool) + self.pool_size.append(pool) elif attr.name == "strides": for stride in attr.ints: - strides.append(stride) - # FIXME: Non-same padding is *NOT* currently supported - padding = 0 - pool_type = "1" - # tensorPooling(input, pool_type, pool_h, pool_w, v_pad, h_pad, v_stride, h_stride) - self.inst_str += "void* " + mapped_output_name + " = " - self.inst_str += "tensorPooling(" + mapped_input_name + "," + \ - pool_type + "," + str(pool_size[0]) + "," + str(pool_size[1]) - self.inst_str += "," + str(padding) + "," + str(padding) + \ - "," + str(strides[0]) + "," + str(strides[1]) - self.inst_str += "); \n" - return self.inst_str + self.strides.append(stride) + + def codegen(self, tensors): + mapped_input_name = tensors[self.input[0]].get_mapped_name() + mapped_output_name = tensors[self.output[0]].get_mapped_name() + inst_str = "void* " + mapped_output_name + " = " + inst_str += "tensorPooling(" + mapped_input_name + "," + \ + self.pool_type + "," + str(self.pool_size[0]) + "," + str(self.pool_size[1]) + inst_str += "," + str(self.padding) + "," + str(self.padding) + \ + "," + str(self.strides[0]) + "," + str(self.strides[1]) + inst_str += "); \n" + return inst_str def hpvm_codegen(self, tensors): - cur_node = self.onnx_node - padding = 0 - strides = list() - pool_size = list() - for attr in cur_node.attribute: - if attr.name == "kernel_shape": - for pool in attr.ints: - pool_size.append(pool) - elif attr.name == "strides": - for stride in attr.ints: - strides.append(stride) inst_str = " void* r = __visc__tensor_pool_avg(t1, " - inst_str += str(pool_size[0]) + ", " + str(pool_size[1]) + ", " - inst_str += str(padding) + ", " + str(padding) + ", " - inst_str += str(strides[0]) + ", " + str(strides[1]) + "); \n" + inst_str += str(self.pool_size[0]) + ", " + str(self.pool_size[1]) + ", " + inst_str += str(self.padding) + ", " + str(self.padding) + ", " + inst_str += str(self.strides[0]) + ", " + str(self.strides[1]) + "); \n" return inst_str class ReluNode(DFGNode): def codegen(self, tensors): - cur_node = self.onnx_node - mapped_input_name = tensors[cur_node.input[0]].get_mapped_name() - mapped_output_name = tensors[cur_node.output[0]].get_mapped_name() - self.inst_str += "void* " + mapped_output_name + " = " - self.inst_str += "tensorRelu(" + mapped_input_name + "); \n" - return self.inst_str + mapped_input_name = tensors[self.input[0]].get_mapped_name() + mapped_output_name = tensors[self.output[0]].get_mapped_name() + inst_str = "void* " + mapped_output_name + " = " + inst_str += "tensorRelu(" + mapped_input_name + "); \n" + return inst_str def hpvm_codegen(self, tensors): return " void* r = __visc__tensor_relu(t1); \n" @@ -249,12 +238,11 @@ class ReluNode(DFGNode): class TanhNode(DFGNode): def codegen(self, tensors): - cur_node = self.onnx_node - mapped_input_name = tensors[cur_node.input[0]].get_mapped_name() - mapped_output_name = tensors[cur_node.output[0]].get_mapped_name() - self.inst_str += "void* " + mapped_output_name + " = " - self.inst_str += "tensorTanh(" + mapped_input_name + "); \n" - return self.inst_str + mapped_input_name = tensors[self.input[0]].get_mapped_name() + mapped_output_name = tensors[self.output[0]].get_mapped_name() + inst_str = "void* " + mapped_output_name + " = " + inst_str += "tensorTanh(" + mapped_input_name + "); \n" + return inst_str def hpvm_codegen(self, tensors): return " void* r = __visc__tensor_tanh(t1); \n" @@ -262,43 +250,52 @@ class TanhNode(DFGNode): class BatchNormalizationNode(DFGNode): - def codegen(self, tensors): - cur_node = self.onnx_node - mapped_input_name = tensors[cur_node.input[0]].get_mapped_name() - mapped_output_name = tensors[cur_node.output[0]].get_mapped_name() - epsilon = "" - for attr in cur_node.attribute: + def __init__(self, onnx_node): + super().__init__(onnx_node) + self.epsilon = "" + for attr in onnx_node.attribute: if attr.name == "epsilon": - epsilon = str(attr.f) - self.inst_str += "void* " + mapped_output_name + " = " - self.inst_str += "tensorBatchNorm(" + mapped_input_name + ", " - self.inst_str += tensors[cur_node.input[1]].get_mapped_name() + ", " - self.inst_str += tensors[cur_node.input[2]].get_mapped_name() + ", " - self.inst_str += tensors[cur_node.input[3]].get_mapped_name() + ", " - self.inst_str += tensors[cur_node.input[4]].get_mapped_name() + ", " - self.inst_str += str(epsilon) - self.inst_str += "); \n" - return self.inst_str + self.epsilon = str(attr.f) + + def codegen(self, tensors): + mapped_input_name = tensors[self.input[0]].get_mapped_name() + mapped_output_name = tensors[self.output[0]].get_mapped_name() + inst_str = "void* " + mapped_output_name + " = " + inst_str += "tensorBatchNorm(" + mapped_input_name + ", " + inst_str += tensors[self.input[1]].get_mapped_name() + ", " + inst_str += tensors[self.input[2]].get_mapped_name() + ", " + inst_str += tensors[self.input[3]].get_mapped_name() + ", " + inst_str += tensors[self.input[4]].get_mapped_name() + ", " + inst_str += str(self.epsilon) + inst_str += "); \n" + return inst_str def hpvm_codegen(self, tensors): - epsilon = "" - cur_node = self.onnx_node - for attr in cur_node.attribute: - if attr.name == "epsilon": - epsilon = str(attr.f) inst_str = " void *r = __visc__tensor_batchnorm(t1, t2, t3, t4, t5, " - inst_str += str(epsilon) + "); \n" + inst_str += str(self.epsilon) + "); \n" return inst_str class PadNode(DFGNode): - pass + def codegen(self, tensors): + return "" + + def hpvm_codegen(self, tensors): + return "" class IdentityNode(DFGNode): - pass + def codegen(self, tensors): + return "" + + def hpvm_codegen(self, tensors): + return "" class FlattenNode(DFGNode): - pass + def codegen(self, tensors): + return "" + + def hpvm_codegen(self, tensors): + return "" class ZeroPadding2DNode(DFGNode): pass diff --git a/hpvm/projects/onnx/frontend/hpvm_codegen.py b/hpvm/projects/onnx/frontend/hpvm_codegen.py index 3d14d97b09fc8b45bc80a2d3ea7acd1baf58cc67..e12c7c99ea06e76741023082e063293ad35c8fbd 100644 --- a/hpvm/projects/onnx/frontend/hpvm_codegen.py +++ b/hpvm/projects/onnx/frontend/hpvm_codegen.py @@ -7,17 +7,20 @@ class HpvmCodeGen: self.graph = DFG.graph self.tensors = DFG.tensors self.nodes = DFG.nodes - self.var_cnt = 0 + self.var_cnt = -1 self.weights_dir = weights_dir self.test_data_shape = test_data_shape # filter_names is essentially weight & 1st input tensor(s) # TODO: Replace manually adding input to filter_names - self.filter_names = dict() - self.filter_names["input"] = 1 + self.hpvm_graph_str = "" + self.filter_names = dict() + self.hpvm_node_names = dict() + for i in self.graph.input: + self.filter_names[self.tensors[i.name].get_mapped_name()] = 1 for tensor in self.tensors.values(): if isinstance(tensor, WeightTensor): self.filter_names[tensor.get_mapped_name()] = 1 - + self.filter_names["input"] = 1 print(self.filter_names) ################################################ @@ -46,6 +49,7 @@ class HpvmCodeGen: self.program_str += headers def emit_hpvm_node_structures(self): + def emit_hpvm_node_header(new_var, input_size): node_header_str = "void " + new_var + "_node(" for i in range(input_size): @@ -83,23 +87,89 @@ class HpvmCodeGen: mapped_output_var + ", 1, 1, 0); \n" root_footer_str += "\n}\n\n" return root_footer_str + + def genHpvmNodeEdges(out_var_name, input_var_name, input_var_name2): + print ("input_var_name2 = ", input_var_name2) + print ("input_var_name = ", input_var_name) + + hpvm_edge_str = "\n void* " + out_var_name + " = " + hpvm_edge_str += "__visc__createNodeND(0, " + out_var_name + "_node); \n\n" + + if input_var_name in self.filter_names: + input_index = self.filter_names[input_var_name] + index1 = input_index * 2 + index2 = index1 + 1 + hpvm_edge_str += " __visc__bindIn(" + out_var_name + ", " + str(index1) + ", 0, 0); \n" + hpvm_edge_str += " __visc__bindIn(" + out_var_name + ", " + str(index2) + ", 1, 0); \n" + + elif input_var_name in self.hpvm_node_names: + hpvm_edge_str += " __visc__edge(" + input_var_name + ", " + out_var_name + ", 1, 0, 0, 0); \n" + hpvm_edge_str += " __visc__edge(" + input_var_name + ", " + out_var_name + ", 1, 1, 1, 0); \n" + + + if input_var_name2 in self.filter_names: + input_index = self.filter_names[input_var_name2] + index1 = input_index * 2 + index2 = index1 + 1 + hpvm_edge_str += " __visc__bindIn(" + out_var_name + ", " + str(index1) + ", 2, 0); \n" + hpvm_edge_str += " __visc__bindIn(" + out_var_name + ", " + str(index2) + ", 3, 0); \n" + + elif input_var_name2 in self.hpvm_node_names: + hpvm_edge_str += " __visc__edge(" + input_var_name2 + ", " + out_var_name + ", 1, 0, 2, 0); \n" + hpvm_edge_str += " __visc__edge(" + input_var_name2 + ", " + out_var_name + ", 1, 1, 3, 0); \n" + + return hpvm_edge_str + + def genHpvmNodeEdges2(out_var_name, input_vars): + + hpvm_edge_str = "\n void* " + hpvm_node_id + " = " + hpvm_edge_str += "__visc__createNodeND(0, " + hpvm_node_id + "_node); \n\n" + + it = 0 + for input_var_name in input_vars: + if input_var_name in self.filter_names: + input_index = self.filter_names[input_var_name] + index1 = input_index * 2 + index2 = index1 + 1 + hpvm_edge_str += " __visc__bindIn(" + hpvm_node_id + ", " + str(index1) + ", " + str(it*2) + ", 0); \n" + hpvm_edge_str += " __visc__bindIn(" + hpvm_node_id + ", " + str(index2) + ", " + str(it*2+1) + ", 0); \n" + + elif input_var_name in self.hpvm_node_names: + hpvm_edge_str += " __visc__edge(" + input_var_name + ", " + hpvm_node_id + ", 1, 0, " + str(it*2) + ", 0); \n" + hpvm_edge_str += " __visc__edge(" + input_var_name + ", " + hpvm_node_id + ", 1, 1, " + str(it*2+1) + ", 0); \n" + + it += 1 + + return hpvm_edge_str node_str = "" for node in self.nodes: - cur_node = node.onnx_node - if node.name in skip_layer: + if 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) - if node.name in skip_layer: + self.tensors[node.output[0]].set_mapped_name(mapped_output_name) + self.hpvm_node_names[mapped_output_name] = 1 + if node.op_type in skip_layer: continue - node_str += emit_hpvm_node_header(mapped_output_name, len(cur_node.input)) + node_str += emit_hpvm_node_header(mapped_output_name, len(node.input)) node_str += node.hpvm_codegen(self.tensors) node_str += emit_hpvm_node_footer(2) # Hardcoded as in Keras frontend - - node_str += emit_root_node_footer(self) + if node.op_type == "BatchNormalization": + out_var_name = self.tensors[node.output[0]].get_mapped_name() + input_vars = list() + for i in node.input: + input_vars.append(self.tensors[i].get_mapped_name()) + self.hpvm_graph_str += genHpvmNodeEdges2(out_var_name, input_vars) + else: + out_var_name = self.tensors[node.output[0]].get_mapped_name() + input_var_name = self.tensors[node.input[0]].get_mapped_name() + input_var_name2 = "" + if len(node.input) == 2: + input_var_name2 = self.tensors[node.input[1]].get_mapped_name() + self.hpvm_graph_str += genHpvmNodeEdges(out_var_name, input_var_name, input_var_name2) + self.hpvm_graph_str += emit_root_node_footer(self) self.program_str += node_str def emit_root_node_header(self): @@ -142,24 +212,7 @@ class HpvmCodeGen: self.program_str += root_struct def emit_hpvm_graph(self): - - def emit_hpvm_edge(node): - return "" - - hpvm_graph_str = "" - for node in self.nodes: - hpvm_graph_str += emit_hpvm_edge(node) - return hpvm_graph_str - - 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 + self.program_str += self.hpvm_graph_str def emit_weights(self): weights_str = "\n" @@ -216,9 +269,8 @@ class HpvmCodeGen: self.emit_header() self.emit_hpvm_node_structures() self.emit_root_node_header() - self.emit_root_structure() self.emit_hpvm_graph() - self.emit_root_node_footer() + self.emit_root_structure() self.emit_main() # dump generated program string to source file self.emit_source(self.weights_dir)