segmodels-keras 0.1.0.dev6__tar.gz → 0.1.0.dev7__tar.gz

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 (39) hide show
  1. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/PKG-INFO +1 -1
  2. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/__init__.py +4 -4
  3. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/_version.py +1 -1
  4. segmodels_keras-0.1.0.dev7/segmodels_keras/backbones/_common_blocks.py +131 -0
  5. segmodels_keras-0.1.0.dev7/segmodels_keras/backbones/_weights.py +363 -0
  6. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/backbones/backbones_factory.py +26 -21
  7. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/backbones/inception_v3.py +1 -0
  8. segmodels_keras-0.1.0.dev7/segmodels_keras/backbones/resnet.py +494 -0
  9. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/base/functional.py +3 -3
  10. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras.egg-info/PKG-INFO +1 -1
  11. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras.egg-info/SOURCES.txt +3 -0
  12. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/tests/test_models.py +8 -8
  13. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/LICENSE +0 -0
  14. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/MANIFEST.in +0 -0
  15. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/README.rst +0 -0
  16. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/pyproject.toml +0 -0
  17. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/_compat.py +0 -0
  18. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/backbones/__init__.py +0 -0
  19. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/backbones/inception_resnet_v2.py +0 -0
  20. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/base/__init__.py +0 -0
  21. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/base/objects.py +0 -0
  22. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/losses.py +0 -0
  23. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/metrics.py +0 -0
  24. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/models/__init__.py +0 -0
  25. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/models/_common_blocks.py +0 -0
  26. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/models/_utils.py +0 -0
  27. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/models/fpn.py +0 -0
  28. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/models/linknet.py +0 -0
  29. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/models/pspnet.py +0 -0
  30. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/models/unet.py +0 -0
  31. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras/utils.py +0 -0
  32. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras.egg-info/dependency_links.txt +0 -0
  33. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras.egg-info/requires.txt +0 -0
  34. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/segmodels_keras.egg-info/top_level.txt +0 -0
  35. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/setup.cfg +0 -0
  36. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/setup.py +0 -0
  37. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/tests/test_backbones.py +0 -0
  38. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/tests/test_metrics.py +0 -0
  39. {segmodels_keras-0.1.0.dev6 → segmodels_keras-0.1.0.dev7}/tests/test_utils.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: segmodels_keras
3
- Version: 0.1.0.dev6
3
+ Version: 0.1.0.dev7
4
4
  Summary: Image segmentation models with pre-trained backbones with Keras.
5
5
  Home-page: https://github.com/orthoseg/segmodels_keras
6
6
  Author: Pieter Roggemans
@@ -59,17 +59,17 @@ def set_framework(name):
59
59
  name = name.lower()
60
60
 
61
61
  if name == _KERAS_FRAMEWORK_NAME:
62
- import keras
62
+ import keras # noqa: PLC0415
63
63
  elif name == _TF_KERAS_FRAMEWORK_NAME:
64
- from tensorflow import keras
64
+ from tensorflow import keras # noqa: PLC0415
65
65
  else:
66
66
  raise ValueError(
67
67
  f"Not correct module name `{name}`, use `{_KERAS_FRAMEWORK_NAME}` or "
68
68
  f"`{_TF_KERAS_FRAMEWORK_NAME}`"
69
69
  )
70
70
 
71
- global _KERAS_BACKEND, _KERAS_LAYERS, _KERAS_MODELS
72
- global _KERAS_UTILS, _KERAS_LOSSES, _KERAS_FRAMEWORK
71
+ global _KERAS_BACKEND, _KERAS_LAYERS, _KERAS_MODELS # noqa: PLW0603
72
+ global _KERAS_UTILS, _KERAS_LOSSES, _KERAS_FRAMEWORK # noqa: PLW0603
73
73
 
74
74
  _KERAS_FRAMEWORK = name
75
75
  _KERAS_BACKEND = keras.backend
@@ -1,2 +1,2 @@
1
- __versioninfo__ = (0, 1, 0, "dev6")
1
+ __versioninfo__ = (0, 1, 0, "dev7")
2
2
  __version__ = ".".join(map(str, __versioninfo__))
@@ -0,0 +1,131 @@
1
+ """Common blocks for backbone models.
2
+
3
+ Source: https://github.com/qubvel/classification_models
4
+ """
5
+
6
+ from keras import backend, layers
7
+
8
+
9
+ def slice_tensor(x, start, stop, axis):
10
+ if axis == 3:
11
+ return x[:, :, :, start:stop]
12
+ elif axis == 1:
13
+ return x[:, start:stop, :, :]
14
+ else:
15
+ raise ValueError(f"Slice axis should be in (1, 3), got {axis}.")
16
+
17
+
18
+ def GroupConv2D(
19
+ filters,
20
+ kernel_size,
21
+ strides=(1, 1),
22
+ groups=32,
23
+ kernel_initializer="he_uniform",
24
+ use_bias=True,
25
+ activation="linear",
26
+ padding="valid",
27
+ **kwargs, # noqa: ARG001
28
+ ):
29
+ """Grouped Convolution Layer implemented as a Slice, Conv2D and Concatenate layers.
30
+
31
+ Split filters to groups, apply Conv2D and concatenate back.
32
+
33
+ Args:
34
+ filters: Integer, the dimensionality of the output space
35
+ (i.e. the number of output filters in the convolution).
36
+ kernel_size: An integer or tuple/list of a single integer,
37
+ specifying the length of the 1D convolution window.
38
+ strides: An integer or tuple/list of a single integer, specifying the stride
39
+ length of the convolution.
40
+ groups: Integer, number of groups to split input filters to.
41
+ kernel_initializer: Regularizer function applied to the kernel weights matrix.
42
+ use_bias: Boolean, whether the layer uses a bias vector.
43
+ activation: Activation function to use (see activations).
44
+ If you don't specify anything, no activation is applied
45
+ (ie. "linear" activation: a(x) = x).
46
+ padding: one of "valid" or "same" (case-insensitive).
47
+
48
+ Input shape:
49
+ 4D tensor with shape: (batch, rows, cols, channels) if data_format is
50
+ "channels_last".
51
+
52
+ Output shape:
53
+ 4D tensor with shape: (batch, new_rows, new_cols, filters) if data_format is
54
+ "channels_last". rows and cols values might have changed due to padding.
55
+
56
+ """
57
+ slice_axis = 3 if backend.image_data_format() == "channels_last" else 1
58
+
59
+ def layer(input_tensor):
60
+ inp_ch = int(
61
+ backend.int_shape(input_tensor)[-1] // groups
62
+ ) # input grouped channels
63
+ out_ch = int(filters // groups) # output grouped channels
64
+
65
+ blocks = []
66
+ for c in range(groups):
67
+ slice_arguments = {
68
+ "start": c * inp_ch,
69
+ "stop": (c + 1) * inp_ch,
70
+ "axis": slice_axis,
71
+ }
72
+ x = layers.Lambda(slice_tensor, arguments=slice_arguments)(input_tensor)
73
+ x = layers.Conv2D(
74
+ out_ch,
75
+ kernel_size,
76
+ strides=strides,
77
+ kernel_initializer=kernel_initializer,
78
+ use_bias=use_bias,
79
+ activation=activation,
80
+ padding=padding,
81
+ )(x)
82
+ blocks.append(x)
83
+
84
+ x = layers.Concatenate(axis=slice_axis)(blocks)
85
+ return x
86
+
87
+ return layer
88
+
89
+
90
+ def expand_dims(x, channels_axis):
91
+ if channels_axis == 3:
92
+ return x[:, None, None, :]
93
+ elif channels_axis == 1:
94
+ return x[:, :, None, None]
95
+ else:
96
+ raise ValueError(f"Slice axis should be in (1, 3), got {channels_axis}.")
97
+
98
+
99
+ def ChannelSE(reduction=16, **kwargs): # noqa: ARG001
100
+ """
101
+ Squeeze and Excitation block, reimplementation inspired by
102
+ https://github.com/Cadene/pretrained-models.pytorch/blob/master/pretrainedmodels/models/senet.py
103
+
104
+ Args:
105
+ reduction: channels squeeze factor
106
+
107
+ """
108
+ channels_axis = 3 if backend.image_data_format() == "channels_last" else 1
109
+
110
+ def layer(input_tensor):
111
+ # get number of channels/filters
112
+ channels = backend.int_shape(input_tensor)[channels_axis]
113
+
114
+ x = input_tensor
115
+
116
+ # squeeze and excitation block in PyTorch style with
117
+ x = layers.GlobalAveragePooling2D()(x)
118
+ x = layers.Lambda(expand_dims, arguments={"channels_axis": channels_axis})(x)
119
+ x = layers.Conv2D(
120
+ channels // reduction, (1, 1), kernel_initializer="he_uniform"
121
+ )(x)
122
+ x = layers.Activation("relu")(x)
123
+ x = layers.Conv2D(channels, (1, 1), kernel_initializer="he_uniform")(x)
124
+ x = layers.Activation("sigmoid")(x)
125
+
126
+ # apply attention
127
+ x = layers.Multiply()([input_tensor, x])
128
+
129
+ return x
130
+
131
+ return layer
@@ -0,0 +1,363 @@
1
+ """Helper to download weights for backbones.
2
+
3
+ Source: https://github.com/qubvel/classification_models
4
+ """
5
+
6
+ from keras.utils import get_file
7
+
8
+ __all__ = ["load_model_weights"]
9
+
10
+
11
+ def _find_weights(model_name, dataset, include_top):
12
+ w = list(filter(lambda x: x["model"] == model_name, WEIGHTS_COLLECTION))
13
+ w = list(filter(lambda x: x["dataset"] == dataset, w))
14
+ w = list(filter(lambda x: x["include_top"] == include_top, w))
15
+ return w
16
+
17
+
18
+ def load_model_weights(model, model_name, dataset, classes, include_top):
19
+
20
+ weights = _find_weights(model_name, dataset, include_top)
21
+
22
+ if weights:
23
+ weights = weights[0]
24
+
25
+ if include_top and weights["classes"] != classes:
26
+ raise ValueError(
27
+ "If using `weights` and `include_top`"
28
+ " as true, `classes` should be {}".format(weights["classes"])
29
+ )
30
+
31
+ weights_path = get_file(
32
+ weights["name"],
33
+ weights["url"],
34
+ cache_subdir="models",
35
+ md5_hash=weights["md5"],
36
+ )
37
+
38
+ model.load_weights(weights_path)
39
+
40
+ else:
41
+ raise ValueError(
42
+ "There is no weights for such configuration: "
43
+ f"model = {model.name}, dataset = {dataset}, "
44
+ f"classes = {classes}, include_top = {include_top}."
45
+ )
46
+
47
+
48
+ WEIGHTS_COLLECTION = [
49
+ # ResNet18
50
+ {
51
+ "model": "resnet18",
52
+ "dataset": "imagenet",
53
+ "classes": 1000,
54
+ "include_top": True,
55
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnet18_imagenet_1000.h5",
56
+ "name": "resnet18_imagenet_1000.h5",
57
+ "md5": "64da73012bb70e16c901316c201d9803",
58
+ },
59
+ {
60
+ "model": "resnet18",
61
+ "dataset": "imagenet",
62
+ "classes": 1000,
63
+ "include_top": False,
64
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnet18_imagenet_1000_no_top.h5",
65
+ "name": "resnet18_imagenet_1000_no_top.h5",
66
+ "md5": "318e3ac0cd98d51e917526c9f62f0b50",
67
+ },
68
+ # ResNet34
69
+ {
70
+ "model": "resnet34",
71
+ "dataset": "imagenet",
72
+ "classes": 1000,
73
+ "include_top": True,
74
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnet34_imagenet_1000.h5",
75
+ "name": "resnet34_imagenet_1000.h5",
76
+ "md5": "2ac8277412f65e5d047f255bcbd10383",
77
+ },
78
+ {
79
+ "model": "resnet34",
80
+ "dataset": "imagenet",
81
+ "classes": 1000,
82
+ "include_top": False,
83
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnet34_imagenet_1000_no_top.h5",
84
+ "name": "resnet34_imagenet_1000_no_top.h5",
85
+ "md5": "8caaa0ad39d927cb8ba5385bf945d582",
86
+ },
87
+ # ResNet50
88
+ {
89
+ "model": "resnet50",
90
+ "dataset": "imagenet",
91
+ "classes": 1000,
92
+ "include_top": True,
93
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnet50_imagenet_1000.h5",
94
+ "name": "resnet50_imagenet_1000.h5",
95
+ "md5": "d0feba4fc650e68ac8c19166ee1ba87f",
96
+ },
97
+ {
98
+ "model": "resnet50",
99
+ "dataset": "imagenet",
100
+ "classes": 1000,
101
+ "include_top": False,
102
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnet50_imagenet_1000_no_top.h5",
103
+ "name": "resnet50_imagenet_1000_no_top.h5",
104
+ "md5": "db3b217156506944570ac220086f09b6",
105
+ },
106
+ {
107
+ "model": "resnet50",
108
+ "dataset": "imagenet11k-places365ch",
109
+ "classes": 11586,
110
+ "include_top": True,
111
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnet50_imagenet11k-places365ch_11586.h5",
112
+ "name": "resnet50_imagenet11k-places365ch_11586.h5",
113
+ "md5": "bb8963db145bc9906452b3d9c9917275",
114
+ },
115
+ {
116
+ "model": "resnet50",
117
+ "dataset": "imagenet11k-places365ch",
118
+ "classes": 11586,
119
+ "include_top": False,
120
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnet50_imagenet11k-places365ch_11586_no_top.h5",
121
+ "name": "resnet50_imagenet11k-places365ch_11586_no_top.h5",
122
+ "md5": "d8bf4e7ea082d9d43e37644da217324a",
123
+ },
124
+ # ResNet101
125
+ {
126
+ "model": "resnet101",
127
+ "dataset": "imagenet",
128
+ "classes": 1000,
129
+ "include_top": True,
130
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnet101_imagenet_1000.h5",
131
+ "name": "resnet101_imagenet_1000.h5",
132
+ "md5": "9489ed2d5d0037538134c880167622ad",
133
+ },
134
+ {
135
+ "model": "resnet101",
136
+ "dataset": "imagenet",
137
+ "classes": 1000,
138
+ "include_top": False,
139
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnet101_imagenet_1000_no_top.h5",
140
+ "name": "resnet101_imagenet_1000_no_top.h5",
141
+ "md5": "1016e7663980d5597a4e224d915c342d",
142
+ },
143
+ # ResNet152
144
+ {
145
+ "model": "resnet152",
146
+ "dataset": "imagenet",
147
+ "classes": 1000,
148
+ "include_top": True,
149
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnet152_imagenet_1000.h5",
150
+ "name": "resnet152_imagenet_1000.h5",
151
+ "md5": "1efffbcc0708fb0d46a9d096ae14f905",
152
+ },
153
+ {
154
+ "model": "resnet152",
155
+ "dataset": "imagenet",
156
+ "classes": 1000,
157
+ "include_top": False,
158
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnet152_imagenet_1000_no_top.h5",
159
+ "name": "resnet152_imagenet_1000_no_top.h5",
160
+ "md5": "5867b94098df4640918941115db93734",
161
+ },
162
+ {
163
+ "model": "resnet152",
164
+ "dataset": "imagenet11k",
165
+ "classes": 11221,
166
+ "include_top": True,
167
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnet152_imagenet11k_11221.h5",
168
+ "name": "resnet152_imagenet11k_11221.h5",
169
+ "md5": "24791790f6ef32f274430ce4a2ffee5d",
170
+ },
171
+ {
172
+ "model": "resnet152",
173
+ "dataset": "imagenet11k",
174
+ "classes": 11221,
175
+ "include_top": False,
176
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnet152_imagenet11k_11221_no_top.h5",
177
+ "name": "resnet152_imagenet11k_11221_no_top.h5",
178
+ "md5": "25ab66dec217cb774a27d0f3659cafb3",
179
+ },
180
+ # ResNeXt50
181
+ {
182
+ "model": "resnext50",
183
+ "dataset": "imagenet",
184
+ "classes": 1000,
185
+ "include_top": True,
186
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnext50_imagenet_1000.h5",
187
+ "name": "resnext50_imagenet_1000.h5",
188
+ "md5": "7c5c40381efb044a8dea5287ab2c83db",
189
+ },
190
+ {
191
+ "model": "resnext50",
192
+ "dataset": "imagenet",
193
+ "classes": 1000,
194
+ "include_top": False,
195
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnext50_imagenet_1000_no_top.h5",
196
+ "name": "resnext50_imagenet_1000_no_top.h5",
197
+ "md5": "7ade5c8aac9194af79b1724229bdaa50",
198
+ },
199
+ # ResNeXt101
200
+ {
201
+ "model": "resnext101",
202
+ "dataset": "imagenet",
203
+ "classes": 1000,
204
+ "include_top": True,
205
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnext101_imagenet_1000.h5",
206
+ "name": "resnext101_imagenet_1000.h5",
207
+ "md5": "432536e85ee811568a0851c328182735",
208
+ },
209
+ {
210
+ "model": "resnext101",
211
+ "dataset": "imagenet",
212
+ "classes": 1000,
213
+ "include_top": False,
214
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/resnext101_imagenet_1000_no_top.h5",
215
+ "name": "resnext101_imagenet_1000_no_top.h5",
216
+ "md5": "91fe0126320e49f6ee607a0719828c7e",
217
+ },
218
+ # SE models
219
+ {
220
+ "model": "seresnet50",
221
+ "dataset": "imagenet",
222
+ "classes": 1000,
223
+ "include_top": True,
224
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/seresnet50_imagenet_1000.h5",
225
+ "name": "seresnet50_imagenet_1000.h5",
226
+ "md5": "ff0ce1ed5accaad05d113ecef2d29149",
227
+ },
228
+ {
229
+ "model": "seresnet50",
230
+ "dataset": "imagenet",
231
+ "classes": 1000,
232
+ "include_top": False,
233
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/seresnet50_imagenet_1000_no_top.h5",
234
+ "name": "seresnet50_imagenet_1000_no_top.h5",
235
+ "md5": "043777781b0d5ca756474d60bf115ef1",
236
+ },
237
+ {
238
+ "model": "seresnet101",
239
+ "dataset": "imagenet",
240
+ "classes": 1000,
241
+ "include_top": True,
242
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/seresnet101_imagenet_1000.h5",
243
+ "name": "seresnet101_imagenet_1000.h5",
244
+ "md5": "5c31adee48c82a66a32dee3d442f5be8",
245
+ },
246
+ {
247
+ "model": "seresnet101",
248
+ "dataset": "imagenet",
249
+ "classes": 1000,
250
+ "include_top": False,
251
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/seresnet101_imagenet_1000_no_top.h5",
252
+ "name": "seresnet101_imagenet_1000_no_top.h5",
253
+ "md5": "1c373b0c196918713da86951d1239007",
254
+ },
255
+ {
256
+ "model": "seresnet152",
257
+ "dataset": "imagenet",
258
+ "classes": 1000,
259
+ "include_top": True,
260
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/seresnet152_imagenet_1000.h5",
261
+ "name": "seresnet152_imagenet_1000.h5",
262
+ "md5": "96fc14e3a939d4627b0174a0e80c7371",
263
+ },
264
+ {
265
+ "model": "seresnet152",
266
+ "dataset": "imagenet",
267
+ "classes": 1000,
268
+ "include_top": False,
269
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/seresnet152_imagenet_1000_no_top.h5",
270
+ "name": "seresnet152_imagenet_1000_no_top.h5",
271
+ "md5": "f58d4c1a511c7445ab9a2c2b83ee4e7b",
272
+ },
273
+ {
274
+ "model": "seresnext50",
275
+ "dataset": "imagenet",
276
+ "classes": 1000,
277
+ "include_top": True,
278
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/seresnext50_imagenet_1000.h5",
279
+ "name": "seresnext50_imagenet_1000.h5",
280
+ "md5": "5310dcd58ed573aecdab99f8df1121d5",
281
+ },
282
+ {
283
+ "model": "seresnext50",
284
+ "dataset": "imagenet",
285
+ "classes": 1000,
286
+ "include_top": False,
287
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/seresnext50_imagenet_1000_no_top.h5",
288
+ "name": "seresnext50_imagenet_1000_no_top.h5",
289
+ "md5": "b0f23d2e1cd406d67335fb92d85cc279",
290
+ },
291
+ {
292
+ "model": "seresnext101",
293
+ "dataset": "imagenet",
294
+ "classes": 1000,
295
+ "include_top": True,
296
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/seresnext101_imagenet_1000.h5",
297
+ "name": "seresnext101_imagenet_1000.h5",
298
+ "md5": "be5b26b697a0f7f11efaa1bb6272fc84",
299
+ },
300
+ {
301
+ "model": "seresnext101",
302
+ "dataset": "imagenet",
303
+ "classes": 1000,
304
+ "include_top": False,
305
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/seresnext101_imagenet_1000_no_top.h5",
306
+ "name": "seresnext101_imagenet_1000_no_top.h5",
307
+ "md5": "e48708cbe40071cc3356016c37f6c9c7",
308
+ },
309
+ {
310
+ "model": "senet154",
311
+ "dataset": "imagenet",
312
+ "classes": 1000,
313
+ "include_top": True,
314
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/senet154_imagenet_1000.h5",
315
+ "name": "senet154_imagenet_1000.h5",
316
+ "md5": "c8eac0e1940ea4d8a2e0b2eb0cdf4e75",
317
+ },
318
+ {
319
+ "model": "senet154",
320
+ "dataset": "imagenet",
321
+ "classes": 1000,
322
+ "include_top": False,
323
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/senet154_imagenet_1000_no_top.h5",
324
+ "name": "senet154_imagenet_1000_no_top.h5",
325
+ "md5": "d854ff2cd7e6a87b05a8124cd283e0f2",
326
+ },
327
+ {
328
+ "model": "seresnet18",
329
+ "dataset": "imagenet",
330
+ "classes": 1000,
331
+ "include_top": True,
332
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/seresnet18_imagenet_1000.h5",
333
+ "name": "seresnet18_imagenet_1000.h5",
334
+ "md5": "9a925fd96d050dbf7cc4c54aabfcf749",
335
+ },
336
+ {
337
+ "model": "seresnet18",
338
+ "dataset": "imagenet",
339
+ "classes": 1000,
340
+ "include_top": False,
341
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/seresnet18_imagenet_1000_no_top.h5",
342
+ "name": "seresnet18_imagenet_1000_no_top.h5",
343
+ "md5": "a46e5cd4114ac946ecdc58741e8d92ea",
344
+ },
345
+ {
346
+ "model": "seresnet34",
347
+ "dataset": "imagenet",
348
+ "classes": 1000,
349
+ "include_top": True,
350
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/seresnet34_imagenet_1000.h5",
351
+ "name": "seresnet34_imagenet_1000.h5",
352
+ "md5": "863976b3bd439ff0cc05c91821218a6b",
353
+ },
354
+ {
355
+ "model": "seresnet34",
356
+ "dataset": "imagenet",
357
+ "classes": 1000,
358
+ "include_top": False,
359
+ "url": "https://github.com/qubvel/classification_models/releases/download/0.0.1/seresnet34_imagenet_1000_no_top.h5",
360
+ "name": "seresnet34_imagenet_1000_no_top.h5",
361
+ "md5": "3348fd049f1f9ad307c070ff2b6ec4cb",
362
+ },
363
+ ]
@@ -2,6 +2,7 @@ import keras.applications as ka
2
2
 
3
3
  from . import inception_resnet_v2 as irv2
4
4
  from . import inception_v3 as iv3
5
+ from . import resnet
5
6
 
6
7
 
7
8
  class BackbonesFactory:
@@ -16,39 +17,37 @@ class BackbonesFactory:
16
17
  """
17
18
 
18
19
  _models = { # noqa: RUF012
19
- # ResNets
20
+ # ResNets < 50 layers are NOT available via keras.applications, so use
21
+ # implementation from classification_models.
22
+ "resnet18": (
23
+ resnet.ResNet18,
24
+ resnet.preprocess_input,
25
+ ("stage4_unit1_relu1", "stage3_unit1_relu1", "stage2_unit1_relu1", "relu0"),
26
+ ),
27
+ "resnet34": (
28
+ resnet.ResNet34,
29
+ resnet.preprocess_input,
30
+ ("stage4_unit1_relu1", "stage3_unit1_relu1", "stage2_unit1_relu1", "relu0"),
31
+ ),
32
+ # ResNets > 50 layers are available via keras.applications, so use those.
33
+ # Skip layers (inverted) from https://github.com/yingkaisha/keras-unet-collection
20
34
  "resnet50": (
21
35
  ka.ResNet50,
22
36
  ka.resnet.preprocess_input,
23
- (
24
- "conv4_block6_out",
25
- "conv3_block4_out",
26
- "conv2_block3_out",
27
- "conv1_relu",
28
- ),
37
+ ("conv4_block6_out", "conv3_block4_out", "conv2_block3_out", "conv1_relu"),
29
38
  ),
30
39
  "resnet101": (
31
40
  ka.ResNet101,
32
41
  ka.resnet.preprocess_input,
33
- (
34
- "conv4_block23_out",
35
- "conv3_block4_out",
36
- "conv2_block3_out",
37
- "conv1_relu",
38
- ),
42
+ ("conv4_block23_out", "conv3_block4_out", "conv2_block3_out", "conv1_relu"),
39
43
  ),
40
44
  "resnet152": (
41
45
  ka.ResNet152,
42
46
  ka.resnet.preprocess_input,
43
- (
44
- "conv4_block36_out",
45
- "conv3_block8_out",
46
- "conv2_block3_out",
47
- "conv1_relu",
48
- ),
47
+ ("conv4_block36_out", "conv3_block8_out", "conv2_block3_out", "conv1_relu"),
49
48
  ),
50
49
  # ResNetV2
51
- # Layers reused from: https://github.com/yingkaisha/keras-unet-collection
50
+ # Skip layers (inverted) from https://github.com/yingkaisha/keras-unet-collection
52
51
  "resnet50v2": (
53
52
  ka.ResNet50V2,
54
53
  ka.resnet_v2.preprocess_input,
@@ -80,6 +79,7 @@ class BackbonesFactory:
80
79
  ),
81
80
  ),
82
81
  # VGG
82
+ # Skip layers from segmentation_models
83
83
  "vgg16": (
84
84
  ka.vgg16.VGG16,
85
85
  ka.vgg16.preprocess_input,
@@ -103,6 +103,7 @@ class BackbonesFactory:
103
103
  ),
104
104
  ),
105
105
  # DenseNet
106
+ # Skip layers (inverted) from https://github.com/yingkaisha/keras-unet-collection
106
107
  "densenet121": (
107
108
  ka.densenet.DenseNet121,
108
109
  ka.densenet.preprocess_input,
@@ -122,6 +123,7 @@ class BackbonesFactory:
122
123
  ("pool4_conv", "pool3_conv", "pool2_conv", "conv1/relu"),
123
124
  ),
124
125
  # Inception
126
+ # Skip layers from segmentation_models
125
127
  "inceptionresnetv2": (
126
128
  irv2.InceptionResNetV2,
127
129
  irv2.preprocess_input,
@@ -138,6 +140,7 @@ class BackbonesFactory:
138
140
  ),
139
141
  "inceptionv3": (iv3.InceptionV3, iv3.preprocess_input, (228, 86, 16, 9)),
140
142
  # MobileNet
143
+ # Skip layers from segmentation_models
141
144
  "mobilenet": (
142
145
  ka.mobilenet.MobileNet,
143
146
  ka.mobilenet.preprocess_input,
@@ -158,6 +161,8 @@ class BackbonesFactory:
158
161
  "block_1_expand_relu",
159
162
  ),
160
163
  ),
164
+ # EfficientNet
165
+ # Skip layers from segmentation_models
161
166
  "efficientnetb0": [
162
167
  ka.EfficientNetB0,
163
168
  ka.efficientnet.preprocess_input,
@@ -239,7 +244,7 @@ class BackbonesFactory:
239
244
  ),
240
245
  ],
241
246
  # EfficientNetV2
242
- # Layers reused from: https://github.com/chinefed/segmentation_models_fork
247
+ # Skip layers from https://github.com/chinefed/segmentation_models_fork
243
248
  "efficientnetv2m": (
244
249
  ka.EfficientNetV2M,
245
250
  ka.efficientnet_v2.preprocess_input,
@@ -8,6 +8,7 @@ and that the input preprocessing function is also different (same as Xception).
8
8
  """
9
9
 
10
10
  import os
11
+ import warnings
11
12
 
12
13
  from keras import backend, layers, models
13
14
  from keras import utils as keras_utils
@@ -0,0 +1,494 @@
1
+ """Resnet keras models.
2
+
3
+ Source: https://github.com/qubvel/classification_models
4
+ """
5
+
6
+ import collections
7
+ import os
8
+
9
+ from keras import backend, layers, models
10
+ from keras.utils import get_source_inputs
11
+
12
+ from ._common_blocks import ChannelSE
13
+ from ._weights import load_model_weights
14
+
15
+ ModelParams = collections.namedtuple(
16
+ "ModelParams", ["model_name", "repetitions", "residual_block", "attention"]
17
+ )
18
+
19
+ BASE_WEIGHT_URL = (
20
+ "https://github.com/qubvel/classification_models/releases/download/0.0.1/"
21
+ )
22
+
23
+ # -------------------------------------------------------------------------
24
+ # Helpers functions
25
+ # -------------------------------------------------------------------------
26
+
27
+
28
+ def handle_block_names(stage, block):
29
+ name_base = f"stage{stage + 1}_unit{block + 1}_"
30
+ conv_name = name_base + "conv"
31
+ bn_name = name_base + "bn"
32
+ relu_name = name_base + "relu"
33
+ sc_name = name_base + "sc"
34
+ return conv_name, bn_name, relu_name, sc_name
35
+
36
+
37
+ def get_conv_params(**params):
38
+ default_conv_params = {
39
+ "kernel_initializer": "he_uniform",
40
+ "use_bias": False,
41
+ "padding": "valid",
42
+ }
43
+ default_conv_params.update(params)
44
+ return default_conv_params
45
+
46
+
47
+ def get_bn_params(**params):
48
+ axis = 3 if backend.image_data_format() == "channels_last" else 1
49
+ default_bn_params = {
50
+ "axis": axis,
51
+ "momentum": 0.99,
52
+ "epsilon": 2e-5,
53
+ "center": True,
54
+ "scale": True,
55
+ }
56
+ default_bn_params.update(params)
57
+ return default_bn_params
58
+
59
+
60
+ # -------------------------------------------------------------------------
61
+ # Residual blocks
62
+ # -------------------------------------------------------------------------
63
+
64
+
65
+ def residual_conv_block(
66
+ filters, stage, block, strides=(1, 1), attention=None, cut="pre"
67
+ ):
68
+ """The identity block is the block that has no conv layer at shortcut.
69
+ # Arguments
70
+ input_tensor: input tensor
71
+ kernel_size: default 3, the kernel size of
72
+ middle conv layer at main path
73
+ filters: list of integers, the filters of 3 conv layer at main path
74
+ stage: integer, current stage label, used for generating layer names
75
+ block: 'a','b'..., current block label, used for generating layer names
76
+ cut: one of 'pre', 'post'. used to decide where skip connection is taken
77
+ # Returns
78
+ Output tensor for the block.
79
+ """
80
+
81
+ def layer(input_tensor):
82
+
83
+ # get params and names of layers
84
+ conv_params = get_conv_params()
85
+ bn_params = get_bn_params()
86
+ conv_name, bn_name, relu_name, sc_name = handle_block_names(stage, block)
87
+
88
+ x = layers.BatchNormalization(name=bn_name + "1", **bn_params)(input_tensor)
89
+ x = layers.Activation("relu", name=relu_name + "1")(x)
90
+
91
+ # defining shortcut connection
92
+ if cut == "pre":
93
+ shortcut = input_tensor
94
+ elif cut == "post":
95
+ shortcut = layers.Conv2D(
96
+ filters, (1, 1), name=sc_name, strides=strides, **conv_params
97
+ )(x)
98
+ else:
99
+ raise ValueError('Cut type not in ["pre", "post"]')
100
+
101
+ # continue with convolution layers
102
+ x = layers.ZeroPadding2D(padding=(1, 1))(x)
103
+ x = layers.Conv2D(
104
+ filters, (3, 3), strides=strides, name=conv_name + "1", **conv_params
105
+ )(x)
106
+
107
+ x = layers.BatchNormalization(name=bn_name + "2", **bn_params)(x)
108
+ x = layers.Activation("relu", name=relu_name + "2")(x)
109
+ x = layers.ZeroPadding2D(padding=(1, 1))(x)
110
+ x = layers.Conv2D(filters, (3, 3), name=conv_name + "2", **conv_params)(x)
111
+
112
+ # use attention block if defined
113
+ if attention is not None:
114
+ x = attention(x)
115
+
116
+ # add residual connection
117
+ x = layers.Add()([x, shortcut])
118
+ return x
119
+
120
+ return layer
121
+
122
+
123
+ def residual_bottleneck_block(
124
+ filters, stage, block, strides=None, attention=None, cut="pre"
125
+ ):
126
+ """The identity block is the block that has no conv layer at shortcut.
127
+ # Arguments
128
+ input_tensor: input tensor
129
+ kernel_size: default 3, the kernel size of
130
+ middle conv layer at main path
131
+ filters: list of integers, the filters of 3 conv layer at main path
132
+ stage: integer, current stage label, used for generating layer names
133
+ block: 'a','b'..., current block label, used for generating layer names
134
+ cut: one of 'pre', 'post'. used to decide where skip connection is taken
135
+ # Returns
136
+ Output tensor for the block.
137
+ """
138
+
139
+ def layer(input_tensor):
140
+
141
+ # get params and names of layers
142
+ conv_params = get_conv_params()
143
+ bn_params = get_bn_params()
144
+ conv_name, bn_name, relu_name, sc_name = handle_block_names(stage, block)
145
+
146
+ x = layers.BatchNormalization(name=bn_name + "1", **bn_params)(input_tensor)
147
+ x = layers.Activation("relu", name=relu_name + "1")(x)
148
+
149
+ # defining shortcut connection
150
+ if cut == "pre":
151
+ shortcut = input_tensor
152
+ elif cut == "post":
153
+ shortcut = layers.Conv2D(
154
+ filters * 4, (1, 1), name=sc_name, strides=strides, **conv_params
155
+ )(x)
156
+ else:
157
+ raise ValueError('Cut type not in ["pre", "post"]')
158
+
159
+ # continue with convolution layers
160
+ x = layers.Conv2D(filters, (1, 1), name=conv_name + "1", **conv_params)(x)
161
+
162
+ x = layers.BatchNormalization(name=bn_name + "2", **bn_params)(x)
163
+ x = layers.Activation("relu", name=relu_name + "2")(x)
164
+ x = layers.ZeroPadding2D(padding=(1, 1))(x)
165
+ x = layers.Conv2D(
166
+ filters, (3, 3), strides=strides, name=conv_name + "2", **conv_params
167
+ )(x)
168
+
169
+ x = layers.BatchNormalization(name=bn_name + "3", **bn_params)(x)
170
+ x = layers.Activation("relu", name=relu_name + "3")(x)
171
+ x = layers.Conv2D(filters * 4, (1, 1), name=conv_name + "3", **conv_params)(x)
172
+
173
+ # use attention block if defined
174
+ if attention is not None:
175
+ x = attention(x)
176
+
177
+ # add residual connection
178
+ x = layers.Add()([x, shortcut])
179
+
180
+ return x
181
+
182
+ return layer
183
+
184
+
185
+ # -------------------------------------------------------------------------
186
+ # Residual Model Builder
187
+ # -------------------------------------------------------------------------
188
+
189
+
190
+ def ResNet(
191
+ model_params,
192
+ input_shape=None,
193
+ input_tensor=None,
194
+ include_top=True,
195
+ classes=1000,
196
+ weights="imagenet",
197
+ **kwargs,
198
+ ):
199
+ """Instantiates the ResNet, SEResNet architecture.
200
+ Optionally loads weights pre-trained on ImageNet.
201
+ Note that the data format convention used by the model is
202
+ the one specified in your Keras config at `~/.keras/keras.json`.
203
+
204
+ Args:
205
+ include_top: whether to include the fully-connected
206
+ layer at the top of the network.
207
+ weights: one of `None` (random initialization),
208
+ 'imagenet' (pre-training on ImageNet),
209
+ or the path to the weights file to be loaded.
210
+ input_tensor: optional Keras tensor
211
+ (i.e. output of `layers.Input()`)
212
+ to use as image input for the model.
213
+ input_shape: optional shape tuple, only to be specified
214
+ if `include_top` is False (otherwise the input shape
215
+ has to be `(224, 224, 3)` (with `channels_last` data format)
216
+ or `(3, 224, 224)` (with `channels_first` data format).
217
+ It should have exactly 3 inputs channels.
218
+ classes: optional number of classes to classify images
219
+ into, only to be specified if `include_top` is True, and
220
+ if no `weights` argument is specified.
221
+
222
+ Returns:
223
+ A Keras model instance.
224
+
225
+ Raises:
226
+ ValueError: in case of invalid argument for `weights`,
227
+ or invalid input shape.
228
+ """
229
+ if input_tensor is None:
230
+ img_input = layers.Input(shape=input_shape, name="data")
231
+ else:
232
+ if not backend.is_keras_tensor(input_tensor):
233
+ img_input = layers.Input(tensor=input_tensor, shape=input_shape)
234
+ else:
235
+ img_input = input_tensor
236
+
237
+ # choose residual block type
238
+ ResidualBlock = model_params.residual_block
239
+ if model_params.attention:
240
+ Attention = model_params.attention(**kwargs)
241
+ else:
242
+ Attention = None
243
+
244
+ # get parameters for model layers
245
+ no_scale_bn_params = get_bn_params(scale=False)
246
+ bn_params = get_bn_params()
247
+ conv_params = get_conv_params()
248
+ init_filters = 64
249
+
250
+ # resnet bottom
251
+ x = layers.BatchNormalization(name="bn_data", **no_scale_bn_params)(img_input)
252
+ x = layers.ZeroPadding2D(padding=(3, 3))(x)
253
+ x = layers.Conv2D(
254
+ init_filters, (7, 7), strides=(2, 2), name="conv0", **conv_params
255
+ )(x)
256
+ x = layers.BatchNormalization(name="bn0", **bn_params)(x)
257
+ x = layers.Activation("relu", name="relu0")(x)
258
+ x = layers.ZeroPadding2D(padding=(1, 1))(x)
259
+ x = layers.MaxPooling2D((3, 3), strides=(2, 2), padding="valid", name="pooling0")(x)
260
+
261
+ # resnet body
262
+ for stage, rep in enumerate(model_params.repetitions):
263
+ for block in range(rep):
264
+ filters = init_filters * (2**stage)
265
+
266
+ # first block of first stage without strides because we have maxpooling
267
+ # before
268
+ if block == 0 and stage == 0:
269
+ x = ResidualBlock(
270
+ filters,
271
+ stage,
272
+ block,
273
+ strides=(1, 1),
274
+ cut="post",
275
+ attention=Attention,
276
+ )(x)
277
+
278
+ elif block == 0:
279
+ x = ResidualBlock(
280
+ filters,
281
+ stage,
282
+ block,
283
+ strides=(2, 2),
284
+ cut="post",
285
+ attention=Attention,
286
+ )(x)
287
+
288
+ else:
289
+ x = ResidualBlock(
290
+ filters,
291
+ stage,
292
+ block,
293
+ strides=(1, 1),
294
+ cut="pre",
295
+ attention=Attention,
296
+ )(x)
297
+
298
+ x = layers.BatchNormalization(name="bn1", **bn_params)(x)
299
+ x = layers.Activation("relu", name="relu1")(x)
300
+
301
+ # resnet top
302
+ if include_top:
303
+ x = layers.GlobalAveragePooling2D(name="pool1")(x)
304
+ x = layers.Dense(classes, name="fc1")(x)
305
+ x = layers.Activation("softmax", name="softmax")(x)
306
+
307
+ # Ensure that the model takes into account any potential predecessors of
308
+ # `input_tensor`.
309
+ if input_tensor is not None:
310
+ inputs = get_source_inputs(input_tensor)
311
+ else:
312
+ inputs = img_input
313
+
314
+ # Create model.
315
+ model = models.Model(inputs, x)
316
+
317
+ if weights:
318
+ if isinstance(weights, str) and os.path.exists(weights):
319
+ model.load_weights(weights)
320
+ else:
321
+ load_model_weights(
322
+ model, model_params.model_name, weights, classes, include_top, **kwargs
323
+ )
324
+
325
+ return model
326
+
327
+
328
+ # -------------------------------------------------------------------------
329
+ # Residual Models
330
+ # -------------------------------------------------------------------------
331
+
332
+ MODELS_PARAMS = {
333
+ "resnet18": ModelParams("resnet18", (2, 2, 2, 2), residual_conv_block, None),
334
+ "resnet34": ModelParams("resnet34", (3, 4, 6, 3), residual_conv_block, None),
335
+ "resnet50": ModelParams("resnet50", (3, 4, 6, 3), residual_bottleneck_block, None),
336
+ "resnet101": ModelParams(
337
+ "resnet101", (3, 4, 23, 3), residual_bottleneck_block, None
338
+ ),
339
+ "resnet152": ModelParams(
340
+ "resnet152", (3, 8, 36, 3), residual_bottleneck_block, None
341
+ ),
342
+ "seresnet18": ModelParams(
343
+ "seresnet18", (2, 2, 2, 2), residual_conv_block, ChannelSE
344
+ ),
345
+ "seresnet34": ModelParams(
346
+ "seresnet34", (3, 4, 6, 3), residual_conv_block, ChannelSE
347
+ ),
348
+ }
349
+
350
+
351
+ def ResNet18(
352
+ input_shape=None,
353
+ input_tensor=None,
354
+ weights=None,
355
+ classes=1000,
356
+ include_top=True,
357
+ **kwargs,
358
+ ):
359
+ return ResNet(
360
+ MODELS_PARAMS["resnet18"],
361
+ input_shape=input_shape,
362
+ input_tensor=input_tensor,
363
+ include_top=include_top,
364
+ classes=classes,
365
+ weights=weights,
366
+ **kwargs,
367
+ )
368
+
369
+
370
+ def ResNet34(
371
+ input_shape=None,
372
+ input_tensor=None,
373
+ weights=None,
374
+ classes=1000,
375
+ include_top=True,
376
+ **kwargs,
377
+ ):
378
+ return ResNet(
379
+ MODELS_PARAMS["resnet34"],
380
+ input_shape=input_shape,
381
+ input_tensor=input_tensor,
382
+ include_top=include_top,
383
+ classes=classes,
384
+ weights=weights,
385
+ **kwargs,
386
+ )
387
+
388
+
389
+ def ResNet50(
390
+ input_shape=None,
391
+ input_tensor=None,
392
+ weights=None,
393
+ classes=1000,
394
+ include_top=True,
395
+ **kwargs,
396
+ ):
397
+ return ResNet(
398
+ MODELS_PARAMS["resnet50"],
399
+ input_shape=input_shape,
400
+ input_tensor=input_tensor,
401
+ include_top=include_top,
402
+ classes=classes,
403
+ weights=weights,
404
+ **kwargs,
405
+ )
406
+
407
+
408
+ def ResNet101(
409
+ input_shape=None,
410
+ input_tensor=None,
411
+ weights=None,
412
+ classes=1000,
413
+ include_top=True,
414
+ **kwargs,
415
+ ):
416
+ return ResNet(
417
+ MODELS_PARAMS["resnet101"],
418
+ input_shape=input_shape,
419
+ input_tensor=input_tensor,
420
+ include_top=include_top,
421
+ classes=classes,
422
+ weights=weights,
423
+ **kwargs,
424
+ )
425
+
426
+
427
+ def ResNet152(
428
+ input_shape=None,
429
+ input_tensor=None,
430
+ weights=None,
431
+ classes=1000,
432
+ include_top=True,
433
+ **kwargs,
434
+ ):
435
+ return ResNet(
436
+ MODELS_PARAMS["resnet152"],
437
+ input_shape=input_shape,
438
+ input_tensor=input_tensor,
439
+ include_top=include_top,
440
+ classes=classes,
441
+ weights=weights,
442
+ **kwargs,
443
+ )
444
+
445
+
446
+ def SEResNet18(
447
+ input_shape=None,
448
+ input_tensor=None,
449
+ weights=None,
450
+ classes=1000,
451
+ include_top=True,
452
+ **kwargs,
453
+ ):
454
+ return ResNet(
455
+ MODELS_PARAMS["seresnet18"],
456
+ input_shape=input_shape,
457
+ input_tensor=input_tensor,
458
+ include_top=include_top,
459
+ classes=classes,
460
+ weights=weights,
461
+ **kwargs,
462
+ )
463
+
464
+
465
+ def SEResNet34(
466
+ input_shape=None,
467
+ input_tensor=None,
468
+ weights=None,
469
+ classes=1000,
470
+ include_top=True,
471
+ **kwargs,
472
+ ):
473
+ return ResNet(
474
+ MODELS_PARAMS["seresnet34"],
475
+ input_shape=input_shape,
476
+ input_tensor=input_tensor,
477
+ include_top=include_top,
478
+ classes=classes,
479
+ weights=weights,
480
+ **kwargs,
481
+ )
482
+
483
+
484
+ def preprocess_input(x, **kwargs): # noqa: ARG001
485
+ return x
486
+
487
+
488
+ ResNet18.__doc__ = ResNet.__doc__
489
+ ResNet34.__doc__ = ResNet.__doc__
490
+ ResNet50.__doc__ = ResNet.__doc__
491
+ ResNet101.__doc__ = ResNet.__doc__
492
+ ResNet152.__doc__ = ResNet.__doc__
493
+ SEResNet18.__doc__ = ResNet.__doc__
494
+ SEResNet34.__doc__ = ResNet.__doc__
@@ -60,7 +60,7 @@ def round_if_needed(x, threshold, **kwargs):
60
60
  return x
61
61
 
62
62
 
63
- def average(x, per_image=False, class_weights=None, **kwargs):
63
+ def average(x, per_image=False, class_weights=None, **kwargs): # noqa: ARG001
64
64
  if per_image:
65
65
  x = ops.mean(x, axis=0)
66
66
  if class_weights is not None:
@@ -308,7 +308,7 @@ def categorical_crossentropy(gt, pr, class_weights=1.0, class_indexes=None, **kw
308
308
  return -ops.mean(output)
309
309
 
310
310
 
311
- def binary_crossentropy(gt, pr, **kwargs):
311
+ def binary_crossentropy(gt, pr, **kwargs): # noqa: ARG001
312
312
  return ops.mean(ops.binary_crossentropy(gt, pr))
313
313
 
314
314
 
@@ -338,7 +338,7 @@ def categorical_focal_loss(gt, pr, gamma=2.0, alpha=0.25, class_indexes=None, **
338
338
  return ops.mean(loss)
339
339
 
340
340
 
341
- def binary_focal_loss(gt, pr, gamma=2.0, alpha=0.25, **kwargs):
341
+ def binary_focal_loss(gt, pr, gamma=2.0, alpha=0.25, **kwargs): # noqa: ARG001
342
342
  r"""Implementation of Focal Loss from the paper in binary classification
343
343
 
344
344
  Formula:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: segmodels_keras
3
- Version: 0.1.0.dev6
3
+ Version: 0.1.0.dev7
4
4
  Summary: Image segmentation models with pre-trained backbones with Keras.
5
5
  Home-page: https://github.com/orthoseg/segmodels_keras
6
6
  Author: Pieter Roggemans
@@ -15,9 +15,12 @@ segmodels_keras.egg-info/dependency_links.txt
15
15
  segmodels_keras.egg-info/requires.txt
16
16
  segmodels_keras.egg-info/top_level.txt
17
17
  segmodels_keras/backbones/__init__.py
18
+ segmodels_keras/backbones/_common_blocks.py
19
+ segmodels_keras/backbones/_weights.py
18
20
  segmodels_keras/backbones/backbones_factory.py
19
21
  segmodels_keras/backbones/inception_resnet_v2.py
20
22
  segmodels_keras/backbones/inception_v3.py
23
+ segmodels_keras/backbones/resnet.py
21
24
  segmodels_keras/base/__init__.py
22
25
  segmodels_keras/base/functional.py
23
26
  segmodels_keras/base/objects.py
@@ -20,13 +20,7 @@ def str2bool(v):
20
20
 
21
21
 
22
22
  def get_backbones():
23
- is_travis = str2bool(os.environ.get("TRAVIS", "False"))
24
- exclude = ["efficientnetb6", "efficientnetb7"]
25
- backbones = get_available_backbone_names()
26
-
27
- if is_travis:
28
- backbones = [b for b in backbones if b not in exclude]
29
- return backbones
23
+ return get_available_backbone_names()
30
24
 
31
25
 
32
26
  BACKBONES = get_backbones()
@@ -35,7 +29,13 @@ BACKBONES = get_backbones()
35
29
  def _test_backbones(names):
36
30
  is_full = str2bool(os.environ.get("FULL_TEST", "False"))
37
31
  if not is_full:
38
- return ["resnet50", "inceptionresnetv2", "efficientnetb0", "efficientnetv2m"]
32
+ return [
33
+ "resnet34",
34
+ "resnet50",
35
+ "inceptionresnetv2",
36
+ "efficientnetb0",
37
+ "efficientnetv2m",
38
+ ]
39
39
  else:
40
40
  return names
41
41