Keras lets you keep the model while choosing the engine
A custom TensorFlow operation is where Keras's portability promise becomes your engineering work. Keras provides a shared Python interface for neural networks across JAX, TensorFlow and PyTorch, plus OpenVINO for inference. That's useful if you want to keep a model definition while reconsidering the framework underneath it. The decision turns on how much of your model stays inside Keras's own interfaces.
The README distinguishes models made from standard components from those containing custom layers or training steps. The former can move between training backends directly, according to the project. Custom code may need conversion. I would choose Keras for a team with a concrete reason to preserve that choice, then prove the case with its hardest custom layer before migrating the rest.
What happened when we ran it
Our Keras run installed 197 dependencies in 102 seconds, occupied 4129 MB, and hit the 900-second test limit. The build succeeded in 6 seconds. We checked commit 052ffeb on 2026-10-16 with 3 CPUs and 8 GB of RAM. The recorded image was ghcr.io/astral-sh/uv:python3.12-bookworm, which does not establish the actual interpreter or operating-system version. Those require raw toolchain logs.
The tail showed California housing cases passing, followed by failures in CIFAR-100 dtype and label-shape cases and CIFAR-10 image dtype and shape cases. A CIFAR-100 invalid-label-mode case passed. Progress still read 0%, and the final line named a CIFAR-10 label dtype case without a result. The excerpt gives no exception trace for the failures. It cannot tell us whether dataset access, package behavior or something else caused them.
Pip-audit reported 30 known vulnerabilities. The supplied block gives neither severity nor affected packages, so we cannot turn that into a count of exploitable Keras defects. The checkout contained 1035 files, about 322075 source lines and 11.7 MB before installation. Our scan recorded 16 CI workflow files, no Dockerfile and no tests directory. The integration-test paths in the log make clear that the directory signal does not mean the project lacks tests.
This run supports a successful installation and build, followed by incomplete validation with visible failures. It says nothing about model accuracy, training speed or GPU behavior. If your adoption gate requires a passing full suite, our evidence leaves that gate open. Obtain the complete failure traces before deciding which corrective action belongs in your environment.
Backend selection happens before Python imports Keras
The documented setting is KERAS_BACKEND, chosen before importing Keras. The README says the backend cannot change afterward in the same process. A comparison job therefore needs a fresh process for each engine. That is a manageable restriction for a training pipeline, but it matters if your application design assumes it can change engines midway through a request.
Keras also needs the backend package itself. Local model work does not ask for a hosted inference credential in the documented path. GPU instructions expect an NVIDIA driver and recommend separate clean environments for the backends. Windows users are directed to WSL2, while Linux and macOS are the named local platforms. Budget for that environment work independently of the attractive high-level model API.
OpenVINO is inference only. A team choosing it for model.predict() still needs another supported engine for training. That boundary makes it a serving option, rather than a route to one identical training setup everywhere. Keep the intended deployment path explicit when someone says the project supports several backends.
Custom components deserve the first migration trial
The README permits existing TensorFlow datasets and PyTorch DataLoaders with Keras models across backends. That can preserve useful input code. It doesn't establish that your custom numerical operations, saved artifacts or training behavior match across engines. Our sandbox did not exercise that comparison, and the unfinished suite cannot supply the missing assurance.
Start with a model containing your custom layer and the input pipeline you actually use. Check that its saved output can be loaded where you intend to serve it, and compare results against tolerances your application can accept. These are adoption checks I recommend, rather than outcomes we measured. A simple tutorial model would miss the part of the decision most likely to cost you a rewrite.
PyTorch and Flax make narrower framework choices
PyTorch provides neural networks with tape-based automatic differentiation. Pick its native interface when your work already depends on PyTorch operations and you have no concrete need to carry Keras model code elsewhere. That recommendation concerns API fit, not a claim that PyTorch would occupy less disk or finish our checks faster.
Flax is a neural-network library for JAX. Choose it when JAX is the settled requirement and you want a library built around it. Keras earns its extra abstraction when maintaining a shared model interface is useful enough to justify checking the engines you intend to support.
October activity matters more than the July release date
GitHub recorded a push on 2026-10-23 and 260 open issues and PRs. The recently updated activity list included work on layer weight layout and a closed pull request concerning sharded PyTorch variable conversion. Together, those observations show ongoing development. The latest-release endpoint still identified v3.12.4, published on 2026-07-29, as a security patch for dataset and model-file handling. Its age alone does not indicate abandonment.
Our documentation rating is 4/5: explicit backend, platform and custom-component guidance earns four points on a five-point scale, with the remaining point reserved for a migration path independently verified here. Setup quality, community support and production maturity remain unscored because this run and the activity snapshot cannot establish them. Before committing a migration, ask for the full CIFAR failure trace and make your custom model pass on each intended backend.

