diff --git a/.gitignore b/.gitignore index ad85eaeaea8d06dbf5e7d5fdd25a6041979a1eb0..fb20a1faf02095795fa73362119c99f0589684bc 100644 --- a/.gitignore +++ b/.gitignore @@ -16,3 +16,4 @@ examples/*/*.vhd examples/debugger_example/*.txt examples/*/__pycache__ +__pycache__/ diff --git a/JSONConfiguration.md b/JSONConfiguration.md new file mode 100644 index 0000000000000000000000000000000000000000..838606a737a81408079071ee55df3d9e59b36c1c --- /dev/null +++ b/JSONConfiguration.md @@ -0,0 +1,247 @@ +# JSON File Configuration Explaination + +The file describe all differents json properties. +A template file can be found inside **modneflib/modnef/template**. Additional commentary, including non requiered properties will be explained in this file. + +## ModNEF Network Description + +ModNEF network model properties + +```json +{ + "name" : "model_name", // name of network model + + "input" : 2312, // number of input features + "num_class" : 10, // number of output class + + // insert layer description + // layer description are described in next section + + "hardware" : { // ModNEF VHDL hardware description + "clock_name" : "clock", // name of clock signal inside VHDL file + "clock_freq" : 125000000, // clock frequency of FPGA internal clock + "baud_rate" : 921600, // UART baud rate + "txd" : "uart_txd", // UART txd signal name + "rxd" : "uart_rxd", // UART rxd signal name + "queue_read_depth" : 4096, /*Optional*/ // UART component queue read depth, can be ignored and will be computed during hardware estimation + "queue_write_depth" : 4096 /*Optional*/ // UART component queue write depth, can be ignored and will be computed during hardware estimation + }, + +} +``` + +### Neuron Description + +In this section, we will describe + +#### Beta LIF Neuron Model Description + +Feed forward layer + +```json +{ + "name of layer" : { // name of layer (will be the name of VHDL component implementation) + "model" : "blif", // neuron model + "in_features" : 64, // number of input features + "neurons" : 10, // number of simulated/emeulated neurons + "beta" : 0.9, // membrane decay value + "threshold" : 0.8, // threshold value + "reset_mechanism" : "subtract", // reset mechanism, can be subtract or zero + "hardware" : { /*Optional*/ // hardware description + "strategy" : "Parallel", /*Optional*/ // hardware emulation strategy, Parallel by default + "weight_size" : 8, /*Optional*/ // synaptic quantized weight bitwidth, 8 by default + "weight_fp" : -1, /*Optional*/ // weight fixed point position, -1 by default. If default, computed automatically depending weight bitwidth weight values + "weight_type" : null, /*Optional*/ // weight type, can be null, w_signed, w_unsigned. If null, determined depending on weights values + "compute_fp" : -1, /*Optional*/ // neuron hyper parameters fixed point value, -1 by default. If -1, compute_fp=weight_size + "mem_init_file" : null, /*Optional*/ // vivado memory file, null by default. If null, file = layer_name_mem.mem + "variable_size" : -1 /*Optional*/ // computational variable bitwidth, -1 by default. If -1, computed during hardware estimation + } + } +} +``` + +Recurrent layer + +```json +{ + "name of layer" : { // name of layer (will be the name of VHDL component implementation) + "model" : "rblif", // neuron model + "in_features" : 64, // number of input features + "neurons" : 10, // number of simulated/emeulated neurons + "beta" : 0.9, // membrane decay value + "threshold" : 0.8, // threshold value + "reset_mechanism" : "subtract", // reset mechanism, can be subtract or zero + "hardware" : { /*Optional*/ // hardware description + "strategy" : "Parallel", /*Optional*/ // hardware emulation strategy, Parallel by default + "weight_size" : 8, /*Optional*/ // synaptic quantized weight bitwidth, 8 by default + "weight_fp" : -1, /*Optional*/ // weight fixed point position, -1 by default. If default, computed automatically depending weight bitwidth weight values + "weight_type" : null, /*Optional*/ // weight type, can be null, w_signed, w_unsigned. If null, determined depending on weights values + "compute_fp" : -1, /*Optional*/ // neuron hyper parameters fixed point value, -1 by default. If -1, compute_fp=weight_size + "mem_init_file" : null, /*Optional*/ // vivado memory file for feed forward weight, null by default. If null, file = layer_name_mem.mem + "mem_init_file_rec" : null, /*Optional*/ // vivado memory file for recurrent weight, null by default. If null, file = layer_name_mem_rec.mem + "variable_size" : -1 /*Optional*/ // computational variable bitwidth, -1 by default. If -1, computed during hardware estimation + } + } +} +``` + +#### Shift Register based LIF Neuron Model Description + +Feed forward layer + +```json +{ + "name of layer" : { // name of layer (will be the name of VHDL component implementation) + "model" : "shiftlif", // neuron model + "in_features" : 64, // number of input features + "neurons" : 10, // number of simulated/emeulated neurons + "beta" : 0.9, // membrane decay value + "threshold" : 0.8, // threshold value + "reset_mechanism" : "subtract", // reset mechanism, can be subtract or zero + "hardware" : { /*Optional*/ // hardware description + "strategy" : "Parallel", /*Optional*/ // hardware emulation strategy, Parallel by default + "weight_size" : 8, /*Optional*/ // synaptic quantized weight bitwidth, 8 by default + "weight_fp" : -1, /*Optional*/ // weight fixed point position, -1 by default. If default, computed automatically depending weight bitwidth weight values + "weight_type" : null, /*Optional*/ // weight type, can be null, w_signed, w_unsigned. If null, determined depending on weights values + "compute_fp" : -1, /*Optional*/ // neuron hyper parameters fixed point value, -1 by default. If -1, compute_fp=weight_size + "mem_init_file" : null, /*Optional*/ // vivado memory file, null by default. If null, file = layer_name_mem.mem + "variable_size" : -1 /*Optional*/ // computational variable bitwidth, -1 by default. If -1, computed during hardware estimation + } + } +} +``` + +Recurrent layer + +```json +{ + "name of layer" : { // name of layer (will be the name of VHDL component implementation) + "model" : "rshiftlif", // neuron model + "in_features" : 64, // number of input features + "neurons" : 10, // number of simulated/emeulated neurons + "beta" : 0.9, // membrane decay value + "threshold" : 0.8, // threshold value + "reset_mechanism" : "subtract", // reset mechanism, can be subtract or zero + "hardware" : { /*Optional*/ // hardware description + "strategy" : "Parallel", /*Optional*/ // hardware emulation strategy, Parallel by default + "weight_size" : 8, /*Optional*/ // synaptic quantized weight bitwidth, 8 by default + "weight_fp" : -1, /*Optional*/ // weight fixed point position, -1 by default. If default, computed automatically depending weight bitwidth weight values + "weight_type" : null, /*Optional*/ // weight type, can be null, w_signed, w_unsigned. If null, determined depending on weights values + "compute_fp" : -1, /*Optional*/ // neuron hyper parameters fixed point value, -1 by default. If -1, compute_fp=weight_size + "mem_init_file" : null, /*Optional*/ // vivado memory file for feed forward weight, null by default. If null, file = layer_name_mem.mem + "mem_init_file_rec" : null, /*Optional*/ // vivado memory file for recurrent weight, null by default. If null, file = layer_name_mem_rec.mem + "variable_size" : -1 /*Optional*/ // computational variable bitwidth, -1 by default. If -1, computed during hardware estimation + } + } +} +``` + +#### Simplified LIF Neuron Model Description + +Feed forward layer + +```json +{ + "name of layer" : { // name of layer (will be the name of VHDL component implementation) + "model" : "slif", // neuron model + "in_features" : 64, // number of input features + "neurons" : 10, // number of simulated/emeulated neurons + "threshold" : 0.8, // threshold value + "leak" : 0.015, // memory leakage value + "min" : 0.0, // minimal memory voltage value + "rest" : 0.0, // resting memory potential + "hardware" : { /*Optional*/ // hardware description + "strategy" : "Parallel", /*Optional*/ // hardware emulation strategy, Parallel by default + "weight_size" : 8, /*Optional*/ // synaptic quantized weight bitwidth, 8 by default + "weight_type" : null, /*Optional*/ // weight type, can be null, w_signed, w_unsigned. If null, determined depending on weights values + "mem_init_file" : null, /*Optional*/ // vivado memory file, null by default. If null, file = layer_name_mem.mem + "variable_size" : -1 /*Optional*/ // computational variable bitwidth, -1 by default. If -1, computed during hardware estimation + } + } +} +``` + +Recurrent layer + +```json +{ + "name of layer" : { // name of layer (will be the name of VHDL component implementation) + "model" : "rslif", // neuron model + "in_features" : 64, // number of input features + "neurons" : 10, // number of simulated/emeulated neurons + "threshold" : 0.8, // threshold value + "leak" : 0.015, // memory leakage value + "min" : 0.0, // minimal memory voltage value + "rest" : 0.0, // resting memory potential + "hardware" : { /*Optional*/ // hardware description + "strategy" : "Parallel", /*Optional*/ // hardware emulation strategy, Parallel by default + "weight_size" : 8, /*Optional*/ // synaptic quantized weight bitwidth, 8 by default + "weight_type" : null, /*Optional*/ // weight type, can be null, w_signed, w_unsigned. If null, determined depending on weights values + "mem_init_file" : null, /*Optional*/ // vivado memory file, null by default. If null, file = layer_name_mem.mem + "mem_init_file_rec" : null, /*Optional*/ // vivado memory file for recurrent weight, null by default. If null, file = layer_name_mem_rec.mem + "variable_size" : -1 /*Optional*/ // computational variable bitwidth, -1 by default. If -1, computed during hardware estimation + } + } +} +``` + +## ModNEF Project Description + +```json +{ + "exp_name" : "template", + + "model": { + // describe you model here + }, + + "optimizer" : { /*Optional*/ // Adam optimizer properties, optional. If no optimizer properties, default optimizer is configured with followed values + "lr" : 1e-4, // learning rate + "betas" : [0.9, 0.99] // betas values + }, + + "best_model" : "best_my_model", /*Optional*/ // best model file name, optional. By default best_{model.name} + + "verbose" : true, /*Optional*/ // verbose mode, by default true + + "device" : "auto", /*Optional*/ // troch device, by default auto. If auto, device is automatically detected + + "train" : { // Train configuration. Optional if you don't want to train with ModNEF Executor. + "name" : "Train", // name printed during trian progression + "n_epoch" : 5, // number of epoch + "save_best_model" : true, /*Optional*/ // save best accuracy model, by default true + "save_history" : true, /*Optional*/ // save average loss, test accuracy and validation accuracy through epoch, by default true + "plot" : true /*Optional*/ // save matplotlib plot, by default true + }, + + "eval" : { // Software evaluation configuration, Optional if you don't want to run software evaluation + "name" : "Evaluation", // name printed during evaluation progression + "use_best_model" : true, /* Optional*/ // use best model for evaluation, by default true + "conf_matrix" : true /* Optional*/ // generate matplotlib confusion matrix, by default true + }, + + "hardware_estimation" : { // Hardware estimation configuration, Optional if you don't want to run hardware estimation + "name" : "Hardware Estimation", // name printed during evaluation progression + "use_best_model" : true, /* Optional*/ // use best model for evaluation, by default true + "conf_matrix" : true /* Optional*/ // generate matplotlib confusion matrix, by default true + }, + + "vhdl" : { // VHDL generation configuration, Optional if you don't want to run vhl generation + "use_best_model" : false, /* Optional*/ // use best model for evaluation, by default true + "driver_config" : "driver.yml", /* Optional*/ // driver configuration file, by default driver.yml + "file_name" : null /* Optional*/ // VHDL file name, if null, model.name.vhd + }, + + "fpga" : { // FPGA evaluation configuration, Optional if you don't want to run FPGA evaluation + "name" : "FPGA Evaluation", // name printed during evaluation progression + "driver_file" : "driver.yml", // driver configuration file + "board_path" : "board path here", // path to UART board + "conf_matrix" : true /* Optional*/ // generate matplotlib confusion matrix, by default true + }, + + "confusion_matrix" : { // Necessary if you want to generate configuration matrix + "class" : ["0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] // Name of classes + } + +} +``` \ No newline at end of file diff --git a/modneflib/modnef/__init__.py b/modneflib/modnef/__init__.py index b3d7654003558f20a66f83ed41ef0eec16a8111b..e622685c6cd83192707566d1fec7984a522b90db 100644 --- a/modneflib/modnef/__init__.py +++ b/modneflib/modnef/__init__.py @@ -1,4 +1,5 @@ from .arch_builder import * from .modnef_driver import * from .tools import * -from .modnef_torch import * \ No newline at end of file +from .modnef_torch import * +from .quantizer import * \ No newline at end of file diff --git a/modneflib/modnef/__pycache__/__init__.cpython-310.pyc b/modneflib/modnef/__pycache__/__init__.cpython-310.pyc index 994b886f581c7f7545bdaa0b73d8e90bf2a0fb39..a633a6b32c555f8bc0a12ede59d6808044acc687 100644 Binary files a/modneflib/modnef/__pycache__/__init__.cpython-310.pyc and b/modneflib/modnef/__pycache__/__init__.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/__pycache__/__init__.cpython-310.pyc b/modneflib/modnef/arch_builder/__pycache__/__init__.cpython-310.pyc index beca1367da962b7eb394e3a253cc92cd13c99bd2..96593e53511f2055d5ca6d15b399ebe4cdaaa805 100644 Binary files a/modneflib/modnef/arch_builder/__pycache__/__init__.cpython-310.pyc and b/modneflib/modnef/arch_builder/__pycache__/__init__.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/__pycache__/modnef_builder.cpython-310.pyc b/modneflib/modnef/arch_builder/__pycache__/modnef_builder.cpython-310.pyc index 504cbd1208501c326392c20cc12ffd618f8c7d22..13dcb3a274bcba9ebcef1c4cf40fd8fa4eabcd36 100644 Binary files a/modneflib/modnef/arch_builder/__pycache__/modnef_builder.cpython-310.pyc and b/modneflib/modnef/arch_builder/__pycache__/modnef_builder.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/__init__.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/__init__.cpython-310.pyc index 49a173f5bb67900460047fbac675a8cea2b50726..0dff00858b51446fe5ccb10619411224722e0250 100644 Binary files a/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/__init__.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/__init__.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/blif.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/blif.cpython-310.pyc index 8b4abc9bf6efed6cff7455367f07e4efdc27e1e3..5e5a6ce1aab3e0ab07ec3e9bc770217363894968 100644 Binary files a/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/blif.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/blif.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/blif_debugger.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/blif_debugger.cpython-310.pyc index 41b72a50c830ad82af323d49e341b407cf404b0f..80ffdc923d7506f65d9752d4590a24bf213bd066 100644 Binary files a/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/blif_debugger.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/blif_debugger.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/rblif.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/rblif.cpython-310.pyc index 4fbc49752317251f2e0cfee2954b9fc19b711512..dcede5bf6638a81f47641b425d9ba73133b55709 100644 Binary files a/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/rblif.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/BLIF/__pycache__/rblif.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/BLIF/blif.py b/modneflib/modnef/arch_builder/modules/BLIF/blif.py index 0f10b9e4a0c7052e42fc1f8c99600d4239abb926..daf1c7681cab813436a564545fab1b79b7bb4a4c 100644 --- a/modneflib/modnef/arch_builder/modules/BLIF/blif.py +++ b/modneflib/modnef/arch_builder/modules/BLIF/blif.py @@ -12,6 +12,7 @@ from ..modnef_arch_mod import ModNEFArchMod from ..utilities import * from math import log, ceil from .blif_debugger import BLif_Debugger +from modnef.quantizer import * _BLIF_DEFINITION = """ component BLif_{0} is @@ -110,7 +111,8 @@ class BLif(ModNEFArchMod): weight_fp : int = -1, mem_init_file : str = None, strategy : str = "Parallel", - variable_size : int = 16 + variable_size : int = 16, + quantizer = FixedPointQuantizer(8) ): """ Init attributes @@ -155,14 +157,7 @@ class BLif(ModNEFArchMod): self.beta = beta self.reset = reset - if compute_fp == -1: - self.compute_fp = weight_size - else: - self.compute_fp = compute_fp - - self.weight_size = weight_size - self.weight_type = weight_type - self.weight_fp = weight_fp + self.quantizer = quantizer if mem_init_file == None: self.mem_init_file = f"{self.name}_weight.mem" @@ -170,7 +165,9 @@ class BLif(ModNEFArchMod): self.mem_init_file = mem_init_file self._strategy = strategy - self.variable_size = variable_size + self.variable_size = 16 + + def vhdl_component_name(self): """ @@ -209,62 +206,39 @@ class BLif(ModNEFArchMod): output_path : str = "." memory file output path """ - - if self.weight_type != "w_signed" and self.weight_type != "w_unsigned" and self.weight_type != None: - print(f"{self.weight_type} is not supported") - return weights = weight_extraction(weights, self.input_neuron, self.output_neuron) - if self.weight_type == None or self.weight_fp == -1: - - w_min = min(min(weights)) - w_max = max(max(weights)) + if not self.quantizer.is_initialiaze: + self.quantizer.init_from_weight(weights) - if w_min < 0: - self.weight_type = "w_signed" - else: - self.weight_type = "w_unsigned" - - if self.weight_fp == -1: - - int_part = int(max(abs(w_min), abs(w_max))) - - if int_part==0: - fp = 0 - elif int_part==1: - fp = 1 - else: - fp = ceil(log(int_part)/log(2)) - - if self.weight_type == "w_signed": - self.weight_fp = self.weight_size-fp-1 - else: - self.weight_fp = self.weight_size-fp + bw = self.quantizer.bitwidth mem_file = open(f"{output_path}/{self.mem_init_file}", 'w') - if self.weight_type == "w_signed": + if self.quantizer.signed: for i in range(self.input_neuron): w_line = 0 for j in range(self.output_neuron-1, -1, -1): - w_line = (w_line<<self.weight_size) + two_comp(to_fixed_point(weights[i][j], self.weight_fp), self.weight_size) + w_line = (w_line<<bw) + two_comp(self.quantizer(weights[i][j]), bw) mem_file.write(f"@{to_hex(i)} {to_hex(w_line)}\n") - self.v_threshold = two_comp(to_fixed_point(self.v_threshold, self.compute_fp), self.variable_size) - self.beta = two_comp(to_fixed_point(self.beta, self.compute_fp), self.variable_size) + print(self.v_threshold) + self.v_threshold = two_comp(self.quantizer(self.v_threshold), self.variable_size) + print(self.v_threshold) + self.beta = two_comp(self.quantizer(self.beta), self.variable_size) - elif self.weight_type == "w_unsigned": + else: for i in range(self.input_neuron): w_line = 0 for j in range(self.output_neuron-1, -1, -1): - w_line = (w_line<<self.weight_size) + to_fixed_point(weights[i][j], self.weight_fp) + w_line = (w_line<<self.weight_size) + self.quantizer(weights[i][j]) mem_file.write(f"@{to_hex(i)} {to_hex(w_line)}\n") - self.v_threshold = to_fixed_point(self.v_threshold, self.compute_fp) - self.beta = to_fixed_point(self.beta, self.compute_fp) + self.v_threshold = self.quantizer(self.v_threshold) + self.beta = self.quantizer(self.beta, self.beta) mem_file.close() @@ -284,10 +258,10 @@ class BLif(ModNEFArchMod): v_threshold = self.v_threshold, beta = self.beta, reset = self.reset, - compute_fp = self.compute_fp, - weight_size = self.weight_size, - weight_type = self.weight_type, - weight_fp = self.weight_fp, + compute_fp = self.quantizer.fixed_point, + weight_size = self.quantizer.bitwidth, + weight_type = "w_signed" if self.quantizer.signed else "w_unsigned", + weight_fp = self.quantizer.fixed_point, mem_init_file = self.mem_init_file, output_file = output_file, variable_size=self.variable_size @@ -312,6 +286,8 @@ class BLif(ModNEFArchMod): if type(self.v_threshold) != int or type(self.beta) != int: print("neuron hyper parameters are not int. If you set hyper parameters as float, pleasse run weight_convert before calling to_vhdl") return + + wt = "w_signed" if self.quantizer.signed else "w_unsigned" vhdl_file.write(f"\t{self.name} : BLif_{self._strategy} generic map(\n") vhdl_file.write(f"\t\tinput_neuron => {self.input_neuron},\n") @@ -320,10 +296,10 @@ class BLif(ModNEFArchMod): vhdl_file.write(f"\t\tv_threshold => x\"{self._to_hex(self.v_threshold, self.variable_size)}\",\n") vhdl_file.write(f"\t\tbeta => x\"{self._to_hex(self.beta, self.variable_size)}\",\n") vhdl_file.write(f"\t\treset => \"{self.reset}\",\n") - vhdl_file.write(f"\t\tcompute_fp => {self.compute_fp},\n") - vhdl_file.write(f"\t\tweight_size => {self.weight_size},\n") - vhdl_file.write(f"\t\tweight_type => \"{self.weight_type}\",\n") - vhdl_file.write(f"\t\tweight_fp => {self.weight_fp},\n") + vhdl_file.write(f"\t\tcompute_fp => {self.quantizer.fixed_point},\n") + vhdl_file.write(f"\t\tweight_size => {self.quantizer.bitwidth},\n") + vhdl_file.write(f"\t\tweight_type => \"{wt}\",\n") + vhdl_file.write(f"\t\tweight_fp => {self.quantizer.fixed_point},\n") vhdl_file.write(f"\t\tmem_init_file => \"{self.mem_init_file}\"\n") vhdl_file.write("\t) port map(\n") vhdl_file.write(f"\t\ti_clk => {clock_name},\n") diff --git a/modneflib/modnef/arch_builder/modules/Debugger/__pycache__/__init__.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/Debugger/__pycache__/__init__.cpython-310.pyc index 0313b89029f0785da81763dd763cc417c34d4f12..25e0145301913abbb4a39ca94a8471c0f40cf179 100644 Binary files a/modneflib/modnef/arch_builder/modules/Debugger/__pycache__/__init__.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/Debugger/__pycache__/__init__.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/Debugger/__pycache__/probe.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/Debugger/__pycache__/probe.cpython-310.pyc index 025d27c86cb4916634bc580991341d7529948ff5..25e0bb87b8145505b169c6b8ba2936f67bde205f 100644 Binary files a/modneflib/modnef/arch_builder/modules/Debugger/__pycache__/probe.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/Debugger/__pycache__/probe.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/__init__.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/__init__.cpython-310.pyc index 4b8b352519bdebb320160c2186cdf940c56d2c37..65eb5bcbf3cdc42ec6d7af92fbfe3677f948e4f4 100644 Binary files a/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/__init__.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/__init__.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/rslif.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/rslif.cpython-310.pyc index 42585a42f7d9a759c0a2944307e4c36eaf589ed8..73460da7b9914ae52c0c423146306725426af7b9 100644 Binary files a/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/rslif.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/rslif.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/slif.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/slif.cpython-310.pyc index 2c3d72db63914c070c3bb611854ce6476686f01c..937248ad9c387cbd8ecf830f069bc71a1e05554e 100644 Binary files a/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/slif.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/slif.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/slif_debugger.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/slif_debugger.cpython-310.pyc index 8c54791368fe6ec77399d7eafcd1fa6da2ecf103..a3704fe76617ca12ee71efad2f51704a5e067ccc 100644 Binary files a/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/slif_debugger.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/SLIF/__pycache__/slif_debugger.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/ShiftLIF/__pycache__/__init__.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/ShiftLIF/__pycache__/__init__.cpython-310.pyc index 5b336006bc2d68f872a4292e44a989684ee8312d..566c9a8d094cc450019c1ae8e1266526df36ed4e 100644 Binary files a/modneflib/modnef/arch_builder/modules/ShiftLIF/__pycache__/__init__.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/ShiftLIF/__pycache__/__init__.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/ShiftLIF/__pycache__/rshiftlif.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/ShiftLIF/__pycache__/rshiftlif.cpython-310.pyc index 54c016a91cbfcf59741329fc4c576747f0053fea..a514ea545f6944369efcd3395d3fba18055971a0 100644 Binary files a/modneflib/modnef/arch_builder/modules/ShiftLIF/__pycache__/rshiftlif.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/ShiftLIF/__pycache__/rshiftlif.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/ShiftLIF/__pycache__/shiftlif.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/ShiftLIF/__pycache__/shiftlif.cpython-310.pyc index f7201157a18495b2dc6efe8e58d2ebb4f81bd79b..cb0fae8d68cdb31b003c4cfcf1e3c151633c9bd4 100644 Binary files a/modneflib/modnef/arch_builder/modules/ShiftLIF/__pycache__/shiftlif.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/ShiftLIF/__pycache__/shiftlif.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/UART/__pycache__/__init__.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/UART/__pycache__/__init__.cpython-310.pyc index 7aa1604b449f29837446d2f22b53a805f4b74b37..caf794d889f13849b091312521bce0911f238d47 100644 Binary files a/modneflib/modnef/arch_builder/modules/UART/__pycache__/__init__.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/UART/__pycache__/__init__.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_1step.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_1step.cpython-310.pyc index edc5d4ea2f5a0ebef07f8f16f02a0ad9c7a74ae9..221fc388f22d486030d600675fe0a88dc0c33cd2 100644 Binary files a/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_1step.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_1step.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_classifier.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_classifier.cpython-310.pyc index 1031f5807b624699fe65cf0e3423a0c6d8b74442..668ad4a56fed0cf22c12fcd057809647baf5af89 100644 Binary files a/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_classifier.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_classifier.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_classifier_timer.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_classifier_timer.cpython-310.pyc index 897da078dec9b61ae3e492a84cf343cd4a94f887..74223ffeb02f0c6bacebe3d309351239a8fab1e3 100644 Binary files a/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_classifier_timer.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_classifier_timer.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_xstep.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_xstep.cpython-310.pyc index e2b148f4a5ea72035d5422a1e2d2770232092533..d8d74e917b06fc1db3e7eaf426fa73fd8fba6aea 100644 Binary files a/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_xstep.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_xstep.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_xstep_timer.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_xstep_timer.cpython-310.pyc index 16115cffb25cfc60343cb1f99576c213c47ba0ed..051d4095987dafa41608a9c67b4557f963df061e 100644 Binary files a/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_xstep_timer.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/UART/__pycache__/uart_xstep_timer.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/__pycache__/__init__.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/__pycache__/__init__.cpython-310.pyc index a51edfc92ae452cb40440d421be6bec3f0d7c74d..72a993f3c9da75932ff9f49c3e4830e5803001a4 100644 Binary files a/modneflib/modnef/arch_builder/modules/__pycache__/__init__.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/__pycache__/__init__.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/__pycache__/io_arch.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/__pycache__/io_arch.cpython-310.pyc index 4d96392ddfe15b191e182cd3aa304e5a41212ef9..245dadd6fd8be725f0c0f18da05b6b92521675e7 100644 Binary files a/modneflib/modnef/arch_builder/modules/__pycache__/io_arch.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/__pycache__/io_arch.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/__pycache__/merger.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/__pycache__/merger.cpython-310.pyc index f21c44887ddbbadd156e313ba6709699a2eebe3d..7dc9c21898d101f136ca404b4df54ddd5f727362 100644 Binary files a/modneflib/modnef/arch_builder/modules/__pycache__/merger.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/__pycache__/merger.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/__pycache__/modnef_arch_mod.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/__pycache__/modnef_arch_mod.cpython-310.pyc index dbd537fe9a3c3c215a0a421d119a235811f28397..f68f888e954b83aa933c071c7741bc21f8c53723 100644 Binary files a/modneflib/modnef/arch_builder/modules/__pycache__/modnef_arch_mod.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/__pycache__/modnef_arch_mod.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/__pycache__/splitter.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/__pycache__/splitter.cpython-310.pyc index 3d1e766bf9ec8f673aa84f47da0bd003c979baa8..fe45a069bca6b68aa714915b24fb9d5ceab09e4a 100644 Binary files a/modneflib/modnef/arch_builder/modules/__pycache__/splitter.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/__pycache__/splitter.cpython-310.pyc differ diff --git a/modneflib/modnef/arch_builder/modules/__pycache__/utilities.cpython-310.pyc b/modneflib/modnef/arch_builder/modules/__pycache__/utilities.cpython-310.pyc index d5d3137b5a44eddfb4553d6c6b4cff1640631648..3ad0426bbf0a93aece2ced26b98ee31e402b62f2 100644 Binary files a/modneflib/modnef/arch_builder/modules/__pycache__/utilities.cpython-310.pyc and b/modneflib/modnef/arch_builder/modules/__pycache__/utilities.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_driver/__pycache__/__init__.cpython-310.pyc b/modneflib/modnef/modnef_driver/__pycache__/__init__.cpython-310.pyc index cbc1e081252e5e639174f5ae3c33e76252839f87..ea62a78b0cb5b140f962fdeb196748167aaac299 100644 Binary files a/modneflib/modnef/modnef_driver/__pycache__/__init__.cpython-310.pyc and b/modneflib/modnef/modnef_driver/__pycache__/__init__.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_driver/__pycache__/modnef_drivers.cpython-310.pyc b/modneflib/modnef/modnef_driver/__pycache__/modnef_drivers.cpython-310.pyc index d643ce5865d1ad4547af351f25fb6b123e8797fa..d16a933fde5112586c1e0be457d7f0d24a37b790 100644 Binary files a/modneflib/modnef/modnef_driver/__pycache__/modnef_drivers.cpython-310.pyc and b/modneflib/modnef/modnef_driver/__pycache__/modnef_drivers.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_driver/drivers/__pycache__/__init__.cpython-310.pyc b/modneflib/modnef/modnef_driver/drivers/__pycache__/__init__.cpython-310.pyc index 063a6d8e0a1751a5009e9a0755b0c7d49d8f2d98..d9a92dd63e49b0cfa5f9c3431d3cbbaa52dfe048 100644 Binary files a/modneflib/modnef/modnef_driver/drivers/__pycache__/__init__.cpython-310.pyc and b/modneflib/modnef/modnef_driver/drivers/__pycache__/__init__.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/__pycache__/__init__.cpython-310.pyc b/modneflib/modnef/modnef_torch/__pycache__/__init__.cpython-310.pyc index d06a4e4b651d758c194df0cea4679c6ff91ca428..19f7ef27a5cc1bde43e8816a7cb74b492a48f2ef 100644 Binary files a/modneflib/modnef/modnef_torch/__pycache__/__init__.cpython-310.pyc and b/modneflib/modnef/modnef_torch/__pycache__/__init__.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/__pycache__/executor.cpython-310.pyc b/modneflib/modnef/modnef_torch/__pycache__/executor.cpython-310.pyc index 844b2557ea78de0a6ee1b411339dc20adb1a169f..38bb176fbb8555dadcc2f704b42be2172e1331eb 100644 Binary files a/modneflib/modnef/modnef_torch/__pycache__/executor.cpython-310.pyc and b/modneflib/modnef/modnef_torch/__pycache__/executor.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/__pycache__/model.cpython-310.pyc b/modneflib/modnef/modnef_torch/__pycache__/model.cpython-310.pyc index d60b785a7b6cca32485dcbd426f83c4876d8e5c1..8ff8fe4de12d2329a5991d47d728d93f45554413 100644 Binary files a/modneflib/modnef/modnef_torch/__pycache__/model.cpython-310.pyc and b/modneflib/modnef/modnef_torch/__pycache__/model.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/__pycache__/trainer.cpython-310.pyc b/modneflib/modnef/modnef_torch/__pycache__/trainer.cpython-310.pyc index 6bc1a750c9e0f5dee467c12d6546e91b75b4bce1..b8b000b1c9b25553fcca13173f5f082ed6f80376 100644 Binary files a/modneflib/modnef/modnef_torch/__pycache__/trainer.cpython-310.pyc and b/modneflib/modnef/modnef_torch/__pycache__/trainer.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/executor.py b/modneflib/modnef/modnef_torch/executor.py index a1234211143c63f99f726ab7efafa4580323e437..4a75d39ee0ccc539f93069b8865fde07838d1048 100644 --- a/modneflib/modnef/modnef_torch/executor.py +++ b/modneflib/modnef/modnef_torch/executor.py @@ -159,7 +159,6 @@ class ModNEFExecutor(): train_config = { "n_epoch" : 5, - "step_save" : -1, "save_best_model" : True, "save_history" : True, "plot" : True, @@ -174,7 +173,6 @@ class ModNEFExecutor(): testLoader=self.testLoader, validationLoader=self.validationLoader, n_epoch=train_config["n_epoch"], - step_save=train_config["step_save"], save_best_model=train_config["save_best_model"], best_model_name=self.best_model_name ) @@ -235,8 +233,7 @@ class ModNEFExecutor(): accuracy, y_pred, y_true = self.runner.hardware_estimation( testLoader=self.testLoader, - name=he_config["name"], - conf_matrix=he_config["conf_matrix_class"] + name=he_config["name"] ) if he_config["conf_matrix"]: @@ -271,8 +268,7 @@ class ModNEFExecutor(): accuracy, y_pred, y_true = self.runner.accuracy( testLoader=self.testLoader, - name=eval_config["name"], - conf_matrix=eval_config["conf_matrix_class"] + name=eval_config["name"] ) if eval_config["conf_matrix"]: @@ -315,7 +311,7 @@ class ModNEFExecutor(): fpga_config = { "name" : "FPGA Eval", - "driver_file" : "driver.yml", + "driver_config" : "", "board_path" : "", "conf_matrix" : False, "conf_matrix_class" : [] @@ -331,8 +327,7 @@ class ModNEFExecutor(): name=fpga_config["name"], testLoader=self.testLoader, board_path=fpga_config["board_path"], - driver_path=f"{self.output_path}/{fpga_config['driver_file']}", - conf_matrix=fpga_config["conf_matrix_class"] + driver_path=f"{self.output_path}/{fpga_config['driver_config']}" ) if fpga_config["conf_matrix"]: diff --git a/modneflib/modnef/modnef_torch/modnef_neurons/__pycache__/__init__.cpython-310.pyc b/modneflib/modnef/modnef_torch/modnef_neurons/__pycache__/__init__.cpython-310.pyc index bdf280b17bc37b26bd5d68650f91c7c7912058d0..627ee9f64f81474b17a5bef807e2c3c8c22526f3 100644 Binary files a/modneflib/modnef/modnef_torch/modnef_neurons/__pycache__/__init__.cpython-310.pyc and b/modneflib/modnef/modnef_torch/modnef_neurons/__pycache__/__init__.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/modnef_neurons/__pycache__/modnef_torch_neuron.cpython-310.pyc b/modneflib/modnef/modnef_torch/modnef_neurons/__pycache__/modnef_torch_neuron.cpython-310.pyc index d658e975ee0e92c7e7ebc69f78326b42da79b877..f26d3e0fda92d6cb8af14786b53848a0e8ef9259 100644 Binary files a/modneflib/modnef/modnef_torch/modnef_neurons/__pycache__/modnef_torch_neuron.cpython-310.pyc and b/modneflib/modnef/modnef_torch/modnef_neurons/__pycache__/modnef_torch_neuron.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/__pycache__/__init__.cpython-310.pyc b/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/__pycache__/__init__.cpython-310.pyc index 829c917976b2b648660d27dd7f7d5092f33094db..594e6978c95b009fc8d7f0e6a145abf78ff24ffd 100644 Binary files a/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/__pycache__/__init__.cpython-310.pyc and b/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/__pycache__/__init__.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/__pycache__/blif.cpython-310.pyc b/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/__pycache__/blif.cpython-310.pyc index c92436ae86ab9fd99d8b250f8466bc91b7936ce1..e535ed2f81ceddb68b47ab69c7383a3d115b9a04 100644 Binary files a/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/__pycache__/blif.cpython-310.pyc and b/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/__pycache__/blif.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/__pycache__/rblif.cpython-310.pyc b/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/__pycache__/rblif.cpython-310.pyc index 657c4c99b4e80642a3f0866776704e1a24bd4f0a..3d8cbdeb81aab586d09ef7d40d314b0054d76798 100644 Binary files a/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/__pycache__/rblif.cpython-310.pyc and b/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/__pycache__/rblif.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/blif.py b/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/blif.py index 9033906f2bbd904860627dd25573214d30b8516f..959bc20527bfe981e8f941d0f3fc9e690940cc26 100644 --- a/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/blif.py +++ b/modneflib/modnef/modnef_torch/modnef_neurons/blif_model/blif.py @@ -16,6 +16,7 @@ from snntorch import Leaky import modnef.arch_builder as builder from modnef.arch_builder.modules.utilities import * from ..modnef_torch_neuron import ModNEFNeuron +from modnef.quantizer import * class BLIF(Leaky, ModNEFNeuron): """ @@ -94,7 +95,8 @@ class BLIF(Leaky, ModNEFNeuron): beta, threshold=1.0, spike_grad=None, - reset_mechanism="subtract" + reset_mechanism="subtract", + quantizer=FixedPointQuantizer(8) ): """ Initialize class @@ -138,6 +140,8 @@ class BLIF(Leaky, ModNEFNeuron): self._init_mem() + self.quantizer = quantizer + self.hardware_description = { "strategy" : "Parallel", "weight_size" : 8, @@ -191,7 +195,7 @@ class BLIF(Leaky, ModNEFNeuron): Returns ------- - tuple of Tensor + tuple of Tensorquantizer spk, mem """ @@ -242,8 +246,8 @@ class BLIF(Leaky, ModNEFNeuron): self.mem = torch.zeros_like(input_, device=self.mem.device) if self.hardware_estimation_flag: - input_.data = self.__quant(input_.data, self.hardware_description["compute_fp"]) - self.mem.data = self.__quant(self.mem.data, self.hardware_description["compute_fp"]) + input_.data = self.quantizer(input_.data, True) + self.mem.data = self.quantizer(self.mem.data, True) self.reset = self.mem_reset(self.mem) @@ -300,7 +304,8 @@ class BLIF(Leaky, ModNEFNeuron): compute_fp=self.hardware_description["compute_fp"], mem_init_file=self.hardware_description["mem_init_file"], strategy=self.hardware_description["strategy"], - variable_size=self.hardware_description["variable_size"] + variable_size=self.hardware_description["variable_size"], + quantizer=self.quantizer ) module.weight_convert( @@ -310,30 +315,7 @@ class BLIF(Leaky, ModNEFNeuron): ) return module - def __quant(self, data, fp, dtype = torch.int32): - """ - Internal quantization function - - Parameters - ---------- - data : Tensor - input tensor to quantize - fp : int - fixed point position - type = torch.int32 : dtype - type use during quantization - - Returns - ------- - Tensor - """ - - scale_factor = 2**fp - scaled_data = (data*scale_factor).to(dtype) - unscaled_data = scaled_data.to(torch.float32)/scale_factor - return unscaled_data - - def quantize_weight(self, size=-1, fp=-1, dtype=torch.int32): + def quantize_weight(self, dtype=torch.int32): """ Quantize synaptic weight @@ -348,37 +330,11 @@ class BLIF(Leaky, ModNEFNeuron): dtype = torch.int32 : dtype type use during quantization """ + self.quantizer.init_from_weight(self.fc.weight) - if self.hardware_description["weight_type"]==None: - if self.fc.weight.min().item() < 0.0: - self.hardware_description["weight_type"] = "w_signed" - else: - self.hardware_description["weight_type"] = "w_unsigned" - - if size != -1: - self.hardware_description["weight_size"] = size - - if fp==-1: - fp=self.hardware_description["weight_fp"] - - if fp==-1: - w_min = self.fc.weight.min().item() - w_max = self.fc.weight.max().item() - int_part = int(max(abs(w_max), abs(w_min))) - - if int_part > 1: - int_part = ceil(log(int_part)/log(2)) - - if self.hardware_description["weight_type"] == "w_signed": - self.hardware_description["weight_fp"] = self.hardware_description["weight_size"]-int_part-1 - else: - self.hardware_description["weight_fp"] = self.hardware_description["weight_size"]-int_part - else: - self.hardware_description["weight_fp"]=fp - - self.fc.weight.data = self.__quant(self.fc.weight.data, self.hardware_description["weight_fp"], dtype) + self.fc.weight.data = self.quantizer(self.fc.weight.data, True, dtype) - def quantize_parameters(self, fp=-1, dtype=torch.int32): + def quantize_parameters(self, dtype=torch.int32): """ Quantize neuron hyper-parameters @@ -391,19 +347,10 @@ class BLIF(Leaky, ModNEFNeuron): type use during quantization """ - if fp ==-1: - if self.hardware_description["compute_fp"]==-1: - if self.hardware_description["weight_size"]==-1: - raise Exception("Impossible to fix quantization value, please fix the point position") - else: - self.hardware_description["compute_fp"] = self.hardware_description["weight_size"] - else: - self.hardware_description["compute_fp"]=fp - - self.threshold.data = self.__quant(self.threshold.data, self.hardware_description["compute_fp"], dtype) - self.beta.data = self.__quant(self.beta.data, self.hardware_description["compute_fp"], dtype) + self.threshold.data = self.quantizer(self.threshold.data, True, dtype) + self.beta.data = self.quantizer(self.beta.data, True, dtype) - def quantize(self, weight_size=-1, weight_fp=-1, compute_fp=-1, dtype=torch.int32): + def quantize(self, dtype=torch.int32): """ Quantize synaptic weight and neuron hyper-parameters @@ -422,8 +369,8 @@ class BLIF(Leaky, ModNEFNeuron): type use during quantization """ - self.quantize_weight(weight_size, weight_fp, dtype) - self.quantize_parameters(compute_fp, dtype) + self.quantize_weight(dtype) + self.quantize_parameters(dtype) @classmethod def detach_hidden(cls): diff --git a/modneflib/modnef/modnef_torch/modnef_neurons/slif_model/__pycache__/__init__.cpython-310.pyc b/modneflib/modnef/modnef_torch/modnef_neurons/slif_model/__pycache__/__init__.cpython-310.pyc index 5d278f77bee4424d05d152cf1cc01563949e8e69..8784ad2e7036bca003137e0c71cb73799cd6bbf1 100644 Binary files a/modneflib/modnef/modnef_torch/modnef_neurons/slif_model/__pycache__/__init__.cpython-310.pyc and b/modneflib/modnef/modnef_torch/modnef_neurons/slif_model/__pycache__/__init__.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/modnef_neurons/slif_model/__pycache__/rslif.cpython-310.pyc b/modneflib/modnef/modnef_torch/modnef_neurons/slif_model/__pycache__/rslif.cpython-310.pyc index 5911ecaa006ced8825be3cdf2dbf92295946c564..fa994e037c22b88e892e363aa046f45f535fbab0 100644 Binary files a/modneflib/modnef/modnef_torch/modnef_neurons/slif_model/__pycache__/rslif.cpython-310.pyc and b/modneflib/modnef/modnef_torch/modnef_neurons/slif_model/__pycache__/rslif.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/modnef_neurons/slif_model/__pycache__/slif.cpython-310.pyc b/modneflib/modnef/modnef_torch/modnef_neurons/slif_model/__pycache__/slif.cpython-310.pyc index cb03f6ba9b5426f0196803f517f16ef5300f5f9f..b4b08468acd0513057cf39e35882417a2c7ababc 100644 Binary files a/modneflib/modnef/modnef_torch/modnef_neurons/slif_model/__pycache__/slif.cpython-310.pyc and b/modneflib/modnef/modnef_torch/modnef_neurons/slif_model/__pycache__/slif.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/modnef_neurons/srlif_model/__pycache__/__init__.cpython-310.pyc b/modneflib/modnef/modnef_torch/modnef_neurons/srlif_model/__pycache__/__init__.cpython-310.pyc index b0d94c36d8094814dcfa4056130323bffdb3350d..1d1cc1681fe19e3794fdf5d7aff3a0dd34eb8c13 100644 Binary files a/modneflib/modnef/modnef_torch/modnef_neurons/srlif_model/__pycache__/__init__.cpython-310.pyc and b/modneflib/modnef/modnef_torch/modnef_neurons/srlif_model/__pycache__/__init__.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/modnef_neurons/srlif_model/__pycache__/rshiftlif.cpython-310.pyc b/modneflib/modnef/modnef_torch/modnef_neurons/srlif_model/__pycache__/rshiftlif.cpython-310.pyc index a7676b86d5c6c7ba5eb842b2ce2246eda2ca81fc..101b33dc0d90cc1a0cb9b8dffff13f51bdcc4f93 100644 Binary files a/modneflib/modnef/modnef_torch/modnef_neurons/srlif_model/__pycache__/rshiftlif.cpython-310.pyc and b/modneflib/modnef/modnef_torch/modnef_neurons/srlif_model/__pycache__/rshiftlif.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/modnef_neurons/srlif_model/__pycache__/shiftlif.cpython-310.pyc b/modneflib/modnef/modnef_torch/modnef_neurons/srlif_model/__pycache__/shiftlif.cpython-310.pyc index 645dd493bfb9d1e28d3f52078cc80096ae869f98..a93ed5d912f83e9b970a05c3053afac8b7e89f3f 100644 Binary files a/modneflib/modnef/modnef_torch/modnef_neurons/srlif_model/__pycache__/shiftlif.cpython-310.pyc and b/modneflib/modnef/modnef_torch/modnef_neurons/srlif_model/__pycache__/shiftlif.cpython-310.pyc differ diff --git a/modneflib/modnef/modnef_torch/trainer.py b/modneflib/modnef/modnef_torch/trainer.py index de8639dc3d9fdeafd84727b2f878424b0b0a2018..9bc8b764def6a89e8cce32b9a737ae70758ce156 100644 --- a/modneflib/modnef/modnef_torch/trainer.py +++ b/modneflib/modnef/modnef_torch/trainer.py @@ -19,8 +19,63 @@ import numpy as np class ModNEFTrainer(): - - def __init__(self, model, optimizer=None, loss=None, device=None, verbose=False, output_path="."): + """ + ModNEF Model Trainer + + Attributes + ---------- + model : ModNEFModel + modnef network model + optimizer : + trainer optimizer + loss : + loss function + device : + torch device + verbose : bool + verbose mod + output_path str + output file path (step save or best model) + + Methods + ------- + train_1_epoch(trainLoader) + Train network for one epoch + train(trainLoader, testLoader, validationLoader, n_epoch, save_best_model, best_model_name) + Train network + accuracy(testLoader, name) + Run software inference + hardware_estimation(testLoader, name) + Run hardware estimation inference + fpga_accuracy(testLoader, board_path, driver_path, name) + Run FPGA inference + """ + + def __init__(self, + model, + optimizer=None, + loss=None, + device=None, + verbose=False, + output_path="." + ): + """ + model : ModNEFModel | dict + ModNEF network model or dictionnary description of model + optimizer = None + trainer optimizer + If None, setup Adam Optimizer + loss = None + loss function + If None, CrossEntropyLoss is use + device = None + torch device + If None, detected automatically depending on cuda core detected or not + verbose = Fasle : bool + verbose mode + output_path = "." : str + output file path + """ if type(model) != ModNEFModel: self.model = ModNEFModel(model) @@ -46,33 +101,20 @@ class ModNEFTrainer(): self.output_path=output_path - self.y_true = [] - self.y_pred = [] - - @classmethod - def load_config(cls, config): - - model = ModNEFModel(config["model"]) - optimizer = torch.optim.Adam(model.parameters(), lr=(config["optimizer"]["lr"]), betas=config["optimizer"]["betas"]) - loss = nn.CrossEntropyLoss() - verbose = config["verbose"] - - return cls( - model=model, - optimizer=optimizer, - loss=loss, - verbose=verbose - ) - - def load_checkpoint(self, path): - - checkpoint = torch.load(path) + def train_1_epoch(self, trainLoader): + """ + Train network for one epoch - self.model.load_state_dict(checkpoint["model"]) - self.optimizer.load_state_dict(checkpoint["optimizer"]) - self.loss.load_state_dict(checkpoint["loss"]) + Parameters + ---------- + trainLoader + train dataset loader - def train_1_epoch(self, trainLoader): + Returns + ------- + float + Average epoch loss + """ epoch_loss = [] @@ -108,8 +150,36 @@ class ModNEFTrainer(): return np.mean(epoch_loss) - def train(self, trainLoader, testLoader, n_epoch=50, validationLoader=None, step_save=-1, save_best_model=True, best_model_name = ""): - + def train(self, trainLoader, testLoader, validationLoader=None, n_epoch=50, save_best_model=True, best_model_name = ""): + """ + Train network + + Parameters + ---------- + trainLoader + train dataset loader + testLoader + test dataset loader + validationLoader=None + validation dataset loader + If None, validation is ignored + n_epoch=50 : int + number of epoch + save_best_model=True : bool + set to true if best accuracy model must be save + best_model_name="" : str + best model file name + if default, name = best_{model.name} + + Returns + ------- + (list, list, list, float) + average loss through epoch + test accuracy through epoch + validation accuracy through epoch + best accuracy + """ + avg_loss_history = [] acc_test_history = [] acc_val_history = [] @@ -135,24 +205,33 @@ class ModNEFTrainer(): acc_val, _, _ = self.accuracy(testLoader=validationLoader, name="Validation") acc_val_history.append(acc_val) - acc_test, self.y_pred, self.y_true = self.accuracy(testLoader=testLoader, name="Test") + acc_test, _, _ = self.accuracy(testLoader=testLoader, name="Test") acc_test_history.append(acc_test) if save_best_model and acc_test>best_acc: torch.save(self.model.state_dict(), f"{self.output_path}/best_{self.model.name}") best_acc = acc_test - if step_save!=-1 and epoch%step_save==0: - checkpoint = { - "model" : self.model.state_dict(), - "loss" : self.loss.state_dict(), - "optimizer" : self.optimizer.state_dict() - } - torch.save(checkpoint, f"{self.output_path}/{self.model.name}_step_save") - return avg_loss_history, acc_val_history, acc_test_history, best_acc - def __run_accuracy(self, testLoader, name, conf_matrix=[]): + def __run_accuracy(self, testLoader, name): + """ + Run inference + + Parameters + ---------- + testLoader + test dataset loader + name : str + name of inference + + Returns + ------- + (float, list, list) + accuracy + predicted class + true class + """ y_true = [] y_pred = [] @@ -191,7 +270,24 @@ class ModNEFTrainer(): return (correct/total), y_pred, y_true - def accuracy(self, testLoader, name="Test", conf_matrix=[]): + def accuracy(self, testLoader, name="Test"): + """ + Run software inference + + Parameters + ---------- + testLoader + test dataset loader + name="Test" : str + name of inference + + Returns + ------- + (float, list, list) + accuracy + predicted class + true class + """ accuracy = 0 y_pred = [] @@ -199,22 +295,62 @@ class ModNEFTrainer(): self.model.eval() - accuracy, y_pred, y_true = self.__run_accuracy(testLoader=testLoader, name=name, conf_matrix=conf_matrix) + accuracy, y_pred, y_true = self.__run_accuracy(testLoader=testLoader, name=name) return accuracy, y_pred, y_true - def hardware_estimation(self, testLoader, name="Hardware Estimation", conf_matrix=[]): + def hardware_estimation(self, testLoader, name="Hardware Estimation"): + """ + Run hardware estimation inference + + Parameters + ---------- + testLoader + test dataset loader + name="Hardware Estimation" : str + name of inference + + Returns + ------- + (float, list, list) + accuracy + predicted class + true class + """ + accuracy = 0 y_pred = [] y_true = [] self.model.hardware_estimation() - accuracy, y_pred, y_true = self.__run_accuracy(testLoader=testLoader, name=name, conf_matrix=conf_matrix) + accuracy, y_pred, y_true = self.__run_accuracy(testLoader=testLoader, name=name) return accuracy, y_pred, y_true - def fpga_accuracy(self, testLoader, board_path, driver_path = "./driver.yml", name="FPGA eval", conf_matrix=[]): + def fpga_accuracy(self, testLoader, board_path, driver_path = "./driver.yml", name="FPGA eval"): + """ + Run FPGA inference + + Parameters + ---------- + testLoader + test dataset loader + board_path : str + path to FPGA UART path + driver_path = "./driver.yml" : str + driver configuration file + name = "FPGA eval" : str + name of inference + + Returns + ------- + (float, list, list) + accuracy + predicted class + true class + """ + accuracy = 0 y_pred = [] y_true = [] @@ -225,7 +361,7 @@ class ModNEFTrainer(): self.device = torch.device("cpu") - accuracy, y_pred, y_true = self.__run_accuracy(testLoader=testLoader, name=name, conf_matrix=conf_matrix) + accuracy, y_pred, y_true = self.__run_accuracy(testLoader=testLoader, name=name) self.device = last_device diff --git a/modneflib/modnef/quantizer/__init__.py b/modneflib/modnef/quantizer/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..71f898cdcd275c7ee455c6fb7063a7de5ee7fa88 --- /dev/null +++ b/modneflib/modnef/quantizer/__init__.py @@ -0,0 +1,5 @@ + +from .quantizer import Quantizer +from .fixed_point_quantizer import FixedPointQuantizer +from .min_max_quantizer import MinMaxQuantizer +from .dynamic_scale_quantizer import DynamicScaleFactorQuantizer \ No newline at end of file diff --git a/modneflib/modnef/quantizer/dynamic_scale_quantizer.py b/modneflib/modnef/quantizer/dynamic_scale_quantizer.py new file mode 100644 index 0000000000000000000000000000000000000000..d5e54030e06804c1ab20e8b6ac878727a32ae208 --- /dev/null +++ b/modneflib/modnef/quantizer/dynamic_scale_quantizer.py @@ -0,0 +1,37 @@ +import torch +import numpy as np +from .quantizer import Quantizer + +class DynamicScaleFactorQuantizer(Quantizer): + + def __init__(self, bitwidth, signed=None, is_initialize=False): + + super().__init__( + bitwidth=bitwidth, + signed=signed, + is_initialize=is_initialize + ) + + self.scale_factor = 0 + + def init_from_weight(self, weight, rec_weight=torch.zeros((1))): + + self.is_initialiaze = True + + if self.signed==None: + self.signed = torch.min(weight.min(), rec_weight.min())<0.0 + + self.scale_factor = torch.max(torch.abs(weight).max(), torch.abs(weight).max())/2**(self.bitwidth-1) + + + def _quant(self, data, unscale, dtype) -> torch.Tensor: + + born_min = -int(self.signed)*2**(self.bitwidth-1) + born_max = 2**(self.bitwidth-int(self.signed))-1 + + scaled = torch.clamp(data/self.scale_factor, min=born_min, max=born_max).to(dtype) + + if unscale: + return scaled*self.scale_factor + else: + return scaled \ No newline at end of file diff --git a/modneflib/modnef/quantizer/fixed_point_quantizer.py b/modneflib/modnef/quantizer/fixed_point_quantizer.py new file mode 100644 index 0000000000000000000000000000000000000000..8471872a166b11de44a9423b95565bc42811edde --- /dev/null +++ b/modneflib/modnef/quantizer/fixed_point_quantizer.py @@ -0,0 +1,56 @@ +import torch +from math import ceil, log +from .quantizer import Quantizer + +class FixedPointQuantizer(Quantizer): + + def __init__(self, bitwidth, fixed_point=-1, signed=None, is_initialize=False): + + if bitwidth==-1 and fixed_point==-1: + raise Exception("You must fix at least one value to compute the other one") + + super().__init__( + bitwidth=bitwidth, + signed=signed, + is_initialize=is_initialize + ) + + self.fixed_point = fixed_point + self.scale_factor = 2**fixed_point + + def init_from_weight(self, weight, rec_weight=torch.zeros((1))): + + self.is_initialiaze = True + + if not torch.is_tensor(weight): + weight = torch.Tensor(weight) + + if not torch.is_tensor(rec_weight): + rec_weight = torch.Tensor(rec_weight) + + if self.signed==None: + self.signed = torch.min(weight.min(), rec_weight.min())<0.0 + + if self.fixed_point==-1: + int_max = int(torch.max(torch.abs(weight).max(), torch.abs(rec_weight).max())) + + if int_max>1: + int_part_size = ceil(log(int_max)/log(2))+int(self.signed) + else: + int_part_size = int_max + + if self.bitwidth==-1: + self.bitwidth = int_part_size+self.fixed_point + elif self.fixed_point==-1: + self.fixed_point = self.bitwidth-int_part_size + self.scale_factor = 2**self.fixed_point + + + def _quant(self, data, unscale, dtype) -> torch.Tensor: + + scaled = torch.round(data*self.scale_factor).to(dtype) + + if unscale: + return (scaled.to(torch.float32))/self.scale_factor + else: + return scaled \ No newline at end of file diff --git a/modneflib/modnef/quantizer/min_max_quantizer.py b/modneflib/modnef/quantizer/min_max_quantizer.py new file mode 100644 index 0000000000000000000000000000000000000000..cc02ff3fd4ad336bacf9e7cf702fb009b69fcc31 --- /dev/null +++ b/modneflib/modnef/quantizer/min_max_quantizer.py @@ -0,0 +1,40 @@ +import torch +from math import ceil, log +from .quantizer import Quantizer + +class MinMaxQuantizer(Quantizer): + + def __init__(self, bitwidth, signed=None, is_initialize=False): + + super().__init__( + bitwidth=bitwidth, + signed=signed, + is_initialize=is_initialize + ) + + self.x_min = 0 + self.x_max = 0 + self.b_min = 0 + self.b_max = 0 + + def init_from_weight(self, weight, rec_weight=torch.zeros((1))): + + self.is_initialiaze = True + + if self.signed==None: + self.signed = torch.min(weight.min(), rec_weight.min())<0.0 + + self.x_max = torch.max(torch.abs(weight).max(), torch.abs(rec_weight).max()) + self.x_min = -self.x_max + + self.b_max = 2**(self.bitwidth-int(self.signed))-1 + self.b_min = -int(self.signed)*self.b_max + + def _quant(self, data, unscale, dtype) -> torch.Tensor: + + scaled = ((data-self.x_min)/(self.x_max-self.x_min)*(self.b_max-self.b_min)+self.b_min).to(dtype) + + if unscale: + return (scaled-self.b_min)/(self.b_max-self.b_min)*(self.x_max-self.x_min)+self.x_min + else: + return scaled \ No newline at end of file diff --git a/modneflib/modnef/quantizer/quantizer.py b/modneflib/modnef/quantizer/quantizer.py new file mode 100644 index 0000000000000000000000000000000000000000..f8c6ae8e95870d8da99283999f7edab2d32a6d51 --- /dev/null +++ b/modneflib/modnef/quantizer/quantizer.py @@ -0,0 +1,29 @@ +import torch +import numpy as np + +class Quantizer(): + + def __init__(self, bitwidth, signed=None, is_initialize=False): + self.bitwidth = bitwidth + self.is_initialiaze = is_initialize + self.signed = signed + pass + + def init_from_weight(self, weight, rec_weight=torch.zeros((1))): + raise NotImplementedError() + + def __call__(self, data, unscale=False, dtype=torch.int32): + + if isinstance(data, (int, float)): + return self._quant(data=torch.tensor(data), unscale=unscale, dtype=dtype).item() + elif isinstance(data, list): + return self._quant(data=torch.tensor(data), unscale=unscale, dtype=dtype).tolist() + elif isinstance(data, np.ndarray): + return self._quant(data=torch.tensor(data), unscale=unscale, dtype=dtype).numpy() + elif torch.is_tensor(data): + return self._quant(data=data, unscale=unscale, dtype=dtype).detach() + else: + raise TypeError("Unsupported data type") + + def _quant(self, data, unscale, dtype) -> torch.Tensor: + pass \ No newline at end of file diff --git a/modneflib/modnef/templates/template_model.json b/modneflib/modnef/templates/template_model.json index ff70dadea9b322c001f6bce578a3980bdd5e10e1..4b91fca4c13f9d15560e661aadd996ef38475e9f 100644 --- a/modneflib/modnef/templates/template_model.json +++ b/modneflib/modnef/templates/template_model.json @@ -85,7 +85,6 @@ "train" : { "name" : "Train", "n_epoch" : 5, - "step_save" : -1, "save_best_model" : true, "save_history" : true, "plot" : true @@ -104,7 +103,7 @@ }, "vhdl" : { - "best_model" : false, + "use_best_model" : false, "driver_config" : "driver.yml", "file_name" : null }, @@ -112,7 +111,7 @@ "fpga" : { "name" : "FPGA Evaluation", "driver_file" : "driver.yml", - "board_path" : "/dev/serial/by-id/usb-FTDI_FT232R_USB_UART_A10OOCRD-if00-port0", + "board_path" : "board path here", "conf_matrix" : true }, diff --git a/modneflib/setup.py b/modneflib/setup.py index 5e185d791e71a62e13b16943218eafb006deee69..23a3b1f460c1803b328cd84643cfa39546ab8ab4 100644 --- a/modneflib/setup.py +++ b/modneflib/setup.py @@ -6,7 +6,7 @@ setup( version = "1.0.0", description="ModNEF python librairy", author="Aurelie Saulquin", - install_requires=["networkx", "matplotlib", "pyyaml"], + install_requires=["networkx", "matplotlib", "pyyaml", "torch", "snntorch"], include_package_data=True, entry_points={ "console_scripts": [ diff --git a/q b/q new file mode 100644 index 0000000000000000000000000000000000000000..fbd676e4aac9fa26bc87b9d12e88a90f8b3dbcf5 --- /dev/null +++ b/q @@ -0,0 +1,30 @@ +[33m218057c[m[33m ([m[1;36mHEAD -> [m[1;32mreccursive[m[33m)[m HEAD@{0}: commit (amend): add documetnation +[33m5bcbbb3[m HEAD@{1}: commit: add documetnation +[33mb1eb462[m HEAD@{2}: checkout: moving from 0bc064ec20991666693711d2536c114401b1cd4b to reccursive +[33m0bc064e[m[33m ([m[1;31morigin/main[m[33m, [m[1;31morigin/HEAD[m[33m, [m[1;32mmain[m[33m)[m HEAD@{3}: checkout: moving from reccursive to origin +[33mb1eb462[m HEAD@{4}: checkout: moving from 6dd9be60953a44154688db676a661977eab27b18 to reccursive +[33m6dd9be6[m HEAD@{5}: commit: add quantizer and documentation +[33m1d84d66[m[33m ([m[1;31morigin/reccursive[m[33m)[m HEAD@{6}: commit: update cache +[33m486cfb8[m HEAD@{7}: pull (start): checkout 486cfb8a8f7c9f7adffc448a86a0bff2d443e317 +[33mb1eb462[m HEAD@{8}: commit: commit +[33mdd574b3[m HEAD@{9}: pull: Fast-forward +[33m22bd59d[m HEAD@{10}: commit: add modnef torch and change srlif to shiftlif +[33m8aa6a16[m HEAD@{11}: pull: Fast-forward +[33m00bcb74[m HEAD@{12}: commit: remove print on xstep driver +[33mc11f4b5[m HEAD@{13}: pull: Fast-forward +[33m0542204[m HEAD@{14}: commit: add rblif modneftorch +[33m6e3e1ec[m HEAD@{15}: pull: Fast-forward +[33mcbf372b[m HEAD@{16}: commit: fix bug modnef torch +[33ma4f3d71[m HEAD@{17}: pull: Fast-forward +[33m3348615[m HEAD@{18}: checkout: moving from main to reccursive +[33m0bc064e[m[33m ([m[1;31morigin/main[m[33m, [m[1;31morigin/HEAD[m[33m, [m[1;32mmain[m[33m)[m HEAD@{19}: pull: Fast-forward +[33m1b686a0[m HEAD@{20}: checkout: moving from reccursive to main +[33m3348615[m HEAD@{21}: pull: Fast-forward +[33mf8432d6[m HEAD@{22}: pull: Fast-forward +[33m2cc1813[m HEAD@{23}: pull: Fast-forward +[33mcf0d4dd[m HEAD@{24}: commit: add test bug fix classifer +[33m9c9df18[m HEAD@{25}: pull: Fast-forward +[33m55646fa[m HEAD@{26}: commit: bug classifier +[33mfc87783[m HEAD@{27}: commit: add blif test and bug fix +[33m12ae129[m HEAD@{28}: checkout: moving from main to reccursive +[33m1b686a0[m HEAD@{29}: clone: from gitlab-ssh.univ-lille.fr:bioinsp/ModNEF.git