diff --git a/bob/bio/face/config/baseline/mobilenetv2_msceleb_arcface_2021.py b/bob/bio/face/config/baseline/mobilenetv2_msceleb_arcface_2021.py new file mode 100644 index 0000000000000000000000000000000000000000..e68e7ef3edf5d8c080efc9aac7bf06a39d85982b --- /dev/null +++ b/bob/bio/face/config/baseline/mobilenetv2_msceleb_arcface_2021.py @@ -0,0 +1,34 @@ +from bob.bio.face.embeddings.mobilenet_v2 import MobileNetv2_MsCeleb_ArcFace_2021 +from bob.bio.face.config.baseline.helpers import embedding_transformer_112x112 +from bob.bio.base.pipelines.vanilla_biometrics import ( + Distance, + VanillaBiometricsPipeline, +) + +memory_demanding = False +if "database" in locals(): + annotation_type = database.annotation_type + fixed_positions = database.fixed_positions + + memory_demanding = ( + database.memory_demanding if hasattr(database, "memory_demanding") else False + ) +else: + annotation_type = None + fixed_positions = None + + +def load(annotation_type, fixed_positions=None): + transformer = embedding_transformer_112x112( + MobileNetv2_MsCeleb_ArcFace_2021(memory_demanding=memory_demanding), + annotation_type, + fixed_positions, + ) + + algorithm = Distance() + + return VanillaBiometricsPipeline(transformer, algorithm) + + +pipeline = load(annotation_type, fixed_positions) +transformer = pipeline.transformer diff --git a/bob/bio/face/config/baseline/resnet50_msceleb_arcface_2021.py b/bob/bio/face/config/baseline/resnet50_msceleb_arcface_2021.py new file mode 100644 index 0000000000000000000000000000000000000000..dfeb4b74af2958879e83c74b4428c2cb7601d308 --- /dev/null +++ b/bob/bio/face/config/baseline/resnet50_msceleb_arcface_2021.py @@ -0,0 +1,34 @@ +from bob.bio.face.embeddings.resnet50 import Resnet50_MsCeleb_ArcFace_2021 +from bob.bio.face.config.baseline.helpers import embedding_transformer_112x112 +from bob.bio.base.pipelines.vanilla_biometrics import ( + Distance, + VanillaBiometricsPipeline, +) + +memory_demanding = False +if "database" in locals(): + annotation_type = database.annotation_type + fixed_positions = database.fixed_positions + + memory_demanding = ( + database.memory_demanding if hasattr(database, "memory_demanding") else False + ) +else: + annotation_type = None + fixed_positions = None + + +def load(annotation_type, fixed_positions=None): + transformer = embedding_transformer_112x112( + Resnet50_MsCeleb_ArcFace_2021(memory_demanding=memory_demanding), + annotation_type, + fixed_positions, + ) + + algorithm = Distance() + + return VanillaBiometricsPipeline(transformer, algorithm) + + +pipeline = load(annotation_type, fixed_positions) +transformer = pipeline.transformer diff --git a/bob/bio/face/embeddings/mobilenet_v2.py b/bob/bio/face/embeddings/mobilenet_v2.py new file mode 100644 index 0000000000000000000000000000000000000000..4966583ff6388b44706eec199fc3e6dcb8768359 --- /dev/null +++ b/bob/bio/face/embeddings/mobilenet_v2.py @@ -0,0 +1,79 @@ +from bob.bio.face.embeddings import download_model + + +from .tf2_inception_resnet import TransformTensorflow +import pkg_resources +import os +from bob.extension import rc +import tensorflow as tf + + +class MobileNetv2_MsCeleb_ArcFace_2021(TransformTensorflow): + """ + MobileNet Backbone trained with the MSCeleb 1M database. + + The bottleneck layer (a.k.a embedding) has 512d. + + The configuration file used to trained is: + + ```yaml + batch-size: 128 + face-size: 112 + face-output_size: 112 + n-classes: 85742 + + + ## Backbone + backbone: 'mobilenet-v2' + head: 'arcface' + s: 10 + bottleneck: 512 + m: 0.5 + + # Training parameters + solver: "sgd" + lr: 0.01 + dropout-rate: 0.5 + epochs: 500 + + + train-tf-record-path: "<PATH>" + validation-tf-record-path: "<PATH>" + + ``` + + + """ + + def __init__(self, memory_demanding=False): + internal_path = pkg_resources.resource_filename( + __name__, os.path.join("data", "mobilenet-v2-msceleb-arcface-2021"), + ) + + checkpoint_path = ( + internal_path + if rc["bob.bio.face.models.mobilenet-v2-msceleb-arcface-2021"] is None + else rc["bob.bio.face.models.mobilenet-v2-msceleb-arcface-2021"] + ) + + urls = [ + "https://www.idiap.ch/software/bob/data/bob/bob.bio.face/master/tf2/mobilenet-v2-msceleb-arcface-2021.tar.gz", + "http://www.idiap.ch/software/bob/data/bob/bob.bio.face/master/tf2/mobilenet-v2-msceleb-arcface-2021.tar.gz", + ] + + download_model(checkpoint_path, urls, "mobilenet-v2-msceleb-arcface-2021.tar.gz") + + super(MobileNetv2_MsCeleb_ArcFace_2021, self).__init__( + checkpoint_path, + preprocessor=lambda X: X / 255.0, + memory_demanding=memory_demanding, + ) + + def inference(self, X): + if self.preprocessor is not None: + X = self.preprocessor(tf.cast(X, "float32")) + + prelogits = self.model.predict_on_batch(X)[0] + embeddings = tf.math.l2_normalize(prelogits, axis=-1) + return embeddings + diff --git a/bob/bio/face/embeddings/resnet50.py b/bob/bio/face/embeddings/resnet50.py new file mode 100644 index 0000000000000000000000000000000000000000..8a75b2ed602e12c0e2dba708ab672b37c0c4bb3b --- /dev/null +++ b/bob/bio/face/embeddings/resnet50.py @@ -0,0 +1,79 @@ +from bob.bio.face.embeddings import download_model + + +from .tf2_inception_resnet import TransformTensorflow +import pkg_resources +import os +from bob.extension import rc +import tensorflow as tf + + +class Resnet50_MsCeleb_ArcFace_2021(TransformTensorflow): + """ + Resnet50 Backbone trained with the MSCeleb 1M database. + + The bottleneck layer (a.k.a embedding) has 512d. + + The configuration file used to trained is: + + ```yaml + batch-size: 128 + face-size: 112 + face-output_size: 112 + n-classes: 85742 + + + ## Backbone + backbone: 'resnet50' + head: 'arcface' + s: 10 + bottleneck: 512 + m: 0.5 + + # Training parameters + solver: "sgd" + lr: 0.01 + dropout-rate: 0.5 + epochs: 500 + + + train-tf-record-path: "<PATH>" + validation-tf-record-path: "<PATH>" + + ``` + + + """ + + def __init__(self, memory_demanding=False): + internal_path = pkg_resources.resource_filename( + __name__, os.path.join("data", "resnet50_msceleb_arcface_2021"), + ) + + checkpoint_path = ( + internal_path + if rc["bob.bio.face.models.resnet50_msceleb_arcface_2021"] is None + else rc["bob.bio.face.models.resnet50_msceleb_arcface_2021"] + ) + + urls = [ + "https://www.idiap.ch/software/bob/data/bob/bob.bio.face/master/tf2/resnet50_msceleb_arcface_2021.tar.gz", + "http://www.idiap.ch/software/bob/data/bob/bob.bio.face/master/tf2/resnet50_msceleb_arcface_2021.tar.gz", + ] + + download_model(checkpoint_path, urls, "resnet50_msceleb_arcface_2021.tar.gz") + + super(Resnet50_MsCeleb_ArcFace_2021, self).__init__( + checkpoint_path, + preprocessor=lambda X: X / 255.0, + memory_demanding=memory_demanding, + ) + + def inference(self, X): + if self.preprocessor is not None: + X = self.preprocessor(tf.cast(X, "float32")) + + prelogits = self.model.predict_on_batch(X)[0] + embeddings = tf.math.l2_normalize(prelogits, axis=-1) + return embeddings + diff --git a/bob/bio/face/embeddings/tf2_inception_resnet.py b/bob/bio/face/embeddings/tf2_inception_resnet.py index 18a2bc15b0279b81b497b4e27c16f2b89e333422..52ad8d266ac43555c6d8acb34ac1d957495f176c 100644 --- a/bob/bio/face/embeddings/tf2_inception_resnet.py +++ b/bob/bio/face/embeddings/tf2_inception_resnet.py @@ -52,14 +52,6 @@ class TransformTensorflow(TransformerMixin, BaseEstimator): def load_model(self): self.model = tf.keras.models.load_model(self.checkpoint_path) - 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 - def transform(self, X): def _transform(X): X = tf.convert_to_tensor(X) diff --git a/setup.py b/setup.py index daf7cdb02e6053673d10f8343262a3103b686a8e..34bcf0e25d3e179309f3962b9b60602ea80c265a 100644 --- a/setup.py +++ b/setup.py @@ -146,6 +146,8 @@ setup( "lgbphs = bob.bio.face.config.baseline.lgbphs:pipeline", "lda = bob.bio.face.config.baseline.lda:pipeline", "dummy = bob.bio.face.config.baseline.dummy:pipeline", + "resnet50-msceleb-arcface-2021 = bob.bio.face.config.baseline.resnet50_msceleb_arcface_2021:pipeline", + "mobilenetv2-msceleb-arcface-2021 = bob.bio.face.config.baseline.mobilenetv2_msceleb_arcface_2021", ], "bob.bio.config": [ "facenet-sanderberg = bob.bio.face.config.baseline.facenet_sanderberg", @@ -174,6 +176,8 @@ setup( "fargo = bob.bio.face.config.database.fargo", "meds = bob.bio.face.config.database.meds", "morph = bob.bio.face.config.database.morph", + "resnet50-msceleb-arcface-2021 = bob.bio.face.config.baseline.resnet50_msceleb_arcface_2021", + "mobilenetv2-msceleb-arcface-2021 = bob.bio.face.config.baseline.mobilenetv2_msceleb_arcface_2021", ], "bob.bio.cli": [ "display-face-annotations = bob.bio.face.script.display_face_annotations:display_face_annotations",