diff --git a/.ci/secret.tar.enc b/.ci/secret.tar.enc
deleted file mode 100644
index 1e9847e7..00000000
Binary files a/.ci/secret.tar.enc and /dev/null differ
diff --git a/.codecov.yml b/.codecov.yml
deleted file mode 100644
index 0d7f5b15..00000000
--- a/.codecov.yml
+++ /dev/null
@@ -1,19 +0,0 @@
-# Automatically generated by nengo-bones, do not edit this file directly
-
-codecov:
- ci:
- - "!ci.appveyor.com"
- notify:
- require_ci_to_pass: no
-
-coverage:
- status:
- project:
- default:
- enabled: yes
- target: auto
- patch:
- default:
- enabled: yes
- target: 100%
- changes: no
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 00000000..fae501ef
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,89 @@
+name: CI testing
+on:
+ pull_request: {}
+ push:
+ branches:
+ - main
+ - release-candidate-*
+ tags:
+ - v*
+ workflow_dispatch:
+ inputs:
+ debug_enabled:
+ description: Run the build with SSH debugging enabled
+ required: false
+ default: false
+
+jobs:
+ static:
+ runs-on: ubuntu-latest
+ timeout-minutes: 30
+ steps:
+ - uses: nengo/nengo-bones/actions/setup@main
+ with:
+ python-version: "3.9"
+ - uses: nengo/nengo-bones/actions/generate-and-check@main
+ - uses: nengo/nengo-bones/actions/run-script@main
+ with:
+ name: static
+ test:
+ needs:
+ - static
+ runs-on: ubuntu-latest
+ timeout-minutes: 60
+ strategy:
+ matrix:
+ include:
+ - script: remote-test
+ tf-version: tensorflow
+ python-version: "3.9"
+ coverage-name: remote-test
+ - script: test
+ tf-version: tensorflow
+ python-version: "3.9"
+ coverage-name: test-latest
+ - script: test
+ tf-version: tensorflow==2.1.0
+ python-version: "3.6"
+ coverage-name: test-old
+ - script: test
+ tf-version: tensorflow~=2.6.0
+ python-version: "3.9"
+ coverage-name: test-2.6
+ - script: remote-docs
+ tf-version: tensorflow
+ python-version: "3.9"
+ - script: remote-examples
+ tf-version: tensorflow
+ python-version: "3.9"
+ fail-fast: false
+ env:
+ TF_VERSION: ${{ matrix.tf-version }}
+ SSH_KEY: ${{ secrets.SSH_KEY }}
+ SSH_CONFIG: ${{ secrets.SSH_CONFIG }}
+ GH_TOKEN: ${{ secrets.GH_TOKEN }}
+ steps:
+ - uses: nengo/nengo-bones/actions/setup@main
+ with:
+ python-version: ${{ matrix.python-version }}
+ - uses: nengo/nengo-bones/actions/generate-and-check@main
+ - name: Write secrets to file
+ run: |
+ mkdir -p ~/.ssh
+ echo '${{ secrets.AZURE_PEM }}' > ~/.ssh/azure.pem
+ - uses: nengo/nengo-bones/actions/run-script@main
+ with:
+ name: ${{ matrix.script }}
+ - uses: actions/upload-artifact@v3
+ if: ${{ always() && matrix.coverage-name }}
+ with:
+ name: coverage-${{ matrix.coverage-name }}
+ path: .coverage
+ coverage:
+ runs-on: ubuntu-latest
+ timeout-minutes: 10
+ needs:
+ - test
+ if: ${{ always() }}
+ steps:
+ - uses: nengo/nengo-bones/actions/coverage-report@main
diff --git a/.gitignore b/.gitignore
index 99cd6944..e3bd3317 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,6 +4,7 @@ keras_lmu.egg-info
*.ipynb_checkpoints
__pycache__
/.idea
+/bones-scripts
/docs/_build
+/secret
/tmp
-/.ci
diff --git a/.nengobones.yml b/.nengobones.yml
index 1ea19546..69302ddf 100644
--- a/.nengobones.yml
+++ b/.nengobones.yml
@@ -62,36 +62,6 @@ docs_conf_py:
sphinx_options:
autodoc_inherit_docstrings: False
-travis_yml:
- python: 3.8
- global_vars:
- TF_VERSION: tensorflow
- jobs:
- - script: static
- - script: remote-test
- - script: test
- env:
- TF_VERSION: tensorflow==2.1.0
- python: 3.6
- - script: test
- env:
- TF_VERSION: tensorflow~=2.6.0
- - script: remote-docs
- - script: remote-examples
- pypi_user: __token__
- slack_notifications: "wZ7l/X7cVeetmwfup7vCeN74pqFGMC5eaJfy/aqRwVGCbY3aHQKoqJaBBrVef\
- c+DsJwPPM9HIOGs7jkPY+Y1pFbklAhWCDCvmc+f3fL4/yPWK1u7r8IIHhM3O0YvYrEHfFfZn+V1nAomx1\
- /wttFOr07LLffaNOn+sFzXgKP1Ebv5MrlCNGY0q3T2A38pwXus60GXaGalI/I/a/vjRdkEmq38eIMqLl0\
- v94oCy67Gqb/5mlB8eT6SffLGoFCctNpC9G9jyh/eRQp+B+YwksjZz+SOQTIy/mOlk8fU1ZL4f9wPguXh\
- eKznckuvX+J0o+o5kspyrQveWW2lo1VjmnFfdifCVjTj4AIcmc60Zb2dMzzBcfcA+zeVlhWkWbB65LuuX\
- kfxxsN97EwP5KVH+Lw7c2ycUyHV8XvKHNzVRLIUuVeOTKLHgGpkVgz/WasT5yBOEbnAyZxxAHQpMbXQr9\
- POwaq92Kwb7du0sLcsP4agdd2L0YACb4JdwQeeD1c8h6RrXua2ejBJ41e+9ZkZcZGad9P6YVmxvI+hddd\
- jdzzvBWq6+B/Ubft9AqQXmn4pg0fKkZLjrzsSYGRhXzINxhVBjZD8b5BQIb/Aeix3IFhLmDdSQMhjdETA\
- gL3jSd9D5t1G5QNp4AdbitqcH+yNoXzZCXye76hrwYr6yrHi3JN9yrM="
- deploy_dists:
- - sdist
- - bdist_wheel
-
ci_scripts:
- template: static
- template: docs
@@ -104,7 +74,6 @@ ci_scripts:
remote_script: test
output_name: remote-test
host: azure
- travis_var_key: 2895d60e3414
azure_name: nengo-dl
azure_group: nengo-ci
coverage: true
@@ -118,7 +87,6 @@ ci_scripts:
remote_script: docs
output_name: remote-docs
host: azure-docs
- travis_var_key: 2895d60e3414
azure_name: nengo-dl-docs
azure_group: nengo-ci
remote_setup:
@@ -128,15 +96,11 @@ ci_scripts:
remote_script: examples
output_name: remote-examples
host: azure-examples
- travis_var_key: 2895d60e3414
azure_name: nengo-dl-examples
azure_group: nengo-ci
remote_setup:
- conda install -y -c conda-forge cudatoolkit=11.3 cudnn=8.2
- export LD_LIBRARY_PATH=\$LD_LIBRARY_PATH:\$CONDA_PREFIX/lib
- - template: deploy
-
-codecov_yml: {}
pre_commit_config_yaml: {}
diff --git a/.travis.yml b/.travis.yml
deleted file mode 100644
index 7ec9000b..00000000
--- a/.travis.yml
+++ /dev/null
@@ -1,120 +0,0 @@
-# Automatically generated by nengo-bones, do not edit this file directly
-
-language: python
-python: 3.8
-notifications:
- email:
- on_success: change
- on_failure: change
- slack:
- if: branch = master
- on_pull_requests: false
- on_success: change
- on_failure: always
- rooms:
- - secure: "wZ7l/X7cVeetmwfup7vCeN74pqFGMC5eaJfy/aqRwVGCbY3aHQKoqJaBBrVefc+DsJwPPM9HIOGs7jkPY+Y1pFbklAhWCDCvmc+f3fL4/yPWK1u7r8IIHhM3O0YvYrEHfFfZn+V1nAomx1/wttFOr07LLffaNOn+sFzXgKP1Ebv5MrlCNGY0q3T2A38pwXus60GXaGalI/I/a/vjRdkEmq38eIMqLl0v94oCy67Gqb/5mlB8eT6SffLGoFCctNpC9G9jyh/eRQp+B+YwksjZz+SOQTIy/mOlk8fU1ZL4f9wPguXheKznckuvX+J0o+o5kspyrQveWW2lo1VjmnFfdifCVjTj4AIcmc60Zb2dMzzBcfcA+zeVlhWkWbB65LuuXkfxxsN97EwP5KVH+Lw7c2ycUyHV8XvKHNzVRLIUuVeOTKLHgGpkVgz/WasT5yBOEbnAyZxxAHQpMbXQr9POwaq92Kwb7du0sLcsP4agdd2L0YACb4JdwQeeD1c8h6RrXua2ejBJ41e+9ZkZcZGad9P6YVmxvI+hdddjdzzvBWq6+B/Ubft9AqQXmn4pg0fKkZLjrzsSYGRhXzINxhVBjZD8b5BQIb/Aeix3IFhLmDdSQMhjdETAgL3jSd9D5t1G5QNp4AdbitqcH+yNoXzZCXye76hrwYr6yrHi3JN9yrM="
-cache: pip
-
-dist: xenial
-
-env:
- global:
- - SCRIPT="test"
- - TEST_ARGS=""
- - BRANCH_NAME="${TRAVIS_PULL_REQUEST_BRANCH:-$TRAVIS_BRANCH}"
- - TF_VERSION="tensorflow"
-
-jobs:
- include:
- -
- env:
- SCRIPT="static"
- -
- env:
- SCRIPT="remote-test"
- -
- env:
- TF_VERSION="tensorflow==2.1.0"
- SCRIPT="test"
- python: 3.6
- -
- env:
- TF_VERSION="tensorflow~=2.6.0"
- SCRIPT="test"
- -
- env:
- SCRIPT="remote-docs"
- -
- env:
- SCRIPT="remote-examples"
- - stage: deploy
- if: branch =~ ^release-candidate-* OR tag =~ ^v[0-9]*
- env: SCRIPT="deploy"
- cache: false
- deploy:
- - provider: pypi
- server: https://test.pypi.org/legacy/
- user: __token__
- password: $PYPI_TEST_TOKEN
- distributions: "sdist bdist_wheel "
- on:
- all_branches: true
- tags: false
- condition: $TRAVIS_BRANCH =~ ^release-candidate-*
- - provider: pypi
- user: __token__
- password: $PYPI_TOKEN
- distributions: "sdist bdist_wheel "
- on:
- all_branches: true
- tags: true
- condition: $TRAVIS_TAG =~ ^v[0-9]*
-
-before_install:
- # export travis_terminate for use in scripts, from here:
- # https://github.com/travis-ci/travis-build/blob/master/lib/travis/build/bash/travis_terminate.bash
- - export -f travis_terminate
- _travis_terminate_agent
- _travis_terminate_freebsd
- _travis_terminate_linux
- _travis_terminate_osx
- _travis_terminate_unix
- _travis_terminate_windows
- # upgrade pip
- - pip install pip setuptools --upgrade
- # fixes setuptools bug, see https://github.com/pypa/setuptools/issues/3293
- - pip install "importlib-metadata>=0.21"
- # install/run nengo-bones
- - pip install git+https://github.com/nengo/nengo-bones#egg=nengo-bones
- - bones-generate --output-dir .ci ci-scripts
- - bones-check --verbose
- # display environment info
- - pip freeze
-
-install:
- - .ci/$SCRIPT.sh install
- - pip freeze
-
-before_script:
- - .ci/$SCRIPT.sh before_script
-
-script:
- - .ci/$SCRIPT.sh script
-
-before_cache:
- - .ci/$SCRIPT.sh before_cache
-
-after_success:
- - .ci/$SCRIPT.sh after_success
-
-after_failure:
- - .ci/$SCRIPT.sh after_failure
-
-before_deploy:
- - .ci/$SCRIPT.sh before_deploy
-
-after_deploy:
- - .ci/$SCRIPT.sh after_deploy
-
-after_script:
- - .ci/$SCRIPT.sh after_script
diff --git a/CHANGES.rst b/CHANGES.rst
index 085ebab6..6dc6ae3b 100644
--- a/CHANGES.rst
+++ b/CHANGES.rst
@@ -22,6 +22,15 @@ Release history
0.4.3 (unreleased)
==================
+*Compatible with TensorFlow 2.1 - 2.10*
+
+**Added**
+
+- Layers are registered with the Keras serialization system (no longer need to
+ be passed as ``custom_objects``). (`#49`_)
+
+.. _#49: https://github.com/nengo/keras-lmu/pull/49
+
0.4.2 (May 17, 2022)
====================
diff --git a/MANIFEST.in b/MANIFEST.in
index 79887354..3925070d 100644
--- a/MANIFEST.in
+++ b/MANIFEST.in
@@ -24,6 +24,7 @@ prune .github
prune .tox
prune .eggs
prune .ci
+prune bones-scripts
# Exclude auto-generated files
recursive-exclude docs *.py
diff --git a/docs/conf.py b/docs/conf.py
index b3586bbb..14bd9448 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -105,7 +105,36 @@
html_theme_options = {
"nengo_logo": "general-full-light.svg",
"nengo_logo_color": "#a8acaf",
- "tagmanager_id": "GTM-KWCR2HN",
+ "analytics": """
+
+
+
+
+
+
+
+ """,
}
html_redirects = [
("getting_started.html", "getting-started.html"),
diff --git a/keras_lmu/layers.py b/keras_lmu/layers.py
index bafce9f4..e5efd983 100644
--- a/keras_lmu/layers.py
+++ b/keras_lmu/layers.py
@@ -1,6 +1,4 @@
-"""
-Core classes for the KerasLMU package.
-"""
+"""Core classes for the KerasLMU package."""
import numpy as np
import tensorflow as tf
@@ -20,6 +18,7 @@
from keras.engine.base_layer import BaseRandomLayer
+@tf.keras.utils.register_keras_serializable("keras-lmu")
class LMUCell(DropoutRNNCellMixin, BaseRandomLayer):
"""
Implementation of LMU cell (to be used within Keras RNN wrapper).
@@ -179,8 +178,8 @@ def theta(self):
"""
Value of the ``theta`` parameter.
- If ``trainable_theta=True`` this returns the trained value, not the initial
- value passed in to the constructor.
+ If ``trainable_theta=True`` this returns the trained value, not the
+ initial value passed in to the constructor.
"""
if self.built:
return 1 / tf.keras.backend.get_value(self.theta_inv)
@@ -444,6 +443,7 @@ def from_config(cls, config):
return super().from_config(config)
+@tf.keras.utils.register_keras_serializable("keras-lmu")
class LMU(tf.keras.layers.Layer):
"""
A layer of trainable low-dimensional delay systems.
@@ -581,8 +581,8 @@ def theta(self):
"""
Value of the ``theta`` parameter.
- If ``trainable_theta=True`` this returns the trained value, not the initial
- value passed in to the constructor.
+ If ``trainable_theta=True`` this returns the trained value, not the
+ initial value passed in to the constructor.
"""
if self.built:
@@ -706,6 +706,7 @@ def from_config(cls, config):
return super().from_config(config)
+@tf.keras.utils.register_keras_serializable("keras-lmu")
class LMUFeedforward(tf.keras.layers.Layer):
"""
Layer class for the feedforward variant of the LMU.
diff --git a/keras_lmu/tests/test_benchmarks.py b/keras_lmu/tests/test_benchmarks.py
index d58de82e..dffb1832 100644
--- a/keras_lmu/tests/test_benchmarks.py
+++ b/keras_lmu/tests/test_benchmarks.py
@@ -38,7 +38,7 @@ def on_predict_batch_end(self, batch, logs=None):
@pytest.mark.skipif(not tf_gpu_installed, reason="Very slow on CPU")
@pytest.mark.parametrize(
"mode, min_time, max_time",
- [("rnn", 0.1, 0.2), ("fft", 0.1, 0.2), ("raw", 0.05, 0.15)],
+ [("rnn", 0.1, 0.2), ("fft", 0.05, 0.15), ("raw", 0.05, 0.15)],
)
def test_performance(mode, min_time, max_time):
# performance is based on Azure NC6 VM
diff --git a/keras_lmu/tests/test_layers.py b/keras_lmu/tests/test_layers.py
index 1fe4a96a..7590a21e 100644
--- a/keras_lmu/tests/test_layers.py
+++ b/keras_lmu/tests/test_layers.py
@@ -82,7 +82,9 @@ def test_layer_vs_cell(rng, has_input_kernel, feedforward, discretizer):
kernel_initializer="glorot_uniform" if has_input_kernel else None,
memory_to_memory=not feedforward,
)
- hidden_cell = lambda: tf.keras.layers.SimpleRNNCell(units=64)
+
+ def hidden_cell():
+ return tf.keras.layers.SimpleRNNCell(units=64)
inp = rng.uniform(-1, 1, size=(2, n_steps, input_d))
@@ -202,14 +204,7 @@ def test_save_load_serialization(mode, tmp_path, trainable_theta, discretizer):
model.save(str(tmp_path))
- model_load = tf.keras.models.load_model(
- str(tmp_path),
- custom_objects={
- "LMUCell": layers.LMUCell,
- "LMU": layers.LMU,
- "LMUFeedforward": layers.LMUFeedforward,
- },
- )
+ model_load = tf.keras.models.load_model(str(tmp_path))
assert np.allclose(
model.predict(np.ones((32, 10, 32))), model_load.predict(np.ones((32, 10, 32)))
@@ -634,9 +629,7 @@ def test_theta_update(discretizer, trainable_theta, tmp_path):
# save model and make sure you get same outputs, that is, correct theta was stored
model.save(str(tmp_path))
- model_load = tf.keras.models.load_model(
- str(tmp_path), custom_objects={"LMUCell": layers.LMUCell}
- )
+ model_load = tf.keras.models.load_model(str(tmp_path))
assert np.allclose(
model.predict(np.ones((32, 10, 20))),
diff --git a/keras_lmu/version.py b/keras_lmu/version.py
index b4f5f83e..260760de 100644
--- a/keras_lmu/version.py
+++ b/keras_lmu/version.py
@@ -1,13 +1,14 @@
# Automatically generated by nengo-bones, do not edit this file directly
-# pylint: disable=consider-using-f-string
+# pylint: disable=consider-using-f-string,bad-string-format-type
-"""KerasLMU version information.
+"""
+KerasLMU version information.
-We use semantic versioning (see http://semver.org/)
-and conform to PEP440 (see https://www.python.org/dev/peps/pep-0440/).
-'.dev0' will be added to the version unless the code base represents
-a release version. Release versions are git tagged with the version.
+We use semantic versioning (see http://semver.org/) and conform to PEP440 (see
+https://www.python.org/dev/peps/pep-0440/). '.dev0' will be added to the version
+unless the code base represents a release version. Release versions are git
+tagged with the version.
"""
version_info = (0, 4, 3)
diff --git a/pyproject.toml b/pyproject.toml
index 84fbf08a..b5c59e83 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -9,3 +9,8 @@ target-version = ['py36']
[tool.isort]
profile = "black"
src_paths = ["keras_lmu"]
+
+[tool.docformatter]
+wrap-summaries = 88
+wrap-descriptions = 81
+pre-summary-newline = true
diff --git a/setup.cfg b/setup.cfg
index a9395c39..ba859c21 100644
--- a/setup.cfg
+++ b/setup.cfg
@@ -7,6 +7,7 @@ all_files = 1
[coverage:run]
source = ./
+relative_files = True
[coverage:report]
# Regexes for lines to exclude from consideration
@@ -59,7 +60,6 @@ disable =
arguments-differ,
assignment-from-no-return,
attribute-defined-outside-init,
- bad-continuation,
blacklisted-name,
comparison-with-callable,
duplicate-code,
@@ -73,7 +73,6 @@ disable =
no-else-return,
no-member,
no-name-in-module,
- no-self-use,
not-an-iterable,
not-context-manager,
protected-access,