Keras 3.15.0 is a multi-backend deep learning framework for Python. Write your model once and run it on TensorFlow, JAX, PyTorch, NumPy, or OpenVINO without changing a single line of model code. Keras provides a high-level, intuitive API for building, training, evaluating, and deploying neural networks of any scale, from quick prototypes to production systems.
1. Quick Start
Build and train a neural network in under 20 lines:
import keras
from keras import layers
# Build a simple classifier
model = keras.Sequential([
layers.Input(shape=(784,)),
layers.Dense(128, activation="relu"),
layers.Dropout(0.3),
layers.Dense(10, activation="softmax"),
])
# Compile with optimizer, loss, and metrics
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"],
)
# Load built-in dataset
(x_train, y_train), (x_test, y_test) = keras.datasets.mnist.load_data()
x_train = x_train.reshape(-1, 784).astype("float32") / 255.0
x_test = x_test.reshape(-1, 784).astype("float32") / 255.0
# Train
model.fit(x_train, y_train, epochs=5, batch_size=32, validation_split=0.1)
# Evaluate
loss, accuracy = model.evaluate(x_test, y_test)
print(f"Test accuracy: {accuracy:.4f}")
Tip
Keras defaults to TensorFlow as its backend. To switch to JAX or PyTorch, set the
KERAS_BACKENDenvironment variable before importing Keras (see Section 3).
Your First Image Classifier with a Pre-trained Model
Transfer learning gets you high accuracy with minimal data:
import keras
from keras import layers
# Load pre-trained MobileNetV2 (without top classification layer)
base_model = keras.applications.MobileNetV2(
weights="imagenet",
include_top=False,
input_shape=(224, 224, 3),
)
base_model.trainable = False # Freeze base weights
# Add custom classification head
model = keras.Sequential([
base_model,
layers.GlobalAveragePooling2D(),
layers.Dense(128, activation="relu"),
layers.Dropout(0.5),
layers.Dense(5, activation="softmax"), # 5 classes
])
model.compile(
optimizer="adam",
loss="sparse_categorical_crossentropy",
metrics=["accuracy"],
)
# Load images from directory structure
train_ds = keras.utils.image_dataset_from_directory(
"data/train",
image_size=(224, 224),
batch_size=32,
)
model.fit(train_ds, epochs=10)
model.save("my_classifier.keras")
2. Installation
Requirements
- Python 3.9 or later
- One backend framework installed (TensorFlow, JAX, or PyTorch)
Install Keras with a Backend
Install Keras alongside your preferred backend:
# TensorFlow backend (default)
pip install keras tensorflow
# JAX backend (CPU)
pip install keras jax
# JAX backend (GPU — NVIDIA CUDA)
pip install keras jax[cuda12]
# PyTorch backend
pip install keras torch torchvision
Important
Keras 3.x is a standalone package. If you previously used
tf.kerasfrom TensorFlow 2.x, you now import Keras separately withimport keras. Thetf.kerasnamespace redirects to the standalone Keras package starting with TensorFlow 2.16.
Verify Installation
import keras
print(keras.__version__) # 3.15.0
print(keras.config.backend()) # "tensorflow" (or whichever you configured)
3.15.0
tensorflow
Optional Dependencies
| Package | Purpose |
|---|---|
pydot + Graphviz |
keras.utils.plot_model() — architecture visualization |
h5py |
Legacy HDF5 model saving |
pillow |
Image preprocessing layers and image_dataset_from_directory |
pandas |
CSVLogger callback, tabular data loading |
scipy |
Sparse matrix support in various layers |
Note
For GPU acceleration, follow the official installation instructions for your backend framework (e.g., CUDA toolkit for TensorFlow/JAX, or PyTorch's CUDA builds). Keras itself has no GPU-specific dependencies — the backend handles device management.
3. Configuration
Choosing a Backend
Keras supports five backends. Set the backend before importing Keras:
Option 1: Environment variable (recommended)
# Linux/macOS
export KERAS_BACKEND=jax
python my_script.py
# Windows (PowerShell)
$env:KERAS_BACKEND = "jax"
python my_script.py
# Windows (cmd)
set KERAS_BACKEND=jax
python my_script.py
Option 2: Configuration file
Edit ~/.keras/keras.json:
{
"floatx": "float32",
"epsilon": 1e-7,
"backend": "jax",
"image_data_format": "channels_last",
"nnx_enabled": false
}
Option 3: Runtime switching
import keras
keras.config.set_backend("torch")
Warning
Switching backends at runtime with
set_backend()after models or tensors have been created can lead to undefined behavior. Set the backend once at the start of your script or rely on the environment variable.
| Backend | Value | Best For |
|---|---|---|
| TensorFlow | tensorflow |
Production serving, TF ecosystem, mobile/edge deployment |
| JAX | jax |
Research, XLA compilation, TPU workloads, functional transforms |
| PyTorch | torch |
PyTorch ecosystem integration, dynamic computation graphs |
| NumPy | numpy |
Inference-only (no training), debugging, testing |
| OpenVINO | openvino |
Intel hardware inference optimization |
Global Configuration API
Tune Keras behavior at runtime using keras.config:
import keras
# Mixed precision for faster GPU training
keras.config.set_dtype_policy("mixed_float16")
# Change default float precision
keras.config.set_floatx("float64")
print(keras.config.floatx()) # "float64"
# Set image data ordering
keras.config.set_image_data_format("channels_first") # NCHW layout
# Flash attention (enabled by default, requires float16/bfloat16)
keras.config.enable_flash_attention()
print(keras.config.is_flash_attention_enabled()) # True
# Debugging: cap training runs
keras.config.set_max_epochs(2)
keras.config.set_max_steps_per_epoch(10)
Environment Variables Reference
| Variable | Purpose | Example |
|---|---|---|
KERAS_BACKEND |
Select backend | jax, torch, tensorflow, numpy, openvino |
KERAS_HOME |
Override config directory | /custom/path (default: ~/.keras) |
KERAS_MAX_EPOCHS |
Cap training epochs | 2 (useful for debugging) |
KERAS_MAX_STEPS_PER_EPOCH |
Cap steps per epoch | 10 |
KERAS_NNX_ENABLED |
Enable Flax NNX features (JAX) | true |
Reproducibility
Lock random seeds across all backends:
keras.utils.set_random_seed(42)
This sets seeds for Python's random, NumPy, and the active backend's random number generator in a single call.
4. Core Usage
Building Models
Keras offers three ways to build models, each suited to different complexity levels.
Sequential API
For linear layer stacks where each layer has exactly one input and one output:
from keras import layers, Sequential
model = Sequential([
layers.Input(shape=(28, 28, 1)),
layers.Conv2D(32, kernel_size=3, activation="relu"),
layers.MaxPooling2D(pool_size=2),
layers.Conv2D(64, kernel_size=3, activation="relu"),
layers.MaxPooling2D(pool_size=2),
layers.Flatten(),
layers.Dense(128, activation="relu"),
layers.Dropout(0.5),
layers.Dense(10, activation="softmax"),
])
model.summary()
Add or remove layers dynamically:
model = Sequential()
model.add(layers.Dense(64, activation="relu", input_shape=(100,)))
model.add(layers.Dense(10, activation="softmax"))
model.pop() # Remove the last layer
model.add(layers.Dense(5, activation="softmax")) # Replace it
Functional API
For models with branches, multiple inputs/outputs, or shared layers:
import keras
from keras import layers
# Multi-input model
text_input = keras.Input(shape=(100,), name="text")
image_input = keras.Input(shape=(224, 224, 3), name="image")
# Text branch
x1 = layers.Embedding(10000, 64)(text_input)
x1 = layers.LSTM(128)(x1)
# Image branch
x2 = layers.Conv2D(32, 3, activation="relu")(image_input)
x2 = layers.GlobalAveragePooling2D()(x2)
# Merge
merged = layers.Concatenate()([x1, x2])
output = layers.Dense(1, activation="sigmoid")(merged)
model = keras.Model(inputs=[text_input, image_input], outputs=output)
Tip
The Functional API lets you inspect and reuse intermediate layers. Access any layer's output with
model.get_layer("layer_name").outputand use it to build new models — invaluable for feature extraction and transfer learning.
Subclassing
For maximum flexibility and custom forward-pass logic:
import keras
from keras import layers
class TransformerBlock(keras.Model):
def __init__(self, embed_dim, num_heads, ff_dim, dropout_rate=0.1):
super().__init__()
self.attention = layers.MultiHeadAttention(
num_heads=num_heads, key_dim=embed_dim
)
self.ffn = keras.Sequential([
layers.Dense(ff_dim, activation="relu"),
layers.Dense(embed_dim),
])
self.norm1 = layers.LayerNormalization()
self.norm2 = layers.LayerNormalization()
self.dropout1 = layers.Dropout(dropout_rate)
self.dropout2 = layers.Dropout(dropout_rate)
def call(self, inputs, training=False):
attn_output = self.attention(inputs, inputs)
attn_output = self.dropout1(attn_output, training=training)
out1 = self.norm1(inputs + attn_output)
ffn_output = self.ffn(out1)
ffn_output = self.dropout2(ffn_output, training=training)
return self.norm2(out1 + ffn_output)
Compiling Models
Configure the training process:
model.compile(
optimizer=keras.optimizers.Adam(learning_rate=1e-3),
loss="categorical_crossentropy",
metrics=["accuracy", keras.metrics.AUC(name="auc")],
)
Common loss functions:
| Task | Loss | Output Activation |
|---|---|---|
| Binary classification | "binary_crossentropy" |
sigmoid |
| Multi-class (integer labels) | "sparse_categorical_crossentropy" |
softmax |
| Multi-class (one-hot labels) | "categorical_crossentropy" |
softmax |
| Regression | "mse" or "mae" |
linear (none) |
Training
history = model.fit(
x_train, y_train,
epochs=20,
batch_size=64,
validation_split=0.2, # Hold out 20% for validation
callbacks=[
keras.callbacks.EarlyStopping(
monitor="val_loss",
patience=3,
restore_best_weights=True,
),
keras.callbacks.ReduceLROnPlateau(
monitor="val_loss",
factor=0.5,
patience=2,
),
],
)
Access training history:
print(history.history.keys())
# dict_keys(['loss', 'accuracy', 'val_loss', 'val_accuracy'])
import matplotlib.pyplot as plt
plt.plot(history.history["loss"], label="train")
plt.plot(history.history["val_loss"], label="val")
plt.legend()
plt.show()
Evaluation and Prediction
# Evaluate on test set
test_loss, test_acc = model.evaluate(x_test, y_test, batch_size=64)
print(f"Test accuracy: {test_acc:.4f}")
# Predict on new data
predictions = model.predict(x_new)
predicted_classes = predictions.argmax(axis=-1)
Saving and Loading Models
# Save entire model (architecture + weights + optimizer state)
model.save("my_model.keras")
# Load it back
loaded_model = keras.saving.load_model("my_model.keras")
# Save/load weights only
model.save_weights("weights.weights.h5")
model.load_weights("weights.weights.h5")
Note
The
.kerasformat is the recommended save format. It uses a ZIP archive containing the model config (JSON) and weights (H5). Legacy HDF5 (.h5) saving is still supported but not recommended for new code.
Exporting for Production
Export models for serving and deployment:
# Export as SavedModel (TensorFlow Serving, TFLite)
export_archive = keras.export.ExportArchive()
export_archive.track(model)
export_archive.add_endpoint(
name="serve",
fn=model.call,
input_signature=[keras.InputSpec(shape=(None, 784), dtype="float32")],
)
export_archive.write_out("exported_model")
5. Common Tasks
Image Classification with Data Augmentation
import keras
from keras import layers
# Data augmentation pipeline
augmentation = keras.Sequential([
layers.RandomFlip("horizontal"),
layers.RandomRotation(0.1),
layers.RandomZoom(0.1),
layers.RandomBrightness(0.2),
layers.RandomContrast(0.2),
])
# Load data from directory
train_ds = keras.utils.image_dataset_from_directory(
"data/train",
image_size=(224, 224),
batch_size=32,
label_mode="categorical",
)
val_ds = keras.utils.image_dataset_from_directory(
"data/val",
image_size=(224, 224),
batch_size=32,
label_mode="categorical",
)
# Build model with augmentation
inputs = keras.Input(shape=(224, 224, 3))
x = augmentation(inputs)
x = keras.applications.EfficientNetB0(
include_top=False, weights="imagenet"
)(x)
x = layers.GlobalAveragePooling2D()(x)
x = layers.Dropout(0.3)(x)
outputs = layers.Dense(10, activation="softmax")(x)
model = keras.Model(inputs, outputs)
model.compile(
optimizer=keras.optimizers.Adam(1e-3),
loss="categorical_crossentropy",
metrics=["accuracy"],
)
model.fit(train_ds, validation_data=val_ds, epochs=20)
Tip
Augmentation layers like
RandomFlip,RandomRotation, andRandomZoomonly apply during training. At inference time they pass data through unchanged, so you can include them directly in your model without worrying about test-time distortion.
Text Classification with Preprocessing
import keras
from keras import layers
# Built-in text preprocessing
max_tokens = 20000
max_length = 200
vectorizer = layers.TextVectorization(
max_tokens=max_tokens,
output_mode="int",
output_sequence_length=max_length,
)
# Adapt to training text
train_texts = ["This movie was great", "Terrible film", ...]
vectorizer.adapt(train_texts)
# Build model
model = keras.Sequential([
keras.Input(shape=(1,), dtype="string"),
vectorizer,
layers.Embedding(max_tokens, 128),
layers.Bidirectional(layers.LSTM(64)),
layers.Dense(64, activation="relu"),
layers.Dropout(0.5),
layers.Dense(1, activation="sigmoid"),
])
model.compile(
optimizer="adam",
loss="binary_crossentropy",
metrics=["accuracy"],
)
Time Series Forecasting
import keras
from keras import layers
# Create windowed dataset from time series
dataset = keras.utils.timeseries_dataset_from_array(
data=time_series_values,
targets=time_series_values[window_size:],
sequence_length=window_size,
batch_size=32,
)
# LSTM model for forecasting
model = keras.Sequential([
layers.Input(shape=(window_size, num_features)),
layers.LSTM(64, return_sequences=True),
layers.LSTM(32),
layers.Dense(1),
])
model.compile(optimizer="adam", loss="mse")
model.fit(dataset, epochs=50)
Transfer Learning with Fine-Tuning
Two-phase training: train the head, then fine-tune deeper layers.
import keras
from keras import layers
# Phase 1: Feature extraction
base = keras.applications.ResNet50(
weights="imagenet", include_top=False, input_shape=(224, 224, 3)
)
base.trainable = False
model = keras.Sequential([
base,
layers.GlobalAveragePooling2D(),
layers.Dense(256, activation="relu"),
layers.Dropout(0.5),
layers.Dense(10, activation="softmax"),
])
model.compile(
optimizer=keras.optimizers.Adam(1e-3),
loss="sparse_categorical_crossentropy",
metrics=["accuracy"],
)
model.fit(train_ds, epochs=10, validation_data=val_ds)
# Phase 2: Fine-tune top layers of the base
base.trainable = True
for layer in base.layers[:-20]:
layer.trainable = False # Only fine-tune last 20 layers
model.compile(
optimizer=keras.optimizers.Adam(1e-5), # Lower learning rate
loss="sparse_categorical_crossentropy",
metrics=["accuracy"],
)
model.fit(train_ds, epochs=10, validation_data=val_ds)
Important
When fine-tuning, always recompile the model after changing
trainableattributes. Use a significantly lower learning rate (10x--100x smaller) to avoid destroying the pre-trained features.
Mixed Precision Training
Speed up training on modern GPUs with mixed precision:
import keras
# Enable mixed precision globally
keras.config.set_dtype_policy("mixed_float16")
# Build your model normally — layers auto-cast
model = keras.Sequential([
keras.Input(shape=(784,)),
keras.layers.Dense(512, activation="relu"),
keras.layers.Dense(10, activation="softmax", dtype="float32"), # Keep output in float32
])
# Use loss scaling for numerical stability
optimizer = keras.optimizers.Adam(1e-3)
optimizer = keras.optimizers.LossScaleOptimizer(optimizer)
model.compile(optimizer=optimizer, loss="sparse_categorical_crossentropy", metrics=["accuracy"])
Warning
Flash attention requires float16 or bfloat16 inputs. If you use float32 precision with
MultiHeadAttention, flash attention is automatically bypassed. Mixed precision is the recommended approach for attention-heavy models like transformers.
Custom Training Loop
For full control over the training process:
import keras
model = keras.Sequential([
keras.layers.Dense(64, activation="relu"),
keras.layers.Dense(10),
])
optimizer = keras.optimizers.Adam(1e-3)
loss_fn = keras.losses.SparseCategoricalCrossentropy(from_logits=True)
for epoch in range(10):
for step, (x_batch, y_batch) in enumerate(train_dataset):
with keras.backend.GradientTape() if hasattr(keras.backend, "GradientTape") else None:
# Use trainable_variables and gradient computation
pass
# Simpler: use train_on_batch for step-by-step control
for x_batch, y_batch in train_dataset:
loss = model.train_on_batch(x_batch, y_batch)
Learning Rate Schedules
from keras.optimizers.schedules import CosineDecay, ExponentialDecay
# Cosine decay with warmup
schedule = CosineDecay(
initial_learning_rate=1e-3,
decay_steps=10000,
alpha=1e-6, # Minimum learning rate
)
# Exponential decay
schedule = ExponentialDecay(
initial_learning_rate=1e-3,
decay_steps=1000,
decay_rate=0.9,
)
optimizer = keras.optimizers.Adam(learning_rate=schedule)
Model Quantization
Reduce model size for deployment:
# Quantize Dense layers to int8
model = keras.Sequential([
keras.layers.Dense(512, activation="relu"),
keras.layers.Dense(10, activation="softmax"),
])
model.build(input_shape=(None, 784))
# Quantize individual layers
model.layers[0].quantize("int8")
# Combine with LoRA for efficient fine-tuning
model.layers[0].enable_lora(rank=4)
Supported quantization modes for Dense, EinsumDense, and Embedding layers include int8, int4, float8, AWQ, and GPTQ.
Using scikit-learn with Keras
Wrap Keras models for scikit-learn pipelines:
from keras.wrappers import SKLearnClassifier
from sklearn.model_selection import cross_val_score
def build_model():
model = keras.Sequential([
keras.layers.Dense(64, activation="relu", input_shape=(20,)),
keras.layers.Dense(3, activation="softmax"),
])
model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
return model
classifier = SKLearnClassifier(model=build_model, epochs=10, batch_size=32)
scores = cross_val_score(classifier, X, y, cv=5)
print(f"Accuracy: {scores.mean():.4f} (+/- {scores.std():.4f})")
Wrapping JAX, Flax, and PyTorch Code
Integrate external framework code into Keras models:
# Wrap a JAX function as a Keras layer
jax_layer = keras.utils.JaxLayer(jax_function, params=initial_params)
# Wrap a PyTorch nn.Module
import torch.nn as nn
torch_module = nn.Linear(64, 10)
keras_layer = keras.utils.TorchModuleWrapper(torch_module)
Audio Processing
from keras import layers
# Mel spectrogram preprocessing
mel_layer = layers.MelSpectrogram(
sample_rate=16000,
fft_length=2048,
num_mel_bins=128,
)
# STFT spectrogram
stft_layer = layers.STFTSpectrogram(
sequence_length=2048,
sequence_stride=512,
)
model = keras.Sequential([
keras.Input(shape=(16000,)), # 1 second of audio at 16kHz
mel_layer,
layers.Conv2D(32, 3, activation="relu"),
layers.GlobalAveragePooling2D(),
layers.Dense(10, activation="softmax"),
])
Using Callbacks Effectively
Save Best Model During Training
checkpoint = keras.callbacks.ModelCheckpoint(
filepath="best_model.keras",
monitor="val_accuracy",
mode="max",
save_best_only=True,
verbose=1,
)
model.fit(x_train, y_train, epochs=50, validation_split=0.2, callbacks=[checkpoint])
TensorBoard Logging
tensorboard = keras.callbacks.TensorBoard(
log_dir="./logs",
histogram_freq=1,
write_graph=True,
)
model.fit(x_train, y_train, epochs=10, callbacks=[tensorboard])
Then view logs:
tensorboard --logdir=./logs
Combine Multiple Callbacks
callbacks = [
keras.callbacks.EarlyStopping(monitor="val_loss", patience=5, restore_best_weights=True),
keras.callbacks.ReduceLROnPlateau(monitor="val_loss", factor=0.2, patience=3),
keras.callbacks.ModelCheckpoint("best.keras", save_best_only=True),
keras.callbacks.CSVLogger("training_log.csv"),
keras.callbacks.TerminateOnNaN(),
keras.callbacks.BackupAndRestore(backup_dir="./backup"),
]
model.fit(x_train, y_train, epochs=100, validation_split=0.2, callbacks=callbacks)
Tip
BackupAndRestoresaves training state (epoch number, optimizer state) to disk each epoch. If training is interrupted, callingmodel.fit()again with the same callback resumes from the last completed epoch rather than starting over.
Backend-Agnostic Operations
Write numerical code that works on any backend:
import keras
from keras import ops
# NumPy-compatible operations
x = ops.numpy.linspace(0, 1, 100)
y = ops.numpy.sin(x * 2 * ops.numpy.pi)
# Neural network operations
logits = ops.numpy.random.normal(shape=(32, 10))
probs = ops.nn.softmax(logits, axis=-1)
# Image operations
images = ops.numpy.random.normal(shape=(4, 224, 224, 3))
resized = ops.image.resize(images, size=(112, 112))
# Control flow
result = ops.core.cond(
pred=ops.numpy.sum(x) > 0,
true_fn=lambda: x * 2,
false_fn=lambda: x,
)
Built-in Datasets
Keras ships with several classic datasets for prototyping:
# Image datasets
(x, y), (x_test, y_test) = keras.datasets.mnist.load_data()
(x, y), (x_test, y_test) = keras.datasets.fashion_mnist.load_data()
(x, y), (x_test, y_test) = keras.datasets.cifar10.load_data()
(x, y), (x_test, y_test) = keras.datasets.cifar100.load_data()
# Text datasets
(x, y), (x_test, y_test) = keras.datasets.imdb.load_data(num_words=10000)
(x, y), (x_test, y_test) = keras.datasets.reuters.load_data(num_words=10000)
# Tabular datasets
(x, y), (x_test, y_test) = keras.datasets.california_housing.load_data()
(x, y), (x_test, y_test) = keras.datasets.boston_housing.load_data()
Visualizing Model Architecture
# Print text summary
model.summary()
# Generate architecture diagram (requires pydot + Graphviz)
keras.utils.plot_model(
model,
to_file="model_architecture.png",
show_shapes=True,
show_layer_names=True,
show_dtype=True,
)
6. Troubleshooting
Error: Could not find matching concrete function to call loaded from the SavedModel
Cause: The model was saved with a different input signature than what you're passing during inference.
Solution:
- Check the expected input shape:
loaded_model.input_shape - Reshape your input data to match
- If exporting, explicitly specify the input signature via
ExportArchive.add_endpoint()
Prevention: Always verify input shapes match before saving and loading.
Error: ValueError: Input 0 of layer "dense" is incompatible with the layer: expected axis -1 of input shape to have value N, but received input with shape (batch, M)
Cause: A shape mismatch between what a layer expects and what it receives, usually after a Flatten or between model components.
Solution:
- Run
model.summary()to inspect shapes at each layer - Add or fix
Reshape/Flattenlayers to produce the expected dimensions
Prevention: Use model.summary() after building to verify the shape chain before training.
Error: RuntimeError: You must compile your model before training/testing. Use model.compile()
Cause: Calling model.fit(), model.evaluate(), or model.predict() before model.compile().
Solution:
- Call
model.compile(optimizer=..., loss=...)before training - After loading a model with
load_model(), the compiled state is restored automatically
Prevention: Always compile immediately after model construction.
Error: OOM when allocating tensor with shape [...] on /device:GPU:0
Cause: The model or batch size exceeds GPU memory.
Solution:
- Reduce
batch_sizeinmodel.fit() - Use mixed precision:
keras.config.set_dtype_policy("mixed_float16") - Use a smaller model architecture
- For TensorFlow backend, enable memory growth:
import tensorflow as tf gpus = tf.config.list_physical_devices("GPU") for gpu in gpus: tf.config.experimental.set_memory_growth(gpu, True)
Prevention: Start with small batch sizes and increase gradually. Monitor GPU memory with nvidia-smi.
Error: ValueError: Failed to convert a NumPy array to a Tensor (Unsupported object type float)
Cause: Input data contains mixed types or Python objects instead of uniform numeric arrays.
Solution:
- Ensure arrays are a consistent numeric dtype:
x = x.astype("float32") - Check for
Nonevalues or nested lists of inconsistent length
Prevention: Always normalize data types before passing to model.fit().
Error: ModuleNotFoundError: No module named 'keras'
Cause: Keras is not installed, or the wrong environment is active.
Solution:
- Install Keras:
pip install keras - Verify the correct Python environment:
which python && pip list | grep keras
Prevention: Use virtual environments and install Keras explicitly.
Error: ValueError: Unknown backend: "xyz". Available backends are: tensorflow, jax, torch, numpy, openvino
Cause: Invalid value for KERAS_BACKEND environment variable or keras.json.
Solution:
- Set a valid backend value:
tensorflow,jax,torch,numpy, oropenvino - Install the corresponding backend package
Prevention: Check ~/.keras/keras.json for typos.
Error: ValueError: Layer weight shape (64, 128) is not compatible with provided weight shape (128, 64)
Cause: Loading weights from a model with different architecture.
Solution:
- Ensure the model architecture matches exactly: same layers, same units, same order
- Use
model.save("model.keras")/load_model()instead ofsave_weights()when the architecture may differ - For transfer learning, use
by_name=True:model.load_weights("weights.h5", by_name=True)
Prevention: Save full models (.keras) rather than weights-only when possible.
Error: Deserialization of Lambda layers or torch.nn.Module is disallowed
Cause: Security restriction prevents deserializing arbitrary code from saved models.
Solution:
- If you trust the model source, enable unsafe deserialization:
keras.config.enable_unsafe_deserialization() model = keras.saving.load_model("model_with_lambda.keras") - Refactor to use named layers/functions instead of
Lambda
Prevention: Avoid Lambda layers in models intended for saving. Use custom layer subclasses with get_config().
Caution
Only call
enable_unsafe_deserialization()for models you created or fully trust. Untrusted models with Lambda layers can execute arbitrary code during loading.
Error: train_on_batch returns cumulative metric values after load_model
Cause: This is a known issue where metric state accumulates incorrectly after loading a saved model.
Solution:
- Reset metrics before resuming training:
model.reset_metrics() - Or use
model.fit()with appropriateinitial_epochinstead oftrain_on_batch()
Prevention: Call model.reset_metrics() after load_model() if using train_on_batch().
Issue: Backend Gradient Differences
Cause: Numerical differences between TensorFlow, JAX, and PyTorch backends can produce slightly different gradient values, especially with operations like Conv1D + Flatten using channels_first format.
Solution:
- Use
channels_last(the default) for maximum cross-backend consistency - Accept small numerical differences (within 1e-5) as normal
- For exact reproducibility, pin a single backend
Prevention: Test on your target backend early in development.
Issue: Traceback Too Verbose
Solution: Filter Keras internal frames from stack traces:
keras.config.enable_traceback_filtering()
This hides Keras internal call stack frames and shows only your code.
7. FAQ
Q: How is Keras 3 different from tf.keras in TensorFlow 2.x?
Keras 3 is a standalone, multi-backend framework. It runs on TensorFlow, JAX, PyTorch, NumPy, and OpenVINO. Starting with TensorFlow 2.16, tf.keras points to the standalone Keras package. The API is largely the same, but you now import keras directly and can choose any backend.
Q: Which backend should I choose?
TensorFlow is the default and best supported for production deployment (TF Serving, TFLite, mobile). JAX excels at research workloads, XLA compilation, and TPU usage. PyTorch is ideal if you need to interoperate with existing PyTorch code. NumPy is inference-only but useful for debugging. Choose based on your deployment target and ecosystem needs.
Q: Can I use multiple backends in the same script?
No. Keras uses one backend per Python process. Set it once at the start via KERAS_BACKEND or keras.config.set_backend(). If you need multiple backends, use separate scripts or subprocesses.
Q: How do I use Keras with a GPU?
Install the GPU-enabled version of your backend (e.g., tensorflow[and-cuda], jax[cuda12], torch with CUDA). Keras automatically uses available GPUs through the backend. No Keras-specific GPU configuration is needed.
Q: What model save format should I use?
Use the .keras format (model.save("model.keras")). It bundles architecture, weights, and optimizer state in a portable ZIP file. Legacy HDF5 (.h5) is supported but not recommended for new projects.
Q: Can I convert my Keras model to ONNX?
Yes. Use keras.export.ExportArchive to export the model, then convert to ONNX using the appropriate backend tool (e.g., tf2onnx for TensorFlow backend, torch.onnx.export for PyTorch backend).
Q: How do I freeze layers for transfer learning?
Set layer.trainable = False on layers you want to freeze. For a pre-trained base model, base_model.trainable = False freezes all its layers. After changing trainable attributes, recompile the model.
Q: What is mixed precision and when should I use it?
Mixed precision (keras.config.set_dtype_policy("mixed_float16")) trains with float16 for speed while keeping critical computations in float32 for numerical stability. Use it on GPUs with Tensor Cores (NVIDIA V100, A100, RTX 30xx/40xx/50xx series) for 2-3x speedups.
Q: How does BackupAndRestore work?
The BackupAndRestore callback saves training state (current epoch, optimizer variables) to a directory each epoch. If your training script restarts, calling model.fit() with the same callback automatically resumes from the last completed epoch. This is essential for long training runs on preemptible instances.
Q: Can I use Keras layers in a PyTorch training loop?
Yes, when using the PyTorch backend. Keras layers are valid torch.nn.Module subclasses. You can mix Keras layers with native PyTorch modules and use standard PyTorch training loops with torch.optim and loss.backward().
Q: How do I pad variable-length sequences?
Use keras.utils.pad_sequences():
padded = keras.utils.pad_sequences(sequences, maxlen=100, padding="post")
This pads shorter sequences with zeros and truncates longer ones.
Q: What pre-trained models are available?
Keras ships with ImageNet-pretrained models including VGG16/19, ResNet50/101/152, InceptionV3, Xception, MobileNet/V2/V3, DenseNet, NASNet, EfficientNet (B0-B7), EfficientNetV2, and ConvNeXt variants. Access them via keras.applications.*.
Q: How do I debug a model that won't converge?
Start by checking: (1) data preprocessing (normalize inputs, verify labels), (2) learning rate (try 1e-3 as a starting point), (3) model capacity (too small or too large for the data), (4) loss function matches your task, (5) use keras.config.set_max_epochs(2) and keras.config.set_max_steps_per_epoch(5) for quick iteration.
Q: What is the keras.ops module for?
keras.ops provides backend-agnostic math operations. keras.ops.numpy.* mirrors NumPy, keras.ops.nn.* provides neural network primitives, keras.ops.image.* handles image operations, and keras.ops.linalg.* provides linear algebra. Code written with keras.ops runs identically on all backends.
Q: How do I use Flax NNX features with the JAX backend?
Set KERAS_NNX_ENABLED=true or configure "nnx_enabled": true in ~/.keras/keras.json. Check status with keras.config.is_nnx_enabled(). This enables Flax NNX integration for JAX-specific features.