Keras 3.15.0 — Multi-backend deep learning framework for Python. Build models once and run them on TensorFlow, JAX, PyTorch, NumPy, or OpenVINO without changing a single line of model code.
This guide covers architecture internals, configuration, deployment patterns, performance tuning, security, and developer workflows. For installation, everyday usage, and model-building tutorials, see the User Guide.
1. Architecture Overview
Keras 3 is a ground-up rewrite that decouples the high-level modeling API from any single computation backend. The architecture consists of five major subsystems: backend dispatch, layer/model hierarchy, training loop, serialization, and ops abstraction.
1.1 Backend Dispatch
Backend selection happens exactly once — at import keras time — and is immutable for the lifetime of the process. The selection logic in keras/src/backend/__init__.py follows this priority:
KERAS_BACKENDenvironment variable (highest priority)"backend"key in~/.keras/keras.json- Default:
"tensorflow"
Once resolved, the backend module (keras.src.backend.{name}) is loaded via wildcard import, making all backend-specific implementations available through a single namespace. Each backend implements a standardized set of modules:
| Module | Purpose |
|---|---|
core.py |
Tensor creation, casting, basic operations |
nn.py |
Neural network primitives (conv, pool, softmax) |
numpy.py |
NumPy-compatible array operations |
math.py |
Mathematical functions |
image.py |
Image processing operations |
linalg.py |
Linear algebra |
random.py |
Random number generation |
rnn.py |
Recurrent network operations |
trainer.py |
Backend-specific training loop |
layer.py |
Backend-specific layer behavior |
export.py |
Model export to backend-native formats |
JAX and TensorFlow backends additionally implement distribution_lib.py for multi-device distributed training. NumPy and OpenVINO backends set distribution_lib = None — these are inference-only backends that do not support training or distribution.
Note
When the active backend is anything other than TensorFlow, Keras automatically sets
TF_FORCE_GPU_ALLOW_GROWTH=trueto prevent TensorFlow (which may still be installed as a dependency) from pre-allocating all GPU memory. This is critical in environments where JAX or PyTorch needs GPU access.
1.2 Layer and Model Hierarchy
The class hierarchy is:
Operation
└── Layer
└── Model (also inherits Trainer)
├── Sequential
└── Functional
Layer (keras/src/layers/layer.py) is the fundamental building block. It implements:
- Deferred weight creation via
build()— weights are allocated on first call when input shapes are known - Forward pass via
call() - Automatic variable tracking through the
Trackerutility (keras/src/utils/tracking.py), which wraps Python containers (TrackedList,TrackedDict,TrackedSet,TrackedOrderedDict) to monitor attribute mutations - Serialization via
get_config()/from_config() - Quantization via
quantize(mode)and LoRA viaenable_lora(rank) - Name scoping via
keras.name_scopefor hierarchical naming
Model (keras/src/models/model.py) adds training capabilities. Its __new__ method inspects the active backend at instantiation time and returns a backend-specific Trainer subclass (JAX Trainer, TF Trainer, Torch Trainer, NumPy Trainer, or OpenVINO Trainer). This is transparent to user code.
Three model construction patterns:
| Pattern | Class | How It Works |
|---|---|---|
| Subclassing | Model |
Override call(), imperative style |
| Sequential | Sequential |
Linear layer stack via add() / pop() |
| Functional | Functional |
DAG from Input() → layer calls → Model(inputs, outputs) |
Sequential validates that each layer accepts a single positional argument and auto-creates an InputLayer when batch_shape is provided. Functional builds a directed acyclic graph and uses _run_through_graph() for graph traversal, supporting optional inputs.
1.3 Operations System
The keras/src/ops/ package provides backend-agnostic mathematical operations. These are not thin wrappers — each op has a symbolic path (for graph tracing) and a concrete path (for eager execution):
core.py: Control flow —scan,while_loop,cond,fori_loop,stop_gradient,custom_gradient,vectorized_mapnumpy.py: Full NumPy-compatible API (200+ functions)nn.py: Neural network operations — convolutions, pooling, activations, normalizationmath.py: Mathematical operations beyond NumPyimage.py: Image processing (resize, crop, affine transforms)linalg.py: Linear algebra (solve, SVD, cholesky, etc.)einops.py: Einstein notation operations (rearrange)
The Operation base class (keras/src/ops/operation.py) tracks computation graphs via Node objects (keras/src/ops/node.py). The Function class (keras/src/ops/function.py) traces operations into a reusable computation graph.
1.4 Trainer System
The training loop (keras/src/trainers/trainer.py) implements compile(), fit(), evaluate(), and predict(). Compilation binds a loss function, optimizer, and metrics to the model via compile_utils.py.
Data flows through data adapters (keras/src/trainers/data_adapters/), which normalize different input formats into a consistent iterator interface:
| Adapter | Input Type |
|---|---|
ArrayDataAdapter |
NumPy arrays, lists |
TFDatasetAdapter |
tf.data.Dataset |
TorchDataLoaderAdapter |
torch.utils.data.DataLoader |
PyDatasetAdapter |
keras.utils.PyDataset (multiprocessing) |
GeneratorDataAdapter |
Python generators |
GrainDatasetAdapter |
Grain datasets (JAX ecosystem) |
The EpochIterator (epoch_iterator.py) manages epoch/step iteration, calling the appropriate data adapter and yielding batches.
1.5 Serialization Architecture
Keras uses a layered serialization system in keras/src/saving/:
.kerasformat (saving_lib.py): A zip archive containingconfig.json(model topology + layer configs) andmodel.weights.h5(weights in HDF5). This is the primary save format.- Object serialization (
serialization_lib.py): Converts arbitrary Keras objects to/from JSON-safe dictionaries using a class registry. Custom objects must be registered via@keras.saving.register_keras_serializable. - Object registration (
object_registration.py): Global registry mapping class names to implementations. - File editor (
file_editor.py): Allows in-place editing of saved model files without full deserialization. - Orbax integration (
orbax_util.py): JAX checkpointing via the Orbax library. - Legacy (
keras/src/legacy/saving/): HDF5 format support for backward compatibility.
1.6 Export Subsystem
The export system (keras/src/export/) converts trained models to deployment-ready formats:
| Format | Module | Requirements |
|---|---|---|
| TF SavedModel | saved_model.py |
TensorFlow backend or installed |
| LiteRT (TFLite) | litert.py |
TensorFlow backend required |
| ONNX | onnx.py, tf2onnx_lib.py |
tf2onnx package |
| OpenVINO IR | openvino.py |
openvino package |
| Neptune | neptune_model_export_archive.py |
Neptune SDK |
The TFSMLayer class (tfsm_layer.py) enables loading a TF SavedModel back as a Keras layer, enabling interop with non-Keras TensorFlow models.
1.7 Quantization Architecture
Keras supports post-training quantization through keras/src/quantizers/:
| Mode | Implementation | Description |
|---|---|---|
int8 |
quantizers.py |
8-bit integer quantization |
int4 |
quantizers.py |
4-bit integer quantization |
float8 |
quantizers.py |
8-bit floating point |
awq |
awq.py, awq_core.py, awq_config.py |
Activation-aware weight quantization |
gptq |
gptq.py, gptq_core.py, gptq_config.py |
Post-training quantization (GPT-Q) |
LoRA (Low-Rank Adaptation) is supported on Dense, EinsumDense, and Embedding layers via enable_lora(rank). LoRA is incompatible with GPTQ quantization and certain kernel constraints.
1.8 Distribution System
Multi-device training is implemented in keras/src/distribution/distribution_lib.py with backend-specific implementations:
- JAX:
keras/src/backend/jax/distribution_lib.py— uses JAX'spjitand mesh-based sharding - TensorFlow:
keras/src/backend/tensorflow/distribution_lib.py— usestf.distributestrategies
NumPy and OpenVINO backends do not support distribution.
1.9 Knowledge Distillation
The keras/src/distillation/ module provides:
distiller.py:Distillerclass — a training wrapper that takes a teacher model and student model, training the student to match the teacher's outputsdistillation_loss.py: Custom loss combining student task loss with teacher-student divergence
2. System Requirements
2.1 Python Version
Keras 3.15.0 requires Python 3.9+. The pyproject.toml specifies requires-python = ">= 3.9".
2.2 Backend-Specific Dependencies
Each backend has its own requirements file. Install only the backend(s) you need:
TensorFlow backend:
pip install keras tensorflow
# GPU (CUDA):
pip install keras -r requirements-tensorflow-cuda.txt
# TPU:
pip install keras -r requirements-tensorflow-tpu.txt
On non-macOS systems, tensorflow-cpu is sufficient for CPU-only workloads. On macOS, use tensorflow (which includes Metal acceleration).
JAX backend:
pip install keras jax[cpu] flax
# GPU (CUDA):
pip install keras -r requirements-jax-cuda.txt
# TPU:
pip install keras -r requirements-jax-tpu.txt
PyTorch backend:
pip install keras torch
# GPU (CUDA):
pip install keras -r requirements-torch-cuda.txt
torch-xla is additionally required on non-macOS platforms for XLA compilation support.
NumPy backend (inference only):
pip install keras numpy
OpenVINO backend (inference only):
pip install keras openvino
Important
The NumPy and OpenVINO backends support inference only —
model.fit()andmodel.train_on_batch()will raise errors. Use these backends strictly formodel.predict()andmodel()calls.
2.3 Common Dependencies
The requirements-common.txt file lists shared dependencies across all backends. These are pulled in automatically when installing Keras via pip.
2.4 Optional Dependencies
| Package | Feature |
|---|---|
pydot |
keras.utils.plot_model() visualization |
tf2onnx |
ONNX export |
openvino |
OpenVINO export (separate from OpenVINO backend) |
ai-edge-litert |
LiteRT (TFLite) export |
3. Configuration Reference
3.1 Config File
Keras reads configuration from ~/.keras/keras.json at import time. The config directory can be overridden with the KERAS_HOME environment variable. If the home directory is not writable, Keras falls back to /tmp.
Example keras.json:
{
"floatx": "float32",
"epsilon": 1e-7,
"backend": "tensorflow",
"image_data_format": "channels_last",
"nnx_enabled": false
}
3.2 Configuration Parameters
All configuration is managed through module-level globals in keras/src/backend/config.py with getter/setter pairs:
| Parameter | Default | Getter | Setter | Description |
|---|---|---|---|---|
_FLOATX |
"float32" |
floatx() |
set_floatx(value) |
Default float dtype for weights and computations |
_EPSILON |
1e-7 |
epsilon() |
set_epsilon(value) |
Small constant for numerical stability |
_IMAGE_DATA_FORMAT |
"channels_last" |
image_data_format() |
set_image_data_format(value) |
"channels_last" (NHWC) or "channels_first" (NCHW) |
_BACKEND |
"tensorflow" |
backend() |
— (immutable after import) | Active computation backend |
_NNX_ENABLED |
False |
is_nnx_enabled() |
set_nnx_enabled(value) |
Enable Flax NNX features for JAX backend |
_MAX_EPOCHS |
None |
max_epochs() |
set_max_epochs(value) |
Cap on training epochs (debugging) |
_MAX_STEPS_PER_EPOCH |
None |
max_steps_per_epoch() |
set_max_steps_per_epoch(value) |
Cap on steps per epoch (debugging) |
Important
The backend cannot be changed after
import keras. To switch backends, set the environment variable before importing:os.environ["KERAS_BACKEND"] = "jax"must come beforeimport keras. Alternatively, set it in the shell:KERAS_BACKEND=jax python train.py.
3.3 Environment Variables
| Variable | Purpose | Default |
|---|---|---|
KERAS_BACKEND |
Select backend: tensorflow, jax, torch, numpy, openvino |
tensorflow |
KERAS_HOME |
Override config directory location | ~/.keras |
KERAS_MAX_EPOCHS |
Cap training epochs (useful for CI/debugging) | None (unlimited) |
KERAS_MAX_STEPS_PER_EPOCH |
Cap steps per epoch | None (unlimited) |
KERAS_NNX_ENABLED |
Enable Flax NNX integration ("true") |
"false" |
TF_FORCE_GPU_ALLOW_GROWTH |
Auto-set by Keras when backend ≠ tensorflow | — |
3.4 Runtime Configuration
Configuration can be changed at runtime through the Python API:
import keras
# Change float precision
keras.config.set_floatx("float16")
# Change image data format
keras.config.set_image_data_format("channels_first")
# Change epsilon for numerical stability
keras.config.set_epsilon(1e-5)
# Limit training for debugging
keras.config.set_max_epochs(2)
keras.config.set_max_steps_per_epoch(10)
# Enable Flax NNX (JAX backend only)
keras.config.set_nnx_enabled(True)
3.5 Mixed Precision
Keras supports mixed precision training through dtype policies (keras/src/dtype_policies/):
keras.mixed_precision.set_global_policy("mixed_float16")
This configures layers to use float16 for computations while keeping float32 for weight storage, reducing memory usage and improving throughput on GPUs with Tensor Cores.
4. Deployment & Scaling
4.1 Model Export for Production
Keras does not include a serving runtime — it is a library for building and training models. Deployment involves exporting to a format consumed by a serving system.
TF SavedModel (recommended for TensorFlow Serving):
model.export("./saved_model_dir")
# Or with format specification:
model.export("./saved_model_dir", format="tf_saved_model")
LiteRT / TFLite (mobile and edge):
model.export("model.tflite", format="tflite")
This requires the TensorFlow backend and the ai-edge-litert package.
ONNX (cross-platform):
model.export("model.onnx", format="onnx")
Requires tf2onnx. The export goes through TF SavedModel as an intermediate step.
OpenVINO IR (Intel hardware):
model.export("model_dir", format="openvino")
Tip
For maximum portability, export to ONNX. For best performance on Intel hardware, export to OpenVINO IR. For the TensorFlow ecosystem (TF Serving, TFX), export to SavedModel.
4.2 Distributed Training
Distributed training is supported on JAX and TensorFlow backends via the distribution API:
import keras
from keras.distribution import DeviceMesh, LayoutMap, ModelParallel
# Create a device mesh
devices = keras.distribution.list_devices()
mesh = DeviceMesh(shape=(2, 4), axis_names=["batch", "model"], devices=devices)
# Define how tensors map to devices
layout_map = LayoutMap(mesh)
layout_map[".*dense.*kernel"] = ("model", None)
layout_map[".*dense.*bias"] = ("model",)
# Apply distribution strategy
distribution = ModelParallel(mesh, layout_map=layout_map)
keras.distribution.set_distribution(distribution)
# Build and train model as usual
model = create_model()
model.compile(optimizer="adam", loss="mse")
model.fit(dataset)
4.3 Quantization for Deployment
Reduce model size and improve inference speed:
# Post-training quantization
model.quantize("int8") # or "int4", "float8"
# AWQ (requires calibration data)
model.quantize("awq")
# GPTQ (requires calibration data)
model.quantize("gptq")
# Save quantized model
model.save("quantized_model.keras")
Warning
Quantization is a one-way operation on the model instance. Always save your full-precision model before quantizing. The quantized model will have reduced numerical precision and may show degraded accuracy on some tasks.
4.4 Build System
Keras uses pip_build.py for wheel creation:
# Build wheel package
python3 pip_build.py
# Output: dist/keras-3.15.0-py3-none-any.whl
# Build and install locally
python3 pip_build.py --install
# Nightly build (appends dev version suffix)
python3 pip_build.py --nightly
# Release candidate
python3 pip_build.py --rc 1
The build process copies source to tmp_build_dir, excludes _test.py files, and runs python3 -m build. Package metadata is defined in pyproject.toml.
5. Operations
5.1 Pre-trained Applications
Keras ships with pre-trained model architectures in keras/src/applications/ (VGG, ResNet, EfficientNet, MobileNet, etc.). Weights are downloaded on first use and cached in KERAS_HOME/models/.
from keras.applications import ResNet50
model = ResNet50(weights="imagenet")
Weight files are fetched via keras.utils.get_file(), which supports SHA256/MD5 hash verification for integrity.
5.2 File Downloads and Caching
The get_file() utility (keras/src/utils/file_utils.py) manages file downloads:
- Default cache directory:
~/.keras/(overridden byKERAS_HOME) - Supports hash verification (SHA256, MD5) for downloaded files
- Implements path traversal protection with symlink validation
5.3 Callbacks for Operational Monitoring
Keras provides built-in callbacks for monitoring training:
| Callback | Purpose |
|---|---|
ModelCheckpoint |
Save model at intervals |
EarlyStopping |
Stop training when metric plateaus |
TensorBoard |
Log metrics for TensorBoard visualization |
CSVLogger |
Log metrics to CSV file |
ProgbarLogger |
Display progress bar |
ReduceLROnPlateau |
Reduce learning rate on plateau |
LearningRateScheduler |
Custom learning rate schedules |
RemoteMonitor |
Send metrics to a remote server |
BackupAndRestore |
Fault-tolerant training with checkpointing |
TerminateOnNaN |
Stop on NaN loss |
LambdaCallback |
Custom callback via lambdas |
SwapEMAWeights |
Swap in EMA weights for evaluation |
Note
BackupAndRestoreis essential for long-running training jobs on preemptible instances. It saves training state (epoch, step) and restores automatically on restart.
5.4 Debugging Training Issues
Use the epoch/step capping environment variables to rapidly iterate:
# Run only 2 epochs with 10 steps each
KERAS_MAX_EPOCHS=2 KERAS_MAX_STEPS_PER_EPOCH=10 python train.py
Or set programmatically:
keras.config.set_max_epochs(2)
keras.config.set_max_steps_per_epoch(10)
Tip
These caps are ideal for CI pipelines where you want to verify the training loop runs without errors, but don't need convergence. They also work for debugging data loading and preprocessing pipelines.
5.5 Model Visualization
Generate architecture diagrams (requires pydot):
keras.utils.plot_model(
model,
to_file="model.png",
show_shapes=True,
show_layer_names=True,
show_dtype=True,
show_layer_activations=True,
show_trainable=True,
)
The model_to_dot() function returns a pydot.Dot object for programmatic graph manipulation.
Image-specific visualization tools in keras/src/visualization/:
draw_bounding_boxes()— overlay boxes on imagesdraw_segmentation_masks()— overlay masks on imagesplot_bounding_box_gallery(),plot_image_gallery(),plot_segmentation_mask_gallery()— gallery views
6. Performance
6.1 Backend Selection for Performance
Backend choice has significant performance implications:
| Backend | Best For | Training | GPU | TPU |
|---|---|---|---|---|
| TensorFlow | Production serving, TF ecosystem | Yes | Yes | Yes |
| JAX | Research, TPU workloads, functional style | Yes | Yes | Yes |
| PyTorch | Research, PyTorch ecosystem integration | Yes | Yes | No |
| NumPy | CPU inference, debugging | No | No | No |
| OpenVINO | Intel CPU/GPU/VPU inference | No | Intel only | No |
6.2 Mixed Precision Training
Enable float16 computation with float32 master weights:
keras.mixed_precision.set_global_policy("mixed_float16")
This typically provides 2-3x speedup on GPUs with Tensor Cores (NVIDIA Volta and later) with minimal accuracy impact. For TPUs, use "mixed_bfloat16".
6.3 Data Pipeline Performance
The data adapter system (keras/src/trainers/data_adapters/) abstracts input formats, but performance characteristics differ:
tf.data.Dataset(TFDatasetAdapter): Best for TensorFlow backend. Supports prefetching, parallel mapping, and interleaving.torch.utils.data.DataLoader(TorchDataLoaderAdapter): Best for PyTorch backend. Supports multi-worker loading.keras.utils.PyDataset(PyDatasetAdapter): Backend-agnostic multiprocessing data loading. Setworkersanduse_multiprocessingparameters.GrainDatasetAdapter: For JAX ecosystem Grain datasets.
6.4 XLA Compilation
JAX uses XLA compilation by default. For TensorFlow, enable with:
model.compile(optimizer="adam", loss="mse", jit_compile=True)
XLA compilation fuses operations and optimizes memory layout, often providing 20-50% speedup for computation-bound models. However, it increases initial compilation time and may not support all operations.
6.5 Image Data Format
The image_data_format setting affects convolution and pooling layer behavior:
"channels_last"(NHWC): Default. Best performance on most GPUs via cuDNN."channels_first"(NCHW): May be faster on some older NVIDIA GPUs and is the PyTorch convention.
keras.config.set_image_data_format("channels_first")
6.6 Quantization Performance Impact
| Mode | Model Size Reduction | Inference Speedup | Accuracy Impact |
|---|---|---|---|
int8 |
~4x | 2-4x (hardware dependent) | Low |
int4 |
~8x | Variable | Moderate |
float8 |
~2x | 1.5-2x | Very low |
awq |
~4x | 2-4x | Low (activation-aware) |
gptq |
~4x | 2-4x | Low (calibration-based) |
7. Security
7.1 Deserialization Safety
Keras implements a security boundary around model deserialization. By default, only known Keras classes can be deserialized. Two scenarios require explicit opt-in:
Lambda layers:
# Lambda layers contain arbitrary Python code
# Loading a model with Lambda layers requires:
keras.config.enable_unsafe_deserialization()
model = keras.models.load_model("model_with_lambda.keras")
Torch nn.Module wrappers:
# TorchModuleWrapper also carries arbitrary code
keras.config.enable_unsafe_deserialization()
model = keras.models.load_model("model_with_torch_module.keras")
Caution
enable_unsafe_deserialization()allows arbitrary code execution during model loading. NEVER call this on models from untrusted sources. A malicious.kerasfile with Lambda layers can execute arbitrary Python code on your system.
7.2 File Download Integrity
The get_file() utility supports cryptographic hash verification:
path = keras.utils.get_file(
"weights.h5",
"https://example.com/weights.h5",
file_hash="abc123...",
hash_algorithm="sha256" # or "md5"
)
Always provide file_hash when downloading weights from external sources to verify integrity.
7.3 Path Traversal Protection
keras/src/utils/file_utils.py implements protections against path traversal attacks:
- Symlink validation prevents following symbolic links outside expected directories
- Path filtering rejects suspicious path components
7.4 Serialization Registry Validation
The serialization_lib.py module validates class names during deserialization against a registry of known safe classes. However, GitHub issue #22703 reports a gap where deserialize_keras_object accepts arbitrary registered_name values. Exercise caution when loading models from untrusted sources, even without enable_unsafe_deserialization().
Warning
Do not load
.kerasmodel files from untrusted sources without reviewing theconfig.jsoninside the archive first. You can inspect it by unzipping the.kerasfile (it is a standard zip archive) and examining the class references.
7.5 Security Checklist for Production
- Never call
enable_unsafe_deserialization()in production serving pipelines - Always verify file hashes when downloading pre-trained weights
- Audit
config.jsonin.kerasfiles before loading models from third parties - Pin Keras and backend versions in production
requirements.txt - Use quantized/exported models (SavedModel, ONNX, OpenVINO IR) for serving — these have a smaller attack surface than
.kerasfiles with arbitrary Python
8. Developer Internals
8.1 API Generation System
The public API in keras/api/ is entirely auto-generated — never edit files in this directory manually. The generation system works as follows:
- Developers annotate classes and functions with
@keras_export("keras.path.to.symbol")(defined inkeras/src/api_export.py) - The
api_gen.pyscript copies source to a build directory and runsnamex.generate_api_files(), which reads the export decorators and generates thekeras/api/tree - A
_tf_keras/compatibility shim directory is created for backward compatibility withtf.kerasimports - The pre-commit hook (
.pre-commit-config.yaml) runsshell/api_gen.shautomatically on every commit, followed byrufffor linting/formatting
To regenerate the API manually:
bash shell/api_gen.sh
Caution
Any manual edits to files under
keras/api/will be silently overwritten by the next API generation run (either via pre-commit hook or manualapi_gen.shexecution). Always edit the source files underkeras/src/and add@keras_exportdecorators.
8.2 Adding a New Layer
- Create the implementation file in the appropriate
keras/src/layers/subdirectory - Implement
__init__,build,call,get_config - Add the
@keras_export("keras.layers.YourLayer")decorator - Write tests in a
*_test.pyfile alongside the implementation - Run
bash shell/api_gen.shto regenerate the public API - The pre-commit hook will also handle this automatically
8.3 Adding a New Op
- Add the symbolic class and function to the appropriate ops module (
keras/src/ops/numpy.py,nn.py, etc.) - Implement the backend-specific version in each backend's corresponding module
- Add
@keras_exportdecorator - Write tests covering all backends
8.4 Testing
Keras uses pytest with custom markers defined in conftest.py:
# Run all tests
pytest
# Run tests for a specific module
pytest keras/src/layers/core/dense_test.py
# Run only tests that don't require a trainable backend
pytest -m "not requires_trainable_backend"
# Run multi-device tests
pytest -m "multi_device"
Test configuration (conftest.py):
- Registers pytest markers:
requires_trainable_backend,multi_device - Disables TF32 for numerical accuracy in tests (TF32 introduces small numerical differences that cause test failures)
- Handles OpenVINO-excluded tests
Tests are colocated with source — every foo.py has a corresponding foo_test.py in the same directory.
Integration tests (integration_tests/):
- Basic flow validation
- Custom training loops per backend (JAX, TF, Torch)
- Model visualization
- PyTorch export
- Dataset tests
Benchmarks (benchmarks/):
- Layer benchmarks
- Model benchmarks (BERT, image classification)
- Torch CTL (Custom Training Loop) benchmarks
8.5 Code Formatting
Keras uses ruff for both linting and formatting:
bash shell/format.sh
The pre-commit hook runs ruff automatically after API generation.
8.6 Key Internal Classes
Variable (keras/src/backend/common/variables.py): Wraps backend-specific tensor variables. Handles dtype casting, naming, and trainable/non-trainable distinction.
KerasTensor (keras/src/backend/common/keras_tensor.py): Symbolic tensor representation used during model building (before eager execution). Carries shape and dtype metadata for graph construction.
AutocastScope: Context manager that temporarily overrides the dtype policy, enabling mixed-precision scoping within specific model sections.
StatelessScope: Context manager for stateless execution — variables are provided as explicit arguments rather than read from the layer's internal state. Used by JAX's functional paradigm.
Tracker (keras/src/utils/tracking.py): Monitors attribute assignments on Layer objects. When you assign a Variable, Layer, Metric, or Optimizer to a layer attribute, Tracker automatically registers it in the appropriate collection (weights, layers, metrics, etc.).
Config: Frozen dict-like object used for layer configuration snapshots. Immutable after creation.
8.7 The __new__ Pattern in Model
Model.__new__ is a critical piece of the multi-backend architecture. When you write model = Model(...), __new__ inspects keras.backend.backend() and returns an instance of the appropriate backend-specific Trainer subclass. This means type(model) is not Model but rather JAXTrainer, TFTrainer, TorchTrainer, NumPyTrainer, or OpenVINOTrainer, depending on the active backend. All of these are transparent to user code since they share the Model interface.
8.8 Tree Utilities
keras/src/tree/ provides a unified interface for traversing nested Python structures (lists, tuples, dicts). It wraps backend-specific implementations:
dmtree(Google DeepMind's tree library)optree(JAX ecosystem)torch.utils._pytree(PyTorch)
These are used extensively in the trainer and ops systems for handling nested inputs/outputs.
9. Integration Points
9.1 Backend Interoperability
Keras models can interoperate with native backend code:
JAX:
# Use JAX transformations on Keras models
import jax
@jax.jit
def predict(params, x):
return model.stateless_call(params, {}, x)[0]
# Use JAX layers in Keras via JaxLayer/FlaxLayer
from keras.wrappers import JaxLayer, FlaxLayer
PyTorch:
# Wrap a torch.nn.Module as a Keras layer
from keras.wrappers import TorchModuleWrapper
keras_layer = TorchModuleWrapper(torch_module)
# Keras models are torch.nn.Module subclasses when using torch backend
# Standard PyTorch training loops work directly
TensorFlow:
# Load TF SavedModel as a Keras layer
from keras.export import TFSMLayer
layer = TFSMLayer("path/to/saved_model")
# Use tf.data.Dataset directly with model.fit()
model.fit(tf_dataset, epochs=10)
9.2 Scikit-learn Integration
keras/src/wrappers/ provides scikit-learn compatible wrappers:
from keras.wrappers import SKLearnClassifier, SKLearnRegressor
# Use with sklearn pipelines, cross-validation, grid search
from sklearn.model_selection import cross_val_score
estimator = SKLearnClassifier(build_fn=create_model)
scores = cross_val_score(estimator, X, y, cv=5)
9.3 Data Format Compatibility
Keras accepts data from multiple ecosystems without conversion:
| Input Format | Adapter | Backend Affinity |
|---|---|---|
| NumPy arrays | ArrayDataAdapter |
All |
| Python lists | ArrayDataAdapter |
All |
tf.data.Dataset |
TFDatasetAdapter |
TensorFlow |
torch.utils.data.DataLoader |
TorchDataLoaderAdapter |
PyTorch |
keras.utils.PyDataset |
PyDatasetAdapter |
All |
| Python generators | GeneratorDataAdapter |
All |
| Grain datasets | GrainDatasetAdapter |
JAX |
9.4 Pre-trained Model Ecosystem
Keras includes pre-trained architectures in keras/src/applications/:
- Classification: VGG16/19, ResNet50/101/152, InceptionV3, EfficientNetV2, MobileNetV2/V3, DenseNet, NASNet, ConvNeXt, Xception
- Feature extraction: Use
include_top=Falseto get feature maps
All weights are downloaded from the Keras model repository and cached in KERAS_HOME/models/.
Troubleshooting
Error: RuntimeError: Backend cannot be changed after import
Cause: KERAS_BACKEND was set or keras.config.set_backend() was called after import keras.
Solution:
- Set the environment variable before any Keras import:
import os os.environ["KERAS_BACKEND"] = "jax" import keras - Or set it in the shell before running your script:
KERAS_BACKEND=jax python train.py
Prevention: Always set backend configuration before importing Keras. Use shell-level environment variables in production scripts.
Error: ValueError: Unknown backend: 'xyz'
Cause: Invalid value for KERAS_BACKEND or backend in keras.json.
Solution:
- Check your
~/.keras/keras.jsonfile for typos - Valid values:
tensorflow,jax,torch,numpy,openvino
Prevention: Validate backend names against the five supported options.
Error: NotImplementedError during model.fit() with NumPy/OpenVINO backend
Cause: NumPy and OpenVINO are inference-only backends. Training operations are not implemented.
Solution:
- Switch to a trainable backend (TensorFlow, JAX, or PyTorch) for training
- Use NumPy/OpenVINO only for
model.predict()or directmodel()calls
Prevention: Choose a trainable backend for any workflow involving fit(), train_on_batch(), or gradient computation.
Error: ImportError: Lambda layers require unsafe deserialization
Cause: Loading a model containing Lambda layers without enabling unsafe deserialization.
Solution:
- If you trust the model source:
keras.config.enable_unsafe_deserialization() model = keras.models.load_model("model.keras") - If you do not trust the source, inspect the
.kerasfile first:
Look forunzip -p model.keras config.json | python -m json.toolLambdaor custom class references.
Prevention: Avoid Lambda layers in production models. Use named layers or subclassing instead.
Error: Gradient divergence between backends (e.g., TF vs Torch)
Cause: Numerical differences in gradient computation across backends. GitHub issue #22695 documents this for Conv1D + Flatten with channels_first. Issue #22697 reports similar divergence in recurrent WDCG.
Solution:
- Ensure
image_data_formatis consistent across backends - Test numerical equivalence with
channels_lastformat (better cross-backend consistency) - Increase
epsilonif losses involve division near zero - Compare outputs layer-by-layer to isolate the divergent operation
Prevention: Run cross-backend numerical tests for critical models. Use channels_last as the default format for maximum compatibility.
Error: MelSpectrogram validation failure with symbolic inputs
Cause: GitHub issue #22535 — fft_length validation fails when input shapes are symbolic (during model building).
Solution:
- Provide explicit
input_shapeto the layer to avoid symbolic shape inference - Check for updates in Keras releases that address this issue
Prevention: Pin to a Keras version where the fix is available. Test preprocessing layers with both symbolic and eager inputs.
Error: IntegerLookup OOV error with num_oov_indices=0
Cause: GitHub issue #22521 — validation logic incorrectly handles the case where num_oov_indices is set to 0.
Solution:
- Set
num_oov_indices=1(default) unless you specifically need to disable OOV handling - Filter input data to ensure all values are in the vocabulary
Prevention: Test preprocessing layers with edge-case configurations before deploying.
Appendix A: Repository Structure
keras-team/keras/
├── keras/
│ ├── api/ # AUTO-GENERATED public API (do not edit)
│ │ ├── activations/
│ │ ├── applications/
│ │ ├── backend/
│ │ ├── callbacks/
│ │ ├── config/
│ │ ├── constraints/
│ │ ├── datasets/
│ │ ├── distillation/
│ │ ├── distribution/
│ │ ├── dtype_policies/
│ │ ├── export/
│ │ ├── initializers/
│ │ ├── layers/
│ │ ├── losses/
│ │ ├── metrics/
│ │ ├── mixed_precision/
│ │ ├── models/
│ │ ├── ops/
│ │ ├── optimizers/
│ │ ├── preprocessing/
│ │ ├── quantizers/
│ │ ├── random/
│ │ ├── regularizers/
│ │ ├── saving/
│ │ ├── tree/
│ │ ├── utils/
│ │ ├── visualization/
│ │ ├── wrappers/
│ │ └── _tf_keras/ # TF-Keras compatibility shim
│ └── src/ # Source implementation
│ ├── version.py # __version__ = "3.15.0"
│ ├── api_export.py # @keras_export decorator
│ ├── backend/ # Multi-backend dispatch
│ │ ├── config.py # Configuration globals
│ │ ├── common/ # KerasTensor, Variable, dtypes
│ │ ├── jax/
│ │ ├── tensorflow/
│ │ ├── torch/
│ │ ├── numpy/
│ │ └── openvino/
│ ├── callbacks/
│ ├── distillation/
│ ├── distribution/
│ ├── dtype_policies/
│ ├── export/
│ ├── layers/
│ │ ├── layer.py # Base Layer class
│ │ ├── core/ # Dense, Embedding, Input
│ │ ├── convolutional/
│ │ ├── normalization/
│ │ ├── attention/
│ │ ├── rnn/
│ │ └── preprocessing/
│ ├── models/ # Sequential, Functional, Model
│ ├── ops/ # Backend-agnostic operations
│ ├── optimizers/
│ ├── quantizers/ # AWQ, GPTQ, int8/int4/float8
│ ├── saving/ # .keras format, serialization
│ ├── trainers/ # Training loop, data adapters
│ ├── utils/
│ ├── visualization/
│ └── wrappers/ # sklearn, torch wrappers
├── integration_tests/
├── benchmarks/
├── shell/ # api_gen.sh, format.sh
├── api_gen.py
├── pip_build.py
├── conftest.py
├── pyproject.toml
└── requirements*.txt # Backend-specific requirements
Appendix B: Complete Configuration Quick Reference
{
"floatx": "float32",
"epsilon": 1e-7,
"backend": "tensorflow",
"image_data_format": "channels_last",
"nnx_enabled": false
}
| Setting | Values | Impact |
|---|---|---|
floatx |
float16, float32, float64 |
Default dtype for all weights |
epsilon |
Any small float | Numerical stability floor |
backend |
tensorflow, jax, torch, numpy, openvino |
Computation engine (immutable after import) |
image_data_format |
channels_last, channels_first |
Tensor layout for image operations |
nnx_enabled |
true, false |
Flax NNX features (JAX backend only) |