segmodels-keras 0.1.0.dev12__tar.gz → 0.1.0.dev13__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 (45) hide show
  1. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/PKG-INFO +1 -1
  2. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/pyproject.toml +1 -0
  3. segmodels_keras-0.1.0.dev13/segmodels_keras/_version.py +2 -0
  4. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/backbones/backbones_factory.py +45 -30
  5. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras.egg-info/PKG-INFO +1 -1
  6. segmodels_keras-0.1.0.dev13/tests/test_backbones.py +23 -0
  7. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/tests/test_models.py +49 -78
  8. segmodels_keras-0.1.0.dev12/segmodels_keras/_version.py +0 -2
  9. segmodels_keras-0.1.0.dev12/tests/test_backbones.py +0 -57
  10. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/LICENSE +0 -0
  11. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/MANIFEST.in +0 -0
  12. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/README.rst +0 -0
  13. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/__init__.py +0 -0
  14. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/_compat.py +0 -0
  15. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/backbones/__init__.py +0 -0
  16. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/backbones/_common_blocks.py +0 -0
  17. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/backbones/_weights.py +0 -0
  18. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/backbones/inception_resnet_v2.py +0 -0
  19. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/backbones/inception_v3.py +0 -0
  20. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/backbones/resnet_18_34.py +0 -0
  21. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/backbones/resnet_common.py +0 -0
  22. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/base/__init__.py +0 -0
  23. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/base/functional.py +0 -0
  24. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/base/objects.py +0 -0
  25. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/losses.py +0 -0
  26. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/metrics.py +0 -0
  27. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/models/__init__.py +0 -0
  28. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/models/_common_blocks.py +0 -0
  29. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/models/_utils.py +0 -0
  30. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/models/fpn.py +0 -0
  31. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/models/linknet.py +0 -0
  32. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/models/model_factory.py +0 -0
  33. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/models/pspnet.py +0 -0
  34. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/models/unet.py +0 -0
  35. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/py.typed +0 -0
  36. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras/utils.py +0 -0
  37. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras.egg-info/SOURCES.txt +0 -0
  38. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras.egg-info/dependency_links.txt +0 -0
  39. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras.egg-info/requires.txt +0 -0
  40. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/segmodels_keras.egg-info/top_level.txt +0 -0
  41. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/setup.cfg +0 -0
  42. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/setup.py +0 -0
  43. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/tests/test_helper.py +0 -0
  44. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/tests/test_metrics.py +0 -0
  45. {segmodels_keras-0.1.0.dev12 → segmodels_keras-0.1.0.dev13}/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.dev12
3
+ Version: 0.1.0.dev13
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
@@ -51,6 +51,7 @@ ignore = [
51
51
  ### Intentionally disabled
52
52
  "E402", # Module level import not at top of file
53
53
  "PLR0913", # Too many arguments to function call
54
+ "PLR0917", # Too many positional arguments
54
55
  "PLR0911", # Too many returns
55
56
  "PLR0912", # Too many branches
56
57
  "PLR0915", # Too many statements
@@ -0,0 +1,2 @@
1
+ __versioninfo__: tuple[int, int, int, str] = (0, 1, 0, "dev13")
2
+ __version__: str = ".".join(map(str, __versioninfo__))
@@ -307,43 +307,68 @@ class BackbonesFactory:
307
307
  # Stage layout differs from EfficientNet-Bx.
308
308
  # Skip layers selected to match decoder resolutions:
309
309
  # x16 -> x8 -> x4 -> x2
310
- "efficientnetv2s": (
311
- ka.EfficientNetV2S,
310
+ #
311
+ # Tests with more compact skip connection layers ("block5i_add" (32x32x160),
312
+ # "block3d_add" (64x64x64), "block2d_add" (128x128x48), "stem_activation"
313
+ # (256x256x24)) showed that the decrease in model size was small (30 MB) but
314
+ # the accuracy performance impact was significant (-1.5%).
315
+ "efficientnetv2b0": (
316
+ ka.EfficientNetV2B0,
312
317
  ka.efficientnet_v2.preprocess_input,
313
318
  (
314
- "block6a_expand_conv", # 32x32x960
315
- "block4a_expand_conv", # 64x64x256
316
- "block2a_expand_activation", # 128x128x96
317
- "stem_activation", # 256x256x24
319
+ "block4b_expand_conv", # 32x32x384
320
+ "block3a_expand_conv", # 64x64x128
321
+ "block2a_expand_activation", # 128x128x64
322
+ "stem_activation", # 256x256x32
318
323
  ),
319
324
  ),
320
- "efficientnetv2s-ss": (
321
- ka.EfficientNetV2S,
325
+ "efficientnetv2b1": (
326
+ ka.EfficientNetV2B1,
322
327
  ka.efficientnet_v2.preprocess_input,
323
328
  (
324
- "block5i_add", # 32x32x160
325
- "block3d_add", # 64x64x64
326
- "block2d_add", # 128x128x48
327
- "stem_activation", # 256x256x24
329
+ "block4b_expand_conv", # 32x32x384
330
+ "block3a_expand_conv", # 64x64x128
331
+ "block2a_expand_activation", # 128x128x64
332
+ "stem_activation", # 256x256x32
328
333
  ),
329
334
  ),
330
- "efficientnetv2m": (
331
- ka.EfficientNetV2M,
335
+ "efficientnetv2b2": (
336
+ ka.EfficientNetV2B2,
332
337
  ka.efficientnet_v2.preprocess_input,
333
338
  (
334
- "block6a_expand_conv", # 32x32x1056
335
- "block4a_expand_conv", # 64x64x320
339
+ "block4b_expand_conv", # 32x32x416
340
+ "block3a_expand_conv", # 64x64x128
341
+ "block2a_expand_activation", # 128x128x64
342
+ "stem_activation", # 256x256x32
343
+ ),
344
+ ),
345
+ "efficientnetv2b3": (
346
+ ka.EfficientNetV2B3,
347
+ ka.efficientnet_v2.preprocess_input,
348
+ (
349
+ "block4b_expand_conv", # 32x32x448
350
+ "block3a_expand_conv", # 64x64x160
351
+ "block2a_expand_activation", # 128x128x64
352
+ "stem_activation", # 256x256x40
353
+ ),
354
+ ),
355
+ "efficientnetv2s": (
356
+ ka.EfficientNetV2S,
357
+ ka.efficientnet_v2.preprocess_input,
358
+ (
359
+ "block6a_expand_conv", # 32x32x960
360
+ "block4a_expand_conv", # 64x64x256
336
361
  "block2a_expand_activation", # 128x128x96
337
362
  "stem_activation", # 256x256x24
338
363
  ),
339
364
  ),
340
- "efficientnetv2m-ss": (
365
+ "efficientnetv2m": (
341
366
  ka.EfficientNetV2M,
342
367
  ka.efficientnet_v2.preprocess_input,
343
368
  (
344
- "block5n_add", # 32x32x176
345
- "block3e_add", # 64x64x80
346
- "block2e_add", # 128x128x48
369
+ "block6a_expand_conv", # 32x32x1056
370
+ "block4a_expand_conv", # 64x64x320
371
+ "block2a_expand_activation", # 128x128x96
347
372
  "stem_activation", # 256x256x24
348
373
  ),
349
374
  ),
@@ -357,16 +382,6 @@ class BackbonesFactory:
357
382
  "stem_activation", # 256x256x32
358
383
  ),
359
384
  ),
360
- "efficientnetv2l-ss": (
361
- ka.EfficientNetV2L,
362
- ka.efficientnet_v2.preprocess_input,
363
- (
364
- "block5s_add", # 32x32x224
365
- "block3g_add", # 64x64x96
366
- "block2g_add", # 128x128x64
367
- "stem_activation", # 256x256x32
368
- ),
369
- ),
370
385
  }
371
386
 
372
387
  @property
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: segmodels_keras
3
- Version: 0.1.0.dev12
3
+ Version: 0.1.0.dev13
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
@@ -0,0 +1,23 @@
1
+ """Tests on the backbone factory and backbone retrieval."""
2
+
3
+ import pytest
4
+
5
+ from segmodels_keras.backbones.backbones_factory import BackbonesFactory
6
+
7
+
8
+ def test_backbones_factory():
9
+ factory = BackbonesFactory()
10
+ assert len(factory.models) > 0
11
+
12
+ for name in factory.models.keys():
13
+ model_fn, preprocess_fn, layers = factory.models[name]
14
+ assert callable(model_fn)
15
+ assert callable(preprocess_fn)
16
+ assert isinstance(layers, tuple)
17
+
18
+
19
+ def test_get_backbone_unknown():
20
+ factory = BackbonesFactory()
21
+
22
+ with pytest.raises(ValueError):
23
+ factory.get_backbone("unknown")
@@ -22,28 +22,25 @@ def str2bool(v):
22
22
  return v.lower() in ("yes", "true", "t", "1")
23
23
 
24
24
 
25
- def get_test_backbones():
26
- is_full = str2bool(os.environ.get("FULL_TEST", "False"))
25
+ def get_test_backbones(with_weights: bool):
26
+ if with_weights:
27
+ is_full = str2bool(os.environ.get("FULL_TEST", "False"))
28
+ else:
29
+ is_full = str2bool(os.environ.get("FULL_TEST_WEIGHTS", "False"))
30
+
27
31
  if not is_full:
28
- return [
29
- "resnet34",
30
- "resnet50",
31
- "inceptionresnetv2",
32
- "efficientnetb0",
33
- "efficientnetv2s",
34
- "efficientnetv2s-ss",
35
- "efficientnetv2m-ss",
36
- "efficientnetv2l-ss",
37
- ]
32
+ return ["resnet34", "resnet50", "inceptionresnetv2", "efficientnetb0"]
38
33
  else:
39
34
  return get_available_backbone_names()
40
35
 
41
36
 
42
37
  def keras_test(func):
43
38
  """Function wrapper to clean up after TensorFlow tests.
44
- # Arguments
39
+
40
+ Args:
45
41
  func: test function to clean up after.
46
- # Returns
42
+
43
+ Returns:
47
44
  A function wrapping the input function.
48
45
  """
49
46
 
@@ -56,40 +53,37 @@ def keras_test(func):
56
53
  return wrapper
57
54
 
58
55
 
59
- @pytest.mark.parametrize("backbone_name", get_test_backbones())
56
+ @pytest.mark.parametrize("backbone_name", get_test_backbones(with_weights=False))
60
57
  @pytest.mark.parametrize(
61
- "model_name, input_shape, encoder_weights",
58
+ "model_name, input_shape",
62
59
  [
63
- ("unet", None, None),
64
- ("unet", None, "imagenet"),
65
- ("unet", (256, 256, 4), None),
66
- ("linknet", None, None),
67
- ("linknet", (256, 256, 4), None),
68
- ("pspnet", (384, 384, 4), None),
69
- ("fpn", None, None),
70
- ("fpn", (256, 256, 4), None),
60
+ ("unet", None),
61
+ ("unet", (256, 256, 4)),
62
+ ("linknet", None),
63
+ ("linknet", (256, 256, 4)),
64
+ ("pspnet", (384, 384, 4)),
65
+ ("fpn", None),
66
+ ("fpn", (256, 256, 4)),
71
67
  ],
72
68
  )
73
69
  @keras_test
74
- def test_get_model(model_name, backbone_name, input_shape, encoder_weights):
75
- """Test all segmentation models with different backbones.
70
+ def test_get_model(model_name, backbone_name, input_shape):
71
+ """Test creation of model/backbone combinations.
76
72
 
77
- input_shape=None means any shape (32x32 used in test), otherwise a fixed shape is
78
- used.
73
+ No weights are used in this test to avoid downloading pretrained models.
79
74
  """
80
- n_channels = 3 if input_shape is None else input_shape[-1]
81
- test_shape = (1, 32, 32, n_channels) if input_shape is None else (1, *input_shape)
75
+ _assert_get_model_output_shape(model_name, backbone_name, input_shape, None)
82
76
 
83
- x = np.ones(test_shape)
84
- model = get_model(
85
- model_name,
86
- backbone_name=backbone_name,
87
- input_shape=input_shape or (None, None, n_channels),
88
- encoder_weights=encoder_weights,
89
- )
90
- y = model.predict(x)
91
77
 
92
- assert x.shape[:-1] == y.shape[:-1]
78
+ @pytest.mark.parametrize("backbone_name", get_test_backbones(with_weights=True))
79
+ @keras_test
80
+ def test_get_model_with_imagenet_weights(backbone_name):
81
+ """Test model creation with ImageNet-pretrained encoder weights.
82
+
83
+ Only tested on a limited set of backbones as this will download the pretrained
84
+ weights.
85
+ """
86
+ _assert_get_model_output_shape("unet", backbone_name, None, "imagenet")
93
87
 
94
88
 
95
89
  def test_get_model_invalid_name():
@@ -98,43 +92,6 @@ def test_get_model_invalid_name():
98
92
  get_model("invalid_model")
99
93
 
100
94
 
101
- @pytest.mark.parametrize(
102
- "standard_backbone, compact_backbone, expected_parameter_reduction",
103
- [
104
- ("efficientnetv2s", "efficientnetv2s-ss", 2_092_032),
105
- ("efficientnetv2m", "efficientnetv2m-ss", 2_331_648),
106
- ("efficientnetv2l", "efficientnetv2l-ss", 2_949_120),
107
- ],
108
- )
109
- @keras_test
110
- def test_efficientnetv2_compact_skips_reduce_unet_parameters(
111
- standard_backbone, compact_backbone, expected_parameter_reduction
112
- ):
113
- input_shape = (32, 32, 3)
114
- standard_model = get_model(
115
- "unet",
116
- backbone_name=standard_backbone,
117
- input_shape=input_shape,
118
- encoder_weights=None,
119
- )
120
- standard_params = standard_model.count_params()
121
- standard_output_shape = standard_model.output_shape
122
- del standard_model
123
- keras.backend.clear_session()
124
-
125
- compact_model = get_model(
126
- "unet",
127
- backbone_name=compact_backbone,
128
- input_shape=input_shape,
129
- encoder_weights=None,
130
- )
131
-
132
- assert compact_model.output_shape == standard_output_shape
133
- assert (
134
- standard_params - compact_model.count_params() == expected_parameter_reduction
135
- )
136
-
137
-
138
95
  def test_get_model_weights_notop_keras2():
139
96
  """Test loading a Keras v2 style HDF5 weight file."""
140
97
  weights_path = data_dir / "mobilenetv2+linknet_notop_k2.weights.h5"
@@ -153,5 +110,19 @@ def test_get_model_weights_notop_keras3():
153
110
  assert len(model.layers) > 0
154
111
 
155
112
 
156
- if __name__ == "__main__":
157
- pytest.main([__file__])
113
+ def _assert_get_model_output_shape(
114
+ model_name, backbone_name, input_shape, encoder_weights
115
+ ):
116
+ n_channels = 3 if input_shape is None else input_shape[-1]
117
+ test_shape = (1, 32, 32, n_channels) if input_shape is None else (1, *input_shape)
118
+
119
+ x = np.ones(test_shape)
120
+ model = get_model(
121
+ model_name,
122
+ backbone_name=backbone_name,
123
+ input_shape=input_shape or (None, None, n_channels),
124
+ encoder_weights=encoder_weights,
125
+ )
126
+ y = model.predict(x)
127
+
128
+ assert x.shape[:-1] == y.shape[:-1]
@@ -1,2 +0,0 @@
1
- __versioninfo__: tuple[int, int, int, str] = (0, 1, 0, "dev12")
2
- __version__: str = ".".join(map(str, __versioninfo__))
@@ -1,57 +0,0 @@
1
- """Tests on the backbone factory and backbone retrieval."""
2
-
3
- import pytest
4
-
5
- from segmodels_keras.backbones.backbones_factory import BackbonesFactory
6
-
7
-
8
- def test_backbones_factory():
9
- factory = BackbonesFactory()
10
- assert len(factory.models) > 0
11
-
12
- for name in factory.models.keys():
13
- model_fn, preprocess_fn, layers = factory.models[name]
14
- assert callable(model_fn)
15
- assert callable(preprocess_fn)
16
- assert isinstance(layers, tuple)
17
-
18
-
19
- def test_get_backbone_unknown():
20
- factory = BackbonesFactory()
21
-
22
- with pytest.raises(ValueError):
23
- factory.get_backbone("unknown")
24
-
25
-
26
- @pytest.mark.parametrize(
27
- "backbone_name, expected_shapes",
28
- [
29
- (
30
- "efficientnetv2s-ss",
31
- ((4, 4, 160), (8, 8, 64), (16, 16, 48), (32, 32, 24)),
32
- ),
33
- (
34
- "efficientnetv2m-ss",
35
- ((4, 4, 176), (8, 8, 80), (16, 16, 48), (32, 32, 24)),
36
- ),
37
- (
38
- "efficientnetv2l-ss",
39
- ((4, 4, 224), (8, 8, 96), (16, 16, 64), (32, 32, 32)),
40
- ),
41
- ],
42
- )
43
- def test_efficientnetv2_compact_skip_shapes(backbone_name, expected_shapes):
44
- factory = BackbonesFactory()
45
- model = factory.get_backbone(
46
- backbone_name,
47
- include_top=False,
48
- weights=None,
49
- input_shape=(64, 64, 3),
50
- )
51
-
52
- feature_shapes = tuple(
53
- tuple(int(size) for size in model.get_layer(layer_name).output.shape[1:])
54
- for layer_name in factory.get_feature_layers(backbone_name, n=4)
55
- )
56
-
57
- assert feature_shapes == expected_shapes