segmodels-keras 0.1.0.dev0__tar.gz → 0.1.0.dev2__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.
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/PKG-INFO +3 -2
- segmodels_keras-0.1.0.dev2/README.rst +53 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/__init__.py +5 -3
- segmodels_keras-0.1.0.dev2/segmodels_keras/_compat.py +4 -0
- segmodels_keras-0.1.0.dev2/segmodels_keras/_version.py +2 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/backbones/backbones_factory.py +8 -1
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/backbones/inception_resnet_v2.py +298 -217
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/base/functional.py +2 -1
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras.egg-info/PKG-INFO +3 -2
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras.egg-info/SOURCES.txt +1 -1
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras.egg-info/requires.txt +1 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/setup.py +4 -4
- segmodels_keras-0.1.0.dev0/README.rst +0 -260
- segmodels_keras-0.1.0.dev0/segmodels_keras/__version__.py +0 -3
- segmodels_keras-0.1.0.dev0/segmodels_keras/_compat.py +0 -3
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/LICENSE +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/MANIFEST.in +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/pyproject.toml +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/backbones/__init__.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/backbones/inception_v3.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/base/__init__.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/base/objects.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/losses.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/metrics.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/models/__init__.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/models/_common_blocks.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/models/_utils.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/models/fpn.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/models/linknet.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/models/pspnet.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/models/unet.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/utils.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras.egg-info/dependency_links.txt +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras.egg-info/top_level.txt +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/setup.cfg +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/tests/test_backbones.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/tests/test_metrics.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/tests/test_models.py +0 -0
- {segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/tests/test_utils.py +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: segmodels_keras
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev2
|
|
4
4
|
Summary: Image segmentation models with pre-trained backbones with Keras.
|
|
5
|
-
Home-page: https://github.com/
|
|
5
|
+
Home-page: https://github.com/orthoseg/segmodels_keras
|
|
6
6
|
Author: Pieter Roggemans
|
|
7
7
|
Author-email: pieter.roggemans@gmail.com
|
|
8
8
|
License: MIT
|
|
@@ -15,6 +15,7 @@ Requires-Python: >=3.0.0
|
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Requires-Dist: keras
|
|
18
|
+
Requires-Dist: packaging
|
|
18
19
|
Provides-Extra: tests
|
|
19
20
|
Requires-Dist: numpy; extra == "tests"
|
|
20
21
|
Requires-Dist: pytest; extra == "tests"
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
|Actions Status| |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
|
+
.. |PyPI version| image:: https://img.shields.io/pypi/v/segmodels-keras.svg
|
|
7
|
+
:target: https://pypi.org/project/segmodels-keras
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
###############
|
|
11
|
+
segmodels_keras
|
|
12
|
+
###############
|
|
13
|
+
|
|
14
|
+
This is a fork of the
|
|
15
|
+
`segmentation_models <https://github.com/qubvel/segmentation_models>`__ library by
|
|
16
|
+
Pavel Iakubovskii, which is not maintained anymore.
|
|
17
|
+
|
|
18
|
+
This fork is updated to support Keras 3, and also contains some bug fixes, some
|
|
19
|
+
improvements and support for some extra backbone models.
|
|
20
|
+
|
|
21
|
+
It is not meant as a full replacement of the original library, but rather as a
|
|
22
|
+
solution for a library I developed and depended on segmentation_models:
|
|
23
|
+
`orthoseg <https://github.com/orthoseg/orthoseg>`__ . Hence, full backwards
|
|
24
|
+
compatibility,... or support for all features is not guaranteed.
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
**The main features** of this library are:
|
|
28
|
+
|
|
29
|
+
- High level API (just two lines of code to create model for segmentation)
|
|
30
|
+
- **4** models architectures for binary and multi-class image segmentation
|
|
31
|
+
(including legendary **Unet**)
|
|
32
|
+
- **20+** available backbones for each architecture
|
|
33
|
+
- All backbones have **pre-trained** weights for faster and better convergence
|
|
34
|
+
- Helpful segmentation losses (Jaccard, Dice, Focal) and metrics (IoU, F-score)
|
|
35
|
+
|
|
36
|
+
Documentation
|
|
37
|
+
~~~~~~~~~~~~~
|
|
38
|
+
The **documentation** of the current stable version is available here:
|
|
39
|
+
`Read the docs, stable <https://segmodels_keras.readthedocs.io/en/stable/>`__.
|
|
40
|
+
|
|
41
|
+
The lastest version of the documentation (= of the main branch) can be found here:
|
|
42
|
+
`Read the docs, latest <https://segmodels_keras.readthedocs.io/en/latest/>`__.
|
|
43
|
+
|
|
44
|
+
Change Log
|
|
45
|
+
~~~~~~~~~~
|
|
46
|
+
To see important changes between versions look at CHANGELOG.md_
|
|
47
|
+
|
|
48
|
+
License
|
|
49
|
+
~~~~~~~
|
|
50
|
+
Project is distributed under `MIT Licence`_.
|
|
51
|
+
|
|
52
|
+
.. _CHANGELOG.md: https://github.com/orthoseg/segmodels_keras/blob/main/CHANGELOG.md
|
|
53
|
+
.. _`MIT Licence`: https://github.com/orthoseg/segmodels_keras/blob/main/LICENSE
|
|
@@ -1,8 +1,10 @@
|
|
|
1
|
-
import functools
|
|
1
|
+
import functools # noqa: I001
|
|
2
2
|
import os
|
|
3
3
|
|
|
4
|
-
|
|
5
|
-
from .
|
|
4
|
+
# __version__ should be defined as soon as possible
|
|
5
|
+
from segmodels_keras._version import __version__
|
|
6
|
+
|
|
7
|
+
from segmodels_keras import base
|
|
6
8
|
|
|
7
9
|
_KERAS_FRAMEWORK_NAME = "keras"
|
|
8
10
|
_TF_KERAS_FRAMEWORK_NAME = "tf.keras"
|
|
@@ -125,7 +125,14 @@ class BackbonesFactory:
|
|
|
125
125
|
"inceptionresnetv2": (
|
|
126
126
|
irv2.InceptionResNetV2,
|
|
127
127
|
irv2.preprocess_input,
|
|
128
|
-
(
|
|
128
|
+
(
|
|
129
|
+
"activation_161",
|
|
130
|
+
"activation_74",
|
|
131
|
+
"activation_3",
|
|
132
|
+
"activation",
|
|
133
|
+
# "input_1",
|
|
134
|
+
),
|
|
135
|
+
# (594, 260, 16, 9),
|
|
129
136
|
),
|
|
130
137
|
"inceptionv3": (iv3.InceptionV3, iv3.preprocess_input, (228, 86, 16, 9)),
|
|
131
138
|
# MobileNet
|
|
@@ -1,166 +1,49 @@
|
|
|
1
1
|
"""Inception-ResNet V2 model for Keras.
|
|
2
|
+
|
|
2
3
|
Model naming and structure follows TF-slim implementation
|
|
3
4
|
(which has some additional layers and different number of
|
|
4
5
|
filters from the original arXiv paper):
|
|
5
6
|
https://github.com/tensorflow/models/blob/master/research/slim/nets/inception_resnet_v2.py
|
|
7
|
+
|
|
6
8
|
Pre-trained ImageNet weights are also converted from TF-slim,
|
|
7
9
|
which can be found in:
|
|
8
10
|
https://github.com/tensorflow/models/tree/master/research/slim#pre-trained-models
|
|
11
|
+
|
|
9
12
|
# Reference
|
|
10
13
|
- [Inception-v4, Inception-ResNet and the Impact of
|
|
11
14
|
Residual Connections on Learning](https://arxiv.org/abs/1602.07261) (AAAI 2017)
|
|
15
|
+
|
|
16
|
+
Differences with the original implementation in keras.applications:
|
|
17
|
+
- For e.g. in the `conv2d_bn` blocks, padding="same" is used instead of "valid". This is
|
|
18
|
+
to make the sizes of the outputs of the layers the correct size for the skip
|
|
19
|
+
connections for the decoders in the segmentation models. It does not affect the
|
|
20
|
+
weights of the layers, so we can still use the pre-trained weights from the original
|
|
21
|
+
implementation.
|
|
22
|
+
An alternative solution is to add a padding layer before the skip connections, but
|
|
23
|
+
that would add extra parameters to the model, which we want to avoid as that might
|
|
24
|
+
also give issues when loading weights that were saved with an older version. An
|
|
25
|
+
example where this solution is used/shown can be found here:
|
|
26
|
+
https://github.com/ayushdabra/dubai-satellite-imagery-segmentation/blob/9446e16134e752dda080ba9d65be18ea47fa26a9/get_activations.py#L40
|
|
27
|
+
- The original implementation uses different imports as it is internal in keras, and
|
|
28
|
+
here we need to use the public API of keras.
|
|
29
|
+
- Use Lambda layer instead of CustomScaleLayer because:
|
|
30
|
+
- it avoids having to define + pass in a custom layer when loading the model
|
|
31
|
+
- otherwise "old" weights cannot be loaded when using keras 3
|
|
12
32
|
"""
|
|
13
33
|
|
|
14
|
-
import os
|
|
15
34
|
import warnings
|
|
35
|
+
from pathlib import Path
|
|
16
36
|
|
|
17
37
|
from keras import backend, layers, models
|
|
18
|
-
from keras import utils as keras_utils
|
|
19
38
|
from keras.applications import imagenet_utils
|
|
39
|
+
from keras.layers import Layer
|
|
40
|
+
from keras.utils import get_file, get_source_inputs
|
|
20
41
|
|
|
21
42
|
BASE_WEIGHT_URL = (
|
|
22
|
-
"https://
|
|
43
|
+
"https://storage.googleapis.com/tensorflow/keras-applications/inception_resnet_v2/"
|
|
23
44
|
)
|
|
24
45
|
|
|
25
46
|
|
|
26
|
-
def preprocess_input(x, **kwargs):
|
|
27
|
-
"""Preprocesses a numpy array encoding a batch of images.
|
|
28
|
-
# Arguments
|
|
29
|
-
x: a 4D numpy array consists of RGB values within [0, 255].
|
|
30
|
-
# Returns
|
|
31
|
-
Preprocessed array.
|
|
32
|
-
"""
|
|
33
|
-
return imagenet_utils.preprocess_input(x, mode="tf", **kwargs)
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
def conv2d_bn(
|
|
37
|
-
x,
|
|
38
|
-
filters,
|
|
39
|
-
kernel_size,
|
|
40
|
-
strides=1,
|
|
41
|
-
padding="same",
|
|
42
|
-
activation="relu",
|
|
43
|
-
use_bias=False,
|
|
44
|
-
name=None,
|
|
45
|
-
):
|
|
46
|
-
"""Utility function to apply conv + BN.
|
|
47
|
-
# Arguments
|
|
48
|
-
x: input tensor.
|
|
49
|
-
filters: filters in `Conv2D`.
|
|
50
|
-
kernel_size: kernel size as in `Conv2D`.
|
|
51
|
-
strides: strides in `Conv2D`.
|
|
52
|
-
padding: padding mode in `Conv2D`.
|
|
53
|
-
activation: activation in `Conv2D`.
|
|
54
|
-
use_bias: whether to use a bias in `Conv2D`.
|
|
55
|
-
name: name of the ops; will become `name + '_ac'` for the activation
|
|
56
|
-
and `name + '_bn'` for the batch norm layer.
|
|
57
|
-
# Returns
|
|
58
|
-
Output tensor after applying `Conv2D` and `BatchNormalization`.
|
|
59
|
-
"""
|
|
60
|
-
x = layers.Conv2D(
|
|
61
|
-
filters,
|
|
62
|
-
kernel_size,
|
|
63
|
-
strides=strides,
|
|
64
|
-
padding=padding,
|
|
65
|
-
use_bias=use_bias,
|
|
66
|
-
name=name,
|
|
67
|
-
)(x)
|
|
68
|
-
if not use_bias:
|
|
69
|
-
bn_axis = 1 if backend.image_data_format() == "channels_first" else 3
|
|
70
|
-
bn_name = None if name is None else name + "_bn"
|
|
71
|
-
x = layers.BatchNormalization(axis=bn_axis, scale=False, name=bn_name)(x)
|
|
72
|
-
if activation is not None:
|
|
73
|
-
ac_name = None if name is None else name + "_ac"
|
|
74
|
-
x = layers.Activation(activation, name=ac_name)(x)
|
|
75
|
-
return x
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
def inception_resnet_block(x, scale, block_type, block_idx, activation="relu"):
|
|
79
|
-
"""Adds a Inception-ResNet block.
|
|
80
|
-
This function builds 3 types of Inception-ResNet blocks mentioned
|
|
81
|
-
in the paper, controlled by the `block_type` argument (which is the
|
|
82
|
-
block name used in the official TF-slim implementation):
|
|
83
|
-
- Inception-ResNet-A: `block_type='block35'`
|
|
84
|
-
- Inception-ResNet-B: `block_type='block17'`
|
|
85
|
-
- Inception-ResNet-C: `block_type='block8'`
|
|
86
|
-
# Arguments
|
|
87
|
-
x: input tensor.
|
|
88
|
-
scale: scaling factor to scale the residuals (i.e., the output of
|
|
89
|
-
passing `x` through an inception module) before adding them
|
|
90
|
-
to the shortcut branch.
|
|
91
|
-
Let `r` be the output from the residual branch,
|
|
92
|
-
the output of this block will be `x + scale * r`.
|
|
93
|
-
block_type: `'block35'`, `'block17'` or `'block8'`, determines
|
|
94
|
-
the network structure in the residual branch.
|
|
95
|
-
block_idx: an `int` used for generating layer names.
|
|
96
|
-
The Inception-ResNet blocks
|
|
97
|
-
are repeated many times in this network.
|
|
98
|
-
We use `block_idx` to identify
|
|
99
|
-
each of the repetitions. For example,
|
|
100
|
-
the first Inception-ResNet-A block
|
|
101
|
-
will have `block_type='block35', block_idx=0`,
|
|
102
|
-
and the layer names will have
|
|
103
|
-
a common prefix `'block35_0'`.
|
|
104
|
-
activation: activation function to use at the end of the block
|
|
105
|
-
(see [activations](../activations.md)).
|
|
106
|
-
When `activation=None`, no activation is applied
|
|
107
|
-
(i.e., "linear" activation: `a(x) = x`).
|
|
108
|
-
# Returns
|
|
109
|
-
Output tensor for the block.
|
|
110
|
-
# Raises
|
|
111
|
-
ValueError: if `block_type` is not one of `'block35'`,
|
|
112
|
-
`'block17'` or `'block8'`.
|
|
113
|
-
"""
|
|
114
|
-
if block_type == "block35":
|
|
115
|
-
branch_0 = conv2d_bn(x, 32, 1)
|
|
116
|
-
branch_1 = conv2d_bn(x, 32, 1)
|
|
117
|
-
branch_1 = conv2d_bn(branch_1, 32, 3)
|
|
118
|
-
branch_2 = conv2d_bn(x, 32, 1)
|
|
119
|
-
branch_2 = conv2d_bn(branch_2, 48, 3)
|
|
120
|
-
branch_2 = conv2d_bn(branch_2, 64, 3)
|
|
121
|
-
branches = [branch_0, branch_1, branch_2]
|
|
122
|
-
elif block_type == "block17":
|
|
123
|
-
branch_0 = conv2d_bn(x, 192, 1)
|
|
124
|
-
branch_1 = conv2d_bn(x, 128, 1)
|
|
125
|
-
branch_1 = conv2d_bn(branch_1, 160, [1, 7])
|
|
126
|
-
branch_1 = conv2d_bn(branch_1, 192, [7, 1])
|
|
127
|
-
branches = [branch_0, branch_1]
|
|
128
|
-
elif block_type == "block8":
|
|
129
|
-
branch_0 = conv2d_bn(x, 192, 1)
|
|
130
|
-
branch_1 = conv2d_bn(x, 192, 1)
|
|
131
|
-
branch_1 = conv2d_bn(branch_1, 224, [1, 3])
|
|
132
|
-
branch_1 = conv2d_bn(branch_1, 256, [3, 1])
|
|
133
|
-
branches = [branch_0, branch_1]
|
|
134
|
-
else:
|
|
135
|
-
raise ValueError(
|
|
136
|
-
"Unknown Inception-ResNet block type. "
|
|
137
|
-
'Expects "block35", "block17" or "block8", '
|
|
138
|
-
"but got: " + str(block_type)
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
block_name = block_type + "_" + str(block_idx)
|
|
142
|
-
channel_axis = 1 if backend.image_data_format() == "channels_first" else 3
|
|
143
|
-
mixed = layers.Concatenate(axis=channel_axis, name=block_name + "_mixed")(branches)
|
|
144
|
-
up = conv2d_bn(
|
|
145
|
-
mixed,
|
|
146
|
-
x.shape[channel_axis],
|
|
147
|
-
1,
|
|
148
|
-
activation=None,
|
|
149
|
-
use_bias=True,
|
|
150
|
-
name=block_name + "_conv",
|
|
151
|
-
)
|
|
152
|
-
|
|
153
|
-
x = layers.Lambda(
|
|
154
|
-
lambda inputs, scale: inputs[0] + inputs[1] * scale,
|
|
155
|
-
output_shape=x.shape[1:],
|
|
156
|
-
arguments={"scale": scale},
|
|
157
|
-
name=block_name,
|
|
158
|
-
)([x, up])
|
|
159
|
-
if activation is not None:
|
|
160
|
-
x = layers.Activation(activation, name=block_name + "_ac")(x)
|
|
161
|
-
return x
|
|
162
|
-
|
|
163
|
-
|
|
164
47
|
def InceptionResNetV2(
|
|
165
48
|
include_top=True,
|
|
166
49
|
weights="imagenet",
|
|
@@ -168,23 +51,47 @@ def InceptionResNetV2(
|
|
|
168
51
|
input_shape=None,
|
|
169
52
|
pooling=None,
|
|
170
53
|
classes=1000,
|
|
171
|
-
|
|
54
|
+
classifier_activation="softmax",
|
|
55
|
+
name="inception_resnet_v2",
|
|
172
56
|
):
|
|
173
57
|
"""Instantiates the Inception-ResNet v2 architecture.
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
58
|
+
|
|
59
|
+
Reference:
|
|
60
|
+
- [Inception-v4, Inception-ResNet and the Impact of
|
|
61
|
+
Residual Connections on Learning](https://arxiv.org/abs/1602.07261)
|
|
62
|
+
(AAAI 2017)
|
|
63
|
+
|
|
64
|
+
This function returns a Keras image classification model,
|
|
65
|
+
optionally loaded with weights pre-trained on ImageNet.
|
|
66
|
+
|
|
67
|
+
For image classification use cases, see
|
|
68
|
+
[this page for detailed examples](
|
|
69
|
+
https://keras.io/api/applications/#usage-examples-for-image-classification-models).
|
|
70
|
+
|
|
71
|
+
For transfer learning use cases, make sure to read the
|
|
72
|
+
[guide to transfer learning & fine-tuning](
|
|
73
|
+
https://keras.io/guides/transfer_learning/).
|
|
74
|
+
|
|
75
|
+
Note: each Keras Application expects a specific kind of
|
|
76
|
+
input preprocessing. For InceptionResNetV2, call
|
|
77
|
+
`keras.applications.inception_resnet_v2.preprocess_input`
|
|
78
|
+
on your inputs before passing them to the model.
|
|
79
|
+
`inception_resnet_v2.preprocess_input`
|
|
80
|
+
will scale input pixels between -1 and 1.
|
|
81
|
+
|
|
82
|
+
Args:
|
|
178
83
|
include_top: whether to include the fully-connected
|
|
179
84
|
layer at the top of the network.
|
|
180
85
|
weights: one of `None` (random initialization),
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
input_tensor: optional Keras tensor
|
|
86
|
+
`"imagenet"` (pre-training on ImageNet),
|
|
87
|
+
or the path to the weights file to be loaded.
|
|
88
|
+
input_tensor: optional Keras tensor
|
|
89
|
+
(i.e. output of `layers.Input()`)
|
|
184
90
|
to use as image input for the model.
|
|
185
91
|
input_shape: optional shape tuple, only to be specified
|
|
186
92
|
if `include_top` is `False` (otherwise the input shape
|
|
187
|
-
has to be `(299, 299, 3)`
|
|
93
|
+
has to be `(299, 299, 3)`
|
|
94
|
+
(with `'channels_last'` data format)
|
|
188
95
|
or `(3, 299, 299)` (with `'channels_first'` data format).
|
|
189
96
|
It should have exactly 3 inputs channels,
|
|
190
97
|
and width and height should be no smaller than 75.
|
|
@@ -199,15 +106,20 @@ def InceptionResNetV2(
|
|
|
199
106
|
the output of the model will be a 2D tensor.
|
|
200
107
|
- `'max'` means that global max pooling will be applied.
|
|
201
108
|
classes: optional number of classes to classify images
|
|
202
|
-
into, only to be specified if `include_top` is `True`,
|
|
203
|
-
if no `weights` argument is specified.
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
109
|
+
into, only to be specified if `include_top` is `True`,
|
|
110
|
+
and if no `weights` argument is specified.
|
|
111
|
+
classifier_activation: A `str` or callable.
|
|
112
|
+
The activation function to use on the "top" layer.
|
|
113
|
+
Ignored unless `include_top=True`.
|
|
114
|
+
Set `classifier_activation=None` to return the logits
|
|
115
|
+
of the "top" layer. When loading pretrained weights,
|
|
116
|
+
`classifier_activation` can only be `None` or `"softmax"`.
|
|
117
|
+
name: The name of the model (string).
|
|
118
|
+
|
|
119
|
+
Returns:
|
|
120
|
+
A model instance.
|
|
209
121
|
"""
|
|
210
|
-
if not (weights in {"imagenet", None} or
|
|
122
|
+
if not (weights in {"imagenet", None} or Path(weights).exists()):
|
|
211
123
|
raise ValueError(
|
|
212
124
|
"The `weights` argument should be either "
|
|
213
125
|
"`None` (random initialization), `imagenet` "
|
|
@@ -217,8 +129,9 @@ def InceptionResNetV2(
|
|
|
217
129
|
|
|
218
130
|
if weights == "imagenet" and include_top and classes != 1000:
|
|
219
131
|
raise ValueError(
|
|
220
|
-
'If using `weights
|
|
221
|
-
"
|
|
132
|
+
'If using `weights="imagenet"` with `include_top=True`, '
|
|
133
|
+
"`classes` should be 1000. "
|
|
134
|
+
f"Received classes={classes}"
|
|
222
135
|
)
|
|
223
136
|
|
|
224
137
|
# Determine proper input shape
|
|
@@ -233,10 +146,11 @@ def InceptionResNetV2(
|
|
|
233
146
|
|
|
234
147
|
if input_tensor is None:
|
|
235
148
|
img_input = layers.Input(shape=input_shape)
|
|
236
|
-
elif not backend.is_keras_tensor(input_tensor):
|
|
237
|
-
img_input = layers.Input(tensor=input_tensor, shape=input_shape)
|
|
238
149
|
else:
|
|
239
|
-
|
|
150
|
+
if not backend.is_keras_tensor(input_tensor):
|
|
151
|
+
img_input = layers.Input(tensor=input_tensor, shape=input_shape)
|
|
152
|
+
else:
|
|
153
|
+
img_input = input_tensor
|
|
240
154
|
|
|
241
155
|
# Stem block: 35 x 35 x 192
|
|
242
156
|
x = conv2d_bn(img_input, 32, 3, strides=2, padding="same")
|
|
@@ -308,27 +222,31 @@ def InceptionResNetV2(
|
|
|
308
222
|
if include_top:
|
|
309
223
|
# Classification block
|
|
310
224
|
x = layers.GlobalAveragePooling2D(name="avg_pool")(x)
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
225
|
+
imagenet_utils.validate_activation(classifier_activation, weights)
|
|
226
|
+
x = layers.Dense(classes, activation=classifier_activation, name="predictions")(
|
|
227
|
+
x
|
|
228
|
+
)
|
|
229
|
+
else:
|
|
230
|
+
if pooling == "avg":
|
|
231
|
+
x = layers.GlobalAveragePooling2D()(x)
|
|
232
|
+
elif pooling == "max":
|
|
233
|
+
x = layers.GlobalMaxPooling2D()(x)
|
|
316
234
|
|
|
317
235
|
# Ensure that the model takes into account
|
|
318
236
|
# any potential predecessors of `input_tensor`.
|
|
319
237
|
if input_tensor is not None:
|
|
320
|
-
inputs =
|
|
238
|
+
inputs = get_source_inputs(input_tensor)
|
|
321
239
|
else:
|
|
322
240
|
inputs = img_input
|
|
323
241
|
|
|
324
242
|
# Create model.
|
|
325
|
-
model = models.Model(inputs, x, name=
|
|
243
|
+
model = models.Model(inputs, x, name=name)
|
|
326
244
|
|
|
327
245
|
# Load weights.
|
|
328
246
|
if weights == "imagenet":
|
|
329
247
|
if include_top:
|
|
330
248
|
fname = "inception_resnet_v2_weights_tf_dim_ordering_tf_kernels.h5"
|
|
331
|
-
weights_path =
|
|
249
|
+
weights_path = get_file(
|
|
332
250
|
fname,
|
|
333
251
|
BASE_WEIGHT_URL + fname,
|
|
334
252
|
cache_subdir="models",
|
|
@@ -336,7 +254,7 @@ def InceptionResNetV2(
|
|
|
336
254
|
)
|
|
337
255
|
else:
|
|
338
256
|
fname = "inception_resnet_v2_weights_tf_dim_ordering_tf_kernels_notop.h5"
|
|
339
|
-
weights_path =
|
|
257
|
+
weights_path = get_file(
|
|
340
258
|
fname,
|
|
341
259
|
BASE_WEIGHT_URL + fname,
|
|
342
260
|
cache_subdir="models",
|
|
@@ -349,46 +267,216 @@ def InceptionResNetV2(
|
|
|
349
267
|
return model
|
|
350
268
|
|
|
351
269
|
|
|
352
|
-
def
|
|
353
|
-
|
|
270
|
+
def conv2d_bn(
|
|
271
|
+
x,
|
|
272
|
+
filters,
|
|
273
|
+
kernel_size,
|
|
274
|
+
strides=1,
|
|
275
|
+
padding="same",
|
|
276
|
+
activation="relu",
|
|
277
|
+
use_bias=False,
|
|
278
|
+
name=None,
|
|
354
279
|
):
|
|
355
|
-
"""
|
|
280
|
+
"""Utility function to apply conv + BN.
|
|
356
281
|
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
If weights='imagenet' input channels must be equal to 3.
|
|
282
|
+
Args:
|
|
283
|
+
x: input tensor.
|
|
284
|
+
filters: filters in `Conv2D`.
|
|
285
|
+
kernel_size: kernel size as in `Conv2D`.
|
|
286
|
+
strides: strides in `Conv2D`.
|
|
287
|
+
padding: padding mode in `Conv2D`.
|
|
288
|
+
activation: activation in `Conv2D`.
|
|
289
|
+
use_bias: whether to use a bias in `Conv2D`.
|
|
290
|
+
name: name of the ops; will become `name + '_ac'`
|
|
291
|
+
for the activation and `name + '_bn'` for the batch norm layer.
|
|
368
292
|
|
|
369
|
-
|
|
370
|
-
|
|
293
|
+
Returns:
|
|
294
|
+
Output tensor after applying `Conv2D` and `BatchNormalization`.
|
|
295
|
+
"""
|
|
296
|
+
x = layers.Conv2D(
|
|
297
|
+
filters,
|
|
298
|
+
kernel_size,
|
|
299
|
+
strides=strides,
|
|
300
|
+
padding=padding,
|
|
301
|
+
use_bias=use_bias,
|
|
302
|
+
name=name,
|
|
303
|
+
)(x)
|
|
304
|
+
if not use_bias:
|
|
305
|
+
bn_axis = 1 if backend.image_data_format() == "channels_first" else 3
|
|
306
|
+
bn_name = None if name is None else f"{name}_bn"
|
|
307
|
+
x = layers.BatchNormalization(axis=bn_axis, scale=False, name=bn_name)(x)
|
|
308
|
+
if activation is not None:
|
|
309
|
+
ac_name = None if name is None else f"{name}_ac"
|
|
310
|
+
x = layers.Activation(activation, name=ac_name)(x)
|
|
311
|
+
return x
|
|
312
|
+
|
|
313
|
+
|
|
314
|
+
def inception_resnet_block(x, scale, block_type, block_idx, activation="relu"):
|
|
315
|
+
"""Adds a Inception-ResNet block.
|
|
371
316
|
|
|
317
|
+
This function builds 3 types of Inception-ResNet blocks mentioned
|
|
318
|
+
in the paper, controlled by the `block_type` argument (which is the
|
|
319
|
+
block name used in the official TF-slim implementation):
|
|
320
|
+
- Inception-ResNet-A: `block_type='block35'`
|
|
321
|
+
- Inception-ResNet-B: `block_type='block17'`
|
|
322
|
+
- Inception-ResNet-C: `block_type='block8'`
|
|
323
|
+
|
|
324
|
+
Args:
|
|
325
|
+
x: input tensor.
|
|
326
|
+
scale: scaling factor to scale the residuals
|
|
327
|
+
(i.e., the output of passing `x` through an inception module)
|
|
328
|
+
before adding them to the shortcut
|
|
329
|
+
branch. Let `r` be the output from the residual branch,
|
|
330
|
+
the output of this block will be `x + scale * r`.
|
|
331
|
+
block_type: `'block35'`, `'block17'` or `'block8'`,
|
|
332
|
+
determines the network structure in the residual branch.
|
|
333
|
+
block_idx: an `int` used for generating layer names.
|
|
334
|
+
The Inception-ResNet blocks are repeated many times
|
|
335
|
+
in this network. We use `block_idx` to identify each
|
|
336
|
+
of the repetitions. For example, the first
|
|
337
|
+
Inception-ResNet-A block will have
|
|
338
|
+
`block_type='block35', block_idx=0`, and the layer names
|
|
339
|
+
will have a common prefix `'block35_0'`.
|
|
340
|
+
activation: activation function to use at the end of the block.
|
|
341
|
+
(see [activations](../activations.md)).
|
|
342
|
+
When `activation=None`, no activation is applied
|
|
343
|
+
(i.e., "linear" activation: `a(x) = x`).
|
|
344
|
+
# Returns
|
|
345
|
+
Output tensor for the block.
|
|
372
346
|
# Raises
|
|
373
|
-
ValueError:
|
|
347
|
+
ValueError: if `block_type` is not one of `'block35'`,
|
|
348
|
+
`'block17'` or `'block8'`.
|
|
349
|
+
Output tensor for the block.
|
|
350
|
+
"""
|
|
351
|
+
if block_type == "block35":
|
|
352
|
+
branch_0 = conv2d_bn(x, 32, 1)
|
|
353
|
+
branch_1 = conv2d_bn(x, 32, 1)
|
|
354
|
+
branch_1 = conv2d_bn(branch_1, 32, 3)
|
|
355
|
+
branch_2 = conv2d_bn(x, 32, 1)
|
|
356
|
+
branch_2 = conv2d_bn(branch_2, 48, 3)
|
|
357
|
+
branch_2 = conv2d_bn(branch_2, 64, 3)
|
|
358
|
+
branches = [branch_0, branch_1, branch_2]
|
|
359
|
+
elif block_type == "block17":
|
|
360
|
+
branch_0 = conv2d_bn(x, 192, 1)
|
|
361
|
+
branch_1 = conv2d_bn(x, 128, 1)
|
|
362
|
+
branch_1 = conv2d_bn(branch_1, 160, [1, 7])
|
|
363
|
+
branch_1 = conv2d_bn(branch_1, 192, [7, 1])
|
|
364
|
+
branches = [branch_0, branch_1]
|
|
365
|
+
elif block_type == "block8":
|
|
366
|
+
branch_0 = conv2d_bn(x, 192, 1)
|
|
367
|
+
branch_1 = conv2d_bn(x, 192, 1)
|
|
368
|
+
branch_1 = conv2d_bn(branch_1, 224, [1, 3])
|
|
369
|
+
branch_1 = conv2d_bn(branch_1, 256, [3, 1])
|
|
370
|
+
branches = [branch_0, branch_1]
|
|
371
|
+
else:
|
|
372
|
+
raise ValueError(
|
|
373
|
+
"Unknown Inception-ResNet block type. "
|
|
374
|
+
'Expects "block35", "block17" or "block8", '
|
|
375
|
+
f"but got: {block_type}"
|
|
376
|
+
)
|
|
377
|
+
|
|
378
|
+
block_name = f"{block_type}_{block_idx}"
|
|
379
|
+
channel_axis = 1 if backend.image_data_format() == "channels_first" else 3
|
|
380
|
+
mixed = layers.Concatenate(axis=channel_axis, name=f"{block_name}_mixed")(branches)
|
|
381
|
+
up = conv2d_bn(
|
|
382
|
+
mixed,
|
|
383
|
+
x.shape[channel_axis],
|
|
384
|
+
1,
|
|
385
|
+
activation=None,
|
|
386
|
+
use_bias=True,
|
|
387
|
+
name=f"{block_name}_conv",
|
|
388
|
+
)
|
|
389
|
+
|
|
390
|
+
x = layers.Lambda(
|
|
391
|
+
lambda inputs, scale: inputs[0] + inputs[1] * scale,
|
|
392
|
+
output_shape=x.shape[1:],
|
|
393
|
+
arguments={"scale": scale},
|
|
394
|
+
name=block_name,
|
|
395
|
+
)([x, up])
|
|
396
|
+
|
|
397
|
+
if activation is not None:
|
|
398
|
+
x = layers.Activation(activation, name=f"{block_name}_ac")(x)
|
|
399
|
+
|
|
400
|
+
return x
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def preprocess_input(x, data_format=None):
|
|
404
|
+
"""Preprocesses a numpy array encoding a batch of images.
|
|
405
|
+
|
|
406
|
+
Args:
|
|
407
|
+
x: a 4D numpy array consists of RGB values within [0, 255].
|
|
408
|
+
|
|
409
|
+
Returns:
|
|
410
|
+
Preprocessed array.
|
|
411
|
+
"""
|
|
412
|
+
return imagenet_utils.preprocess_input(x, data_format=data_format, mode="tf")
|
|
413
|
+
|
|
414
|
+
|
|
415
|
+
def decode_predictions(preds, top=5):
|
|
416
|
+
"""Decodes the prediction of an ImageNet model.
|
|
417
|
+
|
|
418
|
+
Args:
|
|
419
|
+
preds: NumPy array encoding a batch of predictions.
|
|
420
|
+
top: Integer, how many top-guesses to return. Defaults to `5`.
|
|
421
|
+
|
|
422
|
+
Returns:
|
|
423
|
+
A list of lists of top class prediction tuples
|
|
424
|
+
`(class_name, class_description, score)`.
|
|
425
|
+
One list of tuples per sample in batch input.
|
|
426
|
+
|
|
427
|
+
Raises:
|
|
428
|
+
ValueError: In case of invalid shape of the `pred` array
|
|
429
|
+
(must be 2D).
|
|
430
|
+
"""
|
|
431
|
+
return imagenet_utils.decode_predictions(preds, top=top)
|
|
432
|
+
|
|
433
|
+
|
|
434
|
+
def _obtain_input_shape(
|
|
435
|
+
input_shape,
|
|
436
|
+
default_size,
|
|
437
|
+
min_size,
|
|
438
|
+
data_format,
|
|
439
|
+
require_flatten,
|
|
440
|
+
weights=None,
|
|
441
|
+
):
|
|
442
|
+
"""Internal utility to compute/validate a model's input shape.
|
|
443
|
+
|
|
444
|
+
Args:
|
|
445
|
+
input_shape: Either None (will return the default network input shape),
|
|
446
|
+
or a user-provided shape to be validated.
|
|
447
|
+
default_size: Default input width/height for the model.
|
|
448
|
+
min_size: Minimum input width/height accepted by the model.
|
|
449
|
+
data_format: Image data format to use.
|
|
450
|
+
require_flatten: Whether the model is expected to
|
|
451
|
+
be linked to a classifier via a Flatten layer.
|
|
452
|
+
weights: One of `None` (random initialization)
|
|
453
|
+
or 'imagenet' (pre-training on ImageNet).
|
|
454
|
+
If weights='imagenet' input channels must be equal to 3.
|
|
455
|
+
|
|
456
|
+
Returns:
|
|
457
|
+
An integer shape tuple (may include None entries).
|
|
458
|
+
|
|
459
|
+
Raises:
|
|
460
|
+
ValueError: In case of invalid argument values.
|
|
374
461
|
"""
|
|
375
462
|
if weights != "imagenet" and input_shape and len(input_shape) == 3:
|
|
376
463
|
if data_format == "channels_first":
|
|
377
|
-
if input_shape
|
|
378
|
-
|
|
464
|
+
correct_channel_axis = 1 if len(input_shape) == 4 else 0
|
|
465
|
+
if input_shape[correct_channel_axis] not in {1, 3}:
|
|
466
|
+
warnings.warn(
|
|
379
467
|
"This model usually expects 1 or 3 input channels. "
|
|
380
|
-
"However, it was passed an input_shape
|
|
381
|
-
|
|
382
|
-
|
|
468
|
+
"However, it was passed an input_shape "
|
|
469
|
+
f"with {input_shape[0]} input channels.",
|
|
470
|
+
stacklevel=2,
|
|
383
471
|
)
|
|
384
472
|
default_shape = (input_shape[0], default_size, default_size)
|
|
385
473
|
else:
|
|
386
474
|
if input_shape[-1] not in {1, 3}:
|
|
387
|
-
warnings.warn(
|
|
475
|
+
warnings.warn(
|
|
388
476
|
"This model usually expects 1 or 3 input channels. "
|
|
389
|
-
"However, it was passed an input_shape
|
|
390
|
-
|
|
391
|
-
|
|
477
|
+
"However, it was passed an input_shape "
|
|
478
|
+
f"with {input_shape[-1]} input channels.",
|
|
479
|
+
stacklevel=2,
|
|
392
480
|
)
|
|
393
481
|
default_shape = (default_size, default_size, input_shape[-1])
|
|
394
482
|
else:
|
|
@@ -402,7 +490,8 @@ def _obtain_input_shape(
|
|
|
402
490
|
raise ValueError(
|
|
403
491
|
"When setting `include_top=True` "
|
|
404
492
|
"and loading `imagenet` weights, "
|
|
405
|
-
"`input_shape` should be
|
|
493
|
+
f"`input_shape` should be {default_shape}. "
|
|
494
|
+
f"Received: input_shape={input_shape}"
|
|
406
495
|
)
|
|
407
496
|
return default_shape
|
|
408
497
|
if input_shape:
|
|
@@ -412,20 +501,16 @@ def _obtain_input_shape(
|
|
|
412
501
|
raise ValueError("`input_shape` must be a tuple of three integers.")
|
|
413
502
|
if input_shape[0] != 3 and weights == "imagenet":
|
|
414
503
|
raise ValueError(
|
|
415
|
-
"The input must have 3 channels;
|
|
416
|
-
"`input_shape=
|
|
504
|
+
"The input must have 3 channels; Received "
|
|
505
|
+
f"`input_shape={input_shape}`"
|
|
417
506
|
)
|
|
418
507
|
if (input_shape[1] is not None and input_shape[1] < min_size) or (
|
|
419
508
|
input_shape[2] is not None and input_shape[2] < min_size
|
|
420
509
|
):
|
|
421
510
|
raise ValueError(
|
|
422
|
-
"Input size must be at least "
|
|
423
|
-
|
|
424
|
-
|
|
425
|
-
+ str(min_size)
|
|
426
|
-
+ "; got `input_shape="
|
|
427
|
-
+ str(input_shape)
|
|
428
|
-
+ "`"
|
|
511
|
+
f"Input size must be at least {min_size}"
|
|
512
|
+
f"x{min_size}; Received: "
|
|
513
|
+
f"input_shape={input_shape}"
|
|
429
514
|
)
|
|
430
515
|
else:
|
|
431
516
|
if input_shape is not None:
|
|
@@ -433,20 +518,16 @@ def _obtain_input_shape(
|
|
|
433
518
|
raise ValueError("`input_shape` must be a tuple of three integers.")
|
|
434
519
|
if input_shape[-1] != 3 and weights == "imagenet":
|
|
435
520
|
raise ValueError(
|
|
436
|
-
"The input must have 3 channels;
|
|
437
|
-
"`input_shape=
|
|
521
|
+
"The input must have 3 channels; Received "
|
|
522
|
+
f"`input_shape={input_shape}`"
|
|
438
523
|
)
|
|
439
524
|
if (input_shape[0] is not None and input_shape[0] < min_size) or (
|
|
440
525
|
input_shape[1] is not None and input_shape[1] < min_size
|
|
441
526
|
):
|
|
442
527
|
raise ValueError(
|
|
443
528
|
"Input size must be at least "
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
+ str(min_size)
|
|
447
|
-
+ "; got `input_shape="
|
|
448
|
-
+ str(input_shape)
|
|
449
|
-
+ "`"
|
|
529
|
+
f"{min_size}x{min_size}; Received: "
|
|
530
|
+
f"input_shape={input_shape}"
|
|
450
531
|
)
|
|
451
532
|
else:
|
|
452
533
|
if require_flatten:
|
|
@@ -461,6 +542,6 @@ def _obtain_input_shape(
|
|
|
461
542
|
raise ValueError(
|
|
462
543
|
"If `include_top` is True, "
|
|
463
544
|
"you should specify a static `input_shape`. "
|
|
464
|
-
"
|
|
545
|
+
f"Received: input_shape={input_shape}"
|
|
465
546
|
)
|
|
466
547
|
return input_shape
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: segmodels_keras
|
|
3
|
-
Version: 0.1.0.
|
|
3
|
+
Version: 0.1.0.dev2
|
|
4
4
|
Summary: Image segmentation models with pre-trained backbones with Keras.
|
|
5
|
-
Home-page: https://github.com/
|
|
5
|
+
Home-page: https://github.com/orthoseg/segmodels_keras
|
|
6
6
|
Author: Pieter Roggemans
|
|
7
7
|
Author-email: pieter.roggemans@gmail.com
|
|
8
8
|
License: MIT
|
|
@@ -15,6 +15,7 @@ Requires-Python: >=3.0.0
|
|
|
15
15
|
Description-Content-Type: text/markdown
|
|
16
16
|
License-File: LICENSE
|
|
17
17
|
Requires-Dist: keras
|
|
18
|
+
Requires-Dist: packaging
|
|
18
19
|
Provides-Extra: tests
|
|
19
20
|
Requires-Dist: numpy; extra == "tests"
|
|
20
21
|
Requires-Dist: pytest; extra == "tests"
|
|
@@ -10,7 +10,7 @@ from setuptools import find_packages, setup
|
|
|
10
10
|
# Package meta-data.
|
|
11
11
|
NAME = "segmodels_keras"
|
|
12
12
|
DESCRIPTION = "Image segmentation models with pre-trained backbones with Keras."
|
|
13
|
-
URL = "https://github.com/
|
|
13
|
+
URL = "https://github.com/orthoseg/segmodels_keras"
|
|
14
14
|
EMAIL = "pieter.roggemans@gmail.com"
|
|
15
15
|
AUTHOR = "Pieter Roggemans"
|
|
16
16
|
REQUIRES_PYTHON = ">=3.0.0"
|
|
@@ -24,7 +24,7 @@ VERSION = None
|
|
|
24
24
|
here = os.path.abspath(os.path.dirname(__file__))
|
|
25
25
|
|
|
26
26
|
# What packages are required for this module to be executed?
|
|
27
|
-
REQUIRED = ["keras"]
|
|
27
|
+
REQUIRED = ["keras", "packaging"]
|
|
28
28
|
|
|
29
29
|
# What packages are optional?
|
|
30
30
|
EXTRAS = {
|
|
@@ -39,10 +39,10 @@ try:
|
|
|
39
39
|
except FileNotFoundError:
|
|
40
40
|
long_description = DESCRIPTION
|
|
41
41
|
|
|
42
|
-
# Load the package's
|
|
42
|
+
# Load the package's _version.py module as a dictionary.
|
|
43
43
|
about = {}
|
|
44
44
|
if not VERSION:
|
|
45
|
-
with open(os.path.join(here, NAME, "
|
|
45
|
+
with open(os.path.join(here, NAME, "_version.py")) as f:
|
|
46
46
|
exec(f.read(), about)
|
|
47
47
|
else:
|
|
48
48
|
about["__version__"] = VERSION
|
|
@@ -1,260 +0,0 @@
|
|
|
1
|
-
segmodels_keras
|
|
2
|
-
=========================
|
|
3
|
-
|
|
4
|
-
This is a fork of the
|
|
5
|
-
[segmentation_models](https://github.com/qubvel/segmentation_models) library by
|
|
6
|
-
Pavel Iakubovskii, which is not maintained anymore.
|
|
7
|
-
|
|
8
|
-
This fork is updated to support latest versions of Keras and TensorFlow, and also
|
|
9
|
-
contains some bug fixes and improvements.
|
|
10
|
-
|
|
11
|
-
It is not meant as a full replacement of the original library, but rather as a
|
|
12
|
-
solution for a library I developed and depended on segmentation_models:
|
|
13
|
-
[orthoseg](https://github.com/orthoseg/orthoseg).
|
|
14
|
-
|
|
15
|
-
Hence, backwards compatibility,... is not guaranteed or even an explicit goal.
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
**The main features** of this library are:
|
|
19
|
-
|
|
20
|
-
- High level API (just two lines of code to create model for segmentation)
|
|
21
|
-
- **4** models architectures for binary and multi-class image segmentation
|
|
22
|
-
(including legendary **Unet**)
|
|
23
|
-
- **25** available backbones for each architecture
|
|
24
|
-
- All backbones have **pre-trained** weights for faster and better
|
|
25
|
-
convergence
|
|
26
|
-
- Helpful segmentation losses (Jaccard, Dice, Focal) and metrics (IoU, F-score)
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
Table of Contents
|
|
30
|
-
~~~~~~~~~~~~~~~~~
|
|
31
|
-
- `Quick start`_
|
|
32
|
-
- `Simple training pipeline`_
|
|
33
|
-
- `Examples`_
|
|
34
|
-
- `Models and Backbones`_
|
|
35
|
-
- `Installation`_
|
|
36
|
-
- `Documentation`_
|
|
37
|
-
- `Change log`_
|
|
38
|
-
- `Citing`_
|
|
39
|
-
- `License`_
|
|
40
|
-
|
|
41
|
-
Quick start
|
|
42
|
-
~~~~~~~~~~~
|
|
43
|
-
Library is build to work together with Keras and TensorFlow Keras frameworks
|
|
44
|
-
|
|
45
|
-
.. code:: python
|
|
46
|
-
|
|
47
|
-
import segmentation_models as sm
|
|
48
|
-
# Segmentation Models: using `keras` framework.
|
|
49
|
-
|
|
50
|
-
By default it tries to import ``keras``, if it is not installed, it will try to start with ``tensorflow.keras`` framework.
|
|
51
|
-
There are several ways to choose framework:
|
|
52
|
-
|
|
53
|
-
- Provide environment variable ``SM_FRAMEWORK=keras`` / ``SM_FRAMEWORK=tf.keras`` before import ``segmentation_models``
|
|
54
|
-
- Change framework ``sm.set_framework('keras')`` / ``sm.set_framework('tf.keras')``
|
|
55
|
-
|
|
56
|
-
You can also specify what kind of ``image_data_format`` to use, segmentation-models works with both: ``channels_last`` and ``channels_first``.
|
|
57
|
-
This can be useful for further model conversion to Nvidia TensorRT format or optimizing model for cpu/gpu computations.
|
|
58
|
-
|
|
59
|
-
.. code:: python
|
|
60
|
-
|
|
61
|
-
import keras
|
|
62
|
-
# or from tensorflow import keras
|
|
63
|
-
|
|
64
|
-
keras.backend.set_image_data_format('channels_last')
|
|
65
|
-
# or keras.backend.set_image_data_format('channels_first')
|
|
66
|
-
|
|
67
|
-
Created segmentation model is just an instance of Keras Model, which can be build as easy as:
|
|
68
|
-
|
|
69
|
-
.. code:: python
|
|
70
|
-
|
|
71
|
-
model = sm.Unet()
|
|
72
|
-
|
|
73
|
-
Depending on the task, you can change the network architecture by choosing backbones with fewer or more parameters and use pretrainded weights to initialize it:
|
|
74
|
-
|
|
75
|
-
.. code:: python
|
|
76
|
-
|
|
77
|
-
model = sm.Unet('resnet34', encoder_weights='imagenet')
|
|
78
|
-
|
|
79
|
-
Change number of output classes in the model (choose your case):
|
|
80
|
-
|
|
81
|
-
.. code:: python
|
|
82
|
-
|
|
83
|
-
# binary segmentation (this parameters are default when you call Unet('resnet34')
|
|
84
|
-
model = sm.Unet('resnet34', classes=1, activation='sigmoid')
|
|
85
|
-
|
|
86
|
-
.. code:: python
|
|
87
|
-
|
|
88
|
-
# multiclass segmentation with non overlapping class masks (your classes + background)
|
|
89
|
-
model = sm.Unet('resnet34', classes=3, activation='softmax')
|
|
90
|
-
|
|
91
|
-
.. code:: python
|
|
92
|
-
|
|
93
|
-
# multiclass segmentation with independent overlapping/non-overlapping class masks
|
|
94
|
-
model = sm.Unet('resnet34', classes=3, activation='sigmoid')
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
Change input shape of the model:
|
|
98
|
-
|
|
99
|
-
.. code:: python
|
|
100
|
-
|
|
101
|
-
# if you set input channels not equal to 3, you have to set encoder_weights=None
|
|
102
|
-
# how to handle such case with encoder_weights='imagenet' described in docs
|
|
103
|
-
model = Unet('resnet34', input_shape=(None, None, 6), encoder_weights=None)
|
|
104
|
-
|
|
105
|
-
Simple training pipeline
|
|
106
|
-
~~~~~~~~~~~~~~~~~~~~~~~~
|
|
107
|
-
|
|
108
|
-
.. code:: python
|
|
109
|
-
|
|
110
|
-
import segmentation_models as sm
|
|
111
|
-
|
|
112
|
-
BACKBONE = 'resnet34'
|
|
113
|
-
preprocess_input = sm.get_preprocessing(BACKBONE)
|
|
114
|
-
|
|
115
|
-
# load your data
|
|
116
|
-
x_train, y_train, x_val, y_val = load_data(...)
|
|
117
|
-
|
|
118
|
-
# preprocess input
|
|
119
|
-
x_train = preprocess_input(x_train)
|
|
120
|
-
x_val = preprocess_input(x_val)
|
|
121
|
-
|
|
122
|
-
# define model
|
|
123
|
-
model = sm.Unet(BACKBONE, encoder_weights='imagenet')
|
|
124
|
-
model.compile(
|
|
125
|
-
'Adam',
|
|
126
|
-
loss=sm.losses.bce_jaccard_loss,
|
|
127
|
-
metrics=[sm.metrics.iou_score],
|
|
128
|
-
)
|
|
129
|
-
|
|
130
|
-
# fit model
|
|
131
|
-
# if you use data generator use model.fit_generator(...) instead of model.fit(...)
|
|
132
|
-
# more about `fit_generator` here: https://keras.io/models/sequential/#fit_generator
|
|
133
|
-
model.fit(
|
|
134
|
-
x=x_train,
|
|
135
|
-
y=y_train,
|
|
136
|
-
batch_size=16,
|
|
137
|
-
epochs=100,
|
|
138
|
-
validation_data=(x_val, y_val),
|
|
139
|
-
)
|
|
140
|
-
|
|
141
|
-
Same manipulations can be done with ``Linknet``, ``PSPNet`` and ``FPN``. For more detailed information about models API and use cases `Read the Docs <https://segmentation-models.readthedocs.io/en/latest/>`__.
|
|
142
|
-
|
|
143
|
-
Examples
|
|
144
|
-
~~~~~~~~
|
|
145
|
-
Models training examples:
|
|
146
|
-
- [Jupyter Notebook] Binary segmentation (`cars`) on CamVid dataset `here <https://github.com/qubvel/segmentation_models/blob/master/examples/binary%20segmentation%20(camvid).ipynb>`__.
|
|
147
|
-
- [Jupyter Notebook] Multi-class segmentation (`cars`, `pedestrians`) on CamVid dataset `here <https://github.com/qubvel/segmentation_models/blob/master/examples/multiclass%20segmentation%20(camvid).ipynb>`__.
|
|
148
|
-
|
|
149
|
-
Models and Backbones
|
|
150
|
-
~~~~~~~~~~~~~~~~~~~~
|
|
151
|
-
**Models**
|
|
152
|
-
|
|
153
|
-
- `Unet <https://arxiv.org/abs/1505.04597>`__
|
|
154
|
-
- `FPN <http://presentations.cocodataset.org/COCO17-Stuff-FAIR.pdf>`__
|
|
155
|
-
- `Linknet <https://arxiv.org/abs/1707.03718>`__
|
|
156
|
-
- `PSPNet <https://arxiv.org/abs/1612.01105>`__
|
|
157
|
-
|
|
158
|
-
============= ==============
|
|
159
|
-
Unet Linknet
|
|
160
|
-
============= ==============
|
|
161
|
-
|unet_image| |linknet_image|
|
|
162
|
-
============= ==============
|
|
163
|
-
|
|
164
|
-
============= ==============
|
|
165
|
-
PSPNet FPN
|
|
166
|
-
============= ==============
|
|
167
|
-
|psp_image| |fpn_image|
|
|
168
|
-
============= ==============
|
|
169
|
-
|
|
170
|
-
.. _Unet: https://github.com/qubvel/segmentation_models/blob/readme/LICENSE
|
|
171
|
-
.. _Linknet: https://arxiv.org/abs/1707.03718
|
|
172
|
-
.. _PSPNet: https://arxiv.org/abs/1612.01105
|
|
173
|
-
.. _FPN: http://presentations.cocodataset.org/COCO17-Stuff-FAIR.pdf
|
|
174
|
-
|
|
175
|
-
.. |unet_image| image:: https://github.com/qubvel/segmentation_models/blob/master/images/unet.png
|
|
176
|
-
.. |linknet_image| image:: https://github.com/qubvel/segmentation_models/blob/master/images/linknet.png
|
|
177
|
-
.. |psp_image| image:: https://github.com/qubvel/segmentation_models/blob/master/images/pspnet.png
|
|
178
|
-
.. |fpn_image| image:: https://github.com/qubvel/segmentation_models/blob/master/images/fpn.png
|
|
179
|
-
|
|
180
|
-
**Backbones**
|
|
181
|
-
|
|
182
|
-
.. table::
|
|
183
|
-
|
|
184
|
-
============= =====
|
|
185
|
-
Type Names
|
|
186
|
-
============= =====
|
|
187
|
-
VGG ``'vgg16' 'vgg19'``
|
|
188
|
-
ResNet ``'resnet18' 'resnet34' 'resnet50' 'resnet101' 'resnet152'``
|
|
189
|
-
SE-ResNet ``'seresnet18' 'seresnet34' 'seresnet50' 'seresnet101' 'seresnet152'``
|
|
190
|
-
ResNeXt ``'resnext50' 'resnext101'``
|
|
191
|
-
SE-ResNeXt ``'seresnext50' 'seresnext101'``
|
|
192
|
-
SENet154 ``'senet154'``
|
|
193
|
-
DenseNet ``'densenet121' 'densenet169' 'densenet201'``
|
|
194
|
-
Inception ``'inceptionv3' 'inceptionresnetv2'``
|
|
195
|
-
MobileNet ``'mobilenet' 'mobilenetv2'``
|
|
196
|
-
EfficientNet ``'efficientnetb0' 'efficientnetb1' 'efficientnetb2' 'efficientnetb3' 'efficientnetb4' 'efficientnetb5' efficientnetb6' efficientnetb7'``
|
|
197
|
-
============= =====
|
|
198
|
-
|
|
199
|
-
.. epigraph::
|
|
200
|
-
All backbones have weights trained on 2012 ILSVRC ImageNet dataset (``encoder_weights='imagenet'``).
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
Installation
|
|
204
|
-
~~~~~~~~~~~~
|
|
205
|
-
|
|
206
|
-
**Requirements**
|
|
207
|
-
|
|
208
|
-
1) python 3
|
|
209
|
-
2) keras >= 2.2.0 or tensorflow >= 1.13
|
|
210
|
-
3) keras-applications >= 1.0.7, <=1.0.8
|
|
211
|
-
4) image-classifiers == 1.0.*
|
|
212
|
-
5) efficientnet == 1.0.*
|
|
213
|
-
|
|
214
|
-
**PyPI stable package**
|
|
215
|
-
|
|
216
|
-
.. code:: bash
|
|
217
|
-
|
|
218
|
-
$ pip install -U segmentation-models
|
|
219
|
-
|
|
220
|
-
**PyPI latest package**
|
|
221
|
-
|
|
222
|
-
.. code:: bash
|
|
223
|
-
|
|
224
|
-
$ pip install -U --pre segmentation-models
|
|
225
|
-
|
|
226
|
-
**Source latest version**
|
|
227
|
-
|
|
228
|
-
.. code:: bash
|
|
229
|
-
|
|
230
|
-
$ pip install git+https://github.com/qubvel/segmentation_models
|
|
231
|
-
|
|
232
|
-
Documentation
|
|
233
|
-
~~~~~~~~~~~~~
|
|
234
|
-
Latest **documentation** is avaliable on `Read the
|
|
235
|
-
Docs <https://segmentation-models.readthedocs.io/en/latest/>`__
|
|
236
|
-
|
|
237
|
-
Change Log
|
|
238
|
-
~~~~~~~~~~
|
|
239
|
-
To see important changes between versions look at CHANGELOG.md_
|
|
240
|
-
|
|
241
|
-
Citing
|
|
242
|
-
~~~~~~~~
|
|
243
|
-
|
|
244
|
-
.. code::
|
|
245
|
-
|
|
246
|
-
@misc{Yakubovskiy:2019,
|
|
247
|
-
Author = {Pavel Iakubovskii},
|
|
248
|
-
Title = {Segmentation Models},
|
|
249
|
-
Year = {2019},
|
|
250
|
-
Publisher = {GitHub},
|
|
251
|
-
Journal = {GitHub repository},
|
|
252
|
-
Howpublished = {\url{https://github.com/qubvel/segmentation_models}}
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
License
|
|
256
|
-
~~~~~~~
|
|
257
|
-
Project is distributed under `MIT Licence`_.
|
|
258
|
-
|
|
259
|
-
.. _CHANGELOG.md: https://github.com/qubvel/segmentation_models/blob/master/CHANGELOG.md
|
|
260
|
-
.. _`MIT Licence`: https://github.com/qubvel/segmentation_models/blob/master/LICENSE
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/backbones/__init__.py
RENAMED
|
File without changes
|
{segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/backbones/inception_v3.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/models/__init__.py
RENAMED
|
File without changes
|
{segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras/models/_common_blocks.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{segmodels_keras-0.1.0.dev0 → segmodels_keras-0.1.0.dev2}/segmodels_keras.egg-info/top_level.txt
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|