segmodels-keras 0.1.0__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 (43) hide show
  1. segmodels_keras-0.1.0/LICENSE +21 -0
  2. segmodels_keras-0.1.0/MANIFEST.in +1 -0
  3. segmodels_keras-0.1.0/PKG-INFO +36 -0
  4. segmodels_keras-0.1.0/README.rst +58 -0
  5. segmodels_keras-0.1.0/pyproject.toml +68 -0
  6. segmodels_keras-0.1.0/segmodels_keras/__init__.py +141 -0
  7. segmodels_keras-0.1.0/segmodels_keras/_compat.py +6 -0
  8. segmodels_keras-0.1.0/segmodels_keras/_version.py +3 -0
  9. segmodels_keras-0.1.0/segmodels_keras/backbones/__init__.py +1 -0
  10. segmodels_keras-0.1.0/segmodels_keras/backbones/_common_blocks.py +134 -0
  11. segmodels_keras-0.1.0/segmodels_keras/backbones/_weights.py +365 -0
  12. segmodels_keras-0.1.0/segmodels_keras/backbones/backbones_factory.py +423 -0
  13. segmodels_keras-0.1.0/segmodels_keras/backbones/inception_resnet_v2.py +452 -0
  14. segmodels_keras-0.1.0/segmodels_keras/backbones/inception_v3.py +504 -0
  15. segmodels_keras-0.1.0/segmodels_keras/backbones/resnet_18_34.py +367 -0
  16. segmodels_keras-0.1.0/segmodels_keras/backbones/resnet_common.py +122 -0
  17. segmodels_keras-0.1.0/segmodels_keras/base/__init__.py +6 -0
  18. segmodels_keras-0.1.0/segmodels_keras/base/functional.py +390 -0
  19. segmodels_keras-0.1.0/segmodels_keras/base/objects.py +129 -0
  20. segmodels_keras-0.1.0/segmodels_keras/losses.py +295 -0
  21. segmodels_keras-0.1.0/segmodels_keras/metrics.py +286 -0
  22. segmodels_keras-0.1.0/segmodels_keras/models/__init__.py +5 -0
  23. segmodels_keras-0.1.0/segmodels_keras/models/_common_blocks.py +67 -0
  24. segmodels_keras-0.1.0/segmodels_keras/models/_utils.py +14 -0
  25. segmodels_keras-0.1.0/segmodels_keras/models/fpn.py +313 -0
  26. segmodels_keras-0.1.0/segmodels_keras/models/linknet.py +330 -0
  27. segmodels_keras-0.1.0/segmodels_keras/models/model_factory.py +96 -0
  28. segmodels_keras-0.1.0/segmodels_keras/models/pspnet.py +298 -0
  29. segmodels_keras-0.1.0/segmodels_keras/models/unet.py +297 -0
  30. segmodels_keras-0.1.0/segmodels_keras/py.typed +0 -0
  31. segmodels_keras-0.1.0/segmodels_keras/utils.py +314 -0
  32. segmodels_keras-0.1.0/segmodels_keras.egg-info/PKG-INFO +36 -0
  33. segmodels_keras-0.1.0/segmodels_keras.egg-info/SOURCES.txt +41 -0
  34. segmodels_keras-0.1.0/segmodels_keras.egg-info/dependency_links.txt +1 -0
  35. segmodels_keras-0.1.0/segmodels_keras.egg-info/requires.txt +7 -0
  36. segmodels_keras-0.1.0/segmodels_keras.egg-info/top_level.txt +1 -0
  37. segmodels_keras-0.1.0/setup.cfg +4 -0
  38. segmodels_keras-0.1.0/setup.py +84 -0
  39. segmodels_keras-0.1.0/tests/test_backbones.py +23 -0
  40. segmodels_keras-0.1.0/tests/test_helper.py +5 -0
  41. segmodels_keras-0.1.0/tests/test_metrics.py +207 -0
  42. segmodels_keras-0.1.0/tests/test_models.py +128 -0
  43. segmodels_keras-0.1.0/tests/test_utils.py +228 -0
@@ -0,0 +1,21 @@
1
+ The MIT License
2
+
3
+ Copyright (c) 2018, Pavel Yakubovskiy
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1 @@
1
+ include README.md LICENSE requirements.txt
@@ -0,0 +1,36 @@
1
+ Metadata-Version: 2.4
2
+ Name: segmodels_keras
3
+ Version: 0.1.0
4
+ Summary: Image segmentation models with pre-trained backbones with Keras.
5
+ Home-page: https://github.com/orthoseg/segmodels_keras
6
+ Author: Pieter Roggemans
7
+ Author-email: pieter.roggemans@gmail.com
8
+ License: MIT
9
+ Classifier: License :: OSI Approved :: MIT License
10
+ Classifier: Programming Language :: Python
11
+ Classifier: Programming Language :: Python :: 3
12
+ Classifier: Programming Language :: Python :: Implementation :: CPython
13
+ Classifier: Programming Language :: Python :: Implementation :: PyPy
14
+ Requires-Python: >=3.0.0
15
+ Description-Content-Type: text/markdown
16
+ License-File: LICENSE
17
+ Requires-Dist: keras
18
+ Requires-Dist: packaging
19
+ Provides-Extra: tests
20
+ Requires-Dist: numpy; extra == "tests"
21
+ Requires-Dist: pytest; extra == "tests"
22
+ Requires-Dist: scikit-image; extra == "tests"
23
+ Dynamic: author
24
+ Dynamic: author-email
25
+ Dynamic: classifier
26
+ Dynamic: description
27
+ Dynamic: description-content-type
28
+ Dynamic: home-page
29
+ Dynamic: license
30
+ Dynamic: license-file
31
+ Dynamic: provides-extra
32
+ Dynamic: requires-dist
33
+ Dynamic: requires-python
34
+ Dynamic: summary
35
+
36
+ Image segmentation models with pre-trained backbones with Keras.
@@ -0,0 +1,58 @@
1
+ |Actions Status| |Code coverage| |PyPI version|
2
+
3
+ .. |Actions Status| image:: https://github.com/orthoseg/segmodels_keras/actions/workflows/tests.yml/badge.svg?branch=main
4
+ :target: https://github.com/orthoseg/segmodels_keras/actions/workflows/tests.yml?query=workflow%3ATests
5
+
6
+ .. |Code coverage| image:: https://codecov.io/gh/orthoseg/segmodels_keras/graph/badge.svg?token=o01OyTMDuj
7
+ :target: https://codecov.io/gh/orthoseg/segmodels_keras
8
+
9
+ .. |PyPI version| image:: https://img.shields.io/pypi/v/segmodels-keras.svg
10
+ :target: https://pypi.org/project/segmodels-keras
11
+
12
+
13
+ ###############
14
+ segmodels_keras
15
+ ###############
16
+
17
+ This is a fork of the
18
+ `segmentation_models <https://github.com/qubvel/segmentation_models>`__ library by
19
+ Pavel Iakubovskii, which is not maintained anymore.
20
+
21
+ This fork is updated to support Keras 3, and also contains some bug fixes, some
22
+ improvements and support for some extra backbone models.
23
+
24
+ It is not meant as a full replacement of the original library, but rather as a
25
+ solution for a library I developed and depended on segmentation_models:
26
+ `orthoseg <https://github.com/orthoseg/orthoseg>`__ . Hence, full backwards
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.
30
+
31
+
32
+ **The main features** of this library are:
33
+
34
+ - High level API (just two lines of code to create model for segmentation)
35
+ - **4** models architectures for binary and multi-class image segmentation
36
+ (including legendary **Unet**)
37
+ - **20+** available backbones for each architecture
38
+ - All backbones have **pre-trained** weights for faster and better convergence
39
+ - Helpful segmentation losses (Jaccard, Dice, Focal) and metrics (IoU, F-score)
40
+
41
+ Documentation
42
+ ~~~~~~~~~~~~~
43
+ The **documentation** of the current stable version is available here:
44
+ `Read the docs, stable <https://segmodels_keras.readthedocs.io/en/stable/>`__.
45
+
46
+ The lastest version of the documentation (= of the main branch) can be found here:
47
+ `Read the docs, latest <https://segmodels_keras.readthedocs.io/en/latest/>`__.
48
+
49
+ Change Log
50
+ ~~~~~~~~~~
51
+ To see important changes between versions look at CHANGELOG.md_
52
+
53
+ License
54
+ ~~~~~~~
55
+ Project is distributed under `MIT Licence`_.
56
+
57
+ .. _CHANGELOG.md: https://github.com/orthoseg/segmodels_keras/blob/main/CHANGELOG.md
58
+ .. _`MIT Licence`: https://github.com/orthoseg/segmodels_keras/blob/main/LICENSE
@@ -0,0 +1,68 @@
1
+ [[tool.mypy.overrides]]
2
+ module = "h5py.*,keras.*,six.*,setuptools.*,sphinx_rtd_theme.*,tensorflow.*"
3
+ ignore_missing_imports = true
4
+
5
+ [tool.pyright]
6
+ exclude = ["local_ignore", "**/node_modules", "**/__pycache__", "**/.*"]
7
+ ignore = ["*"]
8
+
9
+ [tool.pytest.ini_options]
10
+ log_level = "DEBUG"
11
+ # Write all logging and warnings immediately while running test with debugger.
12
+ # log_cli = true
13
+ # addopts = "-p no:warnings"
14
+
15
+ [tool.ruff]
16
+ line-length = 88
17
+ target-version = "py310"
18
+ extend-exclude = ["docs/conf.py", "local_ignore/*", "examples"]
19
+
20
+ [tool.ruff.lint]
21
+ select = [
22
+ "YTT", # flake8-2020
23
+ # "ANN", # flake8-annotations
24
+ "B", # flake8-bugbear
25
+ "A", # flake8-builtins
26
+ "C4", # flake8-comprehensions
27
+ "T10", # flake8-debugger
28
+ "ISC", # flake8-implicit string concatenation
29
+ # "G", # flake8-logging-format
30
+ "PIE", # flake8-pie misc lints
31
+ # "SIM", # flake8-simplify
32
+ "TC", # flake8-type-checking imports
33
+ "ARG", # flake8-unused-arguments
34
+ # "PTH", # flake8-use-pathlib
35
+ "FLY", # flynt
36
+ "I", # isort
37
+ "NPY", # NumPy-specific rules
38
+ "E", # pycodestyle errors
39
+ "W", # pycodestyle warnings
40
+ "D", # pydocstyle
41
+ "F", # pyflakes
42
+ "PLC", # pylint convention
43
+ "PLE", # pylint error
44
+ "PLR", # pylint refactor
45
+ "PLW", # pylint warning
46
+ "UP", # pyupgrade
47
+ "RUF", # Ruff-specific rules
48
+ ]
49
+
50
+ ignore = [
51
+ ### Intentionally disabled
52
+ "E402", # Module level import not at top of file
53
+ "PLR0913", # Too many arguments to function call
54
+ "PLR0917", # Too many positional arguments
55
+ "PLR0911", # Too many returns
56
+ "PLR0912", # Too many branches
57
+ "PLR0915", # Too many statements
58
+ "PLR2004", # Magic number
59
+ "PLR5501", # Use `elif` instead of `else` then `if`, to reduce indentation
60
+ "PLW2901", # Loop variable overwritten by assignment target
61
+ ]
62
+
63
+ [tool.ruff.lint.per-file-ignores]
64
+ "tests/*" = ["ANN", "D"]
65
+ "perftests/*" = ["ANN", "D"]
66
+
67
+ [tool.ruff.lint.pydocstyle]
68
+ convention = "google"
@@ -0,0 +1,141 @@
1
+ """Segmentation Models for Keras."""
2
+
3
+ import functools # noqa: I001
4
+ import os
5
+ from typing import Any
6
+ from collections.abc import Callable
7
+
8
+ # __version__ should be defined as soon as possible
9
+ from ._version import __version__
10
+
11
+ from . import base
12
+
13
+ _KERAS_FRAMEWORK_NAME: str = "keras"
14
+ _TF_KERAS_FRAMEWORK_NAME: str = "tf.keras"
15
+
16
+ _DEFAULT_KERAS_FRAMEWORK: str = _KERAS_FRAMEWORK_NAME
17
+ _KERAS_FRAMEWORK: str | None = None
18
+ _KERAS_BACKEND: Any = None
19
+ _KERAS_LAYERS: Any = None
20
+ _KERAS_MODELS: Any = None
21
+ _KERAS_UTILS: Any = None
22
+ _KERAS_LOSSES: Any = None
23
+
24
+
25
+ def inject_global_losses(func: Callable[..., Any]) -> Callable[..., Any]:
26
+ @functools.wraps(func)
27
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
28
+ kwargs["losses"] = _KERAS_LOSSES
29
+ return func(*args, **kwargs)
30
+
31
+ return wrapper
32
+
33
+
34
+ def filter_kwargs(func: Callable[..., Any]) -> Callable[..., Any]:
35
+ @functools.wraps(func)
36
+ def wrapper(*args: Any, **kwargs: Any) -> Any:
37
+ new_kwargs = {
38
+ k: v
39
+ for k, v in kwargs.items()
40
+ if k in ["backend", "layers", "models", "utils"]
41
+ }
42
+ return func(*args, **new_kwargs)
43
+
44
+ return wrapper
45
+
46
+
47
+ def framework() -> str | None:
48
+ """Return name of Segmentation Models framework."""
49
+ return _KERAS_FRAMEWORK
50
+
51
+
52
+ def set_framework(name: str) -> None:
53
+ """Set framework for Segmentation Models.
54
+
55
+ Args:
56
+ name (str): one of ``keras``, ``tf.keras``, case insensitive.
57
+
58
+ Raises:
59
+ ValueError: in case of incorrect framework name.
60
+ ImportError: in case framework is not installed.
61
+
62
+ """
63
+ name = name.lower()
64
+
65
+ if name == _KERAS_FRAMEWORK_NAME:
66
+ import keras # noqa: PLC0415
67
+ elif name == _TF_KERAS_FRAMEWORK_NAME:
68
+ from tensorflow import keras # noqa: PLC0415
69
+ else:
70
+ raise ValueError(
71
+ f"Not correct module name `{name}`, use `{_KERAS_FRAMEWORK_NAME}` or "
72
+ f"`{_TF_KERAS_FRAMEWORK_NAME}`"
73
+ )
74
+
75
+ global _KERAS_BACKEND, _KERAS_LAYERS, _KERAS_MODELS # noqa: PLW0603
76
+ global _KERAS_UTILS, _KERAS_LOSSES, _KERAS_FRAMEWORK # noqa: PLW0603
77
+
78
+ _KERAS_FRAMEWORK = name
79
+ _KERAS_BACKEND = keras.backend
80
+ _KERAS_LAYERS = keras.layers
81
+ _KERAS_MODELS = keras.models
82
+ _KERAS_UTILS = keras.utils
83
+ _KERAS_LOSSES = keras.losses
84
+
85
+ # allow losses/metrics get keras submodules
86
+ base.KerasObject.set_submodules(
87
+ backend=keras.backend,
88
+ layers=keras.layers,
89
+ models=keras.models,
90
+ utils=keras.utils,
91
+ )
92
+
93
+
94
+ # set default framework
95
+ _framework = os.environ.get("SM_FRAMEWORK", _DEFAULT_KERAS_FRAMEWORK)
96
+ try:
97
+ set_framework(_framework)
98
+ except ImportError:
99
+ other = (
100
+ _TF_KERAS_FRAMEWORK_NAME
101
+ if _framework == _KERAS_FRAMEWORK_NAME
102
+ else _KERAS_FRAMEWORK_NAME
103
+ )
104
+ set_framework(other)
105
+
106
+ print(f"Segmentation Models: using `{_KERAS_FRAMEWORK}` framework.")
107
+
108
+ # import helper modules
109
+ from . import losses, metrics, utils
110
+
111
+ # wrap segmentation models with framework modules
112
+ from .backbones.backbones_factory import Backbones
113
+ from .models.fpn import FPN
114
+ from .models.linknet import Linknet
115
+ from .models.model_factory import get_model
116
+ from .models.pspnet import PSPNet
117
+ from .models.unet import Unet
118
+
119
+ get_available_backbone_names = Backbones.models_names
120
+
121
+
122
+ def get_preprocessing(name: str) -> Callable[[Any], Any]:
123
+ """Get the preprocessing function for a backbone by name."""
124
+ return Backbones.get_preprocessing(name)
125
+
126
+
127
+ __all__ = [
128
+ "FPN",
129
+ "Linknet",
130
+ "PSPNet",
131
+ "Unet",
132
+ "__version__",
133
+ "framework",
134
+ "get_available_backbone_names",
135
+ "get_model",
136
+ "get_preprocessing",
137
+ "losses",
138
+ "metrics",
139
+ "set_framework",
140
+ "utils",
141
+ ]
@@ -0,0 +1,6 @@
1
+ """Compatibility utilities for Keras 3 and legacy Keras 2."""
2
+
3
+ import keras
4
+ from packaging.version import parse as parse_version
5
+
6
+ KERAS_GTE_3 = parse_version(keras.__version__) >= parse_version("3.0.0")
@@ -0,0 +1,3 @@
1
+ # __versioninfo__: tuple[int, int, int, str] = (0, 1, 0, "")
2
+ __versioninfo__: tuple[int, int, int] = (0, 1, 0)
3
+ __version__: str = ".".join(map(str, __versioninfo__))
@@ -0,0 +1 @@
1
+ """Backbones package."""
@@ -0,0 +1,134 @@
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
+ kwargs: additional keyword arguments (unused).
48
+
49
+ Input shape:
50
+ 4D tensor with shape: (batch, rows, cols, channels) if data_format is
51
+ "channels_last".
52
+
53
+ Output shape:
54
+ 4D tensor with shape: (batch, new_rows, new_cols, filters) if data_format is
55
+ "channels_last". rows and cols values might have changed due to padding.
56
+
57
+ """
58
+ slice_axis = 3 if backend.image_data_format() == "channels_last" else 1
59
+
60
+ def layer(input_tensor):
61
+ inp_ch = int(
62
+ backend.int_shape(input_tensor)[-1] // groups
63
+ ) # input grouped channels
64
+ out_ch = int(filters // groups) # output grouped channels
65
+
66
+ blocks = []
67
+ for c in range(groups):
68
+ slice_arguments = {
69
+ "start": c * inp_ch,
70
+ "stop": (c + 1) * inp_ch,
71
+ "axis": slice_axis,
72
+ }
73
+ x = layers.Lambda(slice_tensor, arguments=slice_arguments)(input_tensor)
74
+ x = layers.Conv2D(
75
+ out_ch,
76
+ kernel_size,
77
+ strides=strides,
78
+ kernel_initializer=kernel_initializer,
79
+ use_bias=use_bias,
80
+ activation=activation,
81
+ padding=padding,
82
+ )(x)
83
+ blocks.append(x)
84
+
85
+ x = layers.Concatenate(axis=slice_axis)(blocks)
86
+ return x
87
+
88
+ return layer
89
+
90
+
91
+ def expand_dims(x, channels_axis):
92
+ if channels_axis == 3:
93
+ return x[:, None, None, :]
94
+ elif channels_axis == 1:
95
+ return x[:, :, None, None]
96
+ else:
97
+ raise ValueError(f"Slice axis should be in (1, 3), got {channels_axis}.")
98
+
99
+
100
+ def ChannelSE(reduction=16, **kwargs): # noqa: ARG001
101
+ """Squeeze and Excitation block.
102
+
103
+ Reimplementation inspired by
104
+ https://github.com/Cadene/pretrained-models.pytorch/blob/master/pretrainedmodels/models/senet.py.
105
+
106
+ Args:
107
+ reduction: channels squeeze factor
108
+ kwargs: additional keyword arguments (unused).
109
+
110
+ """
111
+ channels_axis = 3 if backend.image_data_format() == "channels_last" else 1
112
+
113
+ def layer(input_tensor):
114
+ # get number of channels/filters
115
+ channels = backend.int_shape(input_tensor)[channels_axis]
116
+
117
+ x = input_tensor
118
+
119
+ # squeeze and excitation block in PyTorch style with
120
+ x = layers.GlobalAveragePooling2D()(x)
121
+ x = layers.Lambda(expand_dims, arguments={"channels_axis": channels_axis})(x)
122
+ x = layers.Conv2D(
123
+ channels // reduction, (1, 1), kernel_initializer="he_uniform"
124
+ )(x)
125
+ x = layers.Activation("relu")(x)
126
+ x = layers.Conv2D(channels, (1, 1), kernel_initializer="he_uniform")(x)
127
+ x = layers.Activation("sigmoid")(x)
128
+
129
+ # apply attention
130
+ x = layers.Multiply()([input_tensor, x])
131
+
132
+ return x
133
+
134
+ return layer