Skip to content
Snippets Groups Projects
Commit 31dc6c09 authored by shingjan's avatar shingjan
Browse files

add weights reading and hpvm node structures generation

parent f2fdb01d
No related branches found
No related tags found
No related merge requests found
model_name = "alexnet"
compile_type = 1 # 0 for HPVM Tensor Runtime, 1 for HPVM C Interface
input_size = [1,2,3,4]
onnx_file_dir = "../models/keras/alexnet.onnx"
onnx_file_dir = "../models/keras/lenet.onnx"
opset_version_default = 10
src_emit_dir = "./test_src"
......@@ -52,6 +52,10 @@ class AddNode(DFGNode):
self.inst_str += "tensorAdd(" + left_input + ", " + right_input + "); \n"
return self.inst_str
def hpvm_codegen(self, tensors):
return " void *r = __visc__tensor_add(t1, t2); \n"
class MatMulNode(DFGNode):
......@@ -65,6 +69,9 @@ class MatMulNode(DFGNode):
", " + right_input + "); \n"
return self.inst_str
def hpvm_codegen(self, tensors):
return " void *r = __visc__tensor_mul(t1, t2); \n"
class SoftMaxNode(DFGNode):
......@@ -76,6 +83,9 @@ class SoftMaxNode(DFGNode):
self.inst_str += "tensorSoftmax(" + mapped_input_name + "); \n"
return self.inst_str
def hpvm_codegen(self, tensors):
return " void* r = __visc__tensor_softmax(t1); \n"
class Conv2DNode(DFGNode):
......@@ -112,6 +122,24 @@ class Conv2DNode(DFGNode):
self.inst_str += "); \n"
return self.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 += "); \n"
return inst_str
class MaxPool2DNode(DFGNode):
......@@ -140,6 +168,24 @@ class MaxPool2DNode(DFGNode):
self.inst_str += "); \n"
return self.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"
return inst_str
class AveragePool2DNode(DFGNode):
......@@ -168,6 +214,24 @@ class AveragePool2DNode(DFGNode):
self.inst_str += "); \n"
return self.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"
return inst_str
class ReluNode(DFGNode):
......@@ -179,6 +243,9 @@ class ReluNode(DFGNode):
self.inst_str += "tensorRelu(" + mapped_input_name + "); \n"
return self.inst_str
def hpvm_codegen(self, tensors):
return " void* r = __visc__tensor_relu(t1); \n"
class TanhNode(DFGNode):
def codegen(self, tensors):
......@@ -189,6 +256,9 @@ class TanhNode(DFGNode):
self.inst_str += "tensorTanh(" + mapped_input_name + "); \n"
return self.inst_str
def hpvm_codegen(self, tensors):
return " void* r = __visc__tensor_tanh(t1); \n"
class BatchNormalizationNode(DFGNode):
......@@ -210,6 +280,16 @@ class BatchNormalizationNode(DFGNode):
self.inst_str += "); \n"
return self.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"
return inst_str
class PadNode(DFGNode):
pass
......
......@@ -10,10 +10,14 @@ class HpvmCodeGen:
self.var_cnt = 0
self.weights_dir = weights_dir
self.test_data_shape = test_data_shape
self.filter_names = dict() # essentially weight tensors
# 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
for tensor in self.tensors.values():
if isinstance(tensor, WeightTensor):
self.filter_names[tensor.get_mapped_name()] = 1
print(self.filter_names)
################################################
......@@ -41,6 +45,63 @@ class HpvmCodeGen:
headers += "#include <tensorUtils.h> \n\n"
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):
node_header_str += "void* t" + str(i + 1) + ", "
node_header_str += "size_t bytes_t" + str(i + 1)
if i < input_size - 1:
node_header_str += ", "
node_header_str += ") { \n"
node_header_str += " __visc__hint(visc::CUDNN_TARGET); \n"
node_header_str += " __visc__attributes(" + str(input_size) + ", "
for i in range(input_size):
node_header_str += "t" + str(i + 1)
if i < input_size - 1:
node_header_str += ", "
node_header_str += ", 0); \n\n"
return node_header_str
def emit_hpvm_node_footer(input_size):
node_footer_str = " __visc__return("
node_footer_str += str(input_size) + ", "
node_footer_str += "r, "
node_footer_str += "(size_t) 0); \n"
node_footer_str += "}\n\n"
return node_footer_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"
return root_footer_str
node_str = ""
for node in self.nodes:
cur_node = node.onnx_node
if node.name 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:
continue
node_str += emit_hpvm_node_header(mapped_output_name, len(cur_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)
self.program_str += node_str
def emit_root_node_header(self):
root_signature = "void root("
index = 0
......@@ -81,20 +142,14 @@ 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:
# 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)
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()
......@@ -106,9 +161,35 @@ class HpvmCodeGen:
root_footer_str += "\n}\n\n"
self.program_str += root_footer_str
def emit_main(self, test_data):
def emit_weights(self):
weights_str = "\n"
weights_str += "std::string dir_prefix = std::string(\"" + str(self.weights_dir) + "\");\n"
weights_str += "std::string input_path = dir_prefix + std::string(\"input.bin\");\n"
weights_str += "std::string labels_path = dir_prefix + std::string(\"labels.bin\");\n"
for tensor in self.tensors.values():
if isinstance(tensor, WeightTensor):
from graph_codegen import GraphCodeGen
weights_str += self.emit_single_weight(tensor)
return weights_str
def emit_single_weight(self, tensor):
N = tensor.shape[0]
C = tensor.shape[1]
H = tensor.shape[2]
W = tensor.shape[3]
mapped_name = tensor.get_mapped_name()
file_path = mapped_name + "_path"
unique_file_name = file_path + ".bin"
weight_str = "std::string " + file_path + " = " + " dir_prefix + std::string(\""
weight_str += unique_file_name + "\"); \n"
weight_str += "void* " + mapped_name + " = " + " readTrainedWeights("
weight_str += file_path + ".c_str(), 0," + str(N) + "," + str(C) + "," + str(H) + "," + str(W)
weight_str += "); \n"
return weight_str
def emit_main(self):
main_func_str = "int main(){ \n\n"
#main_func_str += self.weight_str
main_func_str += self.emit_weights()
#main_func_str += self.input_str
main_func_str += "\n__visc__init(); \n"
main_func_str += "RootIn* args = static_cast<RootIn*>(malloc(sizeof(RootIn))); \n\n"
......@@ -119,7 +200,7 @@ class HpvmCodeGen:
main_func_str += "__visc__wait(dfg); \n\n"
main_func_str += "void *result = static_cast<RootIn*>(args)->input; \n"
main_func_str += "hpvm_request_tensor(result, 0); \n\n"
main_func_str += "__visc__cleanup(); \n "
main_func_str += "__visc__cleanup(); \n"
main_func_str += "computeAccuracy3(labels, result); \n"
main_func_str += "return 0; \n\n"
main_func_str += "} \n"
......@@ -133,10 +214,11 @@ class HpvmCodeGen:
def compile(self):
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_main(self.test_data)
self.emit_main()
# dump generated program string to source file
self.emit_source(self.weights_dir)
......@@ -24,21 +24,23 @@ def check_version(model, new_version):
return model
def compile(model):
from config import opset_version_default, src_emit_dir
weights_dir = src_emit_dir
model = check_version(model, opset_version_default)
from config import compile_type, input_size, opset_version_default, src_emit_dir
from graph_builder import GraphBuilder
from graph_codegen import GraphCodeGen
from hpvm_codegen import HpvmCodeGen
from config import input_size
weights_dir = src_emit_dir
model = check_version(model, opset_version_default)
graphBuilder = GraphBuilder(model, None, "float32", weights_dir)
graphCodeGen = GraphCodeGen(graphBuilder.build_graph(), weights_dir, input_size)
graphCodeGen.compile()
#hpvmCodeGen = HpvmCodeGen(graphBuilder.build_graph(), weights_dir)
#hpvmCodeGen.compile()
if compile_type == 0:
graphCodeGen = GraphCodeGen(graphBuilder.build_graph(), weights_dir, input_size)
graphCodeGen.compile()
elif compile_type == 1:
hpvmCodeGen = HpvmCodeGen(graphBuilder.build_graph(), weights_dir)
hpvmCodeGen.compile()
else:
raise ValueError("Wrong type of Compilation! Abort.")
def main():
# TODO: Put it in args
from config import onnx_file_dir
model = onnx.load(onnx_file_dir)
compile(model)
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment