Skip to content

Make TensorFlow an optional dependency (closes #88)#90

Open
cpmpercussion wants to merge 1 commit into
mainfrom
optional-tf-dep
Open

Make TensorFlow an optional dependency (closes #88)#90
cpmpercussion wants to merge 1 commit into
mainfrom
optional-tf-dep

Conversation

@cpmpercussion

Copy link
Copy Markdown
Owner

Summary

Split impsy into a lightweight inference-only base install and a [train] extra that adds TensorFlow + keras-mdn-layer + h5py for training and TFLite conversion. Closes #88.

  • Base install: ~104 MB (numpy + ai-edge-litert + I/O libs). Sufficient to load and run .tflite models.
  • pip install impsy[train]: adds TensorFlow 2.21 + keras-mdn-layer + h5py (~1.4 GB total). Required for impsy train, impsy convert-tflite, impsy test-mdrnn, and .keras/.h5 model loading.

This is a ~13x install-size reduction for the Raspberry Pi / performance-rig use case where models are pre-trained elsewhere.

How it works

The runtime inference path was already built on ai-edge-litert, but TensorFlow was leaking in via top-level imports in compat.py and mdrnn.py. Key changes:

  • TF and keras_mdn_layer imports are deferred inside training-only functions via _require_tensorflow() / _require_keras_mdn() helpers that raise a friendly ImportError naming the [train] extra.
  • keras_mdn_layer.sample_from_output was pure NumPy at runtime but its parent module needs a Keras backend on import. It's inlined as sample_mdn_output in mdrnn.py so the inference path no longer depends on Keras at all.
  • lstm_blank_states now returns NumPy arrays. Keras 3 doesn't allow mixing tf.Tensor and NumPy in nested call arguments, so the PredictiveMusicMDRNN and KerasMDRNN paths also feed NumPy in (Keras converts internally).
  • CLI commands train, convert-tflite, test-mdrnn, and the KerasMDRNN fallback in interaction.build_network catch ImportError and surface pip install impsy[train] via click.ClickException instead of raw tracebacks.

CI

  • New base-install-test job (Ubuntu, Python 3.13): installs pip install . pytest with no extras, asserts tensorflow is absent, runs tests/test_base_install.py, verifies CLI loads. Single-platform on purpose — this test is about dependency surface, not platform compat.
  • Existing smoke-test and full-matrix jobs switch to poetry install --extras train so the full matrix continues to exercise training and TFLite conversion.

Test plan

  • poetry run pytest with [train] extra installed: 162 passed, 1 skipped (the friendly-ImportError test correctly skips when TF is available)
  • pip install . in a fresh venv (no TF): import impsy works, tests/test_base_install.py 5/5 passes, impsy --help works
  • impsy run works on base install (uses DummyMDRNN fallback when no model configured)
  • impsy train, impsy test-mdrnn, impsy convert-tflite on base install emit Error: TensorFlow is required ... Install the training extra: pip install impsy[train].
  • Sanity check on a real Raspberry Pi (out of scope for this PR; the impsy-pi repo will need a follow-up to switch to the slimmer install)
  • Cut a release once merged so the lighter wheel is on PyPI

🤖 Generated with Claude Code

Split `impsy` into a lightweight inference-only base install and a `[train]`
extra that adds TensorFlow + keras-mdn-layer + h5py for training and TFLite
conversion. The base install is ~104 MB vs ~1.4 GB previously, which makes
Raspberry Pi and dedicated performance-rig deployments much faster to set up.

Why this works: the runtime inference path was already built on
`ai-edge-litert`, but TensorFlow was leaking in via top-level imports in
`compat.py` and `mdrnn.py`. The MDN sampler (`keras_mdn_layer.sample_from_output`)
was pure NumPy at runtime but its parent module needs a Keras backend on
import, so it's inlined as `sample_mdn_output` in `mdrnn.py`.

Changes:
- `pyproject.toml`: tensorflow, keras-mdn-layer, h5py move to `[train]` extra;
  numpy added as an explicit base dep (was transitive via TF).
- `impsy/compat.py`, `impsy/mdrnn.py`, `impsy/tflite_converter.py`: TF and
  keras-mdn-layer imports deferred inside training-only functions.
- `lstm_blank_states` returns NumPy arrays; Keras paths now feed NumPy in
  (matching the Keras 3 nested-call rules).
- CLI commands `train`, `convert-tflite`, `test-mdrnn` and the `KerasMDRNN`
  fallback in `interaction.build_network` catch ImportError and surface a
  clear `pip install impsy[train]` hint instead of a raw traceback.
- New base-only CI job (Ubuntu 3.13) that installs without the extra,
  asserts TF is absent, and runs `tests/test_base_install.py`.
- Existing CI jobs switch to `poetry install --extras train` so the full
  matrix still exercises training and conversion.
- README quickstart now distinguishes perform-only from training installs.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copilot AI review requested due to automatic review settings May 24, 2026 02:50

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR splits impsy into an inference-only base install and a [train] extra so TensorFlow/Keras are only required for training and model conversion, reducing install size and making Raspberry Pi/performance-rig deployments feasible without TF.

Changes:

  • Move TensorFlow / keras_mdn_layer usage behind lazy import helpers and inline the MDN sampler so inference paths don’t import TF.
  • Add a new inference-only test (tests/test_base_install.py) and a GitHub Actions job to validate pip install . works without TensorFlow.
  • Update packaging metadata, CLI commands, and docs to support/advertise impsy[train] for training/conversion workflows.

Reviewed changes

Copilot reviewed 10 out of 11 changed files in this pull request and generated 2 comments.

Show a summary per file
File Description
tests/test_base_install.py Adds TF-free smoke tests to ensure inference imports and .tflite execution work without [train].
README.md Documents the base vs train extra install paths and when each is needed.
pyproject.toml Moves TF-related deps to [project.optional-dependencies].train and adds explicit numpy base dep.
impsy/train.py Wraps training entry point to surface missing-TF ImportErrors as ClickExceptions.
impsy/tflite_converter.py Defers TF import and provides a friendly missing-TF error for conversion commands.
impsy/tests.py Wraps test-mdrnn CLI to show a friendly error when training deps are missing.
impsy/mdrnn.py Removes top-level TF/Keras imports, adds lazy import helpers, and inlines MDN sampling for TF-free inference.
impsy/interaction.py Catches missing training deps when attempting to load .keras/.h5 models and shows a user-facing message.
impsy/compat.py Defers TF imports inside TF-only helpers so base installs can import the module.
.github/workflows/python-app.yml Installs [train] extra for existing CI jobs and adds a base-install test job ensuring TF is absent.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.


from __future__ import annotations

import importlib
Comment thread impsy/tflite_converter.py
Comment on lines 79 to 83
def model_file_to_tflite(filename, save_path=None, optimise=False):
"""Converts a given model"""
tf = _require_tensorflow()
import keras_mdn_layer as mdn_layer

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Make TensorFlow an optional dependency — lightweight inference-only install

2 participants