In Keras 3, what does model.save('model.keras') store and how do you load it?
answer
- one file, not a directory
- zip: config JSON plus weights
- optimizer state travels with it
- extension is validated, .keras or .h5
basics
~10 smodel.save('model.keras') writes one zip archive holding the architecture config, the weights and the optimizer state. keras.saving.load_model('model.keras') rebuilds the whole model, ready to predict or resume training without re-running the build code.
solid answer
~30 sThe native Keras 3 format is the `.keras` v3 archive: a zip holding `metadata.json`, `config.json` (the serialized architecture) and `model.weights.h5` (the variable values). `model.save("model.keras")` writes it; `keras.saving.load_model("model.keras")` reads it back and returns a live model with the same layers, the same weights and, if the model was compiled, the optimizer state - so you can call `predict()` at once or resume `fit()`. The extension is checked: `model.save("model")` raises a ValueError asking for `.keras` (native) or `.h5` (legacy HDF5). Pass `compile=False` to `load_model` for inference-only loading.
code
python · 9 linesimport keras
model = keras.Sequential([keras.layers.Dense(8, activation="relu"), keras.layers.Dense(1)])
model.compile(optimizer="adam", loss="mse")
model.build((None, 4))
model.save("model.keras")
restored = keras.saving.load_model("model.keras")
restored.summary()go deeper
Know the two calls by heart: model.save('model.keras') and keras.saving.load_model('model.keras'), and be able to say the archive holds architecture plus weights, not just numbers.
Explain what is inside the archive - metadata, a config JSON and a weights HDF5 - and why including optimizer state is what lets you resume training rather than restart it.
Talk about artifact hygiene: pinning the Keras version next to the file, using compile=False in serving processes, and knowing that reloading depends on your custom classes still being importable.
Frame it as an artifact contract. Decide what your teams ship - a resumable checkpoint for training continuity versus an inference-only export for serving - and make the two paths explicit instead of letting each project improvise.
## What the archive contains `model.save("model.keras")`, equivalently `keras.saving.save_model(model, "model.keras")`, produces the `.keras` v3 archive. Despite the extension it is an ordinary zip file with three entries: - `metadata.json` - the Keras version that wrote it, plus a timestamp. - `config.json` - the model configuration: a JSON tree of class names and the constructor arguments of every layer, wired into the same graph. - `model.weights.h5` - an HDF5 file of the variable values (kernels, biases, normalization moving statistics, and the optimizer variables of a compiled model). The split matters: the config is code-free JSON describing how to rebuild, and the weights file is plain numeric arrays. Nothing in the archive is executable, which is why a saved model is portable but also why Keras must be able to find your own classes again at load time. ## The round trip ``` model.save("model.keras") restored = keras.saving.load_model("model.keras") ``` `load_model` parses `config.json`, instantiates each class with its recorded arguments, then streams the weights into the freshly created variables. The result is a normal model object: `restored.predict(x)` works, `restored.summary()` prints the same table, and because the optimizer variables travelled too, `restored.fit(...)` continues with the optimizer's accumulated state intact rather than from a cold start. That last point is the practical reason to prefer whole-model saving over weights-only saving when you may need to resume a run. `load_model` takes `compile=False` if you only want to serve the model; the layers and weights are restored, the optimizer and loss are not, and the model comes back uncompiled. ## Extensions and the legacy path Keras 3 validates the filepath. No extension raises a ValueError telling you to add `.keras` or `.h5`. A `.h5` or `.hdf5` suffix still works but takes the legacy HDF5 whole-model path, and Keras warns that the native format is recommended. Legacy HDF5 predates the v3 archive, stores weights by layer name, and carries custom objects far less reliably - treat it as a format you read old files with, not one you write new ones in. There is a third verb: `model.export(...)` writes an inference-only artifact for serving stacks rather than a resumable Keras model. Do not reach for it when what you want is to reload the model in Python. ## What can still go wrong The archive stores class names, not class code. A model built only from built-in Keras layers therefore always reloads. A model containing your own `Layer` subclass reloads only if Keras can map the recorded name back to a Python class at load time - otherwise the load fails while trying to locate the class, and the fix is to register the class or pass it in `custom_objects`. The other common surprise is version skew: an archive written by a much newer Keras may contain config keys an older Keras does not understand. Pin the Keras version alongside the artifact the way you pin any other dependency.
- What changes if you pass compile=False to load_model?You get the architecture and the weights but no training configuration: the optimizer, loss and metrics are not restored and the model comes back uncompiled. That is what you want in a serving process, which never calls fit() and should not pay to rebuild optimizer state. Call compile() yourself if you later decide to keep training.
- Why can the same .keras file be loaded on a machine running a different Keras backend?Because nothing in the archive is backend-specific: config.json is class names plus arguments, and model.weights.h5 is plain numeric arrays. Keras re-instantiates the layers using whichever backend is active and fills them with those arrays. Portability only breaks when your own layer code calls a particular framework's ops directly.
saying these in an interview costs you the question
- Thinking .keras is a directory of protobuf files
- Believing the archive stores your layer's source code
- Saying save() writes weights only
- Assuming any filename works and the extension is ignored