def test_set_folding(target_fps, platform): model = make_multi_fclayer_model(128, DataType.INT4, DataType.INT2, DataType.INT16, 5) model = model.transform(GiveUniqueNodeNames()) parent_model = model.transform(CreateDataflowPartition()) sdp_node = parent_model.get_nodes_by_op_type( "StreamingDataflowPartition")[0] sdp_node = getCustomOp(sdp_node) dataflow_model_filename = sdp_node.get_nodeattr("model") dataflow_model = load_test_checkpoint_or_skip(dataflow_model_filename) clk_ns = 5 target_cycles_per_frame = int((10**9 / clk_ns) / target_fps) dataflow_model = dataflow_model.transform( SetFolding(target_cycles_per_frame)) exp_cycles_dict = dataflow_model.analysis(exp_cycles_per_layer) achieved_cycles_per_frame = max(exp_cycles_dict.values()) min_cycles = dict() min_cycles["Pynq-Z1"] = 128 min_cycles["Ultra96"] = 64 min_cycles["U200"] = 1 assert achieved_cycles_per_frame <= max( min_cycles[platform], target_cycles_per_frame), "Folding target not met"
def test_end2end_tfc_w1a2_create_dataflow_partition(): model = ModelWrapper(build_dir + "/end2end_tfc_w1a2_hls_layers.onnx") parent_model = model.transform(CreateDataflowPartition()) parent_model.save(build_dir + "/end2end_tfc_w1a2_dataflow_parent.onnx") sdp_node = getCustomOp(parent_model.graph.node[2]) dataflow_model_filename = sdp_node.get_nodeattr("model") dataflow_model = ModelWrapper(dataflow_model_filename) dataflow_model.save(build_dir + "/end2end_tfc_w1a2_dataflow_model.onnx")
def test_end2end_cnv_w1a1_create_dataflow_partition(): model = ModelWrapper(build_dir + "/end2end_cnv_w1a1_hls_layers.onnx") parent_model = model.transform(CreateDataflowPartition()) parent_model.save(build_dir + "/end2end_cnv_w1a1_dataflow_parent.onnx") sdp_node = parent_model.get_nodes_by_op_type("StreamingDataflowPartition")[0] sdp_node = getCustomOp(sdp_node) dataflow_model_filename = sdp_node.get_nodeattr("model") dataflow_model = ModelWrapper(dataflow_model_filename) dataflow_model.save(build_dir + "/end2end_cnv_w1a1_dataflow_model.onnx")
def test_end2end_mobilenet_create_dataflow_partition(): model = load_test_checkpoint_or_skip(build_dir + "/end2end_mobilenet_folded.onnx") parent_model = model.transform(CreateDataflowPartition()) parent_model.save(build_dir + "/end2end_mobilenet_dataflow_parent.onnx") sdp_node = parent_model.get_nodes_by_op_type("StreamingDataflowPartition")[0] sdp_node = getCustomOp(sdp_node) dataflow_model_filename = sdp_node.get_nodeattr("model") dataflow_model = load_test_checkpoint_or_skip(dataflow_model_filename) dataflow_model = dataflow_model.transform(RemoveUnusedTensors()) dataflow_model.save(build_dir + "/end2end_mobilenet_dataflow_model.onnx")
def create_one_fc_model(mem_mode="const"): # create a model with a StreamingFCLayer instance with no activation # the wider range of the full accumulator makes debugging a bit easier wdt = DataType.INT2 idt = DataType.INT32 odt = DataType.INT32 m = 4 no_act = 1 binary_xnor_mode = 0 actval = 0 simd = 4 pe = 4 inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, m]) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, m]) fc0 = helper.make_node( "StreamingFCLayer_Batch", ["inp", "w0"], ["outp"], domain="finn", backend="fpgadataflow", resType="ap_resource_lut()", MW=m, MH=m, SIMD=simd, PE=pe, inputDataType=idt.name, weightDataType=wdt.name, outputDataType=odt.name, ActVal=actval, binaryXnorMode=binary_xnor_mode, noActivation=no_act, mem_mode=mem_mode, ) graph = helper.make_graph(nodes=[fc0], name="fclayer_graph", inputs=[inp], outputs=[outp]) model = helper.make_model(graph, producer_name="fclayer-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) model.set_tensor_datatype("outp", odt) model.set_tensor_datatype("w0", wdt) # generate weights w0 = np.eye(m, dtype=np.float32) model.set_initializer("w0", w0) model = model.transform(CreateDataflowPartition()) return model
def apply(self, model): _check_vitis_envvars() # first infer layouts model = model.transform(InferDataLayouts()) # prepare at global level, then break up into kernels prep_transforms = [ MakePYNQDriver(platform="alveo"), InsertIODMA(512), InsertDWC(), ] for trn in prep_transforms: model = model.transform(trn) model = model.transform(GiveUniqueNodeNames()) model = model.transform(GiveReadableTensorNames()) model = model.transform(Floorplan(floorplan=self.floorplan_file)) model = model.transform(CreateDataflowPartition()) model = model.transform(GiveUniqueNodeNames()) model = model.transform(GiveReadableTensorNames()) # Build each kernel individually sdp_nodes = model.get_nodes_by_op_type("StreamingDataflowPartition") for sdp_node in sdp_nodes: sdp_node = getCustomOp(sdp_node) dataflow_model_filename = sdp_node.get_nodeattr("model") kernel_model = ModelWrapper(dataflow_model_filename) kernel_model = kernel_model.transform(InsertFIFO()) kernel_model = kernel_model.transform( InsertTLastMarker(both=True, external=False, dynamic=False)) kernel_model = kernel_model.transform(GiveUniqueNodeNames()) kernel_model.save(dataflow_model_filename) kernel_model = kernel_model.transform( PrepareIP(self.fpga_part, self.period_ns)) kernel_model = kernel_model.transform(HLSSynthIP()) kernel_model = kernel_model.transform( CreateStitchedIP(self.fpga_part, self.period_ns, sdp_node.onnx_node.name, True)) kernel_model = kernel_model.transform( CreateVitisXO(sdp_node.onnx_node.name)) kernel_model.set_metadata_prop("platform", "alveo") kernel_model.save(dataflow_model_filename) # Assemble design from kernels model = model.transform( VitisLink( self.platform, round(1000 / self.period_ns), strategy=self.strategy, enable_debug=self.enable_debug, )) # set platform attribute for correct remote execution model.set_metadata_prop("platform", "alveo") return (model, False)
def test_dataflow_partition_create(): # load the onnx model raw_m = get_data( "finn", "data/onnx/finn-hls-model/tfc_w1_a1_after_conv_to_hls.onnx") model = ModelWrapper(raw_m) model = model.transform(CreateDataflowPartition()) assert model.graph.node[2].op_type == "StreamingDataflowPartition" sdp_node = getCustomOp(model.graph.node[2]) assert sdp_node.__class__.__name__ == "StreamingDataflowPartition" assert os.path.isfile(sdp_node.get_nodeattr("model")) model.save(build_dir + "/test_dataflow_partition_create.onnx")
def create_dataflow_partition(model): log("Creating Dataflow Partition") parent_model = model.transform(CreateDataflowPartition()) save(parent_model, "5_dataflow_parent") sdp_node = parent_model.get_nodes_by_op_type( "StreamingDataflowPartition")[0] sdp_node = getCustomOp(sdp_node) dataflow_model_filename = sdp_node.get_nodeattr("model") dataflow_model = ModelWrapper(dataflow_model_filename) save(model, "5_dataflow_model") log("Dataflow partition created") return dataflow_model
def test_create_dataflow_partition(self, topology, wbits, abits): prev_chkpt_name = get_checkpoint_name(topology, wbits, abits, "convert_to_hls_layers") model = load_test_checkpoint_or_skip(prev_chkpt_name) parent_model = model.transform(CreateDataflowPartition()) parent_model_chkpt = get_checkpoint_name(topology, wbits, abits, "dataflow_parent") parent_model.save(parent_model_chkpt) sdp_node = parent_model.get_nodes_by_op_type( "StreamingDataflowPartition")[0] sdp_node = getCustomOp(sdp_node) dataflow_model_filename = sdp_node.get_nodeattr("model") dataflow_model = load_test_checkpoint_or_skip(dataflow_model_filename) dataflow_model_chkpt = get_checkpoint_name(topology, wbits, abits, "dataflow_model") dataflow_model.save(dataflow_model_chkpt)
def step_create_dataflow_partition(model: ModelWrapper, cfg: DataflowBuildConfig): """Separate consecutive groups of HLSCustomOp nodes into StreamingDataflowPartition nodes, which point to a separate ONNX file. Dataflow accelerator synthesis can only be performed on those HLSCustomOp sub-graphs.""" parent_model = model.transform(CreateDataflowPartition()) sdp_nodes = parent_model.get_nodes_by_op_type("StreamingDataflowPartition") assert len( sdp_nodes) == 1, "Only a single StreamingDataflowPartition supported." sdp_node = sdp_nodes[0] sdp_node = getCustomOp(sdp_node) dataflow_model_filename = sdp_node.get_nodeattr("model") if cfg.save_intermediate_models: parent_model.save(cfg.output_dir + "/intermediate_models/dataflow_parent.onnx") model = ModelWrapper(dataflow_model_filename) return model
def apply(self, model): # first infer layouts model = model.transform(InferDataLayouts()) # prepare at global level, then break up into kernels prep_transforms = [ InsertIODMA(64), InsertDWC(), Floorplan(), CreateDataflowPartition(), ] for trn in prep_transforms: model = model.transform(trn) model = model.transform(GiveUniqueNodeNames()) model = model.transform(GiveReadableTensorNames()) # Build each kernel individually sdp_nodes = model.get_nodes_by_op_type("StreamingDataflowPartition") for sdp_node in sdp_nodes: prefix = sdp_node.name + "_" sdp_node = getCustomOp(sdp_node) dataflow_model_filename = sdp_node.get_nodeattr("model") kernel_model = ModelWrapper(dataflow_model_filename) kernel_model = kernel_model.transform(InsertFIFO()) kernel_model = kernel_model.transform(GiveUniqueNodeNames(prefix)) kernel_model.save(dataflow_model_filename) kernel_model = kernel_model.transform( PrepareIP(self.fpga_part, self.period_ns)) kernel_model = kernel_model.transform(HLSSynthIP()) kernel_model = kernel_model.transform( CreateStitchedIP(self.fpga_part, self.period_ns, sdp_node.onnx_node.name, True)) kernel_model.set_metadata_prop("platform", "zynq-iodma") kernel_model.save(dataflow_model_filename) # Assemble design from IPs model = model.transform( MakeZYNQProject(self.platform, enable_debug=self.enable_debug)) # set platform attribute for correct remote execution model.set_metadata_prop("platform", "zynq-iodma") # create driver model = model.transform(MakePYNQDriver(platform="zynq-iodma")) return (model, False)
def create_two_fc_model(mem_mode="decoupled"): # create a model with two StreamingFCLayer instances wdt = DataType.INT2 idt = DataType.INT32 odt = DataType.INT32 m = 4 actval = 0 no_act = 1 binary_xnor_mode = 0 pe = 2 simd = 2 inp = helper.make_tensor_value_info("inp", TensorProto.FLOAT, [1, m]) mid = helper.make_tensor_value_info("mid", TensorProto.FLOAT, [1, m]) outp = helper.make_tensor_value_info("outp", TensorProto.FLOAT, [1, m]) fc0 = helper.make_node( "StreamingFCLayer_Batch", ["inp", "w0"], ["mid"], domain="finn", backend="fpgadataflow", resType="ap_resource_lut()", MW=m, MH=m, SIMD=simd, PE=pe, inputDataType=idt.name, weightDataType=wdt.name, outputDataType=odt.name, ActVal=actval, binaryXnorMode=binary_xnor_mode, noActivation=no_act, mem_mode=mem_mode, ) fc1 = helper.make_node( "StreamingFCLayer_Batch", ["mid", "w1"], ["outp"], domain="finn", backend="fpgadataflow", resType="ap_resource_lut()", MW=m, MH=m, SIMD=simd, PE=pe, inputDataType=idt.name, weightDataType=wdt.name, outputDataType=odt.name, ActVal=actval, binaryXnorMode=binary_xnor_mode, noActivation=no_act, mem_mode=mem_mode, ) graph = helper.make_graph( nodes=[fc0, fc1], name="fclayer_graph", inputs=[inp], outputs=[outp], value_info=[mid], ) model = helper.make_model(graph, producer_name="fclayer-model") model = ModelWrapper(model) model.set_tensor_datatype("inp", idt) model.set_tensor_datatype("mid", idt) model.set_tensor_datatype("outp", odt) model.set_tensor_datatype("w0", wdt) model.set_tensor_datatype("w1", wdt) # generate weights w0 = np.eye(m, dtype=np.float32) w1 = np.eye(m, dtype=np.float32) model.set_initializer("w0", w0) model.set_initializer("w1", w1) model = model.transform(CreateDataflowPartition()) return model