Source code for elasticai.creator.nn.fixed_point.conv1d.design

import math

from elasticai.creator.file_generation.savable import Path
from elasticai.creator.file_generation.template import (
    InProjectTemplate,
    module_to_package,
)
from elasticai.creator.vhdl.auto_wire_protocols.port_definitions import create_port
from elasticai.creator.vhdl.design.design import Design
from elasticai.creator.vhdl.design.ports import Port
from elasticai.creator.vhdl.shared_designs.rom import (
    Rom,
)

from .testbench import Conv1dDesignProtocol


[docs] def generate_parameters_from_port(port: Port) -> dict[str, str]: params = {} for signal in port: if signal.width > 0: params[f"{signal.name}_width"] = str(signal.width) return params
[docs] class Conv1dDesign(Design, Conv1dDesignProtocol): def __init__( self, name: str, total_bits: int, frac_bits: int, in_channels: int, out_channels: int, signal_length: int, kernel_size: int, weights: list[list[list[int]]], bias: list[int], ) -> None: super().__init__(name=name) self._total_bits = total_bits self._frac_bits = frac_bits self._in_channels = in_channels self._out_channels = out_channels self._input_signal_length = signal_length self._kernel_size = kernel_size self._weights = weights self._bias = bias self.output_signal_length = math.floor( self.input_signal_length - self.kernel_size + 1 ) self._port = create_port( x_width=self._total_bits, y_width=self._total_bits, x_count=self.input_signal_length * self._in_channels, y_count=self.output_signal_length * self._out_channels, ) @property def input_signal_length(self) -> int: return self._input_signal_length @property def kernel_size(self) -> int: return self._kernel_size @property def port(self) -> Port: return self._port @property def in_channels(self) -> int: return self._in_channels @property def out_channels(self) -> int: return self._out_channels @staticmethod def _flatten_params(params: list[list[list[int]]]) -> list[int]: result = [] for list_of_lists in params: for list_of_int in list_of_lists: result.extend(list_of_int) return result
[docs] def save_to(self, destination: Path) -> None: print(self.name) rom_name = dict(weights=f"{self.name}_w_rom", bias=f"{self.name}_b_rom") template = InProjectTemplate( package=module_to_package(self.__module__), file_name="conv1d.tpl.vhd", parameters=dict( frac_width=str(self._frac_bits), in_channels=str(self._in_channels), out_channels=str(self._out_channels), kernel_size=str(self.kernel_size), vector_width=str(self.input_signal_length), name=self.name, ) | generate_parameters_from_port(self._port), ) destination.create_subpath(self.name).as_file(".vhd").write(template) core_component = InProjectTemplate( package=module_to_package(self.__module__), file_name="conv1d_function.tpl.vhd", parameters={ "rom_name_weights": rom_name["weights"], "rom_name_bias": rom_name["bias"], }, ) destination.create_subpath(f"{self.name}_fxp_MAC_RoundToZero").as_file( ".vhd" ).write(core_component) mac = InProjectTemplate( package="elasticai.creator.nn.fixed_point.mac", file_name="fxp_mac.tpl.vhd", parameters={}, ) destination.create_subpath("fxp_mac").as_file(".vhd").write(mac) weights_rom = Rom( name=rom_name["weights"], data_width=self._total_bits, values_as_integers=self._flatten_params(self._weights), ) weights_rom.save_to(destination.create_subpath(rom_name["weights"])) bias_rom = Rom( name=rom_name["bias"], data_width=self._total_bits, values_as_integers=self._bias, ) bias_rom.save_to(destination.create_subpath(rom_name["bias"]))