Skip to content

Fix TensorFlow/Keras 3 compatibility for exported .h5 models - #13

Merged
MeqdadDev merged 7 commits into
mainfrom
fix/tf-keras3-compat
Sep 12, 2026
Merged

MeqdadDev merged 7 commits into
mainfrom
fix/tf-keras3-compat

Conversation

@MeqdadDev

Copy link
Copy Markdown
Owner

Summary

Fixes #2. Teachable Machine's exported .h5 models embed a legacy DepthwiseConv2D layer config ('groups': 1) that current Keras (Keras 3, bundled by default since TensorFlow >= 2.16) rejects during deserialization:

TypeError/ValueError: Unrecognized keyword arguments passed to DepthwiseConv2D: {'groups': 1}

Since setup.py never pinned an upper/lower bound on tensorflow, pip install teachable-machine currently pulls the latest TensorFlow and breaks out of the box for the package's core (and only) use case.

Changes

  • Fix: _CompatDepthwiseConv2D shim passed via custom_objects in load_model(), so exported models load correctly on current TF/Keras without requiring users to pin an old TensorFlow version.
  • Tests: a direct unit test for the shim, plus an end-to-end regression test that builds a real model, tampers its saved .h5 config to reproduce Teachable Machine's legacy shape, and verifies it loads/classifies correctly. Confirmed the new test fails without the fix and passes with it, against a real TensorFlow 2.21.0 install.
  • Dependencies: install_requires now specifies tensorflow>=2.16; python_requires raised to >=3.9 (matches current TensorFlow's supported Python range); refreshed the stale (UTF-16 encoded, 2.12.0rc0-pinned) requirements.txt.
  • Version: bumped to 1.3.0; added CHANGELOG.md (also mirrored into the docs site nav).
  • Docs: README and docs site (docs/index.md, docs/requirements.md) get a new "Compatibility with recent TensorFlow/Keras releases" section and the updated Python requirement.
  • CI/CD: .github/workflows/tests.yml runs the test suite on push/PR across Python 3.10-3.13; .github/workflows/publish.yml publishes to PyPI via Trusted Publishing when a GitHub Release is published (setup instructions in the workflow's comments — needs a one-time trusted publisher added on PyPI before it will work).

Verification

Ran the full suite against a clean venv with TensorFlow 2.21.0 (latest as of this PR): all 8 tests pass. Verified the new regression test fails with the pre-fix loader (reproducing the exact error from #2) and passes with the fix.

🤖 Generated with Claude Code

Teachable Machine's exported .h5 models embed a legacy DepthwiseConv2D
layer config ('groups': 1) that current Keras (Keras 3, bundled by
default since TensorFlow >= 2.16) rejects during deserialization:

    TypeError/ValueError: Unrecognized keyword arguments passed to
    DepthwiseConv2D: {'groups': 1}

This has broken `pip install teachable-machine` on any current
TensorFlow install since setup.py never pinned an upper/lower bound.
Fixes #2.

- Add a _CompatDepthwiseConv2D shim passed via custom_objects in
  load_model(), so exported models load on current TF/Keras without
  pinning an old TensorFlow version.
- Add regression tests: a direct unit test for the shim, and an
  end-to-end test that builds a model, tampers its saved .h5 config to
  reproduce Teachable Machine's legacy shape, and verifies it still
  loads and classifies. Verified both that it fails without the fix
  and passes with it, against a real TensorFlow 2.21.0 install.
- Bump install_requires to tensorflow>=2.16; raise python_requires to
  >=3.9 to match current TensorFlow's supported range; refresh the
  (previously stale, UTF-16 encoded) requirements.txt.
- Bump version to 1.3.0; add CHANGELOG.md (mirrored into docs site).
- Update README and docs site with a compatibility note and the new
  Python requirement.
- Add GitHub Actions workflows: run tests on push/PR across Python
  3.10-3.13, and publish to PyPI via Trusted Publishing when a GitHub
  Release is published.
@deepsource-io

deepsource-io Bot commented Aug 31, 2026 •

Copy link
Copy Markdown
Contributor

DeepSource Code Review

We reviewed changes in 28b8891...d03f24e on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
Python Sep 12, 2026 5:57p.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

Docs deployment was entirely manual: someone runs mkdocs build locally
and commits the compiled HTML into a separate `documentation` branch's
/docs folder, which legacy GitHub Pages serves from. That branch hasn't
been touched since Aug 2024, so the live docs site predates this PR's
changes (and everything else merged to main since).

This workflow builds the site with mkdocs on every push to main that
touches docs/mkdocs.yml/src, and deploys it via actions/deploy-pages.
Verified `python -m mkdocs build` locally: mkdocstrings correctly
renders the TeachableMachine class API docs (confirms tensorflow/numpy/
PIL imports resolve during the build), no warnings.

Requires a one-time manual step (documented in the workflow's comments):
switch the repo's Pages source from "Deploy from a branch" to "GitHub
Actions" in Settings -> Pages.
show_prediction_on_image() had two latent bugs that surface together on
Windows with recent Pillow:

- ImageFont.truetype("DejaVuSans-Bold.ttf", ...) assumes that font is
  resolvable by bare name, which only holds on platforms where Pillow's
  bundled test font happens to be on the search path. On Windows it raises
  OSError: cannot open resource. Now falls back to
  ImageFont.load_default(size=...) when the named font can't be found.

- ImageDraw.textsize() was removed in Pillow 10.0.0 (this repo pulls
  Pillow 12.x), so the very next line would raise AttributeError once the
  font issue above is fixed. Replaced with textbbox(), which returns the
  same width/height via the bounding box.
textbbox()'s (left, top, right, bottom) are offsets from the point passed
in, and that offset -- particularly `top`, coming from font ascent -- is
usually not zero. The rectangle was built by measuring the text's extent
at the origin (0, 0) and then reusing that width/height as if the glyphs
started exactly at `position`, which shifts the box up and clips the
bottom of descenders (e.g. "g", "%").

Re-measure the bbox at the actual draw position instead, and pad it by a
few pixels so the highlight comfortably covers the text.
@MeqdadDev
MeqdadDev added this pull request to stack #15 September 12, 2026 17:50
Fix annotation crash: missing font on Windows + removed Pillow API
@MeqdadDev
MeqdadDev merged commit ccd3065 into main Sep 12, 2026
6 checks passed
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.

Newest version of tensorflow does not work

1 participant