diff --git a/README.md b/README.md index 09bd085..1357224 100644 --- a/README.md +++ b/README.md @@ -51,7 +51,7 @@ df = DeepFace.find(img_path = "img1.jpg", db_path = "C:/workspace/my_db") Deepface is a **hybrid** face recognition package. It currently wraps many **state-of-the-art** face recognition models: [`VGG-Face`](https://sefiks.com/2018/08/06/deep-face-recognition-with-keras/) , [`Google FaceNet`](https://sefiks.com/2018/09/03/face-recognition-with-facenet-in-keras/), [`OpenFace`](https://sefiks.com/2019/07/21/face-recognition-with-openface-in-keras/), [`Facebook DeepFace`](https://sefiks.com/2020/02/17/face-recognition-with-facebook-deepface-in-keras/), [`DeepID`](https://sefiks.com/2020/06/16/face-recognition-with-deepid-in-keras/), [`ArcFace`](https://sefiks.com/2020/12/14/deep-face-recognition-with-arcface-in-keras-and-python/) and [`Dlib`](https://sefiks.com/2020/07/11/face-recognition-with-dlib-in-python/). The default configuration uses VGG-Face model. ```python -models = ["VGG-Face", "Facenet", "OpenFace", "DeepFace", "DeepID", "ArcFace", "Dlib"] +models = ["VGG-Face", "Facenet", "Facenet512", "OpenFace", "DeepFace", "DeepID", "ArcFace", "Dlib"] result = DeepFace.verify("img1.jpg", "img2.jpg", model_name = models[1]) df = DeepFace.find(img_path = "img1.jpg", db_path = "C:/workspace/my_db", model_name = models[1]) ``` @@ -62,7 +62,7 @@ FaceNet, VGG-Face, ArcFace and Dlib [overperforms](https://youtu.be/i_MOwvhbLdI) **Similarity** -Face recognition models are regular [convolutional neural networks](https://sefiks.com/2018/03/23/convolutional-autoencoder-clustering-images-with-neural-networks/) and they are responsible to represent faces as vectors. We expect that a face pair of same person should be [more similar](https://sefiks.com/2020/05/22/fine-tuning-the-threshold-in-face-recognition/) than a face pair of different persons. +Face recognition models are regular [convolutional neural networks](https://sefiks.com/2018/03/23/convolutional-autoencoder-clustering-images-with-neural-networks/) and they are responsible to represent faces as vectors. We expect that a face pair of same person should be [more similar](https://sefiks.com/2020/05/22/fine-tuning-the-threshold-in-face-recognition/) than a face pair of different persons. Similarity could be calculated by different metrics such as [Cosine Similarity](https://sefiks.com/2018/08/13/cosine-similarity-in-machine-learning/), Euclidean Distance and L2 form. The default configuration uses cosine similarity. diff --git a/deepface/DeepFace.py b/deepface/DeepFace.py index 23aed72..3ab2fee 100644 --- a/deepface/DeepFace.py +++ b/deepface/DeepFace.py @@ -12,7 +12,7 @@ import pandas as pd from tqdm import tqdm import pickle -from deepface.basemodels import VGGFace, OpenFace, Facenet, FbDeepFace, DeepID, DlibWrapper, ArcFace, Boosting +from deepface.basemodels import VGGFace, OpenFace, Facenet, Facenet512, FbDeepFace, DeepID, DlibWrapper, ArcFace, Boosting from deepface.extendedmodels import Age, Gender, Race, Emotion from deepface.commons import functions, realtime, distance as dst @@ -41,6 +41,7 @@ def build_model(model_name): 'VGG-Face': VGGFace.loadModel, 'OpenFace': OpenFace.loadModel, 'Facenet': Facenet.loadModel, + 'Facenet512': Facenet512.loadModel, 'DeepFace': FbDeepFace.loadModel, 'DeepID': DeepID.loadModel, 'Dlib': DlibWrapper.loadModel, diff --git a/deepface/basemodels/Facenet.py b/deepface/basemodels/Facenet.py index 2b7c6cc..8b7b188 100644 --- a/deepface/basemodels/Facenet.py +++ b/deepface/basemodels/Facenet.py @@ -3,24 +3,42 @@ from pathlib import Path import gdown from functools import partial -from tensorflow.keras.models import Model -from tensorflow.keras.layers import Activation -from tensorflow.keras.layers import BatchNormalization -from tensorflow.keras.layers import Concatenate -from tensorflow.keras.layers import Conv2D -from tensorflow.keras.layers import Dense -from tensorflow.keras.layers import Dropout -from tensorflow.keras.layers import GlobalAveragePooling2D -from tensorflow.keras.layers import Input -from tensorflow.keras.layers import Lambda -from tensorflow.keras.layers import MaxPooling2D -from tensorflow.keras.layers import add -from tensorflow.keras import backend as K +import tensorflow as tf +tf_version = int(tf.__version__.split(".")[0]) + +if tf_version == 1: + from keras.models import Model + from keras.layers import Activation + from keras.layers import BatchNormalization + from keras.layers import Concatenate + from keras.layers import Conv2D + from keras.layers import Dense + from keras.layers import Dropout + from keras.layers import GlobalAveragePooling2D + from keras.layers import Input + from keras.layers import Lambda + from keras.layers import MaxPooling2D + from keras.layers import add + from keras import backend as K +else: + from tensorflow.keras.models import Model + from tensorflow.keras.layers import Activation + from tensorflow.keras.layers import BatchNormalization + from tensorflow.keras.layers import Concatenate + from tensorflow.keras.layers import Conv2D + from tensorflow.keras.layers import Dense + from tensorflow.keras.layers import Dropout + from tensorflow.keras.layers import GlobalAveragePooling2D + from tensorflow.keras.layers import Input + from tensorflow.keras.layers import Lambda + from tensorflow.keras.layers import MaxPooling2D + from tensorflow.keras.layers import add + from tensorflow.keras import backend as K def scaling(x, scale): return x * scale -def InceptionResNetV2(): +def InceptionResNetV2(dimension = 128): inputs = Input(shape=(160, 160, 3)) x = Conv2D(32, 3, strides=2, padding='valid', use_bias=False, name= 'Conv2d_1a_3x3') (inputs) @@ -522,7 +540,7 @@ def InceptionResNetV2(): x = GlobalAveragePooling2D(name='AvgPool')(x) x = Dropout(1.0 - 0.8, name='Dropout')(x) # Bottleneck - x = Dense(128, use_bias=False, name='Bottleneck')(x) + x = Dense(dimension, use_bias=False, name='Bottleneck')(x) x = BatchNormalization(momentum=0.995, epsilon=0.001, scale=False, name='Bottleneck_BatchNorm')(x) # Create model diff --git a/deepface/basemodels/Facenet512.py b/deepface/basemodels/Facenet512.py new file mode 100644 index 0000000..3185c7b --- /dev/null +++ b/deepface/basemodels/Facenet512.py @@ -0,0 +1,26 @@ +from deepface.basemodels import Facenet +from pathlib import Path +import os +import gdown + +def loadModel(url = 'https://github.com/serengil/deepface_models/releases/download/v1.0/facenet512_weights.h5'): + + model = Facenet.InceptionResNetV2(dimension = 512) + + #------------------------- + + home = str(Path.home()) + + if os.path.isfile(home+'/.deepface/weights/facenet512_weights.h5') != True: + print("facenet512_weights.h5 will be downloaded...") + + output = home+'/.deepface/weights/facenet_weights.h5' + gdown.download(url, output, quiet=False) + + #------------------------- + + model.load_weights(home+'/.deepface/weights/facenet512_weights.h5') + + #------------------------- + + return model diff --git a/deepface/commons/distance.py b/deepface/commons/distance.py index 959ce6d..bd55df5 100644 --- a/deepface/commons/distance.py +++ b/deepface/commons/distance.py @@ -29,6 +29,7 @@ def findThreshold(model_name, distance_metric): 'VGG-Face': {'cosine': 0.40, 'euclidean': 0.55, 'euclidean_l2': 0.75}, 'OpenFace': {'cosine': 0.10, 'euclidean': 0.55, 'euclidean_l2': 0.55}, 'Facenet': {'cosine': 0.40, 'euclidean': 10, 'euclidean_l2': 0.80}, + 'Facenet512': {'cosine': 0.3088582207770799, 'euclidean': 23.564685968740186, 'euclidean_l2': 1.0461709266148662}, 'DeepFace': {'cosine': 0.23, 'euclidean': 64, 'euclidean_l2': 0.64}, 'DeepID': {'cosine': 0.015, 'euclidean': 45, 'euclidean_l2': 0.17}, 'Dlib': {'cosine': 0.07, 'euclidean': 0.6, 'euclidean_l2': 0.6}, diff --git a/tests/dataset/img22.jpg b/tests/dataset/img22.jpg new file mode 100644 index 0000000..0d18c94 Binary files /dev/null and b/tests/dataset/img22.jpg differ diff --git a/tests/unit_tests.py b/tests/unit_tests.py index f4d2fca..4350c0c 100644 --- a/tests/unit_tests.py +++ b/tests/unit_tests.py @@ -182,7 +182,7 @@ dataset = [ #models = ['VGG-Face', 'Facenet', 'OpenFace', 'DeepFace', 'DeepID', 'Dlib', 'ArcFace'] metrics = ['cosine', 'euclidean', 'euclidean_l2'] -models = ['VGG-Face', 'Facenet', 'Dlib', 'ArcFace'] #those are robust models +models = ['VGG-Face', 'Facenet', 'Facenet512', 'Dlib', 'ArcFace'] #those are robust models #metrics = ['cosine'] passed_tests = 0; test_cases = 0