Skip to content
Snippets Groups Projects
Select Git revision
  • 10317998a7f336bd1a26dc95b54e7bb7785cfd22
  • v2 default protected
  • master
3 results

conf.py

Blame
  • 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")