Source code for elasticai.creator.nn.fixed_point.linear.design
from itertools import chain
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 LinearDesignProtocol
[docs]
class LinearDesign(Design, LinearDesignProtocol):
def __init__(
self,
*,
in_feature_num: int,
out_feature_num: int,
total_bits: int,
frac_bits: int,
weights: list[list[int]],
bias: list[int],
name: str,
work_library_name: str = "work",
resource_option: str = "auto",
) -> None:
super().__init__(name=name)
self._name = name
self.weights = weights
self.bias = bias
self._in_feature_num = in_feature_num
self._out_feature_num = out_feature_num
self.work_library_name = work_library_name
self.resource_option = resource_option
self._frac_width = frac_bits
self._data_width = total_bits
self.x_addr_width = self.port["x_address"].width
self.y_addr_width = self.port["y_address"].width
@property
def name(self):
return self._name
@property
def in_feature_num(self) -> int:
return self._in_feature_num
@property
def out_feature_num(self) -> int:
return self._out_feature_num
@property
def frac_width(self) -> int:
return self._frac_width
@property
def data_width(self) -> int:
return self._data_width
@property
def port(self) -> Port:
return create_port(
x_width=self.data_width,
y_width=self.data_width,
x_count=self.in_feature_num,
y_count=self.out_feature_num,
)
def _template_parameters(self) -> dict[str, str]:
return dict(
(key, str(getattr(self, key)))
for key in (
"data_width",
"frac_width",
"x_addr_width",
"y_addr_width",
"in_feature_num",
"out_feature_num",
)
)
@staticmethod
def _flatten_params(params: list[list[int]]) -> list[int]:
return list(chain(*params))
[docs]
def save_to(self, destination: Path):
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="linear.tpl.vhd",
parameters=dict(
layer_name=self.name,
weights_rom_name=rom_name["weights"],
bias_rom_name=rom_name["bias"],
work_library_name=self.work_library_name,
resource_option=f'"{self.resource_option}"',
log2_max_value="31",
**self._template_parameters(),
),
)
destination.create_subpath(self.name).as_file(".vhd").write(template)
weights_rom = Rom(
name=rom_name["weights"],
data_width=self.data_width,
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.data_width,
values_as_integers=self.bias,
)
bias_rom.save_to(destination.create_subpath(rom_name["bias"]))