Skip to content

Commit

Permalink
Merge branch 'main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
mgkwill authored Jul 26, 2024
2 parents ec42472 + 642e6ab commit 16f4bb2
Show file tree
Hide file tree
Showing 47 changed files with 5,405 additions and 1,858 deletions.
8 changes: 7 additions & 1 deletion .github/workflows/cd.yml
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,10 @@ jobs:
pip install -U pip
pip install "nbconvert>=7.2.10,<7.3" pytest>=7.2.0 matplotlib>=3.5.1 ipykernel>=6.15.0 nbformat>=5.3.0
artifact=$(ls | grep lava_dl | grep tar)
pip install --no-input $artifact
pip install --no-input $artifact
# There is an issue "ImportError: cannot import name 'packaging' from 'pkg_resources'" when
# using setuptools==70.0.0 -- temp fix to downgrade to setuptools==69.5.1
pip install setuptools==69.5.1
tar -xvf $artifact
mv ./lava*/tests .
mv ./lava*/tutorials .
Expand All @@ -120,6 +123,9 @@ jobs:
pip install "nbconvert>=7.2.10,<7.3" pytest>=7.2.0 matplotlib>=3.5.1 ipykernel>=6.15.0 nbformat>=5.3.0
artifact=$(ls | grep lava_dl | grep whl)
pip install --no-input $artifact
# There is an issue "ImportError: cannot import name 'packaging' from 'pkg_resources'" when
# using setuptools==70.0.0 -- temp fix to downgrade to setuptools==69.5.1
pip install setuptools==69.5.1
# Change $artifact to tar.gz
artifact=$(ls | grep lava_dl | grep tar)
tar -xvf $artifact
Expand Down
26 changes: 21 additions & 5 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,12 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
with:
lfs: true

- name: Setup CI
uses: lava-nc/ci-setup-composite-action@v1.1
uses: lava-nc/ci-setup-composite-action@v1.5.12_py3.10
with:
repository: 'Lava-DL'

Expand All @@ -29,8 +33,12 @@ jobs:
runs-on: ubuntu-latest

steps:
- uses: actions/checkout@v3
with:
lfs: true

- name: Setup CI
uses: lava-nc/ci-setup-composite-action@v1.1
uses: lava-nc/ci-setup-composite-action@v1.5.12_py3.10
with:
repository: 'Lava-DL'

Expand All @@ -46,14 +54,22 @@ jobs:
runs-on: ${{ matrix.operating-system }}
strategy:
matrix:
operating-system: [ubuntu-latest, windows-latest, macos-latest]
operating-system: [ubuntu-latest, windows-latest]

steps:
- uses: actions/checkout@v3
with:
lfs: true

- name: Setup CI
uses: lava-nc/ci-setup-composite-action@v1.1
uses: lava-nc/ci-setup-composite-action@v1.5.12_py3.10
with:
repository: 'Lava-DL'

- name: Run unit tests
run: poetry run pytest
run: |
# There is an issue "ImportError: cannot import name 'packaging' from 'pkg_resources'" when
# using setuptools==70.0.0 -- temp fix to downgrade to setuptools==69.5.1
poetry run pip install setuptools==69.5.1
poetry run pytest
6 changes: 6 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -129,3 +129,9 @@ dmypy.json

# Pyre type checker
.pyre/

#Trained log folders
#Trained_*
#Logs_*
#runs

2,531 changes: 1,239 additions & 1,292 deletions poetry.lock

Large diffs are not rendered by default.

2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ classifiers = [
"Discussions" = "https://github.com/lava-nc/lava-dl/discussions"

[tool.poetry.dependencies]
python = ">=3.8, <3.11"
python = ">=3.10, <3.11"

lava-nc = { git = "https://github.com/lava-nc/lava.git", branch = "main", develop = true }

Expand Down
108 changes: 108 additions & 0 deletions src/lava/lib/dl/netx/blocks/process.py
Original file line number Diff line number Diff line change
Expand Up @@ -172,9 +172,11 @@ def __init__(self, **kwargs: Union[dict, tuple, list, int, bool]) -> None:
self.synapse = Synapse(
weights=weight,
delays=delay.astype(int),
weight_exp=weight_exponent,
max_delay=62,
num_weight_bits=num_weight_bits,
num_message_bits=self.input_message_bits,

)

if self.shape != self.synapse.a_out.shape:
Expand All @@ -197,6 +199,112 @@ def export_hdf5(self, handle: Union[h5py.File, h5py.Group]) -> None:
raise NotImplementedError


class RecurrentDense(AbstractBlock):
"""RecurrentDense layer block.
Parameters
----------
shape : tuple or list
shape of the layer block in (x, y, z)/WHC format.
neuron_params : dict, optional
dictionary of neuron parameters. Defaults to None.
weight : np.ndarray
synaptic weight.
weight_rec : np.ndarray
recurrent synaptic weight.
delay : np.ndarray
synaptic delay.
bias : np.ndarray or None
bias of neuron. None means no bias. Defaults to None.
has_graded_input : dict
flag for graded spikes at input. Defaults to False.
num_weight_bits : int
number of weight bits. Defaults to 8.
weight_exponent : int
weight exponent value. Defaults to 0.
sparse_synapse : bool
connection is sparse
input_message_bits : int, optional
number of message bits in input spike. Defaults to 0 meaning unary
spike.
"""

def __init__(self, **kwargs: Union[dict, tuple, list, int, bool]) -> None:
super().__init__(**kwargs)

weight = kwargs.pop('weight')
weight_rec = kwargs.pop('weight_rec')
delay = kwargs.pop('delay', None)
num_weight_bits = kwargs.pop('num_weight_bits', 8)
weight_exponent = kwargs.pop('weight_exponent', 0)
sparse_synapse = kwargs.pop('sparse_synapse', False)

if delay is None:
if sparse_synapse:
Synapse = SparseSynapse
weight = csr_matrix(weight)
else:
Synapse = DenseSynapse

self.synapse = Synapse(
weights=weight,
weight_exp=weight_exponent,
num_weight_bits=num_weight_bits,
num_message_bits=self.input_message_bits,
shape=weight.shape
)
self.synapse_rec = Synapse(
weights=weight_rec,
weight_exp=weight_exponent,
num_weight_bits=num_weight_bits,
num_message_bits=self.input_message_bits,
shape=weight_rec.shape
)
else:
# TODO test this in greater detail
if sparse_synapse:
Synapse = DelaySparseSynapse
delay[weight == 0] = 0
weight = csr_matrix(weight)
delay = csr_matrix(delay)
else:
Synapse = DelayDenseSynapse

self.synapse = Synapse(
weights=weight,
delays=delay.astype(int),
max_delay=62,
num_weight_bits=num_weight_bits,
num_message_bits=self.input_message_bits,
)
self.synapse_rec = Synapse(
weights=weight_rec,
delays=delay.astype(int),
max_delay=62,
num_weight_bits=num_weight_bits,
num_message_bits=self.input_message_bits,
)

if self.shape != self.synapse.a_out.shape:
raise RuntimeError(
f'Expected synapse output shape to be {self.shape[-1]}, '
f'found {self.synapse.a_out.shape}.'
)

self.neuron = self._neuron(kwargs.pop('bias', None))

self.inp = InPort(shape=self.synapse.s_in.shape)
self.out = OutPort(shape=self.neuron.s_out.shape)
self.inp.connect(self.synapse.s_in)
self.synapse.a_out.connect(self.neuron.a_in)
self.neuron.s_out.connect(self.out)

self.neuron.s_out.connect(self.synapse_rec.s_in)

self.synapse_rec.a_out.connect(self.neuron.a_in)

self._clean()


class ComplexDense(AbstractBlock):
"""Dense Complex layer block.
Expand Down
41 changes: 33 additions & 8 deletions src/lava/lib/dl/netx/hdf5.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@
from lava.lib.dl.slayer.neuron.rf import neuron_params as get_rf_params
from lava.lib.dl.netx.utils import NetDict
from lava.lib.dl.netx.utils import optimize_weight_bits
from lava.lib.dl.netx.blocks.process import Input, Dense, Conv, ComplexDense
from lava.lib.dl.netx.blocks.process import Input, Dense, RecurrentDense, \
Conv, ComplexDense
from lava.lib.dl.netx.blocks.models import AbstractPyBlockModel


Expand Down Expand Up @@ -320,7 +321,8 @@ def create_dense(layer_config: h5py.Group,
reset_interval: Optional[int] = None,
reset_offset: int = 0,
spike_exp: int = 6,
sparse_synapse: bool = 0) -> Tuple[Dense, str]:
sparse_synapse: bool = 0,
rec: bool = False) -> Tuple[Dense, str]:
"""Creates dense layer from layer configuration
Parameters
Expand Down Expand Up @@ -393,11 +395,24 @@ def create_dense(layer_config: h5py.Group,

else:
weight = layer_config['weight']
if rec:
weight_rec = layer_config['weight_rec']
if weight.ndim == 1:
weight = weight.reshape(shape[0], -1)

opt_weights = optimize_weight_bits(weight)
weight, num_weight_bits, weight_exponent, sign_mode = opt_weights
if rec:
weight_rec = weight_rec.reshape(shape[0], -1)

if rec:
weight_concat = np.hstack((weight, weight_rec))
opt_weight_concat = optimize_weight_bits(weight_concat)
weight_concat, num_weight_bits, \
weight_exponent, sign_mode = opt_weight_concat
weight = weight_concat[:, :weight.shape[1]]
weight_rec = weight_concat[:, weight.shape[1]:]
else:
opt_weights = optimize_weight_bits(weight)
weight, num_weight_bits, \
weight_exponent, sign_mode = opt_weights

# arguments for dense block
params = {'shape': shape,
Expand All @@ -408,6 +423,8 @@ def create_dense(layer_config: h5py.Group,
'sign_mode': sign_mode,
'input_message_bits': input_message_bits,
"sparse_synapse": sparse_synapse}
if rec:
params['weight_rec'] = weight_rec

if 'delay' in layer_config.keys():
delay = layer_config['delay']
Expand Down Expand Up @@ -438,7 +455,10 @@ def create_dense(layer_config: h5py.Group,
if 'bias' in layer_config.keys():
params['bias'] = layer_config['bias']

proc = Dense(**params)
if rec:
proc = RecurrentDense(**params)
else:
proc = Dense(**params)
table_entry = Network._table_str(type_str='Dense', width=1, height=1,
channel=shape[0],
delay='delay' in layer_config.keys())
Expand Down Expand Up @@ -619,14 +639,19 @@ def _create(self) -> List[AbstractProcess]:
flatten_next = True
table = None

elif layer_type == 'dense':
elif layer_type == 'dense' or layer_type == 'dense_rec':
if layer_type == 'dense':
rec = False
elif layer_type == 'dense_rec':
rec = True
layer, table = self.create_dense(
layer_config=layer_config[i],
input_message_bits=input_message_bits,
reset_interval=reset_interval,
reset_offset=reset_offset,
spike_exp=self.spike_exp,
sparse_synapse=self.sparse_fc_layer)
sparse_synapse=self.sparse_fc_layer,
rec=rec)
if i >= self.skip_layers:
layers.append(layer)
reset_offset += 1
Expand Down
3 changes: 2 additions & 1 deletion src/lava/lib/dl/netx/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,8 @@ def __init__(
'iDecay', 'refDelay', 'scaleRho', 'tauRho', 'theta', 'vDecay',
'vThMant', 'wgtExp', 'sinDecay', 'cosDecay'
]
self.copy_keys = ['weight', 'bias', 'weight/real', 'weight/imag']
self.copy_keys = ['weight', 'weight_rec',
'bias', 'weight/real', 'weight/imag']

def keys(self) -> h5py._hl.base.KeysViewHDF5:
return self.f.keys()
Expand Down
Loading

0 comments on commit 16f4bb2

Please sign in to comment.