Keras
machine learning
model training
metadata
Python

Saving meta data/information in Keras model

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

Introduction

Keras models can be saved with model.save(), which stores the architecture, weights, and optimizer state. However, custom metadata like class labels, preprocessing parameters, training configuration, or versioning information is not saved automatically. To persist metadata alongside a Keras model, you can use HDF5 file attributes, save a separate JSON sidecar file, use model.save() with the .keras format and custom objects, or store metadata in the model's config via get_config().

Saving Metadata in HDF5 Attributes

The HDF5 format (.h5) supports arbitrary key-value attributes on groups and datasets:

python
1import h5py
2import json
3import numpy as np
4from tensorflow import keras
5
6# Train and save model
7model = keras.Sequential([
8    keras.layers.Dense(64, activation="relu", input_shape=(784,)),
9    keras.layers.Dense(10, activation="softmax"),
10])
11model.compile(optimizer="adam", loss="sparse_categorical_crossentropy", metrics=["accuracy"])
12model.save("model.h5")
13
14# Attach metadata to the HDF5 file
15metadata = {
16    "version": "1.2.0",
17    "class_names": ["airplane", "automobile", "bird", "cat", "deer",
18                     "dog", "frog", "horse", "ship", "truck"],
19    "input_mean": 0.4734,
20    "input_std": 0.2516,
21    "training_epochs": 50,
22    "best_val_accuracy": 0.9234,
23}
24
25with h5py.File("model.h5", "a") as f:  # "a" = append mode
26    for key, value in metadata.items():
27        f.attrs[key] = json.dumps(value) if isinstance(value, (list, dict)) else value
28
29# Read metadata back
30with h5py.File("model.h5", "r") as f:
31    loaded_meta = {key: f.attrs[key] for key in f.attrs}
32    class_names = json.loads(loaded_meta["class_names"])
33    print(f"Version: {loaded_meta['version']}")
34    print(f"Classes: {class_names}")

Saving Metadata as a Sidecar JSON File

The simplest and most portable approach — save a JSON file alongside the model:

python
1import json
2from tensorflow import keras
3
4model.save("model.keras")
5
6# Save metadata separately
7metadata = {
8    "model_version": "2.0.0",
9    "class_names": ["cat", "dog"],
10    "preprocessing": {
11        "resize": [224, 224],
12        "normalize_mean": [0.485, 0.456, 0.406],
13        "normalize_std": [0.229, 0.224, 0.225],
14    },
15    "training_config": {
16        "epochs": 100,
17        "batch_size": 32,
18        "learning_rate": 0.001,
19        "optimizer": "adam",
20    },
21    "metrics": {
22        "val_accuracy": 0.945,
23        "val_loss": 0.178,
24    },
25}
26
27with open("model_metadata.json", "w") as f:
28    json.dump(metadata, f, indent=2)
29
30# Load both together
31loaded_model = keras.models.load_model("model.keras")
32with open("model_metadata.json", "r") as f:
33    loaded_meta = json.load(f)
34
35# Use metadata for inference
36class_names = loaded_meta["class_names"]
37input_size = loaded_meta["preprocessing"]["resize"]

Saving Training History

python
1import json
2from tensorflow import keras
3
4# Training produces a History object
5history = model.fit(x_train, y_train, epochs=50, validation_split=0.2)
6
7# Save training history
8history_dict = {key: [float(v) for v in values]
9                for key, values in history.history.items()}
10
11with open("training_history.json", "w") as f:
12    json.dump(history_dict, f, indent=2)
13
14# Load and plot later
15with open("training_history.json", "r") as f:
16    saved_history = json.load(f)
17
18import matplotlib.pyplot as plt
19plt.plot(saved_history["accuracy"], label="Train")
20plt.plot(saved_history["val_accuracy"], label="Validation")
21plt.xlabel("Epoch")
22plt.ylabel("Accuracy")
23plt.legend()
24plt.show()

Custom Model with Built-in Metadata

Subclass keras.Model and override get_config():

python
1import tensorflow as tf
2from tensorflow import keras
3
4class MetadataModel(keras.Model):
5    def __init__(self, num_classes, class_names=None, version="1.0", **kwargs):
6        super().__init__(**kwargs)
7        self.num_classes = num_classes
8        self.class_names = class_names or []
9        self.version = version
10        self.dense1 = keras.layers.Dense(64, activation="relu")
11        self.output_layer = keras.layers.Dense(num_classes, activation="softmax")
12
13    def call(self, inputs):
14        x = self.dense1(inputs)
15        return self.output_layer(x)
16
17    def get_config(self):
18        config = super().get_config()
19        config.update({
20            "num_classes": self.num_classes,
21            "class_names": self.class_names,
22            "version": self.version,
23        })
24        return config
25
26    @classmethod
27    def from_config(cls, config):
28        return cls(**config)
29
30# Create with metadata
31model = MetadataModel(
32    num_classes=10,
33    class_names=["cat", "dog", "bird"],
34    version="2.1.0",
35)
36
37# Save and reload — metadata preserved in config
38model.save("custom_model.keras")
39
40loaded = keras.models.load_model(
41    "custom_model.keras",
42    custom_objects={"MetadataModel": MetadataModel},
43)
44print(loaded.class_names)  # ["cat", "dog", "bird"]
45print(loaded.version)      # "2.1.0"

Saving Metadata with SavedModel Format

python
1import tensorflow as tf
2import json
3
4model.save("saved_model_dir")
5
6# Save metadata alongside the SavedModel
7metadata = {"class_names": ["cat", "dog"], "version": "1.0"}
8with open("saved_model_dir/metadata.json", "w") as f:
9    json.dump(metadata, f)
10
11# Load together
12loaded_model = tf.keras.models.load_model("saved_model_dir")
13with open("saved_model_dir/metadata.json", "r") as f:
14    loaded_meta = json.load(f)

Using MLflow or Weights & Biases for Metadata

For production workflows, use experiment tracking tools:

python
1import mlflow
2import mlflow.keras
3
4# Log model with metadata
5with mlflow.start_run():
6    mlflow.log_params({
7        "epochs": 50,
8        "batch_size": 32,
9        "learning_rate": 0.001,
10    })
11    mlflow.log_metrics({
12        "val_accuracy": 0.945,
13        "val_loss": 0.178,
14    })
15    mlflow.keras.log_model(model, "model")
16    mlflow.log_artifact("class_names.json")

Common Pitfalls

  • Metadata lost when converting formats: Saving as .h5 with attributes, then converting to SavedModel or .keras format drops the HDF5 attributes. Use a sidecar JSON file that stays format-independent, or re-attach metadata after conversion.
  • HDF5 attributes not supporting complex types: h5py attributes only store scalars, strings, and NumPy arrays. Lists and dicts must be serialized with json.dumps() before storing and deserialized with json.loads() when reading.
  • Forgetting custom_objects when loading: If your model uses a custom get_config(), loading with keras.models.load_model() fails unless you pass custom_objects={"ClassName": ClassName}. Without it, Keras cannot reconstruct the model.
  • Not versioning metadata with the model: Metadata and model files can get out of sync if saved separately. Include a version field in both files and validate at load time that they match. Better yet, package both in a single archive (e.g., a zip file or MLflow artifact).
  • Saving preprocessing parameters separately from the model: If normalization means/stds are in a JSON file but the model expects normalized input, they can drift. Include preprocessing as Keras layers (Normalization, Rescaling) inside the model so they are saved together.

Summary

  • Keras model.save() stores architecture, weights, and optimizer — not custom metadata
  • Use HDF5 attributes (h5py) to attach key-value metadata to .h5 model files
  • Save a sidecar JSON file alongside the model for portable, format-independent metadata
  • Override get_config() in custom keras.Model subclasses to embed metadata in the model config
  • Save training history as JSON for later analysis and visualization
  • Use MLflow or Weights & Biases for production-grade experiment tracking with metadata

Related reading
Free course
Beginner
7 lessons
2 hours
Tackling System Design Interview Problems

A short course that equips you with the skills to approach system design interviews methodically.

Start the free course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

ML System Design practice on Codemia

Design recommenders, ranking systems and training pipelines the way ML interviews actually ask for them, with worked solutions.

Practice ML system design

All Rights Reserved.