# Keras User Guide

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:

```python
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_BACKEND` environment 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:

```python
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:

```bash
# 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.keras` from TensorFlow 2.x, you now import Keras separately with `import keras`. The `tf.keras` namespace redirects to the standalone Keras package starting with TensorFlow 2.16.

### Verify Installation

```python
import keras
print(keras.__version__)   # 3.15.0
print(keras.config.backend())  # "tensorflow" (or whichever you configured)
```

```text
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)**

```bash
# 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`:

```json
{
    "floatx": "float32",
    "epsilon": 1e-7,
    "backend": "jax",
    "image_data_format": "channels_last",
    "nnx_enabled": false
}
```

**Option 3: Runtime switching**

```python
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`:

```python
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:

```python
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:

```python
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:

```python
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:

```python
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").output` and use it to build new models — invaluable for feature extraction and transfer learning.

#### Subclassing

For maximum flexibility and custom forward-pass logic:

```python
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:

```python
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

```python
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:

```python
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

```python
# 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

```python
# 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 `.keras` format 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:

```python
# 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

```python
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`, and `RandomZoom` only 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

```python
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

```python
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.

```python
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 `trainable` attributes. 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:

```python
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:

```python
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

```python
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:

```python
# 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:

```python
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:

```python
# 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

```python
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

```python
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

```python
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:

```bash
tensorboard --logdir=./logs
```

#### Combine Multiple Callbacks

```python
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]
> `BackupAndRestore` saves training state (epoch number, optimizer state) to disk each epoch. If training is interrupted, calling `model.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:

```python
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:

```python
# 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

```python
# 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:**
1. Check the expected input shape: `loaded_model.input_shape`
2. Reshape your input data to match
3. 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:**
1. Run `model.summary()` to inspect shapes at each layer
2. Add or fix `Reshape`/`Flatten` layers 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:**
1. Call `model.compile(optimizer=..., loss=...)` before training
2. 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:**
1. Reduce `batch_size` in `model.fit()`
2. Use mixed precision: `keras.config.set_dtype_policy("mixed_float16")`
3. Use a smaller model architecture
4. For TensorFlow backend, enable memory growth:
   ```python
   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:**
1. Ensure arrays are a consistent numeric dtype: `x = x.astype("float32")`
2. Check for `None` values 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:**
1. Install Keras: `pip install keras`
2. 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:**
1. Set a valid backend value: `tensorflow`, `jax`, `torch`, `numpy`, or `openvino`
2. 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:**
1. Ensure the model architecture matches exactly: same layers, same units, same order
2. Use `model.save("model.keras")` / `load_model()` instead of `save_weights()` when the architecture may differ
3. 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:**
1. If you trust the model source, enable unsafe deserialization:
   ```python
   keras.config.enable_unsafe_deserialization()
   model = keras.saving.load_model("model_with_lambda.keras")
   ```
2. 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:**
1. Reset metrics before resuming training: `model.reset_metrics()`
2. Or use `model.fit()` with appropriate `initial_epoch` instead of `train_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:**
1. Use `channels_last` (the default) for maximum cross-backend consistency
2. Accept small numerical differences (within 1e-5) as normal
3. 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:

```python
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()`:
```python
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.

---

_Generated May 2026 from keras-team/keras at b800fdf. AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it. Unofficial; not affiliated with or reviewed by the project._
