From e68f0822cafc481b7947d02d1efb4204e9d485ff Mon Sep 17 00:00:00 2001 From: yashwanth510 Date: Thu, 26 Feb 2026 22:31:13 +0530 Subject: [PATCH 1/4] fix: serialize head_dtype in ImageClassifier.get_config() head_dtype was accepted by __init__() and used to set the dtype policy for pooler, output_dropout, and output_dense layers, but was never stored on self or included in get_config(). This caused head_dtype to be silently lost on save/load round-trips. Fixes #2085 --- keras_hub/src/models/image_classifier.py | 28 ++++++++++++++++-------- 1 file changed, 19 insertions(+), 9 deletions(-) diff --git a/keras_hub/src/models/image_classifier.py b/keras_hub/src/models/image_classifier.py index e75e390899..75a155c6b2 100644 --- a/keras_hub/src/models/image_classifier.py +++ b/keras_hub/src/models/image_classifier.py @@ -35,17 +35,17 @@ class ImageClassifier(Task): Examples: Call `predict()` to run inference. - ```python +```python # Load preset and train images = np.random.randint(0, 256, size=(2, 224, 224, 3)) classifier = keras_hub.models.ImageClassifier.from_preset( "resnet_50_imagenet" ) classifier.predict(images) - ``` +``` Call `fit()` on a single batch. - ```python +```python # Load preset and train images = np.random.randint(0, 256, size=(2, 224, 224, 3)) labels = [0, 3] @@ -53,10 +53,10 @@ class ImageClassifier(Task): "resnet_50_imagenet" ) classifier.fit(x=images, y=labels, batch_size=2) - ``` +``` Call `fit()` with custom loss, optimizer and backbone. - ```python +```python classifier = keras_hub.models.ImageClassifier.from_preset( "resnet_50_imagenet" ) @@ -66,10 +66,10 @@ class ImageClassifier(Task): ) classifier.backbone.trainable = False classifier.fit(x=images, y=labels, batch_size=2) - ``` +``` Custom backbone. - ```python +```python images = np.random.randint(0, 256, size=(2, 224, 224, 3)) labels = [0, 3] backbone = keras_hub.models.ResNetBackbone( @@ -85,7 +85,7 @@ class ImageClassifier(Task): num_classes=4, ) classifier.fit(x=images, y=labels, batch_size=2) - ``` +``` """ def __init__( @@ -102,6 +102,12 @@ def __init__( head_dtype = head_dtype or backbone.dtype_policy data_format = getattr(backbone, "data_format", None) + # ✅ CHANGE 1: Store head_dtype on self so get_config() can save it. + # Previously head_dtype was computed but never stored — so after + # save/load the dtype policy was silently lost for pooler, + # output_dropout, and output_dense layers. + self.head_dtype = head_dtype + # === Layers === self.backbone = backbone self.preprocessor = preprocessor @@ -161,6 +167,10 @@ def get_config(self): "pooling": self.pooling, "activation": self.activation, "dropout": self.dropout, + # ✅ CHANGE 2: Serialize head_dtype so it survives save/load. + # Previously this key was missing — confirmed by: + # "head_dtype in config: False" + "head_dtype": self.head_dtype, } ) return config @@ -214,4 +224,4 @@ def compile( loss=loss, metrics=metrics, **kwargs, - ) + ) \ No newline at end of file From dec6251670d88f4d4fa44d0a96e7883188844f6c Mon Sep 17 00:00:00 2001 From: yashwanth510 Date: Thu, 26 Feb 2026 22:56:32 +0530 Subject: [PATCH 2/4] fix: serialize head_dtype in ImageClassifier.get_config() head_dtype was accepted by __init__() and used to set dtype policy for pooler, output_dropout, and output_dense layers, but was never stored on self or included in get_config(). This caused head_dtype to be silently lost on save/load round-trips. Fixes #2085 --- keras_hub/src/models/image_classifier.py | 30 +++++++++--------------- 1 file changed, 11 insertions(+), 19 deletions(-) diff --git a/keras_hub/src/models/image_classifier.py b/keras_hub/src/models/image_classifier.py index 75a155c6b2..6bac7089f7 100644 --- a/keras_hub/src/models/image_classifier.py +++ b/keras_hub/src/models/image_classifier.py @@ -35,17 +35,17 @@ class ImageClassifier(Task): Examples: Call `predict()` to run inference. -```python + ```python # Load preset and train images = np.random.randint(0, 256, size=(2, 224, 224, 3)) classifier = keras_hub.models.ImageClassifier.from_preset( "resnet_50_imagenet" ) classifier.predict(images) -``` + ``` Call `fit()` on a single batch. -```python + ```python # Load preset and train images = np.random.randint(0, 256, size=(2, 224, 224, 3)) labels = [0, 3] @@ -53,10 +53,10 @@ class ImageClassifier(Task): "resnet_50_imagenet" ) classifier.fit(x=images, y=labels, batch_size=2) -``` + ``` Call `fit()` with custom loss, optimizer and backbone. -```python + ```python classifier = keras_hub.models.ImageClassifier.from_preset( "resnet_50_imagenet" ) @@ -66,10 +66,10 @@ class ImageClassifier(Task): ) classifier.backbone.trainable = False classifier.fit(x=images, y=labels, batch_size=2) -``` + ``` Custom backbone. -```python + ```python images = np.random.randint(0, 256, size=(2, 224, 224, 3)) labels = [0, 3] backbone = keras_hub.models.ResNetBackbone( @@ -85,7 +85,7 @@ class ImageClassifier(Task): num_classes=4, ) classifier.fit(x=images, y=labels, batch_size=2) -``` + ``` """ def __init__( @@ -100,14 +100,9 @@ def __init__( **kwargs, ): head_dtype = head_dtype or backbone.dtype_policy + self.head_dtype = head_dtype # ✅ CHANGE 1: store for serialization data_format = getattr(backbone, "data_format", None) - # ✅ CHANGE 1: Store head_dtype on self so get_config() can save it. - # Previously head_dtype was computed but never stored — so after - # save/load the dtype policy was silently lost for pooler, - # output_dropout, and output_dense layers. - self.head_dtype = head_dtype - # === Layers === self.backbone = backbone self.preprocessor = preprocessor @@ -167,10 +162,7 @@ def get_config(self): "pooling": self.pooling, "activation": self.activation, "dropout": self.dropout, - # ✅ CHANGE 2: Serialize head_dtype so it survives save/load. - # Previously this key was missing — confirmed by: - # "head_dtype in config: False" - "head_dtype": self.head_dtype, + "head_dtype": self.head_dtype, # ✅ CHANGE 2: serialize head_dtype } ) return config @@ -224,4 +216,4 @@ def compile( loss=loss, metrics=metrics, **kwargs, - ) \ No newline at end of file + ) From bdc5b05ccababe216df8d025d6705aa9d63cd488 Mon Sep 17 00:00:00 2001 From: yashwanth510 Date: Thu, 26 Feb 2026 23:16:08 +0530 Subject: [PATCH 3/4] remove review comments from code --- keras_hub/src/models/image_classifier.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/keras_hub/src/models/image_classifier.py b/keras_hub/src/models/image_classifier.py index 6bac7089f7..1ec352edd2 100644 --- a/keras_hub/src/models/image_classifier.py +++ b/keras_hub/src/models/image_classifier.py @@ -100,7 +100,7 @@ def __init__( **kwargs, ): head_dtype = head_dtype or backbone.dtype_policy - self.head_dtype = head_dtype # ✅ CHANGE 1: store for serialization + self.head_dtype = head_dtype data_format = getattr(backbone, "data_format", None) # === Layers === @@ -162,7 +162,7 @@ def get_config(self): "pooling": self.pooling, "activation": self.activation, "dropout": self.dropout, - "head_dtype": self.head_dtype, # ✅ CHANGE 2: serialize head_dtype + "head_dtype": self.head_dtype, } ) return config From 641d3e5ad0e5d6823ca99d28c9efee35774451a3 Mon Sep 17 00:00:00 2001 From: yashwanth510 Date: Thu, 26 Feb 2026 23:34:22 +0530 Subject: [PATCH 4/4] fix: apply ruff formatting --- keras_hub/src/models/image_classifier.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/keras_hub/src/models/image_classifier.py b/keras_hub/src/models/image_classifier.py index 1ec352edd2..6bcbe4728f 100644 --- a/keras_hub/src/models/image_classifier.py +++ b/keras_hub/src/models/image_classifier.py @@ -100,7 +100,7 @@ def __init__( **kwargs, ): head_dtype = head_dtype or backbone.dtype_policy - self.head_dtype = head_dtype + self.head_dtype = head_dtype data_format = getattr(backbone, "data_format", None) # === Layers === @@ -162,7 +162,7 @@ def get_config(self): "pooling": self.pooling, "activation": self.activation, "dropout": self.dropout, - "head_dtype": self.head_dtype, + "head_dtype": self.head_dtype, } ) return config