keras-hub-nightly 0.16.1.dev202410020340__py3-none-any.whl → 0.16.1.dev202410040340__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. keras_hub/api/layers/__init__.py +3 -3
  2. keras_hub/api/models/__init__.py +10 -1
  3. keras_hub/src/layers/preprocessing/audio_converter.py +3 -7
  4. keras_hub/src/layers/preprocessing/image_converter.py +164 -34
  5. keras_hub/src/models/backbone.py +3 -9
  6. keras_hub/src/models/csp_darknet/csp_darknet_image_classifier.py +0 -109
  7. keras_hub/src/models/deeplab_v3/__init__.py +7 -0
  8. keras_hub/src/models/deeplab_v3/deeplab_v3_backbone.py +196 -0
  9. keras_hub/src/models/deeplab_v3/deeplab_v3_image_converter.py +10 -0
  10. keras_hub/src/models/deeplab_v3/deeplab_v3_image_segmeter_preprocessor.py +16 -0
  11. keras_hub/src/models/deeplab_v3/deeplab_v3_layers.py +215 -0
  12. keras_hub/src/models/deeplab_v3/deeplab_v3_presets.py +4 -0
  13. keras_hub/src/models/deeplab_v3/deeplab_v3_segmenter.py +109 -0
  14. keras_hub/src/models/densenet/densenet_image_classifier.py +0 -128
  15. keras_hub/src/models/densenet/densenet_image_converter.py +2 -4
  16. keras_hub/src/models/feature_pyramid_backbone.py +1 -1
  17. keras_hub/src/models/image_classifier.py +147 -2
  18. keras_hub/src/models/image_classifier_preprocessor.py +3 -3
  19. keras_hub/src/models/image_segmenter.py +0 -5
  20. keras_hub/src/models/image_segmenter_preprocessor.py +29 -4
  21. keras_hub/src/models/mix_transformer/mix_transformer_classifier.py +0 -109
  22. keras_hub/src/models/mobilenet/mobilenet_image_classifier.py +0 -92
  23. keras_hub/src/models/pali_gemma/pali_gemma_image_converter.py +2 -4
  24. keras_hub/src/models/preprocessor.py +3 -5
  25. keras_hub/src/models/resnet/resnet_backbone.py +1 -11
  26. keras_hub/src/models/resnet/resnet_image_classifier.py +0 -137
  27. keras_hub/src/models/resnet/resnet_image_converter.py +2 -4
  28. keras_hub/src/models/sam/__init__.py +5 -0
  29. keras_hub/src/models/sam/sam_image_converter.py +2 -4
  30. keras_hub/src/models/sam/sam_image_segmenter_preprocessor.py +11 -1
  31. keras_hub/src/models/sam/sam_presets.py +3 -3
  32. keras_hub/src/models/stable_diffusion_3/flow_match_euler_discrete_scheduler.py +8 -1
  33. keras_hub/src/models/stable_diffusion_3/stable_diffusion_3_backbone.py +57 -93
  34. keras_hub/src/models/stable_diffusion_3/stable_diffusion_3_presets.py +3 -3
  35. keras_hub/src/models/stable_diffusion_3/stable_diffusion_3_text_to_image.py +5 -3
  36. keras_hub/src/models/task.py +39 -36
  37. keras_hub/src/models/vae/__init__.py +1 -0
  38. keras_hub/src/models/vae/vae_backbone.py +172 -0
  39. keras_hub/src/models/vae/vae_layers.py +740 -0
  40. keras_hub/src/models/vgg/vgg_backbone.py +1 -20
  41. keras_hub/src/models/vgg/vgg_image_classifier.py +108 -29
  42. keras_hub/src/tokenizers/tokenizer.py +3 -6
  43. keras_hub/src/utils/preset_utils.py +103 -61
  44. keras_hub/src/utils/timm/preset_loader.py +8 -9
  45. keras_hub/src/version_utils.py +1 -1
  46. {keras_hub_nightly-0.16.1.dev202410020340.dist-info → keras_hub_nightly-0.16.1.dev202410040340.dist-info}/METADATA +1 -1
  47. {keras_hub_nightly-0.16.1.dev202410020340.dist-info → keras_hub_nightly-0.16.1.dev202410040340.dist-info}/RECORD +49 -41
  48. keras_hub/src/layers/preprocessing/resizing_image_converter.py +0 -138
  49. keras_hub/src/models/stable_diffusion_3/vae_image_decoder.py +0 -320
  50. {keras_hub_nightly-0.16.1.dev202410020340.dist-info → keras_hub_nightly-0.16.1.dev202410040340.dist-info}/WHEEL +0 -0
  51. {keras_hub_nightly-0.16.1.dev202410020340.dist-info → keras_hub_nightly-0.16.1.dev202410040340.dist-info}/top_level.txt +0 -0
@@ -21,17 +21,6 @@ class VGGBackbone(Backbone):
21
21
  blocks per VGG block. For both VGG16 and VGG19 this is [
22
22
  64, 128, 256, 512, 512].
23
23
  image_shape: tuple, optional shape tuple, defaults to (224, 224, 3).
24
- pooling: bool, Optional pooling mode for feature extraction
25
- when `include_top` is `False`.
26
- - `None` means that the output of the model will be
27
- the 4D tensor output of the
28
- last convolutional block.
29
- - `avg` means that global average pooling
30
- will be applied to the output of the
31
- last convolutional block, and thus
32
- the output of the model will be a 2D tensor.
33
- - `max` means that global max pooling will
34
- be applied.
35
24
 
36
25
  Examples:
37
26
  ```python
@@ -46,7 +35,6 @@ class VGGBackbone(Backbone):
46
35
  stackwise_num_repeats = [2, 2, 3, 3, 3],
47
36
  stackwise_num_filters = [64, 128, 256, 512, 512],
48
37
  image_shape = (224, 224, 3),
49
- pooling = "avg",
50
38
  )
51
39
  model(input_data)
52
40
  ```
@@ -56,8 +44,7 @@ class VGGBackbone(Backbone):
56
44
  self,
57
45
  stackwise_num_repeats,
58
46
  stackwise_num_filters,
59
- image_shape=(224, 224, 3),
60
- pooling="avg",
47
+ image_shape=(None, None, 3),
61
48
  **kwargs,
62
49
  ):
63
50
 
@@ -76,10 +63,6 @@ class VGGBackbone(Backbone):
76
63
  max_pool=True,
77
64
  name=f"block{stack_index + 1}",
78
65
  )
79
- if pooling == "avg":
80
- x = layers.GlobalAveragePooling2D()(x)
81
- elif pooling == "max":
82
- x = layers.GlobalMaxPooling2D()(x)
83
66
 
84
67
  super().__init__(inputs=img_input, outputs=x, **kwargs)
85
68
 
@@ -87,14 +70,12 @@ class VGGBackbone(Backbone):
87
70
  self.stackwise_num_repeats = stackwise_num_repeats
88
71
  self.stackwise_num_filters = stackwise_num_filters
89
72
  self.image_shape = image_shape
90
- self.pooling = pooling
91
73
 
92
74
  def get_config(self):
93
75
  return {
94
76
  "stackwise_num_repeats": self.stackwise_num_repeats,
95
77
  "stackwise_num_filters": self.stackwise_num_filters,
96
78
  "image_shape": self.image_shape,
97
- "pooling": self.pooling,
98
79
  }
99
80
 
100
81
 
@@ -2,58 +2,90 @@ import keras
2
2
 
3
3
  from keras_hub.src.api_export import keras_hub_export
4
4
  from keras_hub.src.models.image_classifier import ImageClassifier
5
+ from keras_hub.src.models.task import Task
5
6
  from keras_hub.src.models.vgg.vgg_backbone import VGGBackbone
6
7
 
7
8
 
8
9
  @keras_hub_export("keras_hub.models.VGGImageClassifier")
9
10
  class VGGImageClassifier(ImageClassifier):
10
- """VGG16 image classifier task model.
11
+ """VGG image classification task.
11
12
 
12
- Args:
13
- backbone: A `keras_hub.models.VGGBackbone` instance.
14
- num_classes: int, number of classes to predict.
15
- pooling: str, type of pooling layer. Must be one of "avg", "max".
16
- activation: Optional `str` or callable, defaults to "softmax". The
17
- activation function to use on the Dense layer. Set `activation=None`
18
- to return the output logits.
13
+ `VGGImageClassifier` tasks wrap a `keras_hub.models.VGGBackbone` and
14
+ a `keras_hub.models.Preprocessor` to create a model that can be used for
15
+ image classification. `VGGImageClassifier` tasks take an additional
16
+ `num_classes` argument, controlling the number of predicted output classes.
19
17
 
20
18
  To fine-tune with `fit()`, pass a dataset containing tuples of `(x, y)`
21
19
  labels where `x` is a string and `y` is a integer from `[0, num_classes)`.
22
- All `ImageClassifier` tasks include a `from_preset()` constructor which can be
23
- used to load a pre-trained config and weights.
20
+
21
+ Not that unlike `keras_hub.model.ImageClassifier`, the `VGGImageClassifier`
22
+ allows and defaults to `pooling="flatten"`, when inputs are flatten and
23
+ passed through two intermediate dense layers before the final output
24
+ projection.
25
+
26
+ Args:
27
+ backbone: A `keras_hub.models.VGGBackbone` instance or a `keras.Model`.
28
+ num_classes: int. The number of classes to predict.
29
+ preprocessor: `None`, a `keras_hub.models.Preprocessor` instance,
30
+ a `keras.Layer` instance, or a callable. If `None` no preprocessing
31
+ will be applied to the inputs.
32
+ pooling: `"flatten"`, `"avg"`, or `"max"`. The type of pooling to apply
33
+ on backbone output. The default is flatten to match the original
34
+ VGG implementation, where backbone inputs will be flattened and
35
+ passed through two dense layers with a `"relu"` activation.
36
+ pooling_hidden_dim: the output feature size of the pooling dense layers.
37
+ This only applies when `pooling="flatten"`.
38
+ activation: `None`, str, or callable. The activation function to use on
39
+ the `Dense` layer. Set `activation=None` to return the output
40
+ logits. Defaults to `"softmax"`.
41
+ head_dtype: `None`, str, or `keras.mixed_precision.DTypePolicy`. The
42
+ dtype to use for the classification head's computations and weights.
43
+
24
44
 
25
45
  Examples:
26
- Train from preset
46
+
47
+ Call `predict()` to run inference.
48
+ ```python
49
+ # Load preset and train
50
+ images = np.random.randint(0, 256, size=(2, 224, 224, 3))
51
+ classifier = keras_hub.models.VGGImageClassifier.from_preset(
52
+ "vgg_16_imagenet"
53
+ )
54
+ classifier.predict(images)
55
+ ```
56
+
57
+ Call `fit()` on a single batch.
27
58
  ```python
28
59
  # Load preset and train
29
- images = np.ones((2, 224, 224, 3), dtype="float32")
60
+ images = np.random.randint(0, 256, size=(2, 224, 224, 3))
30
61
  labels = [0, 3]
31
62
  classifier = keras_hub.models.VGGImageClassifier.from_preset(
32
- 'vgg_16_image_classifier')
63
+ "vgg_16_imagenet"
64
+ )
33
65
  classifier.fit(x=images, y=labels, batch_size=2)
66
+ ```
34
67
 
35
- # Re-compile (e.g., with a new learning rate).
68
+ Call `fit()` with custom loss, optimizer and backbone.
69
+ ```python
70
+ classifier = keras_hub.models.VGGImageClassifier.from_preset(
71
+ "vgg_16_imagenet"
72
+ )
36
73
  classifier.compile(
37
74
  loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
38
75
  optimizer=keras.optimizers.Adam(5e-5),
39
- jit_compile=True,
40
76
  )
41
-
42
- # Access backbone programmatically (e.g., to change `trainable`).
43
77
  classifier.backbone.trainable = False
44
- # Fit again.
45
78
  classifier.fit(x=images, y=labels, batch_size=2)
46
79
  ```
47
- Custom backbone
80
+
81
+ Custom backbone.
48
82
  ```python
49
- images = np.ones((2, 224, 224, 3), dtype="float32")
83
+ images = np.random.randint(0, 256, size=(2, 224, 224, 3))
50
84
  labels = [0, 3]
51
-
52
- backbone = keras_hub.models.VGGBackbone(
85
+ model = keras_hub.models.VGGBackbone(
53
86
  stackwise_num_repeats = [2, 2, 3, 3, 3],
54
87
  stackwise_num_filters = [64, 128, 256, 512, 512],
55
88
  image_shape = (224, 224, 3),
56
- pooling = "avg",
57
89
  )
58
90
  classifier = keras_hub.models.VGGImageClassifier(
59
91
  backbone=backbone,
@@ -69,26 +101,67 @@ class VGGImageClassifier(ImageClassifier):
69
101
  self,
70
102
  backbone,
71
103
  num_classes,
72
- activation="softmax",
73
- preprocessor=None, # adding this dummy arg for saved model test
74
- # TODO: once preprocessor flow is figured out, this needs to be updated
104
+ preprocessor=None,
105
+ pooling="flatten",
106
+ pooling_hidden_dim=4096,
107
+ activation=None,
108
+ dropout=0.0,
109
+ head_dtype=None,
75
110
  **kwargs,
76
111
  ):
112
+ head_dtype = head_dtype or backbone.dtype_policy
113
+ data_format = getattr(backbone, "data_format", None)
114
+
77
115
  # === Layers ===
78
116
  self.backbone = backbone
117
+ self.preprocessor = preprocessor
118
+ if pooling == "avg":
119
+ self.pooler = keras.layers.GlobalAveragePooling2D(
120
+ data_format,
121
+ dtype=head_dtype,
122
+ name="pooler",
123
+ )
124
+ elif pooling == "max":
125
+ self.pooler = keras.layers.GlobalMaxPooling2D(
126
+ data_format,
127
+ dtype=head_dtype,
128
+ name="pooler",
129
+ )
130
+ elif pooling == "flatten":
131
+ self.pooler = keras.Sequential(
132
+ [
133
+ keras.layers.Flatten(name="flatten"),
134
+ keras.layers.Dense(pooling_hidden_dim, activation="relu"),
135
+ keras.layers.Dense(pooling_hidden_dim, activation="relu"),
136
+ ],
137
+ name="pooler",
138
+ )
139
+ else:
140
+ raise ValueError(
141
+ "Unknown `pooling` type. Polling should be either `'avg'` or "
142
+ f"`'max'`. Received: pooling={pooling}."
143
+ )
144
+ self.output_dropout = keras.layers.Dropout(
145
+ dropout,
146
+ dtype=head_dtype,
147
+ name="output_dropout",
148
+ )
79
149
  self.output_dense = keras.layers.Dense(
80
150
  num_classes,
81
151
  activation=activation,
152
+ dtype=head_dtype,
82
153
  name="predictions",
83
154
  )
84
155
 
85
156
  # === Functional Model ===
86
157
  inputs = self.backbone.input
87
158
  x = self.backbone(inputs)
159
+ x = self.pooler(x)
160
+ x = self.output_dropout(x)
88
161
  outputs = self.output_dense(x)
89
-
90
- # Instantiate using Functional API Model constructor
91
- super().__init__(
162
+ # Skip the parent class functional model.
163
+ Task.__init__(
164
+ self,
92
165
  inputs=inputs,
93
166
  outputs=outputs,
94
167
  **kwargs,
@@ -97,6 +170,9 @@ class VGGImageClassifier(ImageClassifier):
97
170
  # === Config ===
98
171
  self.num_classes = num_classes
99
172
  self.activation = activation
173
+ self.pooling = pooling
174
+ self.pooling_hidden_dim = pooling_hidden_dim
175
+ self.dropout = dropout
100
176
 
101
177
  def get_config(self):
102
178
  # Backbone serialized in `super`
@@ -104,7 +180,10 @@ class VGGImageClassifier(ImageClassifier):
104
180
  config.update(
105
181
  {
106
182
  "num_classes": self.num_classes,
183
+ "pooling": self.pooling,
107
184
  "activation": self.activation,
185
+ "pooling_hidden_dim": self.pooling_hidden_dim,
186
+ "dropout": self.dropout,
108
187
  }
109
188
  )
110
189
  return config
@@ -10,7 +10,7 @@ from keras_hub.src.utils.preset_utils import builtin_presets
10
10
  from keras_hub.src.utils.preset_utils import find_subclass
11
11
  from keras_hub.src.utils.preset_utils import get_file
12
12
  from keras_hub.src.utils.preset_utils import get_preset_loader
13
- from keras_hub.src.utils.preset_utils import save_serialized_object
13
+ from keras_hub.src.utils.preset_utils import get_preset_saver
14
14
  from keras_hub.src.utils.python_utils import classproperty
15
15
  from keras_hub.src.utils.tensor_utils import preprocessing_function
16
16
 
@@ -189,11 +189,8 @@ class Tokenizer(PreprocessingLayer):
189
189
  Args:
190
190
  preset_dir: The path to the local model preset directory.
191
191
  """
192
- save_serialized_object(self, preset_dir, config_file=self.config_name)
193
- subdir = self.config_name.split(".")[0]
194
- asset_dir = os.path.join(preset_dir, ASSET_DIR, subdir)
195
- os.makedirs(asset_dir, exist_ok=True)
196
- self.save_assets(asset_dir)
192
+ saver = get_preset_saver(preset_dir)
193
+ saver.save_tokenizer(self)
197
194
 
198
195
  @preprocessing_function
199
196
  def call(self, inputs, *args, training=None, **kwargs):
@@ -267,64 +267,6 @@ def check_file_exists(preset, path):
267
267
  return True
268
268
 
269
269
 
270
- def get_tokenizer(layer):
271
- """Get the tokenizer from any KerasHub model or layer."""
272
- # Avoid circular import.
273
- from keras_hub.src.tokenizers.tokenizer import Tokenizer
274
-
275
- if isinstance(layer, Tokenizer):
276
- return layer
277
- if hasattr(layer, "tokenizer"):
278
- return layer.tokenizer
279
- if hasattr(layer, "preprocessor"):
280
- return getattr(layer.preprocessor, "tokenizer", None)
281
- return None
282
-
283
-
284
- def recursive_pop(config, key):
285
- """Remove a key from a nested config object"""
286
- config.pop(key, None)
287
- for value in config.values():
288
- if isinstance(value, dict):
289
- recursive_pop(value, key)
290
-
291
-
292
- # TODO: refactor saving routines into a PresetSaver class?
293
- def make_preset_dir(preset):
294
- os.makedirs(preset, exist_ok=True)
295
-
296
-
297
- def save_serialized_object(
298
- layer,
299
- preset,
300
- config_file=CONFIG_FILE,
301
- config_to_skip=[],
302
- ):
303
- make_preset_dir(preset)
304
- config_path = os.path.join(preset, config_file)
305
- config = keras.saving.serialize_keras_object(layer)
306
- config_to_skip += ["compile_config", "build_config"]
307
- for c in config_to_skip:
308
- recursive_pop(config, c)
309
- with open(config_path, "w") as config_file:
310
- config_file.write(json.dumps(config, indent=4))
311
-
312
-
313
- def save_metadata(layer, preset):
314
- from keras_hub.src.version_utils import __version__ as keras_hub_version
315
-
316
- keras_version = keras.version() if hasattr(keras, "version") else None
317
- metadata = {
318
- "keras_version": keras_version,
319
- "keras_hub_version": keras_hub_version,
320
- "parameter_count": layer.count_params(),
321
- "date_saved": datetime.datetime.now().strftime("%Y-%m-%d@%H:%M:%S"),
322
- }
323
- metadata_path = os.path.join(preset, METADATA_FILE)
324
- with open(metadata_path, "w") as metadata_file:
325
- metadata_file.write(json.dumps(metadata, indent=4))
326
-
327
-
328
270
  def _validate_backbone(preset):
329
271
  config_path = os.path.join(preset, CONFIG_FILE)
330
272
  if not os.path.exists(config_path):
@@ -518,6 +460,8 @@ def load_serialized_object(config, **kwargs):
518
460
  def check_config_class(config):
519
461
  """Validate a preset is being loaded on the correct class."""
520
462
  registered_name = config["registered_name"]
463
+ if registered_name in ("Functional", "Sequential"):
464
+ return keras.Model
521
465
  cls = keras.saving.get_registered_object(registered_name)
522
466
  if cls is None:
523
467
  raise ValueError(
@@ -600,6 +544,13 @@ def get_preset_loader(preset):
600
544
  )
601
545
 
602
546
 
547
+ def get_preset_saver(preset):
548
+ # Unlike loading, we only support one form of saving; Keras serialized
549
+ # configs and saved weights. We keep the rough API structure as loading
550
+ # just for simplicity.
551
+ return KerasPresetSaver(preset)
552
+
553
+
603
554
  class PresetLoader:
604
555
  def __init__(self, preset, config):
605
556
  self.config = config
@@ -684,7 +635,8 @@ class KerasPresetLoader(PresetLoader):
684
635
  def load_tokenizer(self, cls, config_name=TOKENIZER_CONFIG_FILE, **kwargs):
685
636
  tokenizer_config = load_json(self.preset, config_name)
686
637
  tokenizer = load_serialized_object(tokenizer_config, **kwargs)
687
- tokenizer.load_preset_assets(self.preset)
638
+ if hasattr(tokenizer, "load_preset_assets"):
639
+ tokenizer.load_preset_assets(self.preset)
688
640
  return tokenizer
689
641
 
690
642
  def load_audio_converter(self, cls, **kwargs):
@@ -709,7 +661,9 @@ class KerasPresetLoader(PresetLoader):
709
661
  )
710
662
  # We found a `task.json` with a complete config for our class.
711
663
  task = load_serialized_object(task_config, **kwargs)
712
- if task.preprocessor:
664
+ if task.preprocessor and hasattr(
665
+ task.preprocessor, "load_preset_assets"
666
+ ):
713
667
  task.preprocessor.load_preset_assets(self.preset)
714
668
  if load_weights:
715
669
  has_task_weights = check_file_exists(self.preset, TASK_WEIGHTS_FILE)
@@ -735,5 +689,93 @@ class KerasPresetLoader(PresetLoader):
735
689
  return super().load_preprocessor(cls, **kwargs)
736
690
  # We found a `preprocessing.json` with a complete config for our class.
737
691
  preprocessor = load_serialized_object(preprocessor_json, **kwargs)
738
- preprocessor.load_preset_assets(self.preset)
692
+ if hasattr(preprocessor, "load_preset_assets"):
693
+ preprocessor.load_preset_assets(self.preset)
739
694
  return preprocessor
695
+
696
+
697
+ class KerasPresetSaver:
698
+ def __init__(self, preset_dir):
699
+ os.makedirs(preset_dir, exist_ok=True)
700
+ self.preset_dir = preset_dir
701
+
702
+ def save_backbone(self, backbone):
703
+ self._save_serialized_object(backbone, config_file=CONFIG_FILE)
704
+ backbone_weight_path = os.path.join(self.preset_dir, MODEL_WEIGHTS_FILE)
705
+ backbone.save_weights(backbone_weight_path)
706
+ self._save_metadata(backbone)
707
+
708
+ def save_tokenizer(self, tokenizer):
709
+ config_file = TOKENIZER_CONFIG_FILE
710
+ if hasattr(tokenizer, "config_file"):
711
+ config_file = tokenizer.config_file
712
+ self._save_serialized_object(tokenizer, config_file)
713
+ # Save assets.
714
+ subdir = config_file.split(".")[0]
715
+ asset_dir = os.path.join(self.preset_dir, ASSET_DIR, subdir)
716
+ os.makedirs(asset_dir, exist_ok=True)
717
+ tokenizer.save_assets(asset_dir)
718
+
719
+ def save_audio_converter(self, converter):
720
+ self._save_serialized_object(converter, AUDIO_CONVERTER_CONFIG_FILE)
721
+
722
+ def save_image_converter(self, converter):
723
+ self._save_serialized_object(converter, IMAGE_CONVERTER_CONFIG_FILE)
724
+
725
+ def save_task(self, task):
726
+ # Save task specific config and weights.
727
+ self._save_serialized_object(task, TASK_CONFIG_FILE)
728
+ if task.has_task_weights():
729
+ task_weight_path = os.path.join(self.preset_dir, TASK_WEIGHTS_FILE)
730
+ task.save_task_weights(task_weight_path)
731
+ # Save backbone.
732
+ if hasattr(task.backbone, "save_to_preset"):
733
+ task.backbone.save_to_preset(self.preset_dir)
734
+ else:
735
+ # Allow saving a `keras.Model` that is not a backbone subclass.
736
+ self.save_backbone(task.backbone)
737
+ # Save preprocessor.
738
+ if task.preprocessor and hasattr(task.preprocessor, "save_to_preset"):
739
+ task.preprocessor.save_to_preset(self.preset_dir)
740
+ else:
741
+ # Allow saving a `keras.Layer` that is not a preprocessor subclass.
742
+ self.save_preprocessor(task.preprocessor)
743
+
744
+ def save_preprocessor(self, preprocessor):
745
+ config_file = PREPROCESSOR_CONFIG_FILE
746
+ if hasattr(preprocessor, "config_file"):
747
+ config_file = preprocessor.config_file
748
+ self._save_serialized_object(preprocessor, config_file)
749
+ for layer in preprocessor._flatten_layers(include_self=False):
750
+ if hasattr(layer, "save_to_preset"):
751
+ layer.save_to_preset(self.preset_dir)
752
+
753
+ def _recursive_pop(self, config, key):
754
+ """Remove a key from a nested config object"""
755
+ config.pop(key, None)
756
+ for value in config.values():
757
+ if isinstance(value, dict):
758
+ self._recursive_pop(value, key)
759
+
760
+ def _save_serialized_object(self, layer, config_file):
761
+ config_path = os.path.join(self.preset_dir, config_file)
762
+ config = keras.saving.serialize_keras_object(layer)
763
+ config_to_skip = ["compile_config", "build_config"]
764
+ for key in config_to_skip:
765
+ self._recursive_pop(config, key)
766
+ with open(config_path, "w") as config_file:
767
+ config_file.write(json.dumps(config, indent=4))
768
+
769
+ def _save_metadata(self, layer):
770
+ from keras_hub.src.version_utils import __version__ as keras_hub_version
771
+
772
+ keras_version = keras.version() if hasattr(keras, "version") else None
773
+ metadata = {
774
+ "keras_version": keras_version,
775
+ "keras_hub_version": keras_hub_version,
776
+ "parameter_count": layer.count_params(),
777
+ "date_saved": datetime.datetime.now().strftime("%Y-%m-%d@%H:%M:%S"),
778
+ }
779
+ metadata_path = os.path.join(self.preset_dir, METADATA_FILE)
780
+ with open(metadata_path, "w") as metadata_file:
781
+ metadata_file.write(json.dumps(metadata, indent=4))
@@ -14,7 +14,7 @@ class TimmPresetLoader(PresetLoader):
14
14
  architecture = self.config["architecture"]
15
15
  if "resnet" in architecture:
16
16
  self.converter = convert_resnet
17
- if "densenet" in architecture:
17
+ elif "densenet" in architecture:
18
18
  self.converter = convert_densenet
19
19
  else:
20
20
  raise ValueError(
@@ -52,20 +52,19 @@ class TimmPresetLoader(PresetLoader):
52
52
  pretrained_cfg = self.config.get("pretrained_cfg", None)
53
53
  if not pretrained_cfg or "input_size" not in pretrained_cfg:
54
54
  return None
55
- # This assumes the same basic setup for all timm preprocessing, and that
56
- # all our image conversion will be via a `ResizingImageConverter. We may
55
+ # This assumes the same basic setup for all timm preprocessing, We may
57
56
  # need to extend this as we cover more model types.
58
57
  input_size = pretrained_cfg["input_size"]
59
58
  mean = pretrained_cfg["mean"]
60
- variance = [s**2 for s in pretrained_cfg["std"]]
59
+ std = pretrained_cfg["std"]
60
+ scale = [1.0 / 255.0 / s for s in std]
61
+ offset = [-m / s for m, s in zip(mean, std)]
61
62
  interpolation = pretrained_cfg["interpolation"]
62
63
  if interpolation not in ("bilinear", "nearest", "bicubic"):
63
64
  interpolation = "bilinear" # Unsupported interpolation type.
64
65
  return cls(
65
- width=input_size[1],
66
- height=input_size[2],
67
- scale=1 / 255.0,
68
- mean=mean,
69
- variance=variance,
66
+ image_size=input_size[1:],
67
+ scale=scale,
68
+ offset=offset,
70
69
  interpolation=interpolation,
71
70
  )
@@ -1,7 +1,7 @@
1
1
  from keras_hub.src.api_export import keras_hub_export
2
2
 
3
3
  # Unique source of truth for the version number.
4
- __version__ = "0.16.1.dev202410020340"
4
+ __version__ = "0.16.1.dev202410040340"
5
5
 
6
6
 
7
7
  @keras_hub_export("keras_hub.version")
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: keras-hub-nightly
3
- Version: 0.16.1.dev202410020340
3
+ Version: 0.16.1.dev202410040340
4
4
  Summary: Industry-strength Natural Language Processing extensions for Keras.
5
5
  Home-page: https://github.com/keras-team/keras-hub
6
6
  Author: Keras team