keras-hub-nightly 0.22.0.dev202507100418__py3-none-any.whl → 0.22.0.dev202507120419__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/layers/__init__.py +3 -0
- keras_hub/models/__init__.py +12 -0
- keras_hub/src/models/gemma/gemma_attention.py +1 -1
- keras_hub/src/models/hgnetv2/__init__.py +0 -0
- keras_hub/src/models/hgnetv2/hgnetv2_backbone.py +193 -0
- keras_hub/src/models/hgnetv2/hgnetv2_encoder.py +148 -0
- keras_hub/src/models/hgnetv2/hgnetv2_image_classifier.py +216 -0
- keras_hub/src/models/hgnetv2/hgnetv2_image_classifier_preprocessor.py +14 -0
- keras_hub/src/models/hgnetv2/hgnetv2_image_converter.py +8 -0
- keras_hub/src/models/hgnetv2/hgnetv2_layers.py +918 -0
- keras_hub/src/models/hgnetv2/hgnetv2_presets.py +58 -0
- keras_hub/src/models/qwen3/__init__.py +5 -0
- keras_hub/src/models/qwen3/qwen3_attention.py +1 -1
- keras_hub/src/models/qwen3/qwen3_causal_lm.py +390 -0
- keras_hub/src/models/qwen3/qwen3_presets.py +73 -0
- keras_hub/src/models/qwen_moe/qwen_moe_attention.py +1 -0
- keras_hub/src/utils/keras_utils.py +17 -0
- keras_hub/src/version.py +1 -1
- {keras_hub_nightly-0.22.0.dev202507100418.dist-info → keras_hub_nightly-0.22.0.dev202507120419.dist-info}/METADATA +1 -1
- {keras_hub_nightly-0.22.0.dev202507100418.dist-info → keras_hub_nightly-0.22.0.dev202507120419.dist-info}/RECORD +22 -11
- {keras_hub_nightly-0.22.0.dev202507100418.dist-info → keras_hub_nightly-0.22.0.dev202507120419.dist-info}/WHEEL +0 -0
- {keras_hub_nightly-0.22.0.dev202507100418.dist-info → keras_hub_nightly-0.22.0.dev202507120419.dist-info}/top_level.txt +0 -0
keras_hub/layers/__init__.py
CHANGED
@@ -90,6 +90,9 @@ from keras_hub.src.models.efficientnet.efficientnet_image_converter import (
|
|
90
90
|
from keras_hub.src.models.gemma3.gemma3_image_converter import (
|
91
91
|
Gemma3ImageConverter as Gemma3ImageConverter,
|
92
92
|
)
|
93
|
+
from keras_hub.src.models.hgnetv2.hgnetv2_image_converter import (
|
94
|
+
HGNetV2ImageConverter as HGNetV2ImageConverter,
|
95
|
+
)
|
93
96
|
from keras_hub.src.models.mit.mit_image_converter import (
|
94
97
|
MiTImageConverter as MiTImageConverter,
|
95
98
|
)
|
keras_hub/models/__init__.py
CHANGED
@@ -294,6 +294,15 @@ from keras_hub.src.models.gpt_neo_x.gpt_neo_x_causal_lm_preprocessor import (
|
|
294
294
|
from keras_hub.src.models.gpt_neo_x.gpt_neo_x_tokenizer import (
|
295
295
|
GPTNeoXTokenizer as GPTNeoXTokenizer,
|
296
296
|
)
|
297
|
+
from keras_hub.src.models.hgnetv2.hgnetv2_backbone import (
|
298
|
+
HGNetV2Backbone as HGNetV2Backbone,
|
299
|
+
)
|
300
|
+
from keras_hub.src.models.hgnetv2.hgnetv2_image_classifier import (
|
301
|
+
HGNetV2ImageClassifier as HGNetV2ImageClassifier,
|
302
|
+
)
|
303
|
+
from keras_hub.src.models.hgnetv2.hgnetv2_image_classifier_preprocessor import (
|
304
|
+
HGNetV2ImageClassifierPreprocessor as HGNetV2ImageClassifierPreprocessor,
|
305
|
+
)
|
297
306
|
from keras_hub.src.models.image_classifier import (
|
298
307
|
ImageClassifier as ImageClassifier,
|
299
308
|
)
|
@@ -454,6 +463,9 @@ from keras_hub.src.models.qwen.qwen_tokenizer import (
|
|
454
463
|
from keras_hub.src.models.qwen3.qwen3_backbone import (
|
455
464
|
Qwen3Backbone as Qwen3Backbone,
|
456
465
|
)
|
466
|
+
from keras_hub.src.models.qwen3.qwen3_causal_lm import (
|
467
|
+
Qwen3CausalLM as Qwen3CausalLM,
|
468
|
+
)
|
457
469
|
from keras_hub.src.models.qwen3.qwen3_causal_lm_preprocessor import (
|
458
470
|
Qwen3CausalLMPreprocessor as Qwen3CausalLMPreprocessor,
|
459
471
|
)
|
@@ -152,7 +152,7 @@ class CachedGemmaAttention(keras.layers.Layer):
|
|
152
152
|
attention_mask = ops.expand_dims(attention_mask, axis=1)
|
153
153
|
attention_mask = ops.cast(attention_mask, dtype="bool")
|
154
154
|
# Only pass soft cap if needed as not all keras versions support.
|
155
|
-
if self.logit_soft_cap:
|
155
|
+
if self.logit_soft_cap is not None:
|
156
156
|
kwargs = {"attn_logits_soft_cap": self.logit_soft_cap}
|
157
157
|
else:
|
158
158
|
kwargs = {}
|
File without changes
|
@@ -0,0 +1,193 @@
|
|
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.hgnetv2.hgnetv2_encoder import HGNetV2Encoder
|
6
|
+
from keras_hub.src.models.hgnetv2.hgnetv2_layers import HGNetV2Embeddings
|
7
|
+
from keras_hub.src.utils.keras_utils import standardize_data_format
|
8
|
+
|
9
|
+
|
10
|
+
@keras_hub_export("keras_hub.models.HGNetV2Backbone")
|
11
|
+
class HGNetV2Backbone(Backbone):
|
12
|
+
"""This class represents a Keras Backbone of the HGNetV2 model.
|
13
|
+
|
14
|
+
This class implements an HGNetV2 backbone architecture, a convolutional
|
15
|
+
neural network (CNN) optimized for GPU efficiency. HGNetV2 is frequently
|
16
|
+
used as a lightweight CNN backbone in object detection pipelines like
|
17
|
+
RT-DETR and YOLO variants, delivering strong performance on classification
|
18
|
+
and detection tasks, with speed-ups and accuracy gains compared to larger
|
19
|
+
CNN backbones.
|
20
|
+
|
21
|
+
Args:
|
22
|
+
depths: list of ints, the number of blocks in each stage.
|
23
|
+
embedding_size: int, the size of the embedding layer.
|
24
|
+
hidden_sizes: list of ints, the sizes of the hidden layers.
|
25
|
+
stem_channels: list of ints, the channels for the stem part.
|
26
|
+
hidden_act: str, the activation function for hidden layers.
|
27
|
+
use_learnable_affine_block: bool, whether to use learnable affine
|
28
|
+
transformations.
|
29
|
+
stackwise_stage_filters: list of tuples, where each tuple contains
|
30
|
+
configuration for a stage: (stage_in_channels, stage_mid_channels,
|
31
|
+
stage_out_channels, stage_num_blocks, stage_num_of_layers,
|
32
|
+
stage_kernel_size).
|
33
|
+
- stage_in_channels: int, input channels for the stage
|
34
|
+
- stage_mid_channels: int, middle channels for the stage
|
35
|
+
- stage_out_channels: int, output channels for the stage
|
36
|
+
- stage_num_blocks: int, number of blocks in the stage
|
37
|
+
- stage_num_of_layers: int, number of layers in each block
|
38
|
+
- stage_kernel_size: int, kernel size for the stage
|
39
|
+
apply_downsample: list of bools, whether to downsample in each stage.
|
40
|
+
use_lightweight_conv_block: list of bools, whether to use HGNetV2
|
41
|
+
lightweight convolutional blocks in each stage.
|
42
|
+
image_shape: tuple, the shape of the input image without the batch size.
|
43
|
+
Defaults to `(None, None, 3)`.
|
44
|
+
data_format: `None` or str, the data format ('channels_last' or
|
45
|
+
'channels_first'). If not specified, defaults to the
|
46
|
+
`image_data_format` value in your Keras config.
|
47
|
+
out_features: list of str or `None`, the names of the output features to
|
48
|
+
return. If `None`, returns all available features from all stages.
|
49
|
+
Defaults to `None`.
|
50
|
+
dtype: `None` or str or `keras.mixed_precision.DTypePolicy`, the data
|
51
|
+
type for computations and weights.
|
52
|
+
|
53
|
+
Examples:
|
54
|
+
```python
|
55
|
+
import numpy as np
|
56
|
+
from keras_hub.src.models.hgnetv2.hgnetv2_backbone import HGNetV2Backbone
|
57
|
+
input_data = np.ones(shape=(8, 224, 224, 3))
|
58
|
+
|
59
|
+
# Pretrained backbone.
|
60
|
+
model = keras_hub.models.HGNetV2Backbone.from_preset(
|
61
|
+
"hgnetv2_b5_ssld_stage2_ft_in1k"
|
62
|
+
)
|
63
|
+
model(input_data)
|
64
|
+
|
65
|
+
# Randomly initialized backbone with a custom config.
|
66
|
+
model = HGNetV2Backbone(
|
67
|
+
depths=[1, 2, 4],
|
68
|
+
embedding_size=32,
|
69
|
+
hidden_sizes=[64, 128, 256],
|
70
|
+
stem_channels=[3, 16, 32],
|
71
|
+
hidden_act="relu",
|
72
|
+
use_learnable_affine_block=False,
|
73
|
+
stackwise_stage_filters=[
|
74
|
+
(32, 16, 64, 1, 1, 3), # Stage 0
|
75
|
+
(64, 32, 128, 2, 1, 3), # Stage 1
|
76
|
+
(128, 64, 256, 4, 1, 3), # Stage 2
|
77
|
+
],
|
78
|
+
apply_downsample=[False, True, True],
|
79
|
+
use_lightweight_conv_block=[False, False, False],
|
80
|
+
image_shape=(224, 224, 3),
|
81
|
+
)
|
82
|
+
model(input_data)
|
83
|
+
```
|
84
|
+
"""
|
85
|
+
|
86
|
+
def __init__(
|
87
|
+
self,
|
88
|
+
depths,
|
89
|
+
embedding_size,
|
90
|
+
hidden_sizes,
|
91
|
+
stem_channels,
|
92
|
+
hidden_act,
|
93
|
+
use_learnable_affine_block,
|
94
|
+
stackwise_stage_filters,
|
95
|
+
apply_downsample,
|
96
|
+
use_lightweight_conv_block,
|
97
|
+
image_shape=(None, None, 3),
|
98
|
+
data_format=None,
|
99
|
+
out_features=None,
|
100
|
+
dtype=None,
|
101
|
+
**kwargs,
|
102
|
+
):
|
103
|
+
name = kwargs.get("name", None)
|
104
|
+
data_format = standardize_data_format(data_format)
|
105
|
+
channel_axis = -1 if data_format == "channels_last" else 1
|
106
|
+
self.image_shape = image_shape
|
107
|
+
(
|
108
|
+
stage_in_channels,
|
109
|
+
stage_mid_channels,
|
110
|
+
stage_out_filters,
|
111
|
+
stage_num_blocks,
|
112
|
+
stage_num_of_layers,
|
113
|
+
stage_kernel_size,
|
114
|
+
) = zip(*stackwise_stage_filters)
|
115
|
+
|
116
|
+
# === Layers ===
|
117
|
+
self.embedder_layer = HGNetV2Embeddings(
|
118
|
+
stem_channels=stem_channels,
|
119
|
+
hidden_act=hidden_act,
|
120
|
+
use_learnable_affine_block=use_learnable_affine_block,
|
121
|
+
data_format=data_format,
|
122
|
+
channel_axis=channel_axis,
|
123
|
+
name=f"{name}_embedder" if name else "embedder",
|
124
|
+
dtype=dtype,
|
125
|
+
)
|
126
|
+
self.encoder_layer = HGNetV2Encoder(
|
127
|
+
stage_in_channels=stage_in_channels,
|
128
|
+
stage_mid_channels=stage_mid_channels,
|
129
|
+
stage_out_channels=stage_out_filters,
|
130
|
+
stage_num_blocks=stage_num_blocks,
|
131
|
+
stage_num_of_layers=stage_num_of_layers,
|
132
|
+
apply_downsample=apply_downsample,
|
133
|
+
use_lightweight_conv_block=use_lightweight_conv_block,
|
134
|
+
stage_kernel_size=stage_kernel_size,
|
135
|
+
use_learnable_affine_block=use_learnable_affine_block,
|
136
|
+
data_format=data_format,
|
137
|
+
channel_axis=channel_axis,
|
138
|
+
name=f"{name}_encoder" if name else "encoder",
|
139
|
+
dtype=dtype,
|
140
|
+
)
|
141
|
+
self.stage_names = ["stem"] + [
|
142
|
+
f"stage{i + 1}" for i in range(len(stackwise_stage_filters))
|
143
|
+
]
|
144
|
+
self.out_features = (
|
145
|
+
out_features if out_features is not None else self.stage_names
|
146
|
+
)
|
147
|
+
|
148
|
+
# === Functional Model ===
|
149
|
+
pixel_values = keras.layers.Input(
|
150
|
+
shape=image_shape, name="pixel_values_input"
|
151
|
+
)
|
152
|
+
embedding_output = self.embedder_layer(pixel_values)
|
153
|
+
all_encoder_hidden_states_tuple = self.encoder_layer(embedding_output)
|
154
|
+
feature_maps_output = {
|
155
|
+
stage_name: all_encoder_hidden_states_tuple[idx]
|
156
|
+
for idx, stage_name in enumerate(self.stage_names)
|
157
|
+
if stage_name in self.out_features
|
158
|
+
}
|
159
|
+
super().__init__(
|
160
|
+
inputs=pixel_values, outputs=feature_maps_output, **kwargs
|
161
|
+
)
|
162
|
+
|
163
|
+
# === Config ===
|
164
|
+
self.depths = depths
|
165
|
+
self.embedding_size = embedding_size
|
166
|
+
self.hidden_sizes = hidden_sizes
|
167
|
+
self.stem_channels = stem_channels
|
168
|
+
self.hidden_act = hidden_act
|
169
|
+
self.use_learnable_affine_block = use_learnable_affine_block
|
170
|
+
self.stackwise_stage_filters = stackwise_stage_filters
|
171
|
+
self.apply_downsample = apply_downsample
|
172
|
+
self.use_lightweight_conv_block = use_lightweight_conv_block
|
173
|
+
self.data_format = data_format
|
174
|
+
|
175
|
+
def get_config(self):
|
176
|
+
config = super().get_config()
|
177
|
+
config.update(
|
178
|
+
{
|
179
|
+
"depths": self.depths,
|
180
|
+
"embedding_size": self.embedding_size,
|
181
|
+
"hidden_sizes": self.hidden_sizes,
|
182
|
+
"stem_channels": self.stem_channels,
|
183
|
+
"hidden_act": self.hidden_act,
|
184
|
+
"use_learnable_affine_block": self.use_learnable_affine_block,
|
185
|
+
"stackwise_stage_filters": self.stackwise_stage_filters,
|
186
|
+
"apply_downsample": self.apply_downsample,
|
187
|
+
"use_lightweight_conv_block": self.use_lightweight_conv_block,
|
188
|
+
"image_shape": self.image_shape,
|
189
|
+
"out_features": self.out_features,
|
190
|
+
"data_format": self.data_format,
|
191
|
+
}
|
192
|
+
)
|
193
|
+
return config
|
@@ -0,0 +1,148 @@
|
|
1
|
+
import keras
|
2
|
+
|
3
|
+
from keras_hub.src.models.hgnetv2.hgnetv2_layers import HGNetV2Stage
|
4
|
+
|
5
|
+
|
6
|
+
@keras.saving.register_keras_serializable(package="keras_hub")
|
7
|
+
class HGNetV2Encoder(keras.layers.Layer):
|
8
|
+
"""This class represents the encoder of the HGNetV2 model.
|
9
|
+
|
10
|
+
This class implements the encoder part of the HGNetV2 architecture, which
|
11
|
+
consists of multiple stages. Each stage is an instance of `HGNetV2Stage`,
|
12
|
+
and the encoder processes the input through these stages sequentially,
|
13
|
+
collecting the hidden states at each stage.
|
14
|
+
|
15
|
+
Args:
|
16
|
+
stage_in_channels: A list of integers, specifying the input channels
|
17
|
+
for each stage.
|
18
|
+
stage_mid_channels: A list of integers, specifying the mid channels for
|
19
|
+
each stage.
|
20
|
+
stage_out_channels: A list of integers, specifying the output channels
|
21
|
+
for each stage.
|
22
|
+
stage_num_blocks: A list of integers, specifying the number of blocks
|
23
|
+
in each stage.
|
24
|
+
stage_num_of_layers: A list of integers, specifying the number of
|
25
|
+
layers in each block of each stage.
|
26
|
+
apply_downsample: A list of booleans or integers, indicating whether to
|
27
|
+
downsample in each stage.
|
28
|
+
use_lightweight_conv_block: A list of booleans, indicating whether to
|
29
|
+
use HGNetV2 lightweight convolutional blocks in each stage.
|
30
|
+
stage_kernel_size: A list of integers or tuples, specifying the kernel
|
31
|
+
size for each stage.
|
32
|
+
use_learnable_affine_block: A boolean, indicating whether to use
|
33
|
+
learnable affine transformations in the blocks.
|
34
|
+
data_format: `None` or str. If specified, either `"channels_last"` or
|
35
|
+
`"channels_first"`. The ordering of the dimensions in the inputs.
|
36
|
+
`"channels_last"` corresponds to inputs with shape
|
37
|
+
`(batch_size, height, width, channels)` while `"channels_first"`
|
38
|
+
corresponds to inputs with shape `(batch_size, channels, height,
|
39
|
+
width)`. It defaults to the `image_data_format` value found in your
|
40
|
+
Keras config file at `~/.keras/keras.json`. If you never set it,
|
41
|
+
then it will be `"channels_last"`.
|
42
|
+
channel_axis: int, the axis that represents the channels.
|
43
|
+
**kwargs: Additional keyword arguments passed to the parent class.
|
44
|
+
"""
|
45
|
+
|
46
|
+
def __init__(
|
47
|
+
self,
|
48
|
+
stage_in_channels,
|
49
|
+
stage_mid_channels,
|
50
|
+
stage_out_channels,
|
51
|
+
stage_num_blocks,
|
52
|
+
stage_num_of_layers,
|
53
|
+
apply_downsample,
|
54
|
+
use_lightweight_conv_block,
|
55
|
+
stage_kernel_size,
|
56
|
+
use_learnable_affine_block,
|
57
|
+
data_format=None,
|
58
|
+
channel_axis=None,
|
59
|
+
**kwargs,
|
60
|
+
):
|
61
|
+
super().__init__(**kwargs)
|
62
|
+
self.stage_in_channels = stage_in_channels
|
63
|
+
self.stage_mid_channels = stage_mid_channels
|
64
|
+
self.stage_out_channels = stage_out_channels
|
65
|
+
self.stage_num_blocks = stage_num_blocks
|
66
|
+
self.stage_num_of_layers = stage_num_of_layers
|
67
|
+
self.apply_downsample = apply_downsample
|
68
|
+
self.use_lightweight_conv_block = use_lightweight_conv_block
|
69
|
+
self.stage_kernel_size = stage_kernel_size
|
70
|
+
self.use_learnable_affine_block = use_learnable_affine_block
|
71
|
+
self.data_format = data_format
|
72
|
+
self.channel_axis = channel_axis
|
73
|
+
|
74
|
+
self.stages_list = []
|
75
|
+
for stage_idx in range(len(self.stage_in_channels)):
|
76
|
+
stage_layer = HGNetV2Stage(
|
77
|
+
stage_in_channels=self.stage_in_channels,
|
78
|
+
stage_mid_channels=self.stage_mid_channels,
|
79
|
+
stage_out_channels=self.stage_out_channels,
|
80
|
+
stage_num_blocks=self.stage_num_blocks,
|
81
|
+
stage_num_of_layers=self.stage_num_of_layers,
|
82
|
+
apply_downsample=self.apply_downsample,
|
83
|
+
use_lightweight_conv_block=self.use_lightweight_conv_block,
|
84
|
+
stage_kernel_size=self.stage_kernel_size,
|
85
|
+
use_learnable_affine_block=self.use_learnable_affine_block,
|
86
|
+
stage_index=stage_idx,
|
87
|
+
data_format=self.data_format,
|
88
|
+
channel_axis=self.channel_axis,
|
89
|
+
drop_path=0.0,
|
90
|
+
name=f"{self.name}_stage_{stage_idx}"
|
91
|
+
if self.name
|
92
|
+
else f"stage_{stage_idx}",
|
93
|
+
dtype=self.dtype,
|
94
|
+
)
|
95
|
+
self.stages_list.append(stage_layer)
|
96
|
+
|
97
|
+
def build(self, input_shape):
|
98
|
+
super().build(input_shape)
|
99
|
+
current_input_shape = input_shape
|
100
|
+
for stage_keras_layer in self.stages_list:
|
101
|
+
stage_keras_layer.build(current_input_shape)
|
102
|
+
current_input_shape = stage_keras_layer.compute_output_shape(
|
103
|
+
current_input_shape
|
104
|
+
)
|
105
|
+
|
106
|
+
def call(
|
107
|
+
self,
|
108
|
+
hidden_state,
|
109
|
+
training=None,
|
110
|
+
):
|
111
|
+
all_hidden_states_list = []
|
112
|
+
current_hidden_state = hidden_state
|
113
|
+
for stage_keras_layer in self.stages_list:
|
114
|
+
all_hidden_states_list.append(current_hidden_state)
|
115
|
+
current_hidden_state = stage_keras_layer(
|
116
|
+
current_hidden_state, training=training
|
117
|
+
)
|
118
|
+
all_hidden_states_list.append(current_hidden_state)
|
119
|
+
return tuple(all_hidden_states_list)
|
120
|
+
|
121
|
+
def compute_output_shape(self, input_shape):
|
122
|
+
current_shape = input_shape
|
123
|
+
all_hidden_shapes = [input_shape]
|
124
|
+
for stage_keras_layer in self.stages_list:
|
125
|
+
current_shape = stage_keras_layer.compute_output_shape(
|
126
|
+
current_shape
|
127
|
+
)
|
128
|
+
all_hidden_shapes.append(current_shape)
|
129
|
+
return tuple(all_hidden_shapes)
|
130
|
+
|
131
|
+
def get_config(self):
|
132
|
+
config = super().get_config()
|
133
|
+
config.update(
|
134
|
+
{
|
135
|
+
"stage_in_channels": self.stage_in_channels,
|
136
|
+
"stage_mid_channels": self.stage_mid_channels,
|
137
|
+
"stage_out_channels": self.stage_out_channels,
|
138
|
+
"stage_num_blocks": self.stage_num_blocks,
|
139
|
+
"stage_num_of_layers": self.stage_num_of_layers,
|
140
|
+
"apply_downsample": self.apply_downsample,
|
141
|
+
"use_lightweight_conv_block": self.use_lightweight_conv_block,
|
142
|
+
"stage_kernel_size": self.stage_kernel_size,
|
143
|
+
"use_learnable_affine_block": self.use_learnable_affine_block,
|
144
|
+
"data_format": self.data_format,
|
145
|
+
"channel_axis": self.channel_axis,
|
146
|
+
}
|
147
|
+
)
|
148
|
+
return config
|
@@ -0,0 +1,216 @@
|
|
1
|
+
import keras
|
2
|
+
|
3
|
+
from keras_hub.src.api_export import keras_hub_export
|
4
|
+
from keras_hub.src.models.hgnetv2.hgnetv2_backbone import HGNetV2Backbone
|
5
|
+
from keras_hub.src.models.hgnetv2.hgnetv2_image_classifier_preprocessor import (
|
6
|
+
HGNetV2ImageClassifierPreprocessor,
|
7
|
+
)
|
8
|
+
from keras_hub.src.models.hgnetv2.hgnetv2_layers import HGNetV2ConvLayer
|
9
|
+
from keras_hub.src.models.image_classifier import ImageClassifier
|
10
|
+
from keras_hub.src.models.task import Task
|
11
|
+
|
12
|
+
|
13
|
+
@keras_hub_export("keras_hub.models.HGNetV2ImageClassifier")
|
14
|
+
class HGNetV2ImageClassifier(ImageClassifier):
|
15
|
+
"""HGNetV2 image classification model.
|
16
|
+
|
17
|
+
`HGNetV2ImageClassifier` wraps a `HGNetV2Backbone` and
|
18
|
+
a `HGNetV2ImageClassifierPreprocessor` to create a model that can be used
|
19
|
+
for image classification tasks. This model implements the HGNetV2
|
20
|
+
architecture with an additional classification head including a 1x1
|
21
|
+
convolution layer, global pooling, and a dense output layer.
|
22
|
+
|
23
|
+
The model takes an additional `num_classes` argument, controlling the number
|
24
|
+
of predicted output classes, and optionally, a `head_filters` argument to
|
25
|
+
specify the number of filters in the classification head's convolution
|
26
|
+
layer. To fine-tune with `fit()`, pass a dataset containing tuples of
|
27
|
+
`(x, y)` labels where `x` is an image tensor and `y` is an integer from
|
28
|
+
`[0, num_classes)`.
|
29
|
+
|
30
|
+
Args:
|
31
|
+
backbone: A `HGNetV2Backbone` instance.
|
32
|
+
preprocessor: A `HGNetV2ImageClassifierPreprocessor` instance,
|
33
|
+
a `keras.Layer` instance, or a callable. If `None` no preprocessing
|
34
|
+
will be applied to the inputs.
|
35
|
+
num_classes: int. The number of classes to predict.
|
36
|
+
head_filters: int, optional. The number of filters in the
|
37
|
+
classification head's 1x1 convolution layer. If `None`, it defaults
|
38
|
+
to the last value of `hidden_sizes` from the backbone.
|
39
|
+
pooling: `"avg"` or `"max"`. The type of global pooling to apply after
|
40
|
+
the head convolution. Defaults to `"avg"`.
|
41
|
+
activation: `None`, str, or callable. The activation function to use on
|
42
|
+
the final `Dense` layer. Set `activation=None` to return the output
|
43
|
+
logits. Defaults to `None`.
|
44
|
+
dropout: float. Dropout rate applied before the final dense layer.
|
45
|
+
Defaults to 0.0.
|
46
|
+
head_dtype: `None`, str, or `keras.mixed_precision.DTypePolicy`. The
|
47
|
+
dtype to use for the classification head's computations and weights.
|
48
|
+
|
49
|
+
Examples:
|
50
|
+
|
51
|
+
Call `predict()` to run inference.
|
52
|
+
```python
|
53
|
+
# Load preset and predict.
|
54
|
+
images = np.random.randint(0, 256, size=(2, 224, 224, 3))
|
55
|
+
classifier = keras_hub.models.HGNetV2ImageClassifier.from_preset(
|
56
|
+
"hgnetv2_b5_ssld_stage2_ft_in1k"
|
57
|
+
)
|
58
|
+
classifier.predict(images)
|
59
|
+
```
|
60
|
+
|
61
|
+
Call `fit()` on a single batch.
|
62
|
+
```python
|
63
|
+
# Load preset and train.
|
64
|
+
images = np.random.randint(0, 256, size=(2, 224, 224, 3))
|
65
|
+
labels = [0, 3]
|
66
|
+
classifier = keras_hub.models.HGNetV2ImageClassifier.from_preset(
|
67
|
+
"hgnetv2_b5_ssld_stage2_ft_in1k"
|
68
|
+
)
|
69
|
+
classifier.fit(x=images, y=labels, batch_size=2)
|
70
|
+
```
|
71
|
+
|
72
|
+
Call `fit()` with custom loss, optimizer and frozen backbone.
|
73
|
+
```python
|
74
|
+
classifier = keras_hub.models.HGNetV2ImageClassifier.from_preset(
|
75
|
+
"hgnetv2_b5_ssld_stage2_ft_in1k"
|
76
|
+
)
|
77
|
+
classifier.compile(
|
78
|
+
loss=keras.losses.SparseCategoricalCrossentropy(from_logits=True),
|
79
|
+
optimizer=keras.optimizers.Adam(5e-5),
|
80
|
+
)
|
81
|
+
classifier.backbone.trainable = False
|
82
|
+
classifier.fit(x=images, y=labels, batch_size=2)
|
83
|
+
```
|
84
|
+
|
85
|
+
Create a custom HGNetV2 classifier with specific head configuration.
|
86
|
+
```python
|
87
|
+
backbone = keras_hub.models.HGNetV2Backbone.from_preset(
|
88
|
+
"hgnetv2_b5_ssld_stage2_ft_in1k"
|
89
|
+
)
|
90
|
+
preproc = keras_hub.models.HGNetV2ImageClassifierPreprocessor.from_preset(
|
91
|
+
"hgnetv2_b5_ssld_stage2_ft_in1k"
|
92
|
+
)
|
93
|
+
classifier = keras_hub.models.HGNetV2ImageClassifier(
|
94
|
+
backbone=backbone,
|
95
|
+
preprocessor=preproc,
|
96
|
+
num_classes=10,
|
97
|
+
pooling="avg",
|
98
|
+
dropout=0.2,
|
99
|
+
)
|
100
|
+
```
|
101
|
+
"""
|
102
|
+
|
103
|
+
backbone_cls = HGNetV2Backbone
|
104
|
+
preprocessor_cls = HGNetV2ImageClassifierPreprocessor
|
105
|
+
|
106
|
+
def __init__(
|
107
|
+
self,
|
108
|
+
backbone,
|
109
|
+
preprocessor,
|
110
|
+
num_classes,
|
111
|
+
head_filters=None,
|
112
|
+
pooling="avg",
|
113
|
+
activation=None,
|
114
|
+
dropout=0.0,
|
115
|
+
head_dtype=None,
|
116
|
+
**kwargs,
|
117
|
+
):
|
118
|
+
name = kwargs.get("name", "hgnetv2_image_classifier")
|
119
|
+
head_dtype = head_dtype or backbone.dtype_policy
|
120
|
+
data_format = getattr(backbone, "data_format", "channels_last")
|
121
|
+
channel_axis = -1 if data_format == "channels_last" else 1
|
122
|
+
self.head_filters = (
|
123
|
+
head_filters
|
124
|
+
if head_filters is not None
|
125
|
+
else backbone.hidden_sizes[-1]
|
126
|
+
)
|
127
|
+
self.activation = activation
|
128
|
+
|
129
|
+
# === Layers ===
|
130
|
+
self.backbone = backbone
|
131
|
+
self.preprocessor = preprocessor
|
132
|
+
self.last_conv = HGNetV2ConvLayer(
|
133
|
+
in_channels=backbone.hidden_sizes[-1],
|
134
|
+
out_channels=self.head_filters,
|
135
|
+
kernel_size=1,
|
136
|
+
stride=1,
|
137
|
+
groups=1,
|
138
|
+
activation="relu",
|
139
|
+
use_learnable_affine_block=self.backbone.use_learnable_affine_block,
|
140
|
+
data_format=data_format,
|
141
|
+
channel_axis=channel_axis,
|
142
|
+
name="head_last",
|
143
|
+
dtype=head_dtype,
|
144
|
+
)
|
145
|
+
if pooling == "avg":
|
146
|
+
self.pooler = keras.layers.GlobalAveragePooling2D(
|
147
|
+
data_format=data_format,
|
148
|
+
dtype=head_dtype,
|
149
|
+
name=f"{name}_avg_pool" if name else "avg_pool",
|
150
|
+
)
|
151
|
+
elif pooling == "max":
|
152
|
+
self.pooler = keras.layers.GlobalMaxPooling2D(
|
153
|
+
data_format=data_format,
|
154
|
+
dtype=head_dtype,
|
155
|
+
name=f"{name}_max_pool" if name else "max_pool",
|
156
|
+
)
|
157
|
+
# Check valid pooling.
|
158
|
+
else:
|
159
|
+
raise ValueError(
|
160
|
+
"Unknown `pooling` type. Polling should be either `'avg'` or "
|
161
|
+
f"`'max'`. Received: pooling={pooling}."
|
162
|
+
)
|
163
|
+
|
164
|
+
self.flatten_layer = keras.layers.Flatten(
|
165
|
+
dtype=head_dtype,
|
166
|
+
name=f"{name}_flatten" if name else "flatten",
|
167
|
+
)
|
168
|
+
self.output_dropout = keras.layers.Dropout(
|
169
|
+
rate=dropout,
|
170
|
+
dtype=head_dtype,
|
171
|
+
name=f"{name}_output_dropout" if name else "output_dropout",
|
172
|
+
)
|
173
|
+
if num_classes > 0:
|
174
|
+
self.output_dense = keras.layers.Dense(
|
175
|
+
units=num_classes,
|
176
|
+
activation=activation,
|
177
|
+
dtype=head_dtype,
|
178
|
+
name="predictions",
|
179
|
+
)
|
180
|
+
else:
|
181
|
+
self.output_dense = keras.layers.Identity(name="predictions")
|
182
|
+
|
183
|
+
# === Functional Model ===
|
184
|
+
inputs = backbone.input
|
185
|
+
feature_maps = backbone(inputs)
|
186
|
+
last_stage_name = backbone.stage_names[-1]
|
187
|
+
last_hidden_state_for_pooling = feature_maps[last_stage_name]
|
188
|
+
x = self.last_conv(last_hidden_state_for_pooling)
|
189
|
+
x = self.pooler(x)
|
190
|
+
x = self.flatten_layer(x)
|
191
|
+
x = self.output_dropout(x)
|
192
|
+
outputs = self.output_dense(x)
|
193
|
+
Task.__init__(
|
194
|
+
self,
|
195
|
+
inputs=inputs,
|
196
|
+
outputs=outputs,
|
197
|
+
**kwargs,
|
198
|
+
)
|
199
|
+
|
200
|
+
# === Config ===
|
201
|
+
self.pooling = pooling
|
202
|
+
self.dropout = dropout
|
203
|
+
self.num_classes = num_classes
|
204
|
+
|
205
|
+
def get_config(self):
|
206
|
+
config = Task.get_config(self)
|
207
|
+
config.update(
|
208
|
+
{
|
209
|
+
"num_classes": self.num_classes,
|
210
|
+
"pooling": self.pooling,
|
211
|
+
"activation": self.activation,
|
212
|
+
"dropout": self.dropout,
|
213
|
+
"head_filters": self.head_filters,
|
214
|
+
}
|
215
|
+
)
|
216
|
+
return config
|
@@ -0,0 +1,14 @@
|
|
1
|
+
from keras_hub.src.api_export import keras_hub_export
|
2
|
+
from keras_hub.src.models.hgnetv2.hgnetv2_backbone import HGNetV2Backbone
|
3
|
+
from keras_hub.src.models.hgnetv2.hgnetv2_image_converter import (
|
4
|
+
HGNetV2ImageConverter,
|
5
|
+
)
|
6
|
+
from keras_hub.src.models.image_classifier_preprocessor import (
|
7
|
+
ImageClassifierPreprocessor,
|
8
|
+
)
|
9
|
+
|
10
|
+
|
11
|
+
@keras_hub_export("keras_hub.models.HGNetV2ImageClassifierPreprocessor")
|
12
|
+
class HGNetV2ImageClassifierPreprocessor(ImageClassifierPreprocessor):
|
13
|
+
backbone_cls = HGNetV2Backbone
|
14
|
+
image_converter_cls = HGNetV2ImageConverter
|
@@ -0,0 +1,8 @@
|
|
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.hgnetv2.hgnetv2_backbone import HGNetV2Backbone
|
4
|
+
|
5
|
+
|
6
|
+
@keras_hub_export("keras_hub.layers.HGNetV2ImageConverter")
|
7
|
+
class HGNetV2ImageConverter(ImageConverter):
|
8
|
+
backbone_cls = HGNetV2Backbone
|