From 3907515a0db16227652c24bde107436bda369014 Mon Sep 17 00:00:00 2001 From: serengil Date: Wed, 2 Dec 2020 11:10:54 +0300 Subject: [PATCH] clean codes --- README.md | 13 ++++--------- deepface/DeepFace.py | 7 ++----- deepface/basemodels/Boosting.py | 22 +++++++++------------- deepface/commons/distance.py | 17 +++++++++++++++++ deepface/commons/functions.py | 27 +++++---------------------- deepface/commons/realtime.py | 2 +- tests/unit_tests.py | 6 ++++-- 7 files changed, 42 insertions(+), 52 deletions(-) diff --git a/README.md b/README.md index e1638aa..05faac9 100644 --- a/README.md +++ b/README.md @@ -175,12 +175,6 @@ models["race"] = DeepFace.build_model('Race') DeepFace.analyze("img1.jpg", models=models) ``` -## Disclaimer - -Reference face recognition models have different type of licenses. This framework is just a wrapper for those models. That's why, licence types are inherited as well. You should check the licenses for the face recognition models before use. - -Herein, [OpenFace](https://github.com/cmusatyalab/openface/blob/master/LICENSE) is licensed under Apache License 2.0. [FB DeepFace](https://github.com/swghosh/DeepFace) and [Facenet](https://github.com/davidsandberg/facenet/blob/master/LICENSE.md) is licensed under MIT License. [Dlib](https://github.com/davisking/dlib/blob/master/dlib/LICENSE.txt) is licensed under Boost Software License. They all allow you to use for personal and commercial purpose free. On the other hand, [VGG-Face](http://www.robots.ox.ac.uk/~vgg/software/vgg_face/) is licensed under Creative Commons Attribution License. That's why, it is restricted to adopt VGG-Face for commercial use. - ## Support There are many ways to support a project - starring⭐️ the GitHub repos is just one. @@ -189,11 +183,12 @@ There are many ways to support a project - starring⭐️ the GitHub repos is ju Please cite [deepface](https://ieeexplore.ieee.org/document/9259802) in your publications if it helps your research. Here is an example BibTeX entry: -``` -@inproceedings{9259802, +```BibTeX +@inproceedings{serengil2020lightface, title={LightFace: A Hybrid Deep Face Recognition Framework}, author={Serengil, Sefik Ilkin and Ozpinar, Alper}, booktitle={2020 Innovations in Intelligent Systems and Applications Conference (ASYU)}, + pages={23--27}, year={2020}, doi={10.1109/ASYU50717.2020.9259802}, organization={IEEE} @@ -202,6 +197,6 @@ Please cite [deepface](https://ieeexplore.ieee.org/document/9259802) in your pub ## Licence -Deepface is licensed under the MIT License - see [`LICENSE`](https://github.com/serengil/deepface/blob/master/LICENSE) for more details. +Deepface is licensed under the MIT License - see [`LICENSE`](https://github.com/serengil/deepface/blob/master/LICENSE) for more details. However, the library wraps some face recognition models: [VGG-Face](http://www.robots.ox.ac.uk/~vgg/software/vgg_face/), [Facenet](https://github.com/davidsandberg/facenet/blob/master/LICENSE.md), [OpenFace](https://github.com/cmusatyalab/openface/blob/master/LICENSE), [DeepFace](https://github.com/swghosh/DeepFace) and [Dlib](https://github.com/davisking/dlib/blob/master/dlib/LICENSE.txt). Licence types will be inherited if you are going to use those models. [Logo](https://thenounproject.com/term/face-recognition/2965879/) is created by [Adrien Coquet](https://thenounproject.com/coquet_adrien/). Licensed under [Creative Commons: By Attribution 3.0 License](https://creativecommons.org/licenses/by/3.0/). diff --git a/deepface/DeepFace.py b/deepface/DeepFace.py index 4615c64..f38c7a5 100644 --- a/deepface/DeepFace.py +++ b/deepface/DeepFace.py @@ -58,7 +58,6 @@ def verify(img1_path, img2_path = '', model_name = 'VGG-Face', distance_metric = metrics.append(distance_metric) #-------------------------------- - #ensemble learning disabled if model == None: if model_name == 'Ensemble': @@ -135,7 +134,7 @@ def verify(img1_path, img2_path = '', model_name = 'VGG-Face', distance_metric = if model_name != 'Ensemble': - threshold = functions.findThreshold(i, j) + threshold = dst.findThreshold(i, j) if distance <= threshold: identified = True @@ -196,8 +195,6 @@ def verify(img1_path, img2_path = '', model_name = 'VGG-Face', distance_metric = #------------------------- toc = time.time() - - #print("identification lasts ",toc-tic," seconds") if bulkProcess == True: @@ -520,7 +517,7 @@ def find(img_path, db_path, model_name ='VGG-Face', distance_metric = 'cosine', df["%s_%s" % (j, k)] = distances if model_name != 'Ensemble': - threshold = functions.findThreshold(j, k) + threshold = dst.findThreshold(j, k) df = df.drop(columns = ["%s_representation" % (j)]) df = df[df["%s_%s" % (j, k)] <= threshold] diff --git a/deepface/basemodels/Boosting.py b/deepface/basemodels/Boosting.py index de8eb04..fe73ae6 100644 --- a/deepface/basemodels/Boosting.py +++ b/deepface/basemodels/Boosting.py @@ -9,24 +9,19 @@ import lightgbm as lgb #lightgbm==2.3.1 from deepface.commons import functions, distance as dst def loadModel(): + + model_names = ['VGG-Face', 'Facenet', 'OpenFace', 'DeepFace'] + model = {} model_pbar = tqdm(range(0, 4), desc='Face recognition models') for index in model_pbar: - if index == 0: - model_pbar.set_description("Loading VGG-Face") - model["VGG-Face"] = DeepFace.build_model('VGG-Face') - elif index == 1: - model_pbar.set_description("Loading Google FaceNet") - model["Facenet"] = DeepFace.build_model('Facenet') - elif index == 2: - model_pbar.set_description("Loading OpenFace") - model["OpenFace"] = DeepFace.build_model('OpenFace') - elif index == 3: - model_pbar.set_description("Loading Facebook DeepFace") - model["DeepFace"] = DeepFace.build_model('DeepFace') + model_name = model_names[index] + + model_pbar.set_description("Loading %s" % (model_name)) + model[model_name] = DeepFace.build_model(model_name) return model @@ -37,7 +32,8 @@ def validate_model(model): found_models.append(key) if ('VGG-Face' in found_models) and ('Facenet' in found_models) and ('OpenFace' in found_models) and ('DeepFace' in found_models): - print("Ensemble learning will be applied for ", found_models," models") + #print("Ensemble learning will be applied for ", found_models," models") + valid = True else: raise ValueError("You would like to apply ensemble learning and pass pre-built models but models must contain [VGG-Face, Facenet, OpenFace, DeepFace] but you passed "+found_models) diff --git a/deepface/commons/distance.py b/deepface/commons/distance.py index 7529155..63d674b 100644 --- a/deepface/commons/distance.py +++ b/deepface/commons/distance.py @@ -14,3 +14,20 @@ def findEuclideanDistance(source_representation, test_representation): def l2_normalize(x): return x / np.sqrt(np.sum(np.multiply(x, x))) + +def findThreshold(model_name, distance_metric): + + base_threshold = {'cosine': 0.40, 'euclidean': 0.55, 'euclidean_l2': 0.75} + + thresholds = { + '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}, + '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} + } + + threshold = thresholds.get(model_name, base_threshold).get(distance_metric, 0.4) + + return threshold \ No newline at end of file diff --git a/deepface/commons/functions.py b/deepface/commons/functions.py index b6aec02..208bcb9 100644 --- a/deepface/commons/functions.py +++ b/deepface/commons/functions.py @@ -97,12 +97,6 @@ def initialize_detector(detector_backend): elif detector_backend == 'mtcnn': face_detector = MTCNN() - -def loadBase64Img(uri): - encoded_data = uri.split(',')[1] - nparr = np.fromstring(base64.b64decode(encoded_data), np.uint8) - img = cv2.imdecode(nparr, cv2.IMREAD_COLOR) - return img def initializeFolder(): @@ -115,23 +109,12 @@ def initializeFolder(): if not os.path.exists(home+"/.deepface/weights"): os.mkdir(home+"/.deepface/weights") print("Directory ",home,"/.deepface/weights created") - -def findThreshold(model_name, distance_metric): - - base_threshold = {'cosine': 0.40, 'euclidean': 0.55, 'euclidean_l2': 0.75} - - thresholds = { - '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}, - '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} - } - threshold = thresholds.get(model_name, base_threshold).get(distance_metric, 0.4) - - return threshold +def loadBase64Img(uri): + encoded_data = uri.split(',')[1] + nparr = np.fromstring(base64.b64decode(encoded_data), np.uint8) + img = cv2.imdecode(nparr, cv2.IMREAD_COLOR) + return img def get_opencv_path(): opencv_home = cv2.__file__ diff --git a/deepface/commons/realtime.py b/deepface/commons/realtime.py index 1557d99..847aef9 100644 --- a/deepface/commons/realtime.py +++ b/deepface/commons/realtime.py @@ -76,7 +76,7 @@ def analysis(db_path, model_name, distance_metric, enable_face_analysis = True): input_shape_y = input_shape[1] #tuned thresholds for model and metric pair - threshold = functions.findThreshold(model_name, distance_metric) + threshold = dst.findThreshold(model_name, distance_metric) #------------------------ #facial attribute analysis models diff --git a/tests/unit_tests.py b/tests/unit_tests.py index 8c6ddfa..0715110 100644 --- a/tests/unit_tests.py +++ b/tests/unit_tests.py @@ -177,13 +177,15 @@ for model in models: print("Passed unit tests: ",passed_tests," / ",test_cases) +threshold = 70 + accuracy = 100 * passed_tests / test_cases accuracy = round(accuracy, 2) -if accuracy > 75: +if accuracy >= threshold: print("Unit tests are completed successfully. Score: ",accuracy,"%") else: - raise ValueError("Unit test score does not satisfy the minimum required accuracy. Minimum expected score is 80% but this got ",accuracy,"%") + raise ValueError("Unit test score does not satisfy the minimum required accuracy. Minimum expected score is ",threshold,"% but this got ",accuracy,"%") #-----------------------------------