Skip to content

Commit 64ab216

Browse files
authored
Remove nested container warnings (#23172)
* Remove nested container warnings * Remove nested container code and tests not applicable to r3.12
1 parent d338a45 commit 64ab216

2 files changed

Lines changed: 0 additions & 206 deletions

File tree

keras/src/saving/saving_lib.py

Lines changed: 0 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -964,16 +964,6 @@ def _save_container_state(
964964
inner_path=file_utils.join(inner_path, name).replace("\\", "/"),
965965
visited_saveables=visited_saveables,
966966
)
967-
elif isinstance(saveable, (list, dict, tuple)):
968-
name = _get_unique_name("container", used_names)
969-
_save_container_state(
970-
saveable,
971-
weights_store,
972-
assets_store,
973-
inner_path=file_utils.join(inner_path, name).replace("\\", "/"),
974-
visited_saveables=visited_saveables,
975-
visited_containers=visited_containers,
976-
)
977967

978968

979969
def _load_container_state(
@@ -1015,37 +1005,6 @@ def _load_container_state(
10151005
failed_saveables=failed_saveables,
10161006
error_msgs=error_msgs,
10171007
)
1018-
elif isinstance(saveable, (list, dict, tuple)):
1019-
name = _get_unique_name("container", used_names)
1020-
nested_path = file_utils.join(inner_path, name).replace("\\", "/")
1021-
if not _container_path_present(
1022-
weights_store, assets_store, nested_path
1023-
):
1024-
# Legacy files saved before PR #22362 didn't write the
1025-
# `container*` groups for nested containers — silently
1026-
# skip so the model still loads (sublayers keep their
1027-
# freshly-initialized weights).
1028-
warnings.warn(
1029-
f"Skipping nested container at '{nested_path}': no "
1030-
"matching group found in the saved file. This usually "
1031-
"means the file was saved with a Keras version that "
1032-
"did not serialize sublayers nested inside containers. "
1033-
"Affected layers will retain their freshly-initialized "
1034-
"weights.",
1035-
stacklevel=2,
1036-
)
1037-
continue
1038-
_load_container_state(
1039-
saveable,
1040-
weights_store,
1041-
assets_store,
1042-
inner_path=nested_path,
1043-
skip_mismatch=skip_mismatch,
1044-
visited_saveables=visited_saveables,
1045-
failed_saveables=failed_saveables,
1046-
error_msgs=error_msgs,
1047-
visited_containers=visited_containers,
1048-
)
10491008

10501009

10511010
class DiskIOStore:

keras/src/saving/saving_lib_test.py

Lines changed: 0 additions & 165 deletions
Original file line numberDiff line numberDiff line change
@@ -1117,171 +1117,6 @@ def test_bidirectional_lstm_saving(self):
11171117
out = new_model(x)
11181118
self.assertAllClose(out, ref_out)
11191119

1120-
@parameterized.named_parameters(
1121-
("list", list, lambda b: b),
1122-
("tuple", tuple, lambda b: b),
1123-
("dict", dict, lambda b: b.values()),
1124-
)
1125-
def test_nested_container_layer_saving(self, container_type, get_values):
1126-
"""Test that layers stored in nested containers are saved/loaded."""
1127-
1128-
package = f"test_nested_{container_type.__name__}"
1129-
1130-
@keras.saving.register_keras_serializable(package=package)
1131-
class NestedContainerModel(keras.Model):
1132-
def __init__(self, **kwargs):
1133-
super().__init__(**kwargs)
1134-
inner1 = [keras.layers.Dense(8), keras.layers.Dense(8)]
1135-
inner2 = [keras.layers.Dense(8), keras.layers.Dense(8)]
1136-
if container_type is dict:
1137-
self.blocks = {
1138-
"block_a": inner1,
1139-
"block_b": inner2,
1140-
}
1141-
elif container_type is list:
1142-
self.blocks = [inner1, inner2]
1143-
else:
1144-
self.blocks = (tuple(inner1), tuple(inner2))
1145-
self.out_layer = keras.layers.Dense(2)
1146-
1147-
def call(self, x):
1148-
for block in get_values(self.blocks):
1149-
for layer in block:
1150-
x = layer(x)
1151-
return self.out_layer(x)
1152-
1153-
def get_config(self):
1154-
return super().get_config()
1155-
1156-
model = NestedContainerModel()
1157-
x = np.random.random((2, 4))
1158-
model(x) # build weights
1159-
1160-
# Assign distinct constant kernels so that any layer-swapping
1161-
# on reload would produce a detectable mismatch.
1162-
for i, block in enumerate(get_values(model.blocks)):
1163-
for j, layer in enumerate(block):
1164-
val = float(i * 2 + j + 1) # 1.0, 2.0, 3.0, 4.0
1165-
layer.kernel.assign(np.full_like(layer.kernel, val))
1166-
layer.bias.assign(np.zeros_like(layer.bias))
1167-
1168-
ref_out = model(x)
1169-
suffix = container_type.__name__
1170-
temp_filepath = os.path.join(
1171-
self.get_temp_dir(), f"nested_{suffix}.keras"
1172-
)
1173-
model.save(temp_filepath)
1174-
new_model = keras.saving.load_model(temp_filepath)
1175-
1176-
# Verify each nested layer's weights were individually restored.
1177-
for i, (orig_block, new_block) in enumerate(
1178-
zip(get_values(model.blocks), get_values(new_model.blocks))
1179-
):
1180-
for j, (orig_layer, new_layer) in enumerate(
1181-
zip(orig_block, new_block)
1182-
):
1183-
self.assertAllClose(
1184-
orig_layer.kernel,
1185-
new_layer.kernel,
1186-
msg=f"Kernel mismatch at blocks[{i}][{j}]",
1187-
)
1188-
1189-
out = new_model(x)
1190-
self.assertAllClose(ref_out, out)
1191-
1192-
def test_deeply_nested_container_layer_saving(self):
1193-
"""Test 3+ levels of nested containers."""
1194-
1195-
@keras.saving.register_keras_serializable(package="test_deeply_nested")
1196-
class DeeplyNestedModel(keras.Model):
1197-
def __init__(self, **kwargs):
1198-
super().__init__(**kwargs)
1199-
self.blocks = [[[keras.layers.Dense(4), keras.layers.Dense(4)]]]
1200-
self.out_layer = keras.layers.Dense(2)
1201-
1202-
def call(self, x):
1203-
for block_list in self.blocks:
1204-
for block in block_list:
1205-
for layer in block:
1206-
x = layer(x)
1207-
return self.out_layer(x)
1208-
1209-
def get_config(self):
1210-
return super().get_config()
1211-
1212-
model = DeeplyNestedModel()
1213-
x = np.random.random((2, 4))
1214-
model(x)
1215-
ref_out = model(x)
1216-
1217-
temp_filepath = os.path.join(self.get_temp_dir(), "deeply_nested.keras")
1218-
model.save(temp_filepath)
1219-
new_model = keras.saving.load_model(temp_filepath)
1220-
out = new_model(x)
1221-
self.assertAllClose(ref_out, out)
1222-
1223-
def test_mixed_nested_container_layer_saving(self):
1224-
"""Test mixed container types (list + tuple)."""
1225-
1226-
@keras.saving.register_keras_serializable(package="test_mixed_nested")
1227-
class MixedNestedModel(keras.Model):
1228-
def __init__(self, **kwargs):
1229-
super().__init__(**kwargs)
1230-
self.blocks = [(keras.layers.Dense(4), keras.layers.Dense(4))]
1231-
self.out_layer = keras.layers.Dense(2)
1232-
1233-
def call(self, x):
1234-
for block in self.blocks:
1235-
for layer in block:
1236-
x = layer(x)
1237-
return self.out_layer(x)
1238-
1239-
def get_config(self):
1240-
return super().get_config()
1241-
1242-
model = MixedNestedModel()
1243-
x = np.random.random((2, 4))
1244-
model(x)
1245-
ref_out = model(x)
1246-
1247-
temp_filepath = os.path.join(self.get_temp_dir(), "mixed_nested.keras")
1248-
model.save(temp_filepath)
1249-
new_model = keras.saving.load_model(temp_filepath)
1250-
out = new_model(x)
1251-
self.assertAllClose(ref_out, out)
1252-
1253-
def test_cyclic_container_saving(self):
1254-
"""Test that cyclic container references do not cause RecursionError."""
1255-
1256-
@keras.saving.register_keras_serializable(
1257-
package="test_cyclic_container"
1258-
)
1259-
class CyclicContainerModel(keras.Model):
1260-
def __init__(self, **kwargs):
1261-
super().__init__(**kwargs)
1262-
self.blocks = []
1263-
self.blocks.append(self.blocks)
1264-
self.out = keras.layers.Dense(2)
1265-
1266-
def call(self, x):
1267-
return self.out(x)
1268-
1269-
def get_config(self):
1270-
return super().get_config()
1271-
1272-
model = CyclicContainerModel()
1273-
x = np.random.random((2, 4))
1274-
model(x)
1275-
ref_out = model(x)
1276-
1277-
temp_filepath = os.path.join(
1278-
self.get_temp_dir(), "cyclic_container.keras"
1279-
)
1280-
model.save(temp_filepath)
1281-
new_model = keras.saving.load_model(temp_filepath)
1282-
out = new_model(x)
1283-
self.assertAllClose(ref_out, out)
1284-
12851120
def test_remove_weights_only_saving_and_loading(self):
12861121
def is_remote_path(path):
12871122
return True

0 commit comments

Comments
 (0)