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.
- keras_hub/api/layers/__init__.py +3 -3
- keras_hub/api/models/__init__.py +10 -1
- keras_hub/src/layers/preprocessing/audio_converter.py +3 -7
- keras_hub/src/layers/preprocessing/image_converter.py +164 -34
- keras_hub/src/models/backbone.py +3 -9
- keras_hub/src/models/csp_darknet/csp_darknet_image_classifier.py +0 -109
- keras_hub/src/models/deeplab_v3/__init__.py +7 -0
- keras_hub/src/models/deeplab_v3/deeplab_v3_backbone.py +196 -0
- keras_hub/src/models/deeplab_v3/deeplab_v3_image_converter.py +10 -0
- keras_hub/src/models/deeplab_v3/deeplab_v3_image_segmeter_preprocessor.py +16 -0
- keras_hub/src/models/deeplab_v3/deeplab_v3_layers.py +215 -0
- keras_hub/src/models/deeplab_v3/deeplab_v3_presets.py +4 -0
- keras_hub/src/models/deeplab_v3/deeplab_v3_segmenter.py +109 -0
- keras_hub/src/models/densenet/densenet_image_classifier.py +0 -128
- keras_hub/src/models/densenet/densenet_image_converter.py +2 -4
- keras_hub/src/models/feature_pyramid_backbone.py +1 -1
- keras_hub/src/models/image_classifier.py +147 -2
- keras_hub/src/models/image_classifier_preprocessor.py +3 -3
- keras_hub/src/models/image_segmenter.py +0 -5
- keras_hub/src/models/image_segmenter_preprocessor.py +29 -4
- keras_hub/src/models/mix_transformer/mix_transformer_classifier.py +0 -109
- keras_hub/src/models/mobilenet/mobilenet_image_classifier.py +0 -92
- keras_hub/src/models/pali_gemma/pali_gemma_image_converter.py +2 -4
- keras_hub/src/models/preprocessor.py +3 -5
- keras_hub/src/models/resnet/resnet_backbone.py +1 -11
- keras_hub/src/models/resnet/resnet_image_classifier.py +0 -137
- keras_hub/src/models/resnet/resnet_image_converter.py +2 -4
- keras_hub/src/models/sam/__init__.py +5 -0
- keras_hub/src/models/sam/sam_image_converter.py +2 -4
- keras_hub/src/models/sam/sam_image_segmenter_preprocessor.py +11 -1
- keras_hub/src/models/sam/sam_presets.py +3 -3
- keras_hub/src/models/stable_diffusion_3/flow_match_euler_discrete_scheduler.py +8 -1
- keras_hub/src/models/stable_diffusion_3/stable_diffusion_3_backbone.py +57 -93
- keras_hub/src/models/stable_diffusion_3/stable_diffusion_3_presets.py +3 -3
- keras_hub/src/models/stable_diffusion_3/stable_diffusion_3_text_to_image.py +5 -3
- keras_hub/src/models/task.py +39 -36
- keras_hub/src/models/vae/__init__.py +1 -0
- keras_hub/src/models/vae/vae_backbone.py +172 -0
- keras_hub/src/models/vae/vae_layers.py +740 -0
- keras_hub/src/models/vgg/vgg_backbone.py +1 -20
- keras_hub/src/models/vgg/vgg_image_classifier.py +108 -29
- keras_hub/src/tokenizers/tokenizer.py +3 -6
- keras_hub/src/utils/preset_utils.py +103 -61
- keras_hub/src/utils/timm/preset_loader.py +8 -9
- keras_hub/src/version_utils.py +1 -1
- {keras_hub_nightly-0.16.1.dev202410020340.dist-info → keras_hub_nightly-0.16.1.dev202410040340.dist-info}/METADATA +1 -1
- {keras_hub_nightly-0.16.1.dev202410020340.dist-info → keras_hub_nightly-0.16.1.dev202410040340.dist-info}/RECORD +49 -41
- keras_hub/src/layers/preprocessing/resizing_image_converter.py +0 -138
- keras_hub/src/models/stable_diffusion_3/vae_image_decoder.py +0 -320
- {keras_hub_nightly-0.16.1.dev202410020340.dist-info → keras_hub_nightly-0.16.1.dev202410040340.dist-info}/WHEEL +0 -0
- {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=(
|
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
|
-
"""
|
11
|
+
"""VGG image classification task.
|
11
12
|
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
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
|
-
|
23
|
-
|
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
|
-
|
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.
|
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
|
-
|
63
|
+
"vgg_16_imagenet"
|
64
|
+
)
|
33
65
|
classifier.fit(x=images, y=labels, batch_size=2)
|
66
|
+
```
|
34
67
|
|
35
|
-
|
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
|
-
|
80
|
+
|
81
|
+
Custom backbone.
|
48
82
|
```python
|
49
|
-
images = np.
|
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
|
-
|
73
|
-
|
74
|
-
|
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
|
-
|
91
|
-
|
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
|
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
|
-
|
193
|
-
|
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
|
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
|
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
|
-
|
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,
|
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
|
-
|
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
|
-
|
66
|
-
|
67
|
-
|
68
|
-
mean=mean,
|
69
|
-
variance=variance,
|
66
|
+
image_size=input_size[1:],
|
67
|
+
scale=scale,
|
68
|
+
offset=offset,
|
70
69
|
interpolation=interpolation,
|
71
70
|
)
|
keras_hub/src/version_utils.py
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
Metadata-Version: 2.1
|
2
2
|
Name: keras-hub-nightly
|
3
|
-
Version: 0.16.1.
|
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
|