tf2_inception_resnet.py 10.3 KB
Newer Older
1
2
3
4
5
6
7
8
9
10
11
12
import tensorflow as tf
from bob.learn.tensorflow.utils.image import to_channels_last
from sklearn.base import TransformerMixin, BaseEstimator
from sklearn.utils import check_array

from tensorflow.keras import Sequential
from tensorflow.keras.layers.experimental import preprocessing
from bob.extension import rc
from functools import partial
import pkg_resources
import os
from bob.bio.face.embeddings import download_model
13
import numpy as np
14
15
16
17
18
19
20
21
22


def sanderberg_rescaling():
    # FIXED_STANDARDIZATION from https://github.com/davidsandberg/facenet
    # [-0.99609375, 0.99609375]
    preprocessor = preprocessing.Rescaling(scale=1 / 128, offset=-127.5 / 128)
    return preprocessor


23
class TransformTensorflow(TransformerMixin, BaseEstimator):
24
    """
25
    Base Transformer for Tensorflow architectures.
26
27
28
29
30
31
32
33
34

    Szegedy, Christian, et al. "Inception-v4, inception-resnet and the impact of residual connections on learning." arXiv preprint arXiv:1602.07261 (2016).

    Parameters
    ----------

    checkpoint_path: str
       Path containing the checkpoint

Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
35
    preprocessor:
36
37
        Preprocessor function

38
39
40
    memory_demanding bool
        If `True`, the `transform` method will run one sample at the time.
        This is useful when there is not enough memory available to forward big chucks of data.
41
42
    """

43
44
45
    def __init__(
        self, checkpoint_path, preprocessor=None, memory_demanding=False, **kwargs
    ):
46
47
48
49
        super().__init__(**kwargs)
        self.checkpoint_path = checkpoint_path
        self.model = None
        self.preprocessor = preprocessor
50
        self.memory_demanding = memory_demanding
51
52
53
54
55

    def load_model(self):
        self.model = tf.keras.models.load_model(self.checkpoint_path)

    def transform(self, X):
56
57
58
59
60
61
62
63
64
65
66
        def _transform(X):
            X = tf.convert_to_tensor(X)
            X = to_channels_last(X)

            if X.shape[-3:] != self.model.input_shape[-3:]:
                raise ValueError(
                    f"Image shape {X.shape} not supported. Expected {self.model.input_shape}"
                )

            return self.inference(X).numpy()

67
68
69
70
71
        if self.model is None:
            self.load_model()

        X = check_array(X, allow_nd=True)

72
73
74
75
        if self.memory_demanding:
            return np.array([_transform(x[None, ...]) for x in X])
        else:
            return _transform(X)
76
77
78
79

    def __getstate__(self):
        # Handling unpicklable objects
        d = self.__dict__.copy()
80
        d["model"] = None
81
82
        return d

83
84
85
86
87
88
89
90
    def inference(self, X):
        if self.preprocessor is not None:
            X = self.preprocessor(tf.cast(X, "float32"))

        prelogits = self.model.predict_on_batch(X)
        embeddings = tf.math.l2_normalize(prelogits, axis=-1)
        return embeddings

91
92
93
    def _more_tags(self):
        return {"stateless": True, "requires_fit": False}

94
95
96
    def __del__(self):
        self.model = None

97

98
class InceptionResnetv2_MsCeleb_CenterLoss_2018(TransformTensorflow):
99
100
101
102
103
104
105
    """
    InceptionResnet v2 model trained in 2018 using the MSCeleb dataset in the context of the work:

    Freitas Pereira, Tiago, André Anjos, and Sébastien Marcel. "Heterogeneous face recognition using domain specific units." IEEE Transactions on Information Forensics and Security 14.7 (2018): 1803-1816.

    """

106
    def __init__(self, memory_demanding=False):
107
108
109
110
111
112
113
114
115
116
117
118
        internal_path = pkg_resources.resource_filename(
            __name__, os.path.join("data", "inceptionresnetv2_msceleb_centerloss_2018"),
        )

        checkpoint_path = (
            internal_path
            if rc["bob.bio.face.models.InceptionResnetv2_MsCeleb_CenterLoss_2018"]
            is None
            else rc["bob.bio.face.models.InceptionResnetv2_MsCeleb_CenterLoss_2018"]
        )

        urls = [
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
119
            "https://www.idiap.ch/software/bob/data/bob/bob.bio.face/master/tf2/inceptionresnetv2_msceleb_centerloss_2018.tar.gz",
120
            "http://www.idiap.ch/software/bob/data/bob/bob.bio.face/master/tf2/inceptionresnetv2_msceleb_centerloss_2018.tar.gz",
121
122
123
124
125
126
127
        ]

        download_model(
            checkpoint_path, urls, "inceptionresnetv2_msceleb_centerloss_2018.tar.gz"
        )

        super(InceptionResnetv2_MsCeleb_CenterLoss_2018, self).__init__(
128
129
130
            checkpoint_path,
            preprocessor=tf.image.per_image_standardization,
            memory_demanding=memory_demanding,
131
132
133
        )


134
class InceptionResnetv2_Casia_CenterLoss_2018(TransformTensorflow):
135
136
137
138
139
140
141
    """
    InceptionResnet v2 model trained in 2018 using the CasiaWebFace dataset in the context of the work:

    Freitas Pereira, Tiago, André Anjos, and Sébastien Marcel. "Heterogeneous face recognition using domain specific units." IEEE Transactions on Information Forensics and Security 14.7 (2018): 1803-1816.

    """

142
    def __init__(self, memory_demanding=False):
143
144
145
146
147
148
149
150
151
152
153
        internal_path = pkg_resources.resource_filename(
            __name__, os.path.join("data", "inceptionresnetv2_casia_centerloss_2018"),
        )

        checkpoint_path = (
            internal_path
            if rc["bob.bio.face.models.InceptionResnetv2_Casia_CenterLoss_2018"] is None
            else rc["bob.bio.face.models.InceptionResnetv2_Casia_CenterLoss_2018"]
        )

        urls = [
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
154
            "https://www.idiap.ch/software/bob/data/bob/bob.bio.face/master/tf2/inceptionresnetv2_casia_centerloss_2018.tar.gz",
155
            "http://www.idiap.ch/software/bob/data/bob/bob.bio.face/master/tf2/inceptionresnetv2_casia_centerloss_2018.tar.gz",
156
157
158
159
160
161
162
        ]

        download_model(
            checkpoint_path, urls, "inceptionresnetv2_casia_centerloss_2018.tar.gz"
        )

        super(InceptionResnetv2_Casia_CenterLoss_2018, self).__init__(
163
164
165
            checkpoint_path,
            preprocessor=tf.image.per_image_standardization,
            memory_demanding=memory_demanding,
166
167
168
        )


169
class InceptionResnetv1_Casia_CenterLoss_2018(TransformTensorflow):
170
171
172
173
174
175
176
    """
    InceptionResnet v1 model trained in 2018 using the CasiaWebFace dataset in the context of the work:

    Freitas Pereira, Tiago, André Anjos, and Sébastien Marcel. "Heterogeneous face recognition using domain specific units." IEEE Transactions on Information Forensics and Security 14.7 (2018): 1803-1816.

    """

177
    def __init__(self, memory_demanding=False):
178
179
180
181
182
183
184
185
186
187
188
        internal_path = pkg_resources.resource_filename(
            __name__, os.path.join("data", "inceptionresnetv1_casia_centerloss_2018"),
        )

        checkpoint_path = (
            internal_path
            if rc["bob.bio.face.models.InceptionResnetv1_Casia_CenterLoss_2018"] is None
            else rc["bob.bio.face.models.InceptionResnetv1_Casia_CenterLoss_2018"]
        )

        urls = [
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
189
            "https://www.idiap.ch/software/bob/data/bob/bob.bio.face/master/tf2/inceptionresnetv1_casia_centerloss_2018.tar.gz",
190
            "http://www.idiap.ch/software/bob/data/bob/bob.bio.face/master/tf2/inceptionresnetv1_casia_centerloss_2018.tar.gz",
191
192
193
194
        ]

        download_model(
            checkpoint_path, urls, "inceptionresnetv1_casia_centerloss_2018.tar.gz"
195
        )
196
197

        super(InceptionResnetv1_Casia_CenterLoss_2018, self).__init__(
198
199
200
            checkpoint_path,
            preprocessor=tf.image.per_image_standardization,
            memory_demanding=memory_demanding,
201
202
        )

203

204
class InceptionResnetv1_MsCeleb_CenterLoss_2018(TransformTensorflow):
205
206
207
208
209
210
211
    """
    InceptionResnet v1 model trained in 2018 using the MsCeleb dataset in the context of the work:

    Freitas Pereira, Tiago, André Anjos, and Sébastien Marcel. "Heterogeneous face recognition using domain specific units." IEEE Transactions on Information Forensics and Security 14.7 (2018): 1803-1816.

    """

212
    def __init__(self, memory_demanding=False):
213
214
215
216
217
218
        internal_path = pkg_resources.resource_filename(
            __name__, os.path.join("data", "inceptionresnetv1_msceleb_centerloss_2018"),
        )

        checkpoint_path = (
            internal_path
219
220
            if rc["bob.bio.face.models.InceptionResnetv1_MsCeleb_CenterLoss_2018"]
            is None
221
222
223
224
            else rc["bob.bio.face.models.InceptionResnetv1_MsCeleb_CenterLoss_2018"]
        )

        urls = [
Amir MOHAMMADI's avatar
Amir MOHAMMADI committed
225
            "https://www.idiap.ch/software/bob/data/bob/bob.bio.face/master/tf2/inceptionresnetv1_msceleb_centerloss_2018.tar.gz",
226
            "http://www.idiap.ch/software/bob/data/bob/bob.bio.face/master/tf2/inceptionresnetv1_msceleb_centerloss_2018.tar.gz",
227
228
229
230
        ]

        download_model(
            checkpoint_path, urls, "inceptionresnetv1_msceleb_centerloss_2018.tar.gz"
231
        )
232
233

        super(InceptionResnetv1_MsCeleb_CenterLoss_2018, self).__init__(
234
235
236
            checkpoint_path,
            preprocessor=tf.image.per_image_standardization,
            memory_demanding=memory_demanding,
237
238
239
        )


240
class FaceNetSanderberg_20170512_110547(TransformTensorflow):
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
    """
    Wrapper for the free FaceNet from David Sanderberg model 20170512_110547:
    https://github.com/davidsandberg/facenet

    And for a preprocessor you can use::

        from bob.bio.face.preprocessor import FaceCrop
        # This is the size of the image that this model expects
        CROPPED_IMAGE_HEIGHT = 160
        CROPPED_IMAGE_WIDTH = 160
        # eye positions for frontal images
        RIGHT_EYE_POS = (46, 53)
        LEFT_EYE_POS = (46, 107)
        # Crops the face using eye annotations
        preprocessor = FaceCrop(
            cropped_image_size=(CROPPED_IMAGE_HEIGHT, CROPPED_IMAGE_WIDTH),
            cropped_positions={'leye': LEFT_EYE_POS, 'reye': RIGHT_EYE_POS},
            color_channel='rgb'
        )
    """

262
    def __init__(self, memory_demanding=False):
263
264
265
266
267
268
269
270
271
272
273
        internal_path = pkg_resources.resource_filename(
            __name__, os.path.join("data", "facenet_sanderberg_20170512_110547"),
        )

        checkpoint_path = (
            internal_path
            if rc["bob.bio.face.models.facenet_sanderberg_20170512_110547"] is None
            else rc["bob.bio.face.models.facenet_sanderberg_20170512_110547"]
        )

        urls = [
274
            "http://www.idiap.ch/software/bob/data/bob/bob.bio.face/master/tf2/facenet_sanderberg_20170512_110547.tar.gz"
275
276
277
278
        ]

        download_model(
            checkpoint_path, urls, "facenet_sanderberg_20170512_110547.tar.gz"
279
        )
280
281

        super(FaceNetSanderberg_20170512_110547, self).__init__(
282
283
284
            checkpoint_path,
            tf.image.per_image_standardization,
            memory_demanding=memory_demanding,
285
        )
286