Select Git revision
shiftlif.py
shiftlif.py 7.95 KiB
"""
File name: srlif
Author: Aurélie Saulquin
Version: 2.0.0
License: GPL-3.0-or-later
Contact: aurelie.saulquin@univ-lille.fr
Dependencies: modnef_arch_mod, utilities, math, modnef.quantizer
Descriptions: Shift Register based LIF ModNEF archbuilder
"""
from ..modnef_arch_mod import ModNEFArchMod
from ..utilities import *
from math import log
from modnef.quantizer import DynamicScaleFactorQuantizer
_SHIFTLIF_DEFINITION = """
component ShiftLif_{0} is
generic(
input_neuron : integer := 8;
output_neuron : integer := 8;
variable_size : integer := 16;
v_threshold : std_logic_vector;
shift : integer := 8;
reset : string := "zero";
compute_fp : integer := 8;
weight_size : integer := 1;
weight_signed : boolean := false;
weight_fp : integer := 1;
mem_init_file : string := "none"
);
port (
i_clk : in std_logic;
i_start_emu : in std_logic;
i_reset_membrane : in std_logic;
i_req : in std_logic;
o_ack : out std_logic;
i_emu_busy : in std_logic;
i_spike_flag : in std_logic;
i_aer : in std_logic_vector(log_b(input_neuron, 2)-1 downto 0);
o_req : out std_logic;
i_ack : in std_logic;
o_emu_busy : out std_logic;
o_spike_flag : out std_logic;
o_aer : out std_logic_vector(log_b(output_neuron, 2)-1 downto 0)
);
end component;
"""
class ShiftLif(ModNEFArchMod):
"""
Shift Register LIF class module
Attributes
----------
name : str
name of module
input_neuron : int
number of input neurons
output_neuron : int
number of emulated (and so output) neurons
v_threshold : float
treshold value in fixed point representation
shift : int
shifting value
reset : str
reset method, can be zero or subtract
quantizer : Quantizer
quantization method
mem_init_file : str
synaptic weight memory file
variable_size : int
size in bit of computational variable
Methods
-------
vhdl_component_name()
return component name
vhdl_component_definition()
return vhdl component definition
to_debugger(output_file=""):
generate debugger module from current module
weight_convert(weights, compute_size, weight_exctraction = modnef.arch_builder.utilities.default_exctraction, output_path="."):
generate synaptic weight file understable by vivado from float synaptic weight file and convert neuron hyper parameters
to_vhdl(vhdl_file, pred, suc, clock_name)
write vhdl component implementation
"""
def __init__(self,
name : str,
input_neuron : int,
output_neuron : int,
v_threshold : float,
beta : float,
reset : str = "subtract",
mem_init_file : str = None,
strategy : str = "Parallel",
variable_size : int = 16,
quantizer=DynamicScaleFactorQuantizer(8)
):
"""
Init attributes
Parameters
----------
name : str
name of module
input_neuron : int
number of input neurons
output_neuron : int
number of emulated (and so output) neurons
v_threshold : float
treshold value
beta : int
beta value
reset : str = "subtract"
reset method, can be zero or subtract
quantizer = FixedPointQuantizer(8) : Quantizer
quantization method
mem_init_file : str : None
synaptic weight memory file
If None, mem_init_file = name_weight.mem
strategy : str = "Parallel"
Emulation strategy, can be Parallel or Sequential
variable_size : int = 16
size in bit of computational variable
"""
super().__init__(name, input_neuron, output_neuron)
self.v_threshold = v_threshold
self.shift = int(-log(1-beta)/log(2))
self.reset = reset
self.quantizer = quantizer
if mem_init_file == None:
self.mem_init_file = f"{self.name}_weight.mem"
else:
self.mem_init_file = mem_init_file
self._strategy = strategy
self.variable_size = variable_size
def vhdl_component_name(self):
"""
Module identifier use during component definition
Returns
-------
str
"""
return f"ShiftLif_{self._strategy}"
def vhdl_component_definition(self):
"""
VHDL component definition
Returns
-------
str
"""
return _SHIFTLIF_DEFINITION.format(self._strategy)
def weight_convert(self, weights, weight_extraction = default_extraction, output_path="."):
"""
Write architecture memory from synaptic weight file and convert neuron hyper parameters to correct emulation values
Parameters
----------
weight_files
initial value of synaptic weight
weight_exctraction : function
function taht convert line of weight file to synaptic weight (see utilities.default_exctraction)
utilities.default_exctraction by default
output_path : str = "."
memory file output path
"""
weights = weight_extraction(weights, self.input_neuron, self.output_neuron)
if not self.quantizer.is_initialize:
self.quantizer.init_from_weight(weight=weights)
mem_file = open(f"{output_path}/{self.mem_init_file}", 'w')
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.quantizer.bitwidth) + two_comp(self.quantizer(weights[i][j]), self.quantizer.bitwidth)
mem_file.write(f"@{to_hex(i)} {to_hex(w_line)}\n")
self.v_threshold = two_comp(self.quantizer(self.v_threshold), self.variable_size)
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.quantizer.bitwidth) + self.quantizer(weights[i][j])
mem_file.write(f"@{to_hex(i)} {to_hex(w_line)}\n")
self.v_threshold = self.quantizer(self.v_threshold)
mem_file.close()
def to_debugger(self, output_file : str = ""):
"""
Generate debugger from module description
Returns
-------
NotImplementedError
"""
raise NotImplementedError()
def to_vhdl(self, vhdl_file, pred, suc, clock_name):
"""
write vhdl module implementation
Parameters
----------
vhdl_file : TextIOWrapper
vhdl file
pred : List of ModNEFArchMod
list of predecessor modules (only 1 predecessor for this module)
suc : List of ModNEFArchMod
list of successor module (only 1 for this module)
clock_name : str
name of clock signal
"""
if type(self.v_threshold) != int:
print("neuron hyper parameters are not int. If you set hyper parameters as float, pleasse run weight_convert before calling to_vhdl")
return
vhdl_file.write(f"\t{self.name} : ShiftLif_{self._strategy} generic map(\n")
vhdl_file.write(f"\t\tinput_neuron => {self.input_neuron},\n")
vhdl_file.write(f"\t\toutput_neuron => {self.output_neuron},\n")
vhdl_file.write(f"\t\tvariable_size => {self.variable_size},\n")
vhdl_file.write(f"\t\tv_threshold => x\"{self._to_hex(self.v_threshold, self.variable_size)}\",\n")
vhdl_file.write(f"\t\tshift => {self.shift},\n")
vhdl_file.write(f"\t\treset => \"{self.reset}\",\n")
vhdl_file.write(f"\t\tweight_size => {self.quantizer.bitwidth},\n")
vhdl_file.write(f"\t\tweight_signed => {self.quantizer.signed},\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")
vhdl_file.write("\t\ti_start_emu => start_emu,\n")
vhdl_file.write("\t\ti_reset_membrane => reset_membrane,\n")
self._write_port_map(vhdl_file, pred[0].name, self.name, "in", "", False)
self._write_port_map(vhdl_file, self.name, suc[0].name, "out", "", True)
vhdl_file.write("\t);\n")