Skip to content

Commit

Permalink
Merge branch 'fastmachinelearning:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
dgburnette authored Feb 7, 2025
2 parents 400d645 + 3b7e595 commit b450a08
Show file tree
Hide file tree
Showing 54 changed files with 454 additions and 347 deletions.
16 changes: 8 additions & 8 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -2,20 +2,26 @@ exclude: (^hls4ml\/templates\/(vivado|quartus)\/(ap_types|ac_types)\/|^test/pyte

repos:
- repo: https://github.com/psf/black
rev: 24.10.0
rev: 25.1.0
hooks:
- id: black
language_version: python3
args: ['--line-length=125',
'--skip-string-normalization']

- repo: https://github.com/tox-dev/pyproject-fmt
rev: v2.5.0
hooks:
- id: pyproject-fmt

- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v5.0.0
hooks:
- id: check-added-large-files
- id: check-case-conflict
- id: check-merge-conflict
- id: check-symlinks
- id: check-toml
- id: check-yaml
- id: debug-statements
- id: end-of-file-fixer
Expand All @@ -24,22 +30,16 @@ repos:
- id: trailing-whitespace

- repo: https://github.com/PyCQA/isort
rev: 5.13.2
rev: 6.0.0
hooks:
- id: isort
args: ["--profile", "black", --line-length=125]

- repo: https://github.com/asottile/pyupgrade
rev: v3.19.1
hooks:
- id: pyupgrade
args: ["--py36-plus"]

- repo: https://github.com/asottile/setup-cfg-fmt
rev: v2.7.0
hooks:
- id: setup-cfg-fmt

- repo: https://github.com/pycqa/flake8
rev: 7.1.1
hooks:
Expand Down
6 changes: 4 additions & 2 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
include LICENSE README.md CONTRIBUTING.md CITATION.cff pyproject.toml setup.py setup.cfg .clang-format
include LICENSE README.md CONTRIBUTING.md CITATION.cff pyproject.toml .clang-format
graft example-models
graft test
graft contrib
recursive-include hls4ml/templates *
global-exclude .git .gitmodules .gitlab-ci.yml
recursive-include hls4ml *.py
recursive-include hls4ml/contrib *
global-exclude .git .gitmodules .gitlab-ci.yml *.pyc
include hls4ml/backends/vivado_accelerator/supported_boards.json
30 changes: 0 additions & 30 deletions hls4ml/__init__.py
Original file line number Diff line number Diff line change
@@ -1,33 +1,3 @@
# Temporary workaround for QKeras installation requirement, will be removed after 1.0.0
def maybe_install_qkeras():
import subprocess
import sys

QKERAS_PKG_NAME = 'QKeras'
# QKERAS_PKG_SOURCE = QKERAS_PKG_NAME
QKERAS_PKG_SOURCE = 'qkeras@git+https://github.com/fastmachinelearning/qkeras.git'

def pip_list():
p = subprocess.run([sys.executable, '-m', 'pip', 'list'], check=True, capture_output=True)
return p.stdout.decode()

def pip_install(package):
subprocess.check_call([sys.executable, '-m', 'pip', 'install', package])

all_pkgs = pip_list()
if QKERAS_PKG_NAME not in all_pkgs:
print('QKeras installation not found, installing one...')
pip_install(QKERAS_PKG_SOURCE)
print('QKeras installed.')


try:
maybe_install_qkeras()
except Exception:
print('Could not find QKeras installation, make sure you have QKeras installed.')

# End of workaround

from hls4ml import converters, report, utils # noqa: F401, E402

try:
Expand Down
57 changes: 26 additions & 31 deletions hls4ml/backends/catapult/passes/conv_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ class GenerateConvStreamingInstructions(OptimizerPass):
'''Generates the instructions for streaming implementation of CNNs'''

def match(self, node):
return isinstance(node, (Conv1D, SeparableConv1D, Conv2D, SeparableConv2D))
is_match = (
isinstance(node, (Conv1D, SeparableConv1D, Conv2D, SeparableConv2D))
and node.model.config.get_config_value('IOType').lower() == 'io_stream'
and node.get_attr('implementation').lower() == 'encoded'
)
return is_match

def transform(self, model, node):
node_class = node.__class__.__name__
Expand All @@ -18,35 +23,25 @@ def transform(self, model, node):
raise Exception(f'Cannot generate instructions for node {node.name} ({node_class})')

def _generate_1d_instructions(self, node):
if node.model.config.get_config_value('IOType') == 'io_stream':
min_w, instructions = node.model.config.backend.compute_conv1d_instructions(
node.get_input_variable().shape[0],
node.get_input_variable().shape[1],
node.get_attr('filt_width'),
node.get_attr('stride_width'),
)
instructions_str = ','.join(str(i) for i in instructions)
node.set_attr('min_width', min_w)
node.set_attr('instructions', instructions_str)
else:
# these are unused; just put dummy values
node.set_attr('min_width', node.get_attr('in_width'))
node.set_attr('instructions', '0')
min_w, instructions = node.model.config.backend.compute_conv1d_instructions(
node.get_input_variable().shape[0],
node.get_input_variable().shape[1],
node.get_attr('filt_width'),
node.get_attr('stride_width'),
)
instructions_str = ','.join(str(i) for i in instructions)
node.set_attr('min_width', min_w)
node.set_attr('instructions', instructions_str)

def _generate_2d_instructions(self, node):
if node.model.config.get_config_value('IOType') == 'io_stream':
min_h, min_w, instructions = node.model.config.backend.compute_conv2d_instructions(
node.get_input_variable().shape[0],
node.get_input_variable().shape[1],
node.get_input_variable().shape[2],
node.get_attr('filt_height'),
node.get_attr('stride_height'),
)
instructions_str = ','.join(str(i) for i in instructions)
node.set_attr('min_height', min_h)
node.set_attr('min_width', min_w)
node.set_attr('instructions', instructions_str)
else:
node.set_attr('min_height', node.get_attr('in_height'))
node.set_attr('min_width', node.get_attr('in_width'))
node.set_attr('instructions', '0')
min_h, min_w, instructions = node.model.config.backend.compute_conv2d_instructions(
node.get_input_variable().shape[0],
node.get_input_variable().shape[1],
node.get_input_variable().shape[2],
node.get_attr('filt_height'),
node.get_attr('stride_height'),
)
instructions_str = ','.join(str(i) for i in instructions)
node.set_attr('min_height', min_h)
node.set_attr('min_width', min_w)
node.set_attr('instructions', instructions_str)
7 changes: 7 additions & 0 deletions hls4ml/backends/catapult/passes/convolution_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,9 @@ def format(self, node):
else:
params['fill_fn'] = 'FillConv1DBuffer'

params['min_width'] = node.get_attr('min_width', node.get_attr('in_width'))
params['instructions'] = node.get_attr('instructions', '0')

conv_config = self.template.format(**params)

mult_params = self._default_config_params(node)
Expand Down Expand Up @@ -337,6 +340,10 @@ def format(self, node):
else:
params['fill_fn'] = 'FillConv2DBuffer'

params['min_height'] = node.get_attr('min_height', node.get_attr('in_height'))
params['min_width'] = node.get_attr('min_width', node.get_attr('in_width'))
params['instructions'] = node.get_attr('instructions', '0')

conv_config = self.template.format(**params)

mult_params = self._default_config_params(node)
Expand Down
3 changes: 1 addition & 2 deletions hls4ml/backends/oneapi/passes/clone_templates.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
""" The clone templates in the fpga backend are not enough for oneAPI, so this adds the missing parts
"""
"""The clone templates in the fpga backend are not enough for oneAPI, so this adds the missing parts"""

from hls4ml.backends.fpga.passes.clone import Clone
from hls4ml.backends.oneapi.oneapi_template import StreamFunctionCallTemplate, TaskSequenceTemplate
Expand Down
57 changes: 26 additions & 31 deletions hls4ml/backends/vivado/passes/conv_stream.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ class GenerateConvStreamingInstructions(OptimizerPass):
'''Generates the instructions for streaming implementation of CNNs'''

def match(self, node):
return isinstance(node, (Conv1D, SeparableConv1D, Conv2D, SeparableConv2D))
is_match = (
isinstance(node, (Conv1D, SeparableConv1D, Conv2D, SeparableConv2D))
and node.model.config.get_config_value('IOType').lower() == 'io_stream'
and node.get_attr('implementation').lower() == 'encoded'
)
return is_match

def transform(self, model, node):
node_class = node.__class__.__name__
Expand All @@ -18,35 +23,25 @@ def transform(self, model, node):
raise Exception(f'Cannot generate instructions for node {node.name} ({node_class})')

def _generate_1d_instructions(self, node):
if node.model.config.get_config_value('IOType') == 'io_stream':
min_w, instructions = node.model.config.backend.compute_conv1d_instructions(
node.get_input_variable().shape[0],
node.get_input_variable().shape[1],
node.get_attr('filt_width'),
node.get_attr('stride_width'),
)
instructions_str = ','.join(str(i) for i in instructions)
node.set_attr('min_width', min_w)
node.set_attr('instructions', instructions_str)
else:
# these are unused; just put dummy values
node.set_attr('min_width', node.get_attr('in_width'))
node.set_attr('instructions', '0')
min_w, instructions = node.model.config.backend.compute_conv1d_instructions(
node.get_input_variable().shape[0],
node.get_input_variable().shape[1],
node.get_attr('filt_width'),
node.get_attr('stride_width'),
)
instructions_str = ','.join(str(i) for i in instructions)
node.set_attr('min_width', min_w)
node.set_attr('instructions', instructions_str)

def _generate_2d_instructions(self, node):
if node.model.config.get_config_value('IOType') == 'io_stream':
min_h, min_w, instructions = node.model.config.backend.compute_conv2d_instructions(
node.get_input_variable().shape[0],
node.get_input_variable().shape[1],
node.get_input_variable().shape[2],
node.get_attr('filt_height'),
node.get_attr('stride_height'),
)
instructions_str = ','.join(str(i) for i in instructions)
node.set_attr('min_height', min_h)
node.set_attr('min_width', min_w)
node.set_attr('instructions', instructions_str)
else:
node.set_attr('min_height', node.get_attr('in_height'))
node.set_attr('min_width', node.get_attr('in_width'))
node.set_attr('instructions', '0')
min_h, min_w, instructions = node.model.config.backend.compute_conv2d_instructions(
node.get_input_variable().shape[0],
node.get_input_variable().shape[1],
node.get_input_variable().shape[2],
node.get_attr('filt_height'),
node.get_attr('stride_height'),
)
instructions_str = ','.join(str(i) for i in instructions)
node.set_attr('min_height', min_h)
node.set_attr('min_width', min_w)
node.set_attr('instructions', instructions_str)
7 changes: 7 additions & 0 deletions hls4ml/backends/vivado/passes/convolution_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,9 @@ def format(self, node):
else:
params['conv_fn'] = 'Conv1DResource'

params['min_width'] = node.get_attr('min_width', node.get_attr('in_width'))
params['instructions'] = node.get_attr('instructions', '0')

conv_config = self.template.format(**params)

mult_params = self._default_config_params(node)
Expand Down Expand Up @@ -239,6 +242,10 @@ def format(self, node):
else:
params['fill_fn'] = 'FillConv2DBuffer'

params['min_height'] = node.get_attr('min_height', node.get_attr('in_height'))
params['min_width'] = node.get_attr('min_width', node.get_attr('in_width'))
params['instructions'] = node.get_attr('instructions', '0')

conv_config = self.template.format(**params)

mult_params = self._default_config_params(node)
Expand Down
26 changes: 23 additions & 3 deletions hls4ml/backends/vivado/passes/recurrent_templates.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

# recurrent multiplication template

recr_mult_config_template = """struct config{index} : nnet::dense_config {{
recr_mult_config_template_1 = """struct config{index} : nnet::dense_config {{
static const unsigned n_in = {n_in};
static const unsigned n_out = {n_out};
static const unsigned strategy = nnet::{strategy};
Expand All @@ -22,6 +22,24 @@
using product = nnet::product::{product_type}<x_T, y_T>;
}};\n"""

recr_mult_config_template_2 = """struct config{index} : nnet::dense_config {{
static const unsigned n_in = {n_in};
static const unsigned n_out = {n_out};
static const unsigned strategy = nnet::{strategy};
static const unsigned reuse_factor = {reuse};
static const unsigned n_zeros = {nzeros};
static const unsigned n_nonzeros = {nonzeros};
static const unsigned multiplier_limit = DIV_ROUNDUP(n_in * n_out, reuse_factor) - n_zeros / reuse_factor;
static const bool store_weights_in_bram = false;
typedef {accum_t.name} accum_t;
typedef {recurrent_bias_t.name} bias_t;
typedef {recurrent_weight_t.name} weight_t;
template<class data_T, class res_T, class CONFIG_T>
using kernel = nnet::{dense_function}<data_T, res_T, CONFIG_T>;
template<class x_T, class y_T>
using product = nnet::product::{product_type}<x_T, y_T>;
}};\n"""

# activation templates

activ_config_template = """struct {type}_config{index} : nnet::activ_config {{
Expand All @@ -45,7 +63,9 @@
recr_config_template = """struct config{index} : nnet::{recr_type}_config {{
typedef {accum_t.name} accum_t;
typedef {weight_t.name} weight_t; // Matrix
typedef {recurrent_weight_t.name} recurrent_weight_t; // Matrix
typedef {bias_t.name} bias_t; // Vector
typedef {recurrent_bias_t.name} recurrent_bias_t; // Vector
typedef {config_mult_t1} mult_config1;
typedef {config_mult_t2} mult_config2;
typedef {recr_act_t} ACT_CONFIG_{RECR_TYPE};
Expand Down Expand Up @@ -77,8 +97,8 @@ def __init__(self):
self.template = recr_config_template
self.act_template = activ_config_template
self.recr_act_template = recr_activ_config_template
self.mult1_template = recr_mult_config_template
self.mult2_template = recr_mult_config_template
self.mult1_template = recr_mult_config_template_1
self.mult2_template = recr_mult_config_template_2

def format(self, node):
params = self._default_config_params(node)
Expand Down
File renamed without changes.
3 changes: 3 additions & 0 deletions hls4ml/cli/__main__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from . import main

main()
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
File renamed without changes.
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
"""
Usage example for a custom KL loss layer
Takes as an input two arrays: z_mean and z_log_var
and computes KL "distance" between normal distribution
and Gaussian with mu=z_mean and sigma=z_log_var
Usage example for a custom KL loss layer
Takes as an input two arrays: z_mean and z_log_var
and computes KL "distance" between normal distribution
and Gaussian with mu=z_mean and sigma=z_log_var
The HLS part is in contrib/kl_layer/kl_layer.h
The HLS part is in contrib/kl_layer/kl_layer.h
"""

from pathlib import Path
Expand Down
Loading

0 comments on commit b450a08

Please sign in to comment.