From ed8a6404d9390996868eff1c489110d5b187f214 Mon Sep 17 00:00:00 2001 From: Sefik Ilkin Serengil Date: Sat, 31 Aug 2024 17:12:19 +0100 Subject: [PATCH 1/5] unit test for broken weight file --- tests/test_verify.py | 35 +++++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/tests/test_verify.py b/tests/test_verify.py index c1a80e4..b932605 100644 --- a/tests/test_verify.py +++ b/tests/test_verify.py @@ -1,9 +1,13 @@ +# built-in dependencies +import os + # 3rd party dependencies import pytest import cv2 # project dependencies from deepface import DeepFace +from deepface.commons import folder_utils from deepface.commons.logger import Logger logger = Logger() @@ -186,3 +190,34 @@ def test_verify_for_nested_embeddings(): match="When passing img1_path as a list, ensure that all its items are of type float", ): _ = DeepFace.verify(img1_path=img1_embeddings, img2_path=img2_path) + + logger.info("✅ test verify for nested embeddings is done") + + +def test_verify_for_broken_weights(): + home = folder_utils.get_deepface_home() + + weights_file = os.path.join(home, ".deepface/weights/vgg_face_weights.h5") + backup_file = os.path.join(home, ".deepface/weights/vgg_face_weights_backup.h5") + + assert os.path.exists(weights_file) is True + + # backup original weight file + os.rename(weights_file, backup_file) + + # Create a dummy vgg_face_weights.h5 file + with open(weights_file, "w", encoding="UTF-8") as f: + f.write("dummy content") + + with pytest.raises(ValueError, match="Exception while loading pre-trained weights from"): + _ = DeepFace.verify( + img1_path="dataset/img1.jpg", + img2_path="dataset/img2.jpg", + model_name="VGG-Face", + ) + + # restore weight file + os.remove(weights_file) + os.rename(backup_file, weights_file) + + logger.info("✅ test verify for broken weight file is done") From 074e81ba50c1d008840630ae64f9330d22fddfa0 Mon Sep 17 00:00:00 2001 From: Sefik Ilkin Serengil Date: Sat, 31 Aug 2024 17:31:00 +0100 Subject: [PATCH 2/5] enforce broken weight file test at the end of all tests --- deepface/commons/package_utils.py | 19 +++++++++++++++++++ tests/test_verify.py | 19 ++++++++++++++++--- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/deepface/commons/package_utils.py b/deepface/commons/package_utils.py index e7e3bd4..8513f67 100644 --- a/deepface/commons/package_utils.py +++ b/deepface/commons/package_utils.py @@ -1,3 +1,6 @@ +# built-in dependencies +import hashlib + # 3rd party dependencies import tensorflow as tf @@ -44,3 +47,19 @@ def validate_for_keras3(): "tf-keras package. Please run `pip install tf-keras` " "or downgrade your tensorflow." ) from err + + +def find_file_hash(file_path: str, hash_algorithm: str = "sha256") -> str: + """ + Find the hash of a given file with its content + Args: + file_path (str): exact path of a given file + hash_algorithm (str): hash algorithm + Returns: + hash (str) + """ + hash_func = hashlib.new(hash_algorithm) + with open(file_path, "rb") as f: + while chunk := f.read(8192): + hash_func.update(chunk) + return hash_func.hexdigest() diff --git a/tests/test_verify.py b/tests/test_verify.py index b932605..b519221 100644 --- a/tests/test_verify.py +++ b/tests/test_verify.py @@ -7,7 +7,7 @@ import cv2 # project dependencies from deepface import DeepFace -from deepface.commons import folder_utils +from deepface.commons import folder_utils, package_utils from deepface.commons.logger import Logger logger = Logger() @@ -75,6 +75,9 @@ def test_different_facial_recognition_models(): logger.info(f"✅ facial recognition models test passed with {coverage_score}") + # test_different_facial_recognition_models takes long time. run broken weight test after it. + verify_for_broken_weights() + def test_different_face_detectors(): for detector in detectors: @@ -194,13 +197,23 @@ def test_verify_for_nested_embeddings(): logger.info("✅ test verify for nested embeddings is done") -def test_verify_for_broken_weights(): +def verify_for_broken_weights(): home = folder_utils.get_deepface_home() weights_file = os.path.join(home, ".deepface/weights/vgg_face_weights.h5") backup_file = os.path.join(home, ".deepface/weights/vgg_face_weights_backup.h5") - assert os.path.exists(weights_file) is True + # confirm that weight file is available + if os.path.exists(weights_file) is False: + _ = DeepFace.verify( + img1_path="dataset/img1.jpg", + img2_path="dataset/img2.jpg", + model_name="VGG-Face", + ) + + # confirm that weith file is not broken + weights_file_hash = package_utils.find_file_hash(weights_file) + assert "759266b9614d0fd5d65b97bf716818b746cc77ab5944c7bffc937c6ba9455d8c" == weights_file_hash # backup original weight file os.rename(weights_file, backup_file) From f23d63c6433e2d8918d6cc595c6ebb7405b41e72 Mon Sep 17 00:00:00 2001 From: Sefik Ilkin Serengil Date: Sat, 31 Aug 2024 17:51:07 +0100 Subject: [PATCH 3/5] do broken file test with unused model --- tests/test_verify.py | 34 ++++++++++++---------------------- 1 file changed, 12 insertions(+), 22 deletions(-) diff --git a/tests/test_verify.py b/tests/test_verify.py index b519221..f87c745 100644 --- a/tests/test_verify.py +++ b/tests/test_verify.py @@ -75,9 +75,6 @@ def test_different_facial_recognition_models(): logger.info(f"✅ facial recognition models test passed with {coverage_score}") - # test_different_facial_recognition_models takes long time. run broken weight test after it. - verify_for_broken_weights() - def test_different_face_detectors(): for detector in detectors: @@ -197,26 +194,19 @@ def test_verify_for_nested_embeddings(): logger.info("✅ test verify for nested embeddings is done") -def verify_for_broken_weights(): +def test_verify_for_broken_weights(): home = folder_utils.get_deepface_home() - weights_file = os.path.join(home, ".deepface/weights/vgg_face_weights.h5") - backup_file = os.path.join(home, ".deepface/weights/vgg_face_weights_backup.h5") + # we are not performing anything with model deepid - # confirm that weight file is available - if os.path.exists(weights_file) is False: - _ = DeepFace.verify( - img1_path="dataset/img1.jpg", - img2_path="dataset/img2.jpg", - model_name="VGG-Face", - ) - - # confirm that weith file is not broken - weights_file_hash = package_utils.find_file_hash(weights_file) - assert "759266b9614d0fd5d65b97bf716818b746cc77ab5944c7bffc937c6ba9455d8c" == weights_file_hash + weights_file = os.path.join(home, ".deepface/weights/deepid_keras_weights.h5.h5") + backup_file = os.path.join(home, ".deepface/weights/deepid_keras_weights.h5_backup.h5") + restore = False # backup original weight file - os.rename(weights_file, backup_file) + if os.path.exists(weights_file) is True: + os.rename(weights_file, backup_file) + restore = True # Create a dummy vgg_face_weights.h5 file with open(weights_file, "w", encoding="UTF-8") as f: @@ -226,11 +216,11 @@ def verify_for_broken_weights(): _ = DeepFace.verify( img1_path="dataset/img1.jpg", img2_path="dataset/img2.jpg", - model_name="VGG-Face", + model_name="DeepId", ) - # restore weight file - os.remove(weights_file) - os.rename(backup_file, weights_file) + if restore: + os.remove(weights_file) + os.rename(backup_file, weights_file) logger.info("✅ test verify for broken weight file is done") From e8346601e230661c710f59af44ec12903fd67ab1 Mon Sep 17 00:00:00 2001 From: Sefik Ilkin Serengil Date: Sat, 31 Aug 2024 17:53:34 +0100 Subject: [PATCH 4/5] typo in weight file name --- tests/test_verify.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_verify.py b/tests/test_verify.py index f87c745..979b1bd 100644 --- a/tests/test_verify.py +++ b/tests/test_verify.py @@ -199,8 +199,8 @@ def test_verify_for_broken_weights(): # we are not performing anything with model deepid - weights_file = os.path.join(home, ".deepface/weights/deepid_keras_weights.h5.h5") - backup_file = os.path.join(home, ".deepface/weights/deepid_keras_weights.h5_backup.h5") + weights_file = os.path.join(home, ".deepface/weights/deepid_keras_weights.h5") + backup_file = os.path.join(home, ".deepface/weights/deepid_keras_weights_backup.h5") restore = False # backup original weight file From 005280f684c95e14c1d5065fd419a6af7ac06a8a Mon Sep 17 00:00:00 2001 From: Sefik Ilkin Serengil Date: Sat, 31 Aug 2024 18:04:50 +0100 Subject: [PATCH 5/5] customize broken weight file test --- tests/test_commons.py | 46 +++++++++++++++++++++++++++++++++++++++++++ tests/test_verify.py | 36 --------------------------------- 2 files changed, 46 insertions(+), 36 deletions(-) create mode 100644 tests/test_commons.py diff --git a/tests/test_commons.py b/tests/test_commons.py new file mode 100644 index 0000000..5e8be38 --- /dev/null +++ b/tests/test_commons.py @@ -0,0 +1,46 @@ +# built-in dependencies +import os +import pytest + +# project dependencies +from deepface.commons import folder_utils, weight_utils, package_utils +from deepface.commons.logger import Logger + +logger = Logger() + +tf_version = package_utils.get_tf_major_version() + +if tf_version == 1: + from keras.models import Sequential + from keras.layers import ( + Dropout, + Dense, + ) +else: + from tensorflow.keras.models import Sequential + from tensorflow.keras.layers import ( + Dropout, + Dense, + ) + + +def test_loading_broken_weights(): + home = folder_utils.get_deepface_home() + weight_file = os.path.join(home, ".deepface/weights/vgg_face_weights.h5") + + # construct a dummy model + model = Sequential() + + # Add layers to the model + model.add( + Dense(units=64, activation="relu", input_shape=(100,)) + ) # Input layer with 100 features + model.add(Dropout(0.5)) # Dropout layer to prevent overfitting + model.add(Dense(units=32, activation="relu")) # Hidden layer + model.add(Dense(units=10, activation="softmax")) # Output layer with 10 classes + + # vgg's weights cannot be loaded to this model + with pytest.raises(ValueError, match="Exception while loading pre-trained weights from"): + model = weight_utils.load_model_weights(model=model, weight_file=weight_file) + + logger.info("✅ test loading broken weight file is done") diff --git a/tests/test_verify.py b/tests/test_verify.py index 979b1bd..2a6951b 100644 --- a/tests/test_verify.py +++ b/tests/test_verify.py @@ -1,13 +1,9 @@ -# built-in dependencies -import os - # 3rd party dependencies import pytest import cv2 # project dependencies from deepface import DeepFace -from deepface.commons import folder_utils, package_utils from deepface.commons.logger import Logger logger = Logger() @@ -192,35 +188,3 @@ def test_verify_for_nested_embeddings(): _ = DeepFace.verify(img1_path=img1_embeddings, img2_path=img2_path) logger.info("✅ test verify for nested embeddings is done") - - -def test_verify_for_broken_weights(): - home = folder_utils.get_deepface_home() - - # we are not performing anything with model deepid - - weights_file = os.path.join(home, ".deepface/weights/deepid_keras_weights.h5") - backup_file = os.path.join(home, ".deepface/weights/deepid_keras_weights_backup.h5") - - restore = False - # backup original weight file - if os.path.exists(weights_file) is True: - os.rename(weights_file, backup_file) - restore = True - - # Create a dummy vgg_face_weights.h5 file - with open(weights_file, "w", encoding="UTF-8") as f: - f.write("dummy content") - - with pytest.raises(ValueError, match="Exception while loading pre-trained weights from"): - _ = DeepFace.verify( - img1_path="dataset/img1.jpg", - img2_path="dataset/img2.jpg", - model_name="DeepId", - ) - - if restore: - os.remove(weights_file) - os.rename(backup_file, weights_file) - - logger.info("✅ test verify for broken weight file is done")