segmodels-keras 0.1.0.dev7__tar.gz → 0.1.0.dev8__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 (41) hide show
  1. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/PKG-INFO +1 -1
  2. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/README.rst +3 -1
  3. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/_version.py +1 -1
  4. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/backbones/backbones_factory.py +14 -9
  5. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/backbones/inception_resnet_v2.py +2 -117
  6. segmodels_keras-0.1.0.dev8/segmodels_keras/backbones/resnet_18_34.py +368 -0
  7. segmodels_keras-0.1.0.dev8/segmodels_keras/backbones/resnet_common.py +122 -0
  8. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras.egg-info/PKG-INFO +1 -1
  9. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras.egg-info/SOURCES.txt +2 -1
  10. segmodels_keras-0.1.0.dev7/segmodels_keras/backbones/resnet.py +0 -494
  11. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/LICENSE +0 -0
  12. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/MANIFEST.in +0 -0
  13. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/pyproject.toml +0 -0
  14. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/__init__.py +0 -0
  15. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/_compat.py +0 -0
  16. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/backbones/__init__.py +0 -0
  17. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/backbones/_common_blocks.py +0 -0
  18. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/backbones/_weights.py +0 -0
  19. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/backbones/inception_v3.py +0 -0
  20. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/base/__init__.py +0 -0
  21. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/base/functional.py +0 -0
  22. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/base/objects.py +0 -0
  23. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/losses.py +0 -0
  24. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/metrics.py +0 -0
  25. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/models/__init__.py +0 -0
  26. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/models/_common_blocks.py +0 -0
  27. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/models/_utils.py +0 -0
  28. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/models/fpn.py +0 -0
  29. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/models/linknet.py +0 -0
  30. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/models/pspnet.py +0 -0
  31. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/models/unet.py +0 -0
  32. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras/utils.py +0 -0
  33. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras.egg-info/dependency_links.txt +0 -0
  34. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras.egg-info/requires.txt +0 -0
  35. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/segmodels_keras.egg-info/top_level.txt +0 -0
  36. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/setup.cfg +0 -0
  37. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/setup.py +0 -0
  38. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/tests/test_backbones.py +0 -0
  39. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/tests/test_metrics.py +0 -0
  40. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/tests/test_models.py +0 -0
  41. {segmodels_keras-0.1.0.dev7 → segmodels_keras-0.1.0.dev8}/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.dev7
3
+ Version: 0.1.0.dev8
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
@@ -24,7 +24,9 @@ improvements and support for some extra backbone models.
24
24
  It is not meant as a full replacement of the original library, but rather as a
25
25
  solution for a library I developed and depended on segmentation_models:
26
26
  `orthoseg <https://github.com/orthoseg/orthoseg>`__ . Hence, full backwards
27
- compatibility,... or support for all features is not guaranteed.
27
+ compatibility or support for all features is not an explicit goal. For example,
28
+ the resnet backbones got small changes compared to the original library, so existing
29
+ weights you saved for them won't be compatible.
28
30
 
29
31
 
30
32
  **The main features** of this library are:
@@ -1,2 +1,2 @@
1
- __versioninfo__ = (0, 1, 0, "dev7")
1
+ __versioninfo__ = (0, 1, 0, "dev8")
2
2
  __version__ = ".".join(map(str, __versioninfo__))
@@ -2,7 +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
+ from . import resnet_18_34
6
6
 
7
7
 
8
8
  class BackbonesFactory:
@@ -17,17 +17,22 @@ class BackbonesFactory:
17
17
  """
18
18
 
19
19
  _models = { # noqa: RUF012
20
- # ResNets < 50 layers are NOT available via keras.applications, so use
21
- # implementation from classification_models.
20
+ # ResNets < 50 layers are NOT available via keras.applications, so use a
21
+ # torchvision-compatible post-activation BasicBlock implementation.
22
+ # Layer names follow the keras.applications ResNet50+ naming convention.
22
23
  "resnet18": (
23
- resnet.ResNet18,
24
- resnet.preprocess_input,
25
- ("stage4_unit1_relu1", "stage3_unit1_relu1", "stage2_unit1_relu1", "relu0"),
24
+ resnet_18_34.ResNet18,
25
+ resnet_18_34.preprocess_input,
26
+ # resnet18: layer1=2, layer2=2, layer3=2, layer4=2 blocks
27
+ # backbone output = conv5_block2_out (512ch); skips are the 4 stages before it
28
+ ("conv4_block2_out", "conv3_block2_out", "conv2_block2_out", "conv1_relu"),
26
29
  ),
27
30
  "resnet34": (
28
- resnet.ResNet34,
29
- resnet.preprocess_input,
30
- ("stage4_unit1_relu1", "stage3_unit1_relu1", "stage2_unit1_relu1", "relu0"),
31
+ resnet_18_34.ResNet34,
32
+ resnet_18_34.preprocess_input,
33
+ # resnet34: layer1=3, layer2=4, layer3=6, layer4=3 blocks
34
+ # backbone output = conv5_block3_out (512ch); skips are the 4 stages before it
35
+ ("conv4_block6_out", "conv3_block4_out", "conv2_block3_out", "conv1_relu"),
31
36
  ),
32
37
  # ResNets > 50 layers are available via keras.applications, so use those.
33
38
  # Skip layers (inverted) from https://github.com/yingkaisha/keras-unet-collection
@@ -32,13 +32,14 @@ are the following:
32
32
  keras, and here we need to use the public API of keras.
33
33
  """
34
34
 
35
- import warnings
36
35
  from pathlib import Path
37
36
 
38
37
  from keras import backend, layers, models
39
38
  from keras.applications import imagenet_utils
40
39
  from keras.utils import get_file, get_source_inputs
41
40
 
41
+ from .resnet_common import _obtain_input_shape
42
+
42
43
  BASE_WEIGHT_URL = (
43
44
  "https://storage.googleapis.com/tensorflow/keras-applications/inception_resnet_v2/"
44
45
  )
@@ -442,119 +443,3 @@ def decode_predictions(preds, top=5):
442
443
 
443
444
  def get_custom_objects():
444
445
  return {"CustomScaleLayer": CustomScaleLayer}
445
-
446
-
447
- def _obtain_input_shape(
448
- input_shape,
449
- default_size,
450
- min_size,
451
- data_format,
452
- require_flatten,
453
- weights=None,
454
- ):
455
- """Internal utility to compute/validate a model's input shape.
456
-
457
- Args:
458
- input_shape: Either None (will return the default network input shape),
459
- or a user-provided shape to be validated.
460
- default_size: Default input width/height for the model.
461
- min_size: Minimum input width/height accepted by the model.
462
- data_format: Image data format to use.
463
- require_flatten: Whether the model is expected to
464
- be linked to a classifier via a Flatten layer.
465
- weights: One of `None` (random initialization)
466
- or 'imagenet' (pre-training on ImageNet).
467
- If weights='imagenet' input channels must be equal to 3.
468
-
469
- Returns:
470
- An integer shape tuple (may include None entries).
471
-
472
- Raises:
473
- ValueError: In case of invalid argument values.
474
- """
475
- if weights != "imagenet" and input_shape and len(input_shape) == 3:
476
- if data_format == "channels_first":
477
- correct_channel_axis = 1 if len(input_shape) == 4 else 0
478
- if input_shape[correct_channel_axis] not in {1, 3}:
479
- warnings.warn(
480
- "This model usually expects 1 or 3 input channels. "
481
- "However, it was passed an input_shape "
482
- f"with {input_shape[0]} input channels.",
483
- stacklevel=2,
484
- )
485
- default_shape = (input_shape[0], default_size, default_size)
486
- else:
487
- if input_shape[-1] not in {1, 3}:
488
- warnings.warn(
489
- "This model usually expects 1 or 3 input channels. "
490
- "However, it was passed an input_shape "
491
- f"with {input_shape[-1]} input channels.",
492
- stacklevel=2,
493
- )
494
- default_shape = (default_size, default_size, input_shape[-1])
495
- else:
496
- if data_format == "channels_first":
497
- default_shape = (3, default_size, default_size)
498
- else:
499
- default_shape = (default_size, default_size, 3)
500
- if weights == "imagenet" and require_flatten:
501
- if input_shape is not None:
502
- if input_shape != default_shape:
503
- raise ValueError(
504
- "When setting `include_top=True` "
505
- "and loading `imagenet` weights, "
506
- f"`input_shape` should be {default_shape}. "
507
- f"Received: input_shape={input_shape}"
508
- )
509
- return default_shape
510
- if input_shape:
511
- if data_format == "channels_first":
512
- if input_shape is not None:
513
- if len(input_shape) != 3:
514
- raise ValueError("`input_shape` must be a tuple of three integers.")
515
- if input_shape[0] != 3 and weights == "imagenet":
516
- raise ValueError(
517
- "The input must have 3 channels; Received "
518
- f"`input_shape={input_shape}`"
519
- )
520
- if (input_shape[1] is not None and input_shape[1] < min_size) or (
521
- input_shape[2] is not None and input_shape[2] < min_size
522
- ):
523
- raise ValueError(
524
- f"Input size must be at least {min_size}"
525
- f"x{min_size}; Received: "
526
- f"input_shape={input_shape}"
527
- )
528
- else:
529
- if input_shape is not None:
530
- if len(input_shape) != 3:
531
- raise ValueError("`input_shape` must be a tuple of three integers.")
532
- if input_shape[-1] != 3 and weights == "imagenet":
533
- raise ValueError(
534
- "The input must have 3 channels; Received "
535
- f"`input_shape={input_shape}`"
536
- )
537
- if (input_shape[0] is not None and input_shape[0] < min_size) or (
538
- input_shape[1] is not None and input_shape[1] < min_size
539
- ):
540
- raise ValueError(
541
- "Input size must be at least "
542
- f"{min_size}x{min_size}; Received: "
543
- f"input_shape={input_shape}"
544
- )
545
- else:
546
- if require_flatten:
547
- input_shape = default_shape
548
- else:
549
- if data_format == "channels_first":
550
- input_shape = (3, None, None)
551
- else:
552
- input_shape = (None, None, 3)
553
- if require_flatten:
554
- if None in input_shape:
555
- raise ValueError(
556
- "If `include_top` is True, "
557
- "you should specify a static `input_shape`. "
558
- f"Received: input_shape={input_shape}"
559
- )
560
- return input_shape
@@ -0,0 +1,368 @@
1
+ """ResNet18 and ResNet34 Keras models.
2
+
3
+ Complements keras.applications (which provides ResNet50+) with BasicBlock-based
4
+ ResNet18 and ResNet34. The implementation follows the keras.applications structure
5
+ closely so that the two can be maintained together:
6
+
7
+ - ``ResNet(stack_fn, ...)`` is the generic builder, matching the signature of
8
+ ``keras.applications.resnet.ResNet``.
9
+ - ``residual_basicblock(x, filters, ..., name)`` is the BasicBlock equivalent of
10
+ ``keras.applications.resnet.residual_block_v1``.
11
+ - ``stack_residual_basicblocks(x, filters, blocks, ..., name)`` groups blocks into a
12
+ stage, equivalent to ``keras.applications.resnet.stack_residual_blocks_v1``.
13
+
14
+ Layer naming follows the same ``conv{N}_block{M}_*`` convention used by
15
+ keras.applications, so models built here share the same weight-loading patterns.
16
+
17
+ Note that the resulting resnet18 and resnet34 are not exactly the same as the version
18
+ in https://github.com/qubvel/classification_models and hence is also different than
19
+ the segmentation models in https://github.com/qubvel/segmentation_models.
20
+ There are some differences in the bottom and top layers of the resnet, e.g. because
21
+ the classification_models version applies also post-activation after the last residual
22
+ block.
23
+
24
+ This implementation is designed to be compatible with torchvision ResNet18/34 pretrained
25
+ weights. Because the resnet implementation in keras.applications.resnet.ResNet (which
26
+ only supports ResNet50+) already uses the same bottom and top layers this implementation
27
+ is based on it, but in addition the following tweaks have been applied:
28
+ - BatchNormalization uses ``momentum=0.9`` and ``epsilon=1e-5`` (torchvision defaults)
29
+ instead of the keras.applications defaults of ``momentum=0.99`` and
30
+ ``epsilon=1.001e-5``.
31
+ Note that momentum is only used during training. In addition, the value in pytorch
32
+ is inverted compared to the tf.keras implementation, so the default in pytorch
33
+ is actually ``momentum=0.1``, but after inversion we use ``momentum=0.9`` here.
34
+ - The single bottom convolutional layer gets ``use_bias=False`` (like all convolutional
35
+ layers in the model just like the version in torchvision and in segmentation_models.
36
+ In the keras.applications ResNet(50+) implementation ``use_bias=True`` is used for the
37
+ single bottom convolutional layer.
38
+ """
39
+
40
+ import os
41
+
42
+ from keras import backend, layers, models
43
+ from keras.applications import imagenet_utils
44
+ from keras.utils import get_source_inputs
45
+
46
+ from .resnet_common import _obtain_input_shape
47
+
48
+
49
+ def ResNet(
50
+ stack_fn,
51
+ preact,
52
+ use_bias,
53
+ include_top=True,
54
+ weights=None,
55
+ input_tensor=None,
56
+ input_shape=None,
57
+ pooling=None,
58
+ classes=1000,
59
+ classifier_activation="softmax",
60
+ name="resnet",
61
+ ):
62
+ """Generic ResNet builder for BasicBlock variants (ResNet18/34).
63
+
64
+ Follows the same signature as ``keras.applications.resnet.ResNet`` so that
65
+ both can be used interchangeably.
66
+
67
+ Args:
68
+ stack_fn: A function that returns output tensor for the
69
+ stacked residual blocks.
70
+ preact: Whether to use pre-activation (BN before conv). `True` for ResNetV2,
71
+ `False` (post-activation) for ResNet (including ResNet18/34) and ResNeXt.
72
+ use_bias: Whether to use bias for the single bottom convolutional layer or not.
73
+ `True` for ResNet and ResNetV2 in the standard keras.applications
74
+ implementation, `False` for ResNeXt. However, for torchvision compatibility
75
+ we will use False here for ResNet18/34.
76
+ include_top: Whether to include the fully-connected layer at the top of the
77
+ network (=classification head). Defaults to ``True``.
78
+ weights: Path to a weights file to load, or ``None``. Defaults to
79
+ ``None``.
80
+ input_tensor: Optional Keras tensor to use as the model input.
81
+ (i.e. output of `layers.Input()`)
82
+ input_shape: Optional shape tuple, only to be specified
83
+ if `include_top` is `False` (otherwise the input shape
84
+ has to be `(224, 224, 3)` (with `channels_last` data format)
85
+ or `(3, 224, 224)` (with `"channels_first"` data format). It
86
+ should have exactly 3 inputs channels.
87
+ pooling: Optional pooling mode for feature extraction
88
+ when `include_top` is `False`.
89
+ - `None` means that the output of the model will be
90
+ the 4D tensor output of the
91
+ last convolutional layer.
92
+ - `avg` means that global average pooling
93
+ will be applied to the output of the
94
+ last convolutional layer, and thus
95
+ the output of the model will be a 2D tensor.
96
+ - `max` means that global max pooling will
97
+ be applied.
98
+ classes: optional number of classes to classify images
99
+ into, only to be specified if `include_top` is `True`,
100
+ and if no `weights` argument is specified.
101
+ Defaults to ``1000``.
102
+ classifier_activation: A `str` or callable. The activation
103
+ function to use on the "top" layer. Ignored unless
104
+ `include_top=True`. Set `classifier_activation=None` to
105
+ return the logits of the "top" layer. When loading
106
+ pretrained weights, `classifier_activation` can only be
107
+ `None` or `"softmax"`. Defaults to ``"softmax"``.
108
+ name: The name of the model (string). Defaults to ``"resnet"``.
109
+
110
+ Returns:
111
+ A ``keras.Model`` instance.
112
+ """
113
+
114
+ # Determine proper input shape
115
+ input_shape = _obtain_input_shape(
116
+ input_shape,
117
+ default_size=224,
118
+ min_size=32,
119
+ data_format=backend.image_data_format(),
120
+ require_flatten=include_top,
121
+ weights=weights,
122
+ )
123
+
124
+ if input_tensor is None:
125
+ img_input = layers.Input(shape=input_shape)
126
+ else:
127
+ if not backend.is_keras_tensor(input_tensor):
128
+ img_input = layers.Input(tensor=input_tensor, shape=input_shape)
129
+ else:
130
+ img_input = input_tensor
131
+
132
+ if backend.image_data_format() == "channels_last":
133
+ bn_axis = 3
134
+ else:
135
+ bn_axis = 1
136
+
137
+ x = layers.ZeroPadding2D(padding=((3, 3), (3, 3)), name="conv1_pad")(img_input)
138
+ x = layers.Conv2D(64, 7, strides=2, use_bias=use_bias, name="conv1_conv")(x)
139
+
140
+ if not preact:
141
+ # The batchnormalization parameters have been changed to be compatible with the
142
+ # torchvision ResNet18/34 pretrained weights.
143
+ x = layers.BatchNormalization(
144
+ axis=bn_axis, momentum=0.1, epsilon=1e-5, name="conv1_bn"
145
+ )(x)
146
+ x = layers.Activation("relu", name="conv1_relu")(x)
147
+
148
+ x = layers.ZeroPadding2D(padding=((1, 1), (1, 1)), name="pool1_pad")(x)
149
+ x = layers.MaxPooling2D(3, strides=2, name="pool1_pool")(x)
150
+
151
+ x = stack_fn(x)
152
+
153
+ if preact:
154
+ # The batchnormalization parameters have been changed to be compatible with the
155
+ # torchvision ResNet18/34 pretrained weights.
156
+ x = layers.BatchNormalization(
157
+ axis=bn_axis, momentum=0.1, epsilon=1e-5, name="post_bn"
158
+ )(x)
159
+ x = layers.Activation("relu", name="post_relu")(x)
160
+
161
+ if include_top:
162
+ x = layers.GlobalAveragePooling2D(name="avg_pool")(x)
163
+
164
+ # Validate activation for the classifier layer
165
+ imagenet_utils.validate_activation(classifier_activation, weights)
166
+
167
+ x = layers.Dense(classes, activation=classifier_activation, name="predictions")(
168
+ x
169
+ )
170
+ else:
171
+ if pooling == "avg":
172
+ x = layers.GlobalAveragePooling2D(name="avg_pool")(x)
173
+ elif pooling == "max":
174
+ x = layers.GlobalMaxPooling2D(name="max_pool")(x)
175
+
176
+ # Ensure that the model takes into account
177
+ # any potential predecessors of `input_tensor`.
178
+ if input_tensor is not None:
179
+ inputs = get_source_inputs(input_tensor)
180
+ else:
181
+ inputs = img_input
182
+
183
+ # Create model.
184
+ model = models.Model(inputs, x, name=name)
185
+
186
+ if weights is not None and os.path.exists(weights):
187
+ model.load_weights(weights)
188
+
189
+ return model
190
+
191
+
192
+ def residual_basicblock(
193
+ x, filters, kernel_size=3, stride=1, conv_shortcut=True, name=None
194
+ ):
195
+ """A BasicBlock residual block for ResNet18/34.
196
+
197
+ Similar to ``keras.applications.resnet.residual_block_v1`` that is used for
198
+ ResNet50+, but with following differences for resnet 18/34:
199
+ - two 3x3 convolutions instead of the 1x1 / 3x3 / 1x1 bottleneck.
200
+ - ``use_bias=False`` instead of ``True``
201
+
202
+ Following changes have been applied to be compatible with torchvision ResNet18/34
203
+ pretrained weights:
204
+ - BN momentum is set to 0.1 instead of 0.99
205
+ - BN epsilon is set to 1e-5 instead of 1.001e-5
206
+
207
+ Args:
208
+ x: Input tensor.
209
+ filters: No of filters for both 3x3 convolutions.
210
+ kernel_size: Kernel size of the 3x3 convolutions. Defaults to ``3``.
211
+ stride: Stride of the first convolution. Defaults to ``1``.
212
+ conv_shortcut: Use a strided 1x1 conv on the shortcut path if ``True``,
213
+ otherwise use an identity shortcut. Defaults to ``True``.
214
+ name: Block name prefix, e.g. ``"conv3_block1"``.
215
+
216
+ Returns:
217
+ Output tensor for the block.
218
+ """
219
+ if backend.image_data_format() == "channels_last":
220
+ bn_axis = 3
221
+ else:
222
+ bn_axis = 1
223
+
224
+ if conv_shortcut:
225
+ shortcut = layers.Conv2D(
226
+ filters, 1, strides=stride, use_bias=False, name=f"{name}_0_conv"
227
+ )(x)
228
+ shortcut = layers.BatchNormalization(
229
+ axis=bn_axis, momentum=0.1, epsilon=1e-5, name=f"{name}_0_bn"
230
+ )(shortcut)
231
+ else:
232
+ shortcut = x
233
+
234
+ x = layers.ZeroPadding2D(padding=((1, 1), (1, 1)), name=f"{name}_1_pad")(x)
235
+ x = layers.Conv2D(
236
+ filters, kernel_size, strides=stride, use_bias=False, name=f"{name}_1_conv"
237
+ )(x)
238
+ x = layers.BatchNormalization(
239
+ axis=bn_axis, momentum=0.1, epsilon=1e-5, name=f"{name}_1_bn"
240
+ )(x)
241
+ x = layers.Activation("relu", name=f"{name}_1_relu")(x)
242
+
243
+ x = layers.ZeroPadding2D(padding=((1, 1), (1, 1)), name=f"{name}_2_pad")(x)
244
+ x = layers.Conv2D(filters, kernel_size, use_bias=False, name=f"{name}_2_conv")(x)
245
+ x = layers.BatchNormalization(
246
+ axis=bn_axis, momentum=0.1, epsilon=1e-5, name=f"{name}_2_bn"
247
+ )(x)
248
+
249
+ x = layers.Add(name=f"{name}_add")([shortcut, x])
250
+ x = layers.Activation("relu", name=f"{name}_out")(x)
251
+ return x
252
+
253
+
254
+ def stack_residual_basicblocks(x, filters, blocks, stride1=2, name=None):
255
+ """A set of stacked BasicBlock residual blocks forming one ResNet stage.
256
+
257
+ Similar to ``keras.applications.resnet.stack_residual_blocks_v1``.
258
+
259
+ Args:
260
+ x: Input tensor.
261
+ filters: Number of filters for all blocks in this stage.
262
+ blocks: Number of BasicBlocks in the stage.
263
+ stride1: Stride of the first block (use ``2`` to downsample spatially,
264
+ ``1`` for the first stage where spatial size is unchanged). Defaults
265
+ to ``2``.
266
+ name: Stage name prefix, e.g. ``"conv3"``.
267
+
268
+ Returns:
269
+ Output tensor for the stacked blocks.
270
+ """
271
+ x = residual_basicblock(
272
+ x, filters, stride=stride1, conv_shortcut=stride1 > 1, name=f"{name}_block1"
273
+ )
274
+ for i in range(2, blocks + 1):
275
+ x = residual_basicblock(
276
+ x, filters, conv_shortcut=False, name=f"{name}_block{i}"
277
+ )
278
+ return x
279
+
280
+
281
+ def ResNet18(
282
+ include_top=True,
283
+ weights=None,
284
+ input_tensor=None,
285
+ input_shape=None,
286
+ pooling=None,
287
+ classes=1000,
288
+ classifier_activation="softmax",
289
+ name="resnet18",
290
+ use_bias=False,
291
+ ):
292
+ """Instantiates the ResNet18 architecture with torchvision-compatible tweaks.
293
+
294
+ Remark: torchvision uses bias=False, keras.applications ResNet uses bias=True, but
295
+ for torchvision compatibility we will use False here.
296
+ """
297
+
298
+ def stack_fn(x):
299
+ x = stack_residual_basicblocks(x, 64, 2, stride1=1, name="conv2")
300
+ x = stack_residual_basicblocks(x, 128, 2, stride1=2, name="conv3")
301
+ x = stack_residual_basicblocks(x, 256, 2, stride1=2, name="conv4")
302
+ return stack_residual_basicblocks(x, 512, 2, stride1=2, name="conv5")
303
+
304
+ return ResNet(
305
+ stack_fn,
306
+ preact=False, # torchvision ResNet18/34 is post-activation (Conv -> BN -> ReLU)
307
+ use_bias=use_bias,
308
+ name=name,
309
+ include_top=include_top,
310
+ weights=weights,
311
+ input_tensor=input_tensor,
312
+ input_shape=input_shape,
313
+ pooling=pooling,
314
+ classes=classes,
315
+ classifier_activation=classifier_activation,
316
+ )
317
+
318
+
319
+ def ResNet34(
320
+ include_top=True,
321
+ weights=None,
322
+ input_tensor=None,
323
+ input_shape=None,
324
+ pooling=None,
325
+ classes=1000,
326
+ classifier_activation="softmax",
327
+ name="resnet34",
328
+ use_bias=False,
329
+ ):
330
+ """Instantiates the ResNet34 architecture with torchvision-compatible tweaks.
331
+
332
+ Remark: torchvision uses bias=False, keras.applications ResNet uses bias=True, but
333
+ for torchvision compatibility we will use False here.
334
+ """
335
+
336
+ def stack_fn(x):
337
+ x = stack_residual_basicblocks(x, 64, 3, stride1=1, name="conv2")
338
+ x = stack_residual_basicblocks(x, 128, 4, stride1=2, name="conv3")
339
+ x = stack_residual_basicblocks(x, 256, 6, stride1=2, name="conv4")
340
+ return stack_residual_basicblocks(x, 512, 3, stride1=2, name="conv5")
341
+
342
+ return ResNet(
343
+ stack_fn,
344
+ preact=False, # torchvision ResNet18/34 is post-activation (Conv -> BN -> ReLU)
345
+ use_bias=use_bias,
346
+ name=name,
347
+ include_top=include_top,
348
+ weights=weights,
349
+ input_tensor=input_tensor,
350
+ input_shape=input_shape,
351
+ pooling=pooling,
352
+ classes=classes,
353
+ classifier_activation=classifier_activation,
354
+ )
355
+
356
+
357
+ def preprocess_input(x, **kwargs):
358
+ """Torchvision-compatible ImageNet normalization (input in [0, 1])."""
359
+ import numpy as np
360
+
361
+ # FLAIR-compatible normalization (input in [0, 255]).
362
+ mean = np.array([105.08, 110.87, 101.82, 106.38, 53.26], dtype="float32")
363
+ std = np.array([52.17, 45.38, 44, 39.69, 79.3], dtype="float32")
364
+
365
+ # Torchvision-compatible ImageNet normalization (input in [0, 1]).
366
+ # mean = np.array([0.485, 0.456, 0.406], dtype="float32")
367
+ # std = np.array([0.229, 0.224, 0.225], dtype="float32")
368
+ return (x - mean) / std
@@ -0,0 +1,122 @@
1
+ """Some common utilities for ResNet backbones.
2
+
3
+ Source: keras.applications.
4
+ """
5
+
6
+ import warnings
7
+
8
+
9
+ def _obtain_input_shape(
10
+ input_shape,
11
+ default_size,
12
+ min_size,
13
+ data_format,
14
+ require_flatten,
15
+ weights=None,
16
+ ):
17
+ """Internal utility to compute/validate a model's input shape.
18
+
19
+ Args:
20
+ input_shape: Either None (will return the default network input shape),
21
+ or a user-provided shape to be validated.
22
+ default_size: Default input width/height for the model.
23
+ min_size: Minimum input width/height accepted by the model.
24
+ data_format: Image data format to use.
25
+ require_flatten: Whether the model is expected to
26
+ be linked to a classifier via a Flatten layer.
27
+ weights: One of `None` (random initialization)
28
+ or 'imagenet' (pre-training on ImageNet).
29
+ If weights='imagenet' input channels must be equal to 3.
30
+
31
+ Returns:
32
+ An integer shape tuple (may include None entries).
33
+
34
+ Raises:
35
+ ValueError: In case of invalid argument values.
36
+ """
37
+ if weights != "imagenet" and input_shape and len(input_shape) == 3:
38
+ if data_format == "channels_first":
39
+ correct_channel_axis = 1 if len(input_shape) == 4 else 0
40
+ if input_shape[correct_channel_axis] not in {1, 3}:
41
+ warnings.warn(
42
+ "This model usually expects 1 or 3 input channels. "
43
+ "However, it was passed an input_shape "
44
+ f"with {input_shape[0]} input channels.",
45
+ stacklevel=2,
46
+ )
47
+ default_shape = (input_shape[0], default_size, default_size)
48
+ else:
49
+ if input_shape[-1] not in {1, 3}:
50
+ warnings.warn(
51
+ "This model usually expects 1 or 3 input channels. "
52
+ "However, it was passed an input_shape "
53
+ f"with {input_shape[-1]} input channels.",
54
+ stacklevel=2,
55
+ )
56
+ default_shape = (default_size, default_size, input_shape[-1])
57
+ else:
58
+ if data_format == "channels_first":
59
+ default_shape = (3, default_size, default_size)
60
+ else:
61
+ default_shape = (default_size, default_size, 3)
62
+ if weights == "imagenet" and require_flatten:
63
+ if input_shape is not None:
64
+ if input_shape != default_shape:
65
+ raise ValueError(
66
+ "When setting `include_top=True` "
67
+ "and loading `imagenet` weights, "
68
+ f"`input_shape` should be {default_shape}. "
69
+ f"Received: input_shape={input_shape}"
70
+ )
71
+ return default_shape
72
+ if input_shape:
73
+ if data_format == "channels_first":
74
+ if input_shape is not None:
75
+ if len(input_shape) != 3:
76
+ raise ValueError("`input_shape` must be a tuple of three integers.")
77
+ if input_shape[0] != 3 and weights == "imagenet":
78
+ raise ValueError(
79
+ "The input must have 3 channels; Received "
80
+ f"`input_shape={input_shape}`"
81
+ )
82
+ if (input_shape[1] is not None and input_shape[1] < min_size) or (
83
+ input_shape[2] is not None and input_shape[2] < min_size
84
+ ):
85
+ raise ValueError(
86
+ f"Input size must be at least {min_size}"
87
+ f"x{min_size}; Received: "
88
+ f"input_shape={input_shape}"
89
+ )
90
+ else:
91
+ if input_shape is not None:
92
+ if len(input_shape) != 3:
93
+ raise ValueError("`input_shape` must be a tuple of three integers.")
94
+ if input_shape[-1] != 3 and weights == "imagenet":
95
+ raise ValueError(
96
+ "The input must have 3 channels; Received "
97
+ f"`input_shape={input_shape}`"
98
+ )
99
+ if (input_shape[0] is not None and input_shape[0] < min_size) or (
100
+ input_shape[1] is not None and input_shape[1] < min_size
101
+ ):
102
+ raise ValueError(
103
+ "Input size must be at least "
104
+ f"{min_size}x{min_size}; Received: "
105
+ f"input_shape={input_shape}"
106
+ )
107
+ else:
108
+ if require_flatten:
109
+ input_shape = default_shape
110
+ else:
111
+ if data_format == "channels_first":
112
+ input_shape = (3, None, None)
113
+ else:
114
+ input_shape = (None, None, 3)
115
+ if require_flatten:
116
+ if None in input_shape:
117
+ raise ValueError(
118
+ "If `include_top` is True, "
119
+ "you should specify a static `input_shape`. "
120
+ f"Received: input_shape={input_shape}"
121
+ )
122
+ return input_shape
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: segmodels_keras
3
- Version: 0.1.0.dev7
3
+ Version: 0.1.0.dev8
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
@@ -20,7 +20,8 @@ segmodels_keras/backbones/_weights.py
20
20
  segmodels_keras/backbones/backbones_factory.py
21
21
  segmodels_keras/backbones/inception_resnet_v2.py
22
22
  segmodels_keras/backbones/inception_v3.py
23
- segmodels_keras/backbones/resnet.py
23
+ segmodels_keras/backbones/resnet_18_34.py
24
+ segmodels_keras/backbones/resnet_common.py
24
25
  segmodels_keras/base/__init__.py
25
26
  segmodels_keras/base/functional.py
26
27
  segmodels_keras/base/objects.py
@@ -1,494 +0,0 @@
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__