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
keras_hub/api/layers/__init__.py
CHANGED
@@ -33,10 +33,10 @@ from keras_hub.src.layers.preprocessing.multi_segment_packer import (
|
|
33
33
|
)
|
34
34
|
from keras_hub.src.layers.preprocessing.random_deletion import RandomDeletion
|
35
35
|
from keras_hub.src.layers.preprocessing.random_swap import RandomSwap
|
36
|
-
from keras_hub.src.layers.preprocessing.resizing_image_converter import (
|
37
|
-
ResizingImageConverter,
|
38
|
-
)
|
39
36
|
from keras_hub.src.layers.preprocessing.start_end_packer import StartEndPacker
|
37
|
+
from keras_hub.src.models.deeplab_v3.deeplab_v3_image_converter import (
|
38
|
+
DeepLabV3ImageConverter,
|
39
|
+
)
|
40
40
|
from keras_hub.src.models.densenet.densenet_image_converter import (
|
41
41
|
DenseNetImageConverter,
|
42
42
|
)
|
keras_hub/api/models/__init__.py
CHANGED
@@ -85,6 +85,15 @@ from keras_hub.src.models.deberta_v3.deberta_v3_text_classifier_preprocessor imp
|
|
85
85
|
from keras_hub.src.models.deberta_v3.deberta_v3_tokenizer import (
|
86
86
|
DebertaV3Tokenizer,
|
87
87
|
)
|
88
|
+
from keras_hub.src.models.deeplab_v3.deeplab_v3_backbone import (
|
89
|
+
DeepLabV3Backbone,
|
90
|
+
)
|
91
|
+
from keras_hub.src.models.deeplab_v3.deeplab_v3_image_segmeter_preprocessor import (
|
92
|
+
DeepLabV3ImageSegmenterPreprocessor,
|
93
|
+
)
|
94
|
+
from keras_hub.src.models.deeplab_v3.deeplab_v3_segmenter import (
|
95
|
+
DeepLabV3ImageSegmenter,
|
96
|
+
)
|
88
97
|
from keras_hub.src.models.densenet.densenet_backbone import DenseNetBackbone
|
89
98
|
from keras_hub.src.models.densenet.densenet_image_classifier import (
|
90
99
|
DenseNetImageClassifier,
|
@@ -254,7 +263,7 @@ from keras_hub.src.models.roberta.roberta_tokenizer import RobertaTokenizer
|
|
254
263
|
from keras_hub.src.models.sam.sam_backbone import SAMBackbone
|
255
264
|
from keras_hub.src.models.sam.sam_image_segmenter import SAMImageSegmenter
|
256
265
|
from keras_hub.src.models.sam.sam_image_segmenter_preprocessor import (
|
257
|
-
SAMImageSegmenterPreprocessor
|
266
|
+
SAMImageSegmenterPreprocessor,
|
258
267
|
)
|
259
268
|
from keras_hub.src.models.seq_2_seq_lm import Seq2SeqLM
|
260
269
|
from keras_hub.src.models.seq_2_seq_lm_preprocessor import Seq2SeqLMPreprocessor
|
@@ -2,11 +2,10 @@ from keras_hub.src.api_export import keras_hub_export
|
|
2
2
|
from keras_hub.src.layers.preprocessing.preprocessing_layer import (
|
3
3
|
PreprocessingLayer,
|
4
4
|
)
|
5
|
-
from keras_hub.src.utils.preset_utils import AUDIO_CONVERTER_CONFIG_FILE
|
6
5
|
from keras_hub.src.utils.preset_utils import builtin_presets
|
7
6
|
from keras_hub.src.utils.preset_utils import find_subclass
|
8
7
|
from keras_hub.src.utils.preset_utils import get_preset_loader
|
9
|
-
from keras_hub.src.utils.preset_utils import
|
8
|
+
from keras_hub.src.utils.preset_utils import get_preset_saver
|
10
9
|
from keras_hub.src.utils.python_utils import classproperty
|
11
10
|
|
12
11
|
|
@@ -101,8 +100,5 @@ class AudioConverter(PreprocessingLayer):
|
|
101
100
|
Args:
|
102
101
|
preset_dir: The path to the local model preset directory.
|
103
102
|
"""
|
104
|
-
|
105
|
-
|
106
|
-
preset_dir,
|
107
|
-
config_file=AUDIO_CONVERTER_CONFIG_FILE,
|
108
|
-
)
|
103
|
+
saver = get_preset_saver(preset_dir)
|
104
|
+
saver.save_audio_converter(self)
|
@@ -1,47 +1,184 @@
|
|
1
|
+
import math
|
2
|
+
|
3
|
+
import keras
|
4
|
+
import numpy as np
|
5
|
+
from keras import ops
|
6
|
+
|
1
7
|
from keras_hub.src.api_export import keras_hub_export
|
2
8
|
from keras_hub.src.layers.preprocessing.preprocessing_layer import (
|
3
9
|
PreprocessingLayer,
|
4
10
|
)
|
5
|
-
from keras_hub.src.utils.
|
11
|
+
from keras_hub.src.utils.keras_utils import standardize_data_format
|
6
12
|
from keras_hub.src.utils.preset_utils import builtin_presets
|
7
13
|
from keras_hub.src.utils.preset_utils import find_subclass
|
8
14
|
from keras_hub.src.utils.preset_utils import get_preset_loader
|
9
|
-
from keras_hub.src.utils.preset_utils import
|
15
|
+
from keras_hub.src.utils.preset_utils import get_preset_saver
|
10
16
|
from keras_hub.src.utils.python_utils import classproperty
|
17
|
+
from keras_hub.src.utils.tensor_utils import preprocessing_function
|
11
18
|
|
12
19
|
|
13
20
|
@keras_hub_export("keras_hub.layers.ImageConverter")
|
14
21
|
class ImageConverter(PreprocessingLayer):
|
15
|
-
"""
|
22
|
+
"""Preprocess raw images into model ready inputs.
|
23
|
+
|
24
|
+
This class converts from raw images to model ready inputs. This conversion
|
25
|
+
proceeds in the following steps:
|
16
26
|
|
17
|
-
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
27
|
+
1. Resize the image using to `image_size`. If `image_size` is `None`, this
|
28
|
+
step will be skipped.
|
29
|
+
2. Rescale the image by multiplying by `scale`, which can be either global
|
30
|
+
or per channel. If `scale` is `None`, this step will be skipped.
|
31
|
+
3. Offset the image by adding `offset`, which can be either global
|
32
|
+
or per channel. If `offset` is `None`, this step will be skipped.
|
22
33
|
|
23
34
|
The layer will take as input a raw image tensor in the channels last or
|
24
35
|
channels first format, and output a preprocessed image input for modeling.
|
25
|
-
|
26
|
-
|
27
|
-
|
36
|
+
This tensor can be batched (rank 4), or unbatched (rank 3).
|
37
|
+
|
38
|
+
This layer can be used with the `from_preset()` constructor to load a layer
|
39
|
+
that will rescale and resize an image for a specific pretrained model.
|
40
|
+
Using the layer this way allows writing preprocessing code that does not
|
41
|
+
need updating when switching between model checkpoints.
|
42
|
+
|
43
|
+
Args:
|
44
|
+
image_size: `(int, int)` tuple or `None`. The output size of the image,
|
45
|
+
not including the channels axis. If `None`, the input will not be
|
46
|
+
resized.
|
47
|
+
scale: float, tuple of floats, or `None`. The scale to apply to the
|
48
|
+
inputs. If `scale` is a single float, the entire input will be
|
49
|
+
multiplied by `scale`. If `scale` is a tuple, it's assumed to
|
50
|
+
contain per-channel scale value multiplied against each channel of
|
51
|
+
the input images. If `scale` is `None`, no scaling is applied.
|
52
|
+
offset: float, tuple of floats, or `None`. The offset to apply to the
|
53
|
+
inputs. If `offset` is a single float, the entire input will be
|
54
|
+
summed with `offset`. If `offset` is a tuple, it's assumed to
|
55
|
+
contain per-channel offset value summed against each channel of the
|
56
|
+
input images. If `offset` is `None`, no scaling is applied.
|
57
|
+
crop_to_aspect_ratio: If `True`, resize the images without aspect
|
58
|
+
ratio distortion. When the original aspect ratio differs
|
59
|
+
from the target aspect ratio, the output image will be
|
60
|
+
cropped so as to return the
|
61
|
+
largest possible window in the image (of size `(height, width)`)
|
62
|
+
that matches the target aspect ratio. By default
|
63
|
+
(`crop_to_aspect_ratio=False`), aspect ratio may not be preserved.
|
64
|
+
interpolation: String, the interpolation method.
|
65
|
+
Supports `"bilinear"`, `"nearest"`, `"bicubic"`,
|
66
|
+
`"lanczos3"`, `"lanczos5"`. Defaults to `"bilinear"`.
|
67
|
+
data_format: String, either `"channels_last"` or `"channels_first"`.
|
68
|
+
The ordering of the dimensions in the inputs. `"channels_last"`
|
69
|
+
corresponds to inputs with shape `(batch, height, width, channels)`
|
70
|
+
while `"channels_first"` corresponds to inputs with shape
|
71
|
+
`(batch, channels, height, width)`. It defaults to the
|
72
|
+
`image_data_format` value found in your Keras config file at
|
73
|
+
`~/.keras/keras.json`. If you never set it, then it will be
|
74
|
+
`"channels_last"`.
|
28
75
|
|
29
76
|
Examples:
|
30
77
|
```python
|
31
|
-
# Resize images
|
32
|
-
converter = keras_hub.layers.ImageConverter
|
33
|
-
|
34
|
-
|
35
|
-
|
36
|
-
converter(np.
|
78
|
+
# Resize raw images and scale them to [0, 1].
|
79
|
+
converter = keras_hub.layers.ImageConverter(
|
80
|
+
image_size=(128, 128),
|
81
|
+
scale=1. / 255,
|
82
|
+
)
|
83
|
+
converter(np.random.randint(0, 256, size=(2, 512, 512, 3)))
|
84
|
+
|
85
|
+
# Resize images to the specific size needed for a PaliGemma preset.
|
86
|
+
converter = keras_hub.layers.ImageConverter.from_preset(
|
87
|
+
"pali_gemma_3b_224"
|
88
|
+
)
|
89
|
+
converter(np.random.randint(0, 256, size=(2, 512, 512, 3)))
|
37
90
|
```
|
38
91
|
"""
|
39
92
|
|
40
93
|
backbone_cls = None
|
41
94
|
|
95
|
+
def __init__(
|
96
|
+
self,
|
97
|
+
image_size=None,
|
98
|
+
scale=None,
|
99
|
+
offset=None,
|
100
|
+
crop_to_aspect_ratio=True,
|
101
|
+
interpolation="bilinear",
|
102
|
+
data_format=None,
|
103
|
+
**kwargs,
|
104
|
+
):
|
105
|
+
# TODO: old arg names. Delete this block after resaving Kaggle assets.
|
106
|
+
if "height" in kwargs and "width" in kwargs:
|
107
|
+
image_size = (kwargs.pop("height"), kwargs.pop("width"))
|
108
|
+
if "variance" in kwargs and "mean" in kwargs:
|
109
|
+
std = [math.sqrt(v) for v in kwargs.pop("variance")]
|
110
|
+
scale = [scale / s for s in std]
|
111
|
+
offset = [-m / s for m, s in zip(kwargs.pop("mean"), std)]
|
112
|
+
|
113
|
+
super().__init__(**kwargs)
|
114
|
+
|
115
|
+
# Create the `Resizing` layer here even if it's not being used. That
|
116
|
+
# allows us to make `image_size` a settable property.
|
117
|
+
self.resizing = keras.layers.Resizing(
|
118
|
+
height=image_size[0] if image_size else None,
|
119
|
+
width=image_size[1] if image_size else None,
|
120
|
+
crop_to_aspect_ratio=crop_to_aspect_ratio,
|
121
|
+
interpolation=interpolation,
|
122
|
+
data_format=data_format,
|
123
|
+
dtype=self.dtype_policy,
|
124
|
+
name="resizing",
|
125
|
+
)
|
126
|
+
self.scale = scale
|
127
|
+
self.offset = offset
|
128
|
+
self.crop_to_aspect_ratio = crop_to_aspect_ratio
|
129
|
+
self.interpolation = interpolation
|
130
|
+
self.data_format = standardize_data_format(data_format)
|
131
|
+
|
132
|
+
@property
|
42
133
|
def image_size(self):
|
43
|
-
"""
|
44
|
-
|
134
|
+
"""Settable tuple of `(height, width)` ints. The output image shape."""
|
135
|
+
if self.resizing.height is None:
|
136
|
+
return None
|
137
|
+
return (self.resizing.height, self.resizing.width)
|
138
|
+
|
139
|
+
@image_size.setter
|
140
|
+
def image_size(self, value):
|
141
|
+
if value is None:
|
142
|
+
value = (None, None)
|
143
|
+
self.resizing.height = value[0]
|
144
|
+
self.resizing.width = value[1]
|
145
|
+
|
146
|
+
@preprocessing_function
|
147
|
+
def call(self, inputs):
|
148
|
+
if self.image_size is not None:
|
149
|
+
x = self.resizing(inputs)
|
150
|
+
if self.scale is not None:
|
151
|
+
x = x * self._expand_non_channel_dims(self.scale, x)
|
152
|
+
if self.offset is not None:
|
153
|
+
x = x + self._expand_non_channel_dims(self.offset, x)
|
154
|
+
return x
|
155
|
+
|
156
|
+
def _expand_non_channel_dims(self, value, inputs):
|
157
|
+
unbatched = len(ops.shape(inputs)) == 3
|
158
|
+
channels_first = self.data_format == "channels_first"
|
159
|
+
if unbatched:
|
160
|
+
broadcast_dims = (1, 2) if channels_first else (0, 1)
|
161
|
+
else:
|
162
|
+
broadcast_dims = (0, 2, 3) if channels_first else (0, 1, 2)
|
163
|
+
# If inputs are not a tensor type, return a numpy array.
|
164
|
+
# This might happen when running under tf.data.
|
165
|
+
if ops.is_tensor(inputs):
|
166
|
+
return ops.expand_dims(value, broadcast_dims)
|
167
|
+
else:
|
168
|
+
return np.expand_dims(value, broadcast_dims)
|
169
|
+
|
170
|
+
def get_config(self):
|
171
|
+
config = super().get_config()
|
172
|
+
config.update(
|
173
|
+
{
|
174
|
+
"image_size": self.image_size,
|
175
|
+
"scale": self.scale,
|
176
|
+
"offset": self.offset,
|
177
|
+
"interpolation": self.interpolation,
|
178
|
+
"crop_to_aspect_ratio": self.crop_to_aspect_ratio,
|
179
|
+
}
|
180
|
+
)
|
181
|
+
return config
|
45
182
|
|
46
183
|
@classproperty
|
47
184
|
def presets(cls):
|
@@ -69,13 +206,6 @@ class ImageConverter(PreprocessingLayer):
|
|
69
206
|
You can run `cls.presets.keys()` to list all built-in presets available
|
70
207
|
on the class.
|
71
208
|
|
72
|
-
This constructor can be called in one of two ways. Either from the base
|
73
|
-
class like `keras_hub.models.ImageConverter.from_preset()`, or from a
|
74
|
-
model class like
|
75
|
-
`keras_hub.models.PaliGemmaImageConverter.from_preset()`. If calling
|
76
|
-
from the base class, the subclass of the returning object will be
|
77
|
-
inferred from the config in the preset directory.
|
78
|
-
|
79
209
|
Args:
|
80
210
|
preset: string. A built-in preset identifier, a Kaggle Models
|
81
211
|
handle, a Hugging Face handle, or a path to a local directory.
|
@@ -85,17 +215,20 @@ class ImageConverter(PreprocessingLayer):
|
|
85
215
|
|
86
216
|
Examples:
|
87
217
|
```python
|
218
|
+
batch = np.random.randint(0, 256, size=(2, 512, 512, 3))
|
219
|
+
|
88
220
|
# Resize images for `"pali_gemma_3b_224"`.
|
89
221
|
converter = keras_hub.layers.ImageConverter.from_preset(
|
90
222
|
"pali_gemma_3b_224"
|
91
223
|
)
|
92
|
-
converter(
|
93
|
-
|
224
|
+
converter(batch) # Output shape: (2, 224, 224, 3)
|
225
|
+
|
226
|
+
# Resize images for `"pali_gemma_3b_448"` without cropping.
|
94
227
|
converter = keras_hub.layers.ImageConverter.from_preset(
|
95
228
|
"pali_gemma_3b_448",
|
96
229
|
crop_to_aspect_ratio=False,
|
97
230
|
)
|
98
|
-
converter(
|
231
|
+
converter(batch) # Output shape: (2, 448, 448, 3)
|
99
232
|
```
|
100
233
|
"""
|
101
234
|
loader = get_preset_loader(preset)
|
@@ -110,8 +243,5 @@ class ImageConverter(PreprocessingLayer):
|
|
110
243
|
Args:
|
111
244
|
preset_dir: The path to the local model preset directory.
|
112
245
|
"""
|
113
|
-
|
114
|
-
|
115
|
-
preset_dir,
|
116
|
-
config_file=IMAGE_CONVERTER_CONFIG_FILE,
|
117
|
-
)
|
246
|
+
saver = get_preset_saver(preset_dir)
|
247
|
+
saver.save_image_converter(self)
|
keras_hub/src/models/backbone.py
CHANGED
@@ -1,15 +1,10 @@
|
|
1
|
-
import os
|
2
|
-
|
3
1
|
import keras
|
4
2
|
|
5
3
|
from keras_hub.src.api_export import keras_hub_export
|
6
4
|
from keras_hub.src.utils.keras_utils import assert_quantization_support
|
7
|
-
from keras_hub.src.utils.preset_utils import CONFIG_FILE
|
8
|
-
from keras_hub.src.utils.preset_utils import MODEL_WEIGHTS_FILE
|
9
5
|
from keras_hub.src.utils.preset_utils import builtin_presets
|
10
6
|
from keras_hub.src.utils.preset_utils import get_preset_loader
|
11
|
-
from keras_hub.src.utils.preset_utils import
|
12
|
-
from keras_hub.src.utils.preset_utils import save_serialized_object
|
7
|
+
from keras_hub.src.utils.preset_utils import get_preset_saver
|
13
8
|
from keras_hub.src.utils.python_utils import classproperty
|
14
9
|
|
15
10
|
|
@@ -193,9 +188,8 @@ class Backbone(keras.Model):
|
|
193
188
|
Args:
|
194
189
|
preset_dir: The path to the local model preset directory.
|
195
190
|
"""
|
196
|
-
|
197
|
-
|
198
|
-
save_metadata(self, preset_dir)
|
191
|
+
saver = get_preset_saver(preset_dir)
|
192
|
+
saver.save_backbone(self)
|
199
193
|
|
200
194
|
def enable_lora(self, rank):
|
201
195
|
"""Enable Lora on the backbone.
|
@@ -1,5 +1,3 @@
|
|
1
|
-
import keras
|
2
|
-
|
3
1
|
from keras_hub.src.api_export import keras_hub_export
|
4
2
|
from keras_hub.src.models.csp_darknet.csp_darknet_backbone import (
|
5
3
|
CSPDarkNetBackbone,
|
@@ -9,111 +7,4 @@ from keras_hub.src.models.image_classifier import ImageClassifier
|
|
9
7
|
|
10
8
|
@keras_hub_export("keras_hub.models.CSPDarkNetImageClassifier")
|
11
9
|
class CSPDarkNetImageClassifier(ImageClassifier):
|
12
|
-
"""CSPDarkNet image classifier task model.
|
13
|
-
|
14
|
-
Args:
|
15
|
-
backbone: A `keras_hub.models.CSPDarkNetBackbone` instance.
|
16
|
-
num_classes: int. The number of classes to predict.
|
17
|
-
activation: `None`, str or callable. The activation function to use on
|
18
|
-
the `Dense` layer. Set `activation=None` to return the output
|
19
|
-
logits. Defaults to `"softmax"`.
|
20
|
-
|
21
|
-
To fine-tune with `fit()`, pass a dataset containing tuples of `(x, y)`
|
22
|
-
where `x` is a tensor and `y` is a integer from `[0, num_classes)`.
|
23
|
-
All `ImageClassifier` tasks include a `from_preset()` constructor which can
|
24
|
-
be used to load a pre-trained config and weights.
|
25
|
-
|
26
|
-
Examples:
|
27
|
-
|
28
|
-
Call `predict()` to run inference.
|
29
|
-
```python
|
30
|
-
# Load preset and train
|
31
|
-
images = np.ones((2, 224, 224, 3), dtype="float32")
|
32
|
-
classifier = keras_hub.models.CSPDarkNetImageClassifier.from_preset(
|
33
|
-
"csp_darknet_tiny_imagenet")
|
34
|
-
classifier.predict(images)
|
35
|
-
```
|
36
|
-
|
37
|
-
Call `fit()` on a single batch.
|
38
|
-
```python
|
39
|
-
# Load preset and train
|
40
|
-
images = np.ones((2, 224, 224, 3), dtype="float32")
|
41
|
-
labels = [0, 3]
|
42
|
-
classifier = keras_hub.models.CSPDarkNetImageClassifier.from_preset(
|
43
|
-
"csp_darknet_tiny_imagenet")
|
44
|
-
classifier.fit(x=images, y=labels, batch_size=2)
|
45
|
-
```
|
46
|
-
|
47
|
-
Call `fit()` with custom loss, optimizer and backbone.
|
48
|
-
```python
|
49
|
-
classifier = keras_hub.models.CSPDarkNetImageClassifier.from_preset(
|
50
|
-
"csp_darknet_tiny_imagenet")
|
51
|
-
classifier.compile(
|
52
|
-
loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
|
53
|
-
optimizer=keras.optimizers.Adam(5e-5),
|
54
|
-
)
|
55
|
-
classifier.backbone.trainable = False
|
56
|
-
classifier.fit(x=images, y=labels, batch_size=2)
|
57
|
-
```
|
58
|
-
|
59
|
-
Custom backbone.
|
60
|
-
```python
|
61
|
-
images = np.ones((2, 224, 224, 3), dtype="float32")
|
62
|
-
labels = [0, 3]
|
63
|
-
backbone = keras_hub.models.CSPDarkNetBackbone(
|
64
|
-
stackwise_num_filters=[128, 256, 512, 1024],
|
65
|
-
stackwise_depth=[3, 9, 9, 3],
|
66
|
-
block_type="basic_block",
|
67
|
-
image_shape = (224, 224, 3),
|
68
|
-
)
|
69
|
-
classifier = keras_hub.models.CSPDarkNetImageClassifier(
|
70
|
-
backbone=backbone,
|
71
|
-
num_classes=4,
|
72
|
-
)
|
73
|
-
classifier.fit(x=images, y=labels, batch_size=2)
|
74
|
-
```
|
75
|
-
"""
|
76
|
-
|
77
10
|
backbone_cls = CSPDarkNetBackbone
|
78
|
-
|
79
|
-
def __init__(
|
80
|
-
self,
|
81
|
-
backbone,
|
82
|
-
num_classes,
|
83
|
-
activation="softmax",
|
84
|
-
preprocessor=None, # adding this dummy arg for saved model test
|
85
|
-
# TODO: once preprocessor flow is figured out, this needs to be updated
|
86
|
-
**kwargs,
|
87
|
-
):
|
88
|
-
# === Layers ===
|
89
|
-
self.backbone = backbone
|
90
|
-
self.output_dense = keras.layers.Dense(
|
91
|
-
num_classes,
|
92
|
-
activation=activation,
|
93
|
-
name="predictions",
|
94
|
-
)
|
95
|
-
|
96
|
-
# === Functional Model ===
|
97
|
-
inputs = self.backbone.input
|
98
|
-
x = self.backbone(inputs)
|
99
|
-
outputs = self.output_dense(x)
|
100
|
-
super().__init__(
|
101
|
-
inputs=inputs,
|
102
|
-
outputs=outputs,
|
103
|
-
**kwargs,
|
104
|
-
)
|
105
|
-
|
106
|
-
# === Config ===
|
107
|
-
self.num_classes = num_classes
|
108
|
-
self.activation = activation
|
109
|
-
|
110
|
-
def get_config(self):
|
111
|
-
# Backbone serialized in `super`
|
112
|
-
config = super().get_config()
|
113
|
-
config.update(
|
114
|
-
{
|
115
|
-
"num_classes": self.num_classes,
|
116
|
-
"activation": self.activation,
|
117
|
-
}
|
118
|
-
)
|
119
|
-
return config
|
@@ -0,0 +1,7 @@
|
|
1
|
+
from keras_hub.src.models.deeplab_v3.deeplab_v3_backbone import (
|
2
|
+
DeepLabV3Backbone,
|
3
|
+
)
|
4
|
+
from keras_hub.src.models.deeplab_v3.deeplab_v3_presets import backbone_presets
|
5
|
+
from keras_hub.src.utils.preset_utils import register_presets
|
6
|
+
|
7
|
+
register_presets(backbone_presets, DeepLabV3Backbone)
|
@@ -0,0 +1,196 @@
|
|
1
|
+
import keras
|
2
|
+
|
3
|
+
from keras_hub.src.api_export import keras_hub_export
|
4
|
+
from keras_hub.src.models.backbone import Backbone
|
5
|
+
from keras_hub.src.models.deeplab_v3.deeplab_v3_layers import (
|
6
|
+
SpatialPyramidPooling,
|
7
|
+
)
|
8
|
+
|
9
|
+
|
10
|
+
@keras_hub_export("keras_hub.models.DeepLabV3Backbone")
|
11
|
+
class DeepLabV3Backbone(Backbone):
|
12
|
+
"""DeepLabV3 & DeepLabV3Plus architecture for semantic segmentation.
|
13
|
+
|
14
|
+
This class implements a DeepLabV3 & DeepLabV3Plus architecture as described
|
15
|
+
in [Encoder-Decoder with Atrous Separable Convolution for Semantic Image Segmentation](
|
16
|
+
https://arxiv.org/abs/1802.02611)(ECCV 2018)
|
17
|
+
and [Rethinking Atrous Convolution for Semantic Image Segmentation](
|
18
|
+
https://arxiv.org/abs/1706.05587)(CVPR 2017)
|
19
|
+
|
20
|
+
Args:
|
21
|
+
image_encoder: `keras.Model`. An instance that is used as a feature
|
22
|
+
extractor for the Encoder. Should either be a
|
23
|
+
`keras_hub.models.Backbone` or a `keras.Model` that implements the
|
24
|
+
`pyramid_outputs` property with keys "P2", "P3" etc as values.
|
25
|
+
A somewhat sensible backbone to use in many cases is
|
26
|
+
the `keras_hub.models.ResNetBackbone.from_preset("resnet_v2_50")`.
|
27
|
+
projection_filters: int. Number of filters in the convolution layer
|
28
|
+
projecting low-level features from the `image_encoder`.
|
29
|
+
spatial_pyramid_pooling_key: str. A layer level to extract and perform
|
30
|
+
`spatial_pyramid_pooling`, one of the key from the `image_encoder`
|
31
|
+
`pyramid_outputs` property such as "P4", "P5" etc.
|
32
|
+
upsampling_size: int or tuple of 2 integers. The upsampling factors for
|
33
|
+
rows and columns of `spatial_pyramid_pooling` layer.
|
34
|
+
If `low_level_feature_key` is given then `spatial_pyramid_pooling`s
|
35
|
+
layer resolution should match with the `low_level_feature`s layer
|
36
|
+
resolution to concatenate both the layers for combined encoder
|
37
|
+
outputs.
|
38
|
+
dilation_rates: list. A `list` of integers for parallel dilated conv applied to
|
39
|
+
`SpatialPyramidPooling`. Usually a
|
40
|
+
sample choice of rates are `[6, 12, 18]`.
|
41
|
+
low_level_feature_key: str optional. A layer level to extract the feature
|
42
|
+
from one of the key from the `image_encoder`s `pyramid_outputs`
|
43
|
+
property such as "P2", "P3" etc which will be the Decoder block.
|
44
|
+
Required only when the DeepLabV3Plus architecture needs to be applied.
|
45
|
+
image_shape: tuple. The input shape without the batch size.
|
46
|
+
Defaults to `(None, None, 3)`.
|
47
|
+
|
48
|
+
Example:
|
49
|
+
```python
|
50
|
+
# Load a trained backbone to extract features from it's `pyramid_outputs`.
|
51
|
+
image_encoder = keras_hub.models.ResNetBackbone.from_preset("resnet_50_imagenet")
|
52
|
+
|
53
|
+
model = keras_hub.models.DeepLabV3Backbone(
|
54
|
+
image_encoder=image_encoder,
|
55
|
+
projection_filters=48,
|
56
|
+
low_level_feature_key="P2",
|
57
|
+
spatial_pyramid_pooling_key="P5",
|
58
|
+
upsampling_size = 8,
|
59
|
+
dilation_rates = [6, 12, 18]
|
60
|
+
)
|
61
|
+
```
|
62
|
+
"""
|
63
|
+
|
64
|
+
def __init__(
|
65
|
+
self,
|
66
|
+
image_encoder,
|
67
|
+
spatial_pyramid_pooling_key,
|
68
|
+
upsampling_size,
|
69
|
+
dilation_rates,
|
70
|
+
low_level_feature_key=None,
|
71
|
+
projection_filters=48,
|
72
|
+
image_shape=(None, None, 3),
|
73
|
+
**kwargs,
|
74
|
+
):
|
75
|
+
if not isinstance(image_encoder, keras.Model):
|
76
|
+
raise ValueError(
|
77
|
+
"Argument `image_encoder` must be a `keras.Model` instance. Received instead "
|
78
|
+
f"{image_encoder} (of type {type(image_encoder)})."
|
79
|
+
)
|
80
|
+
data_format = keras.config.image_data_format()
|
81
|
+
channel_axis = -1 if data_format == "channels_last" else 1
|
82
|
+
|
83
|
+
# === Layers ===
|
84
|
+
inputs = keras.layers.Input(image_shape, name="inputs")
|
85
|
+
|
86
|
+
fpn_model = keras.Model(
|
87
|
+
image_encoder.inputs, image_encoder.pyramid_outputs
|
88
|
+
)
|
89
|
+
|
90
|
+
fpn_outputs = fpn_model(inputs)
|
91
|
+
|
92
|
+
spatial_pyramid_pooling = SpatialPyramidPooling(
|
93
|
+
dilation_rates=dilation_rates
|
94
|
+
)
|
95
|
+
spatial_backbone_features = fpn_outputs[spatial_pyramid_pooling_key]
|
96
|
+
spp_outputs = spatial_pyramid_pooling(spatial_backbone_features)
|
97
|
+
|
98
|
+
encoder_outputs = keras.layers.UpSampling2D(
|
99
|
+
size=upsampling_size,
|
100
|
+
interpolation="bilinear",
|
101
|
+
name="encoder_output_upsampling",
|
102
|
+
data_format=data_format,
|
103
|
+
)(spp_outputs)
|
104
|
+
|
105
|
+
if low_level_feature_key:
|
106
|
+
decoder_feature = fpn_outputs[low_level_feature_key]
|
107
|
+
low_level_projected_features = apply_low_level_feature_network(
|
108
|
+
decoder_feature, projection_filters, channel_axis
|
109
|
+
)
|
110
|
+
|
111
|
+
encoder_outputs = keras.layers.Concatenate(
|
112
|
+
axis=channel_axis, name="encoder_decoder_concat"
|
113
|
+
)([encoder_outputs, low_level_projected_features])
|
114
|
+
# upsampling to the original image size
|
115
|
+
upsampling = (2 ** int(spatial_pyramid_pooling_key[-1])) // (
|
116
|
+
int(upsampling_size[0])
|
117
|
+
if isinstance(upsampling_size, tuple)
|
118
|
+
else upsampling_size
|
119
|
+
)
|
120
|
+
# === Functional Model ===
|
121
|
+
x = keras.layers.Conv2D(
|
122
|
+
name="segmentation_head_conv",
|
123
|
+
filters=256,
|
124
|
+
kernel_size=1,
|
125
|
+
padding="same",
|
126
|
+
use_bias=False,
|
127
|
+
data_format=data_format,
|
128
|
+
)(encoder_outputs)
|
129
|
+
x = keras.layers.BatchNormalization(
|
130
|
+
name="segmentation_head_norm", axis=channel_axis
|
131
|
+
)(x)
|
132
|
+
x = keras.layers.ReLU(name="segmentation_head_relu")(x)
|
133
|
+
x = keras.layers.UpSampling2D(
|
134
|
+
size=upsampling,
|
135
|
+
interpolation="bilinear",
|
136
|
+
data_format=data_format,
|
137
|
+
name="backbone_output_upsampling",
|
138
|
+
)(x)
|
139
|
+
|
140
|
+
super().__init__(inputs=inputs, outputs=x, **kwargs)
|
141
|
+
|
142
|
+
# === Config ===
|
143
|
+
self.image_shape = image_shape
|
144
|
+
self.image_encoder = image_encoder
|
145
|
+
self.projection_filters = projection_filters
|
146
|
+
self.upsampling_size = upsampling_size
|
147
|
+
self.dilation_rates = dilation_rates
|
148
|
+
self.low_level_feature_key = low_level_feature_key
|
149
|
+
self.spatial_pyramid_pooling_key = spatial_pyramid_pooling_key
|
150
|
+
|
151
|
+
def get_config(self):
|
152
|
+
config = super().get_config()
|
153
|
+
config.update(
|
154
|
+
{
|
155
|
+
"image_encoder": keras.saving.serialize_keras_object(
|
156
|
+
self.image_encoder
|
157
|
+
),
|
158
|
+
"projection_filters": self.projection_filters,
|
159
|
+
"dilation_rates": self.dilation_rates,
|
160
|
+
"upsampling_size": self.upsampling_size,
|
161
|
+
"low_level_feature_key": self.low_level_feature_key,
|
162
|
+
"spatial_pyramid_pooling_key": self.spatial_pyramid_pooling_key,
|
163
|
+
"image_shape": self.image_shape,
|
164
|
+
}
|
165
|
+
)
|
166
|
+
return config
|
167
|
+
|
168
|
+
@classmethod
|
169
|
+
def from_config(cls, config):
|
170
|
+
if "image_encoder" in config and isinstance(
|
171
|
+
config["image_encoder"], dict
|
172
|
+
):
|
173
|
+
config["image_encoder"] = keras.layers.deserialize(
|
174
|
+
config["image_encoder"]
|
175
|
+
)
|
176
|
+
return super().from_config(config)
|
177
|
+
|
178
|
+
|
179
|
+
def apply_low_level_feature_network(
|
180
|
+
input_tensor, projection_filters, channel_axis
|
181
|
+
):
|
182
|
+
data_format = keras.config.image_data_format()
|
183
|
+
x = keras.layers.Conv2D(
|
184
|
+
name="decoder_conv",
|
185
|
+
filters=projection_filters,
|
186
|
+
kernel_size=1,
|
187
|
+
padding="same",
|
188
|
+
use_bias=False,
|
189
|
+
data_format=data_format,
|
190
|
+
)(input_tensor)
|
191
|
+
|
192
|
+
x = keras.layers.BatchNormalization(name="decoder_norm", axis=channel_axis)(
|
193
|
+
x
|
194
|
+
)
|
195
|
+
x = keras.layers.ReLU(name="decoder_relu")(x)
|
196
|
+
return x
|
@@ -0,0 +1,10 @@
|
|
1
|
+
from keras_hub.src.api_export import keras_hub_export
|
2
|
+
from keras_hub.src.layers.preprocessing.image_converter import ImageConverter
|
3
|
+
from keras_hub.src.models.deeplab_v3.deeplab_v3_backbone import (
|
4
|
+
DeepLabV3Backbone,
|
5
|
+
)
|
6
|
+
|
7
|
+
|
8
|
+
@keras_hub_export("keras_hub.layers.DeepLabV3ImageConverter")
|
9
|
+
class DeepLabV3ImageConverter(ImageConverter):
|
10
|
+
backbone_cls = DeepLabV3Backbone
|