Stabilize container weight paths across compatible layer subclasses#23216
Stabilize container weight paths across compatible layer subclasses#23216SID-6921 wants to merge 7 commits into
Conversation
Signed-off-by: SID <nandasiddhardha@gmail.com>
There was a problem hiding this comment.
Code Review
This pull request aims to allow weight loading between compatible subclasses (such as a custom LSTM and a base LSTM) by using generic object types instead of concrete class names during serialization. However, using generic names like 'Layer' breaks backward compatibility for existing saved models. The feedback suggests traversing the class's MRO to find the nearest Keras built-in class name, preserving compatibility while still allowing subclass swapping.
Important
The consumer version of Gemini Code Assist on GitHub is being sunset. Starting June 18, 2026, new organization installations will be blocked, and all code review activity will officially cease on July 17, 2026.
For more details on the timeline and next steps, please review the Help Documentation.
| def _container_saveable_name(saveable, used_names): | ||
| # Use `_obj_type()` (e.g. "Layer", "Optimizer") rather than concrete | ||
| # class names so swapping compatible subclasses keeps the same path keys. | ||
| base_name = naming.to_snake_case(saveable._obj_type()) | ||
| return _get_unique_name(base_name, used_names) |
There was a problem hiding this comment.
Using _obj_type() (which returns "Layer" for all layers) to name container saveables breaks backward compatibility for all existing saved models. Any weights saved with previous versions of Keras 3 (which used class-based names like "dense", "conv2d", etc.) will fail to load because the loader will now look for generic names like "layer", "layer_1", etc. Additionally, this makes the saved weights file structure much less readable.
To fix this while still resolving the issue of swapping compatible subclasses (like MyCustomLSTM <-> LSTM), we can traverse the class's MRO to find the nearest Keras built-in class name, falling back to the class's own name if no built-in Keras class is found.
def _container_saveable_name(saveable, used_names):
# Find the nearest Keras built-in class in the MRO to keep paths stable
# when swapping compatible subclasses (e.g. MyCustomLSTM <-> LSTM)
# while preserving backward compatibility for existing saved models.
base_name = None
for cls in saveable.__class__.__mro__:
if (
cls.__module__.startswith("keras.")
and cls.__name__ not in (
"Layer",
"Model",
"KerasSaveable",
"Operation",
"Optimizer",
"Metric",
"Loss",
)
):
base_name = naming.to_snake_case(cls.__name__)
break
if base_name is None:
base_name = naming.to_snake_case(saveable.__class__.__name__)
return _get_unique_name(base_name, used_names)Signed-off-by: SID <nandasiddhardha@gmail.com>
Signed-off-by: SID <nandasiddhardha@gmail.com>
Signed-off-by: SID <nandasiddhardha@gmail.com>
Signed-off-by: SID <nandasiddhardha@gmail.com>
Signed-off-by: SID <nandasiddhardha@gmail.com>
Signed-off-by: SID <nandasiddhardha@gmail.com>
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #23216 +/- ##
==========================================
- Coverage 84.80% 84.04% -0.77%
==========================================
Files 465 465
Lines 69201 69251 +50
Branches 11379 11397 +18
==========================================
- Hits 58687 58203 -484
- Misses 7577 8118 +541
+ Partials 2937 2930 -7
Flags with carried forward coverage won't be shown. Click here to find out more. ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
Summary
_obj_type) rather than concrete class nameLSTMsubclass <-> baseLSTM)keras/src/layers/rnn/lstm_test.pythat saves weights from a customLSTMsubclass model and loads them into a baseLSTMmodelWhy
Container naming currently uses class names. A custom subclass like
MyCustomLSTMand the built-inLSTMthen serialize under different container paths, soload_weights()can miss variables and fail with errors such as:Layer 'lstm_cell' expected 3 variables, but received 0 variables during loadingUsing
_obj_typegives stable path keys for compatible saveables while preserving deterministic ordering.Validation
test_load_weights_from_custom_lstm_into_base_lstmpython -m py_compileon modified files)Contributor Agreement
Fixes #20322