diff --git a/hls4ml/converters/__init__.py b/hls4ml/converters/__init__.py index 2f658d62d..3b06c9a7c 100644 --- a/hls4ml/converters/__init__.py +++ b/hls4ml/converters/__init__.py @@ -86,5 +86,8 @@ def convert_from_keras_model(model, output_dir='my-hls-test', project_name='mypr if 'Optimizers' in hls_config: config['HLSConfig']['Optimizers'] = hls_config['Optimizers'] + + if 'SkipOptimizers' in hls_config: + config['HLSConfig']['SkipOptimizers'] = hls_config['SkipOptimizers'] return keras_to_hls(config) diff --git a/hls4ml/model/hls_layers.py b/hls4ml/model/hls_layers.py index 057474035..5a2824ae3 100644 --- a/hls4ml/model/hls_layers.py +++ b/hls4ml/model/hls_layers.py @@ -1144,6 +1144,7 @@ def _get_transforms_config(self, params): params['sublayer_configs'] = '\n'.join(sublayer_configs) layer_map = { + 'Input' : Input, 'InputLayer' : Input, 'Activation' : Activation, 'QActivation' : Activation, diff --git a/hls4ml/model/hls_model.py b/hls4ml/model/hls_model.py index 1518f3ccc..fe8cb0ec1 100644 --- a/hls4ml/model/hls_model.py +++ b/hls4ml/model/hls_model.py @@ -12,7 +12,7 @@ from hls4ml.model.hls_layers import * from hls4ml.templates import get_backend from hls4ml.writer import get_writer -from hls4ml.model.optimizer import optimize_model +from hls4ml.model.optimizer import optimize_model, get_available_passes class HLSConfig(object): def __init__(self, config): @@ -143,7 +143,20 @@ def get_compression(self, layer): def _parse_hls_config(self): hls_config = self.config['HLSConfig'] + self.optimizers = hls_config.get('Optimizers') + if 'SkipOptimizers' in hls_config: + if self.optimizers is not None: + raise Exception('Invalid optimizer configuration, please use either "Optimizers" or "SkipOptimizers".') + skip_optimizers = hls_config.get('SkipOptimizers') + selected_optimizers = get_available_passes() + for opt in skip_optimizers: + try: + selected_optimizers.remove(opt) + except ValueError: + pass + self.optimizers = selected_optimizers + model_cfg = hls_config.get('Model') if model_cfg is not None: precision_cfg = model_cfg.get('Precision') @@ -355,6 +368,14 @@ def get_layer_output_variable(self, output_name): return self.output_vars[output_name] def write(self): + def make_stamp(): + from string import hexdigits + from random import choice + length = 8 + return ''.join(choice(hexdigits) for m in range(length)) + + self.config.config['Stamp'] = make_stamp() + self.config.writer.write_hls(self) def compile(self): @@ -367,7 +388,7 @@ def compile(self): ret_val = os.system('bash build_lib.sh') if ret_val != 0: raise Exception('Failed to compile project "{}"'.format(self.config.get_project_name())) - lib_name = 'firmware/{}.so'.format(self.config.get_project_name()) + lib_name = 'firmware/{}-{}.so'.format(self.config.get_project_name(), self.config.get_config_value('Stamp')) if self._top_function_lib is not None: if platform.system() == "Linux": diff --git a/hls4ml/model/optimizer/__init__.py b/hls4ml/model/optimizer/__init__.py index 5bba66f7c..fb171be74 100644 --- a/hls4ml/model/optimizer/__init__.py +++ b/hls4ml/model/optimizer/__init__.py @@ -1,6 +1,6 @@ from __future__ import absolute_import -from hls4ml.model.optimizer.optimizer import OptimizerPass, register_pass, get_optimizer, optimize_model +from hls4ml.model.optimizer.optimizer import OptimizerPass, register_pass, get_optimizer, optimize_model, get_available_passes from hls4ml.model.optimizer.passes.nop import EliminateLinearActivation diff --git a/hls4ml/model/optimizer/optimizer.py b/hls4ml/model/optimizer/optimizer.py index 1a21d5d1b..2a45947f0 100644 --- a/hls4ml/model/optimizer/optimizer.py +++ b/hls4ml/model/optimizer/optimizer.py @@ -24,6 +24,9 @@ def register_pass(name, opt_cls): def get_optimizer(name): return optimizer_map[name]() +def get_available_passes(): + return list(optimizer_map.keys()) + def optimize_model(model, passes=None): if passes is None: passes = optimizer_map.keys() diff --git a/hls4ml/templates/vivado/build_lib.sh b/hls4ml/templates/vivado/build_lib.sh index 16db2cdec..4409fe463 100755 --- a/hls4ml/templates/vivado/build_lib.sh +++ b/hls4ml/templates/vivado/build_lib.sh @@ -9,8 +9,9 @@ fi LDFLAGS= INCFLAGS="-Ifirmware/ap_types/" PROJECT=myproject +LIB_STAMP=mystamp ${CC} ${CFLAGS} ${INCFLAGS} -c firmware/${PROJECT}.cpp -o ${PROJECT}.o ${CC} ${CFLAGS} ${INCFLAGS} -c ${PROJECT}_bridge.cpp -o ${PROJECT}_bridge.o -${CC} ${CFLAGS} ${INCFLAGS} -shared ${PROJECT}.o ${PROJECT}_bridge.o -o firmware/${PROJECT}.so +${CC} ${CFLAGS} ${INCFLAGS} -shared ${PROJECT}.o ${PROJECT}_bridge.o -o firmware/${PROJECT}-${LIB_STAMP}.so rm -f *.o \ No newline at end of file diff --git a/hls4ml/templates/vivado/build_prj.tcl b/hls4ml/templates/vivado/build_prj.tcl index adbe5f064..2a473c1e5 100644 --- a/hls4ml/templates/vivado/build_prj.tcl +++ b/hls4ml/templates/vivado/build_prj.tcl @@ -92,6 +92,8 @@ if {$opt(cosim)} { set time_start [clock clicks -milliseconds] cosim_design -trace_level all set time_end [clock clicks -milliseconds] + puts "INFO:" + puts [read [open myproject_prj/solution1/sim/report/myproject_cosim.rpt r]] report_time "C/RTL SIMULATION" $time_start $time_end } diff --git a/hls4ml/templates/vivado/myproject_test.cpp b/hls4ml/templates/vivado/myproject_test.cpp index ed6f6e732..6e093f619 100644 --- a/hls4ml/templates/vivado/myproject_test.cpp +++ b/hls4ml/templates/vivado/myproject_test.cpp @@ -56,7 +56,6 @@ int main(int argc, char **argv) if (fin.is_open() && fpr.is_open()) { while ( std::getline(fin,iline) && std::getline (fpr,pline) ) { if (e % CHECKPOINT == 0) std::cout << "Processing input " << e << std::endl; - e++; char* cstr=const_cast(iline.c_str()); char* current; std::vector in; @@ -85,6 +84,7 @@ int main(int argc, char **argv) std::cout << "Quantized predictions" << std::endl; //hls-fpga-machine-learning insert quantized } + e++; } fin.close(); fpr.close(); diff --git a/hls4ml/utils/config.py b/hls4ml/utils/config.py index 0336b7fdf..f62ecfefe 100644 --- a/hls4ml/utils/config.py +++ b/hls4ml/utils/config.py @@ -84,11 +84,12 @@ def config_from_keras_model(model, granularity='model', default_precision='ap_fi keras_layer_config = model_arch['config'] if 'layers' in keras_layer_config: # Newer Keras versions have 'layers' in 'config' key keras_layer_config = keras_layer_config['layers'] - # Sequential doesn't have InputLayer - input_layer = {} - input_layer['name'] = 'input1' - input_layer['class_name'] = 'InputLayer' - layer_list.append(input_layer) + # Sequential doesn't have InputLayer in TF < 2.3 (Keras 2.4.0) + if keras_layer_config[0]['class_name'] != 'InputLayer': + input_layer = {} + input_layer['name'] = 'input1' + input_layer['class_name'] = 'Input' + layer_list.append(input_layer) elif model_arch['class_name'] in ['Model', 'Functional']: print('Interpreting Model') keras_layer_config = model_arch['config']['layers'] @@ -108,6 +109,9 @@ def config_from_keras_model(model, granularity='model', default_precision='ap_fi layer['class_name'] = keras_layer['class_name'] layer['config'] = keras_layer['config'] + if layer['class_name'] == 'InputLayer': + layer['class_name'] = 'Input' + if layer['class_name'] in qkeras_layers: layer['precision'] = {} for qname, qclass in layer['config'].items(): @@ -169,6 +173,11 @@ def make_layer_config(layer): print('WARNING: Found no precision information in QKeras layer {} ({})'.format(layer['name'], layer['class_name'])) layer_config['Precision'] = default_precision layer_config['ReuseFactor'] = default_reuse_factor + + elif layer['class_name'] == 'Input': + layer_config['Precision'] = {} + layer_config['Precision']['result'] = default_precision + else: layer_config['Precision'] = default_precision @@ -189,7 +198,7 @@ def make_layer_config(layer): elif granularity.lower() == 'type': type_config = {} for layer in layer_list: - if layer['class_name'] in type_config or layer['class_name'] == 'InputLayer': + if layer['class_name'] in type_config: continue layer_config = make_layer_config(layer) type_config[layer['class_name']] = layer_config @@ -199,8 +208,6 @@ def make_layer_config(layer): elif granularity.lower() == 'name': name_config = {} for layer in layer_list: - if layer['class_name'] == 'InputLayer': # Skip INputLayer - continue layer_config = make_layer_config(layer) name_config[layer['name']] = layer_config diff --git a/hls4ml/writer/vivado_writer.py b/hls4ml/writer/vivado_writer.py index da49b37bb..8a4eaeb29 100644 --- a/hls4ml/writer/vivado_writer.py +++ b/hls4ml/writer/vivado_writer.py @@ -531,6 +531,7 @@ def write_build_script(self, model): for line in f.readlines(): line = line.replace('myproject', model.config.get_project_name()) + line = line.replace('mystamp', model.config.get_config_value('Stamp')) fout.write(line) f.close() diff --git a/setup.py b/setup.py index c0a45a9d7..75f7f6e2d 100644 --- a/setup.py +++ b/setup.py @@ -7,7 +7,7 @@ long_description = f.read() setup(name='hls4ml', - version='0.3.0', + version='0.4.0', description='Machine learning in FPGAs using HLS', long_description=long_description, long_description_content_type='text/markdown', @@ -36,8 +36,6 @@ 'Intended Audience :: Science/Research', 'License :: OSI Approved :: Apache Software License', 'Programming Language :: C++', - 'Programming Language :: Python :: 2', - 'Programming Language :: Python :: 2.7', 'Programming Language :: Python :: 3', 'Programming Language :: Python :: 3.6', 'Topic :: Software Development :: Libraries',