From 9d8d2ddf4fbe67b4b66738b2ad4357be11cc20da Mon Sep 17 00:00:00 2001 From: Sefik Ilkin Serengil Date: Sat, 31 Aug 2024 13:24:04 +0100 Subject: [PATCH 1/2] weight downloads moved to a common place --- deepface/commons/file_utils.py | 31 --------- deepface/commons/weight_utils.py | 65 +++++++++++++++++++ deepface/models/demography/Age.py | 23 +++---- deepface/models/demography/Emotion.py | 17 ++--- deepface/models/demography/Gender.py | 18 ++--- deepface/models/demography/Race.py | 18 ++--- deepface/models/face_detection/CenterFace.py | 19 ++---- deepface/models/face_detection/Dlib.py | 33 ++++------ deepface/models/face_detection/FastMtCnn.py | 14 ++-- deepface/models/face_detection/MediaPipe.py | 21 ++++-- deepface/models/face_detection/MtCnn.py | 5 ++ deepface/models/face_detection/OpenCv.py | 5 ++ deepface/models/face_detection/RetinaFace.py | 5 ++ deepface/models/face_detection/Ssd.py | 46 ++++++------- deepface/models/face_detection/Yolo.py | 30 ++++----- deepface/models/face_detection/YuNet.py | 16 ++--- deepface/models/facial_recognition/ArcFace.py | 20 ++---- deepface/models/facial_recognition/DeepID.py | 16 ++--- deepface/models/facial_recognition/Dlib.py | 32 ++++----- deepface/models/facial_recognition/Facenet.py | 41 +++--------- .../models/facial_recognition/FbDeepFace.py | 23 ++----- .../models/facial_recognition/GhostFaceNet.py | 18 ++--- .../models/facial_recognition/OpenFace.py | 20 +++--- deepface/models/facial_recognition/SFace.py | 15 ++--- deepface/models/facial_recognition/VGGFace.py | 20 +++--- deepface/models/spoofing/FasNet.py | 30 ++++----- 26 files changed, 266 insertions(+), 335 deletions(-) delete mode 100644 deepface/commons/file_utils.py create mode 100644 deepface/commons/weight_utils.py diff --git a/deepface/commons/file_utils.py b/deepface/commons/file_utils.py deleted file mode 100644 index 58ae36b..0000000 --- a/deepface/commons/file_utils.py +++ /dev/null @@ -1,31 +0,0 @@ -# built-in dependencies -import os - -# 3rd party dependencies -import gdown - -# project dependencies -from deepface.commons.logger import Logger - -logger = Logger() - - -def download_external_file(file_name: str, exact_file_path: str, url: str) -> None: - """ - Download an external file - Args: - file_name (str): file name with extension - exact_file_path (str): exact location of the file with file name - url (str): url to be downloaded - Returns: - None - """ - if not os.path.exists(exact_file_path): - logger.info(f"Downloading MiniFASNetV2 weights to {exact_file_path}") - try: - gdown.download(url, exact_file_path, quiet=False) - except Exception as err: - raise ValueError( - f"Exception while downloading {file_name} from {url} to {exact_file_path}." - "You may consider to download it and copy to the target destination." - ) from err diff --git a/deepface/commons/weight_utils.py b/deepface/commons/weight_utils.py new file mode 100644 index 0000000..ad0d15b --- /dev/null +++ b/deepface/commons/weight_utils.py @@ -0,0 +1,65 @@ +# built-in dependencies +import os +from typing import Optional +import zipfile +import bz2 + +# 3rd party dependencies +import gdown + +# project dependencies +from deepface.commons import folder_utils +from deepface.commons.logger import Logger + +logger = Logger() + + +def download_weights_if_necessary( + file_name: str, source_url: str, compress_type: Optional[str] = None +) -> str: + """ + Download the weights of a pre-trained model from external source if not downloaded yet. + Args: + file_name (str): target file name with extension + source_url (url): source url to be downloaded + compress_type (optional str): compress type e.g. zip or bz2 + Returns + target_file (str): exact path for the target file + """ + home = folder_utils.get_deepface_home() + + target_file = os.path.join(home, ".deepface/weights", file_name) + + if os.path.isfile(target_file): + logger.debug(f"{file_name} is already available at {target_file}") + return target_file + + try: + logger.info(f"🔗 {file_name} will be downloaded from {source_url} to {target_file}...") + + if compress_type is None: + gdown.download(source_url, target_file, quiet=False) + elif compress_type is not None: + gdown.download(source_url, f"{target_file}.{compress_type}", quiet=False) + + except Exception as err: + exception_msg = ( + f"⛓️‍💥 Exception while downloading {file_name} from {source_url}. " + f"You may consider to download it manually to {target_file}." + ) + logger.error(exception_msg) + raise ValueError(exception_msg) from err + + # uncompress downloaded file + if compress_type == "zip": + with zipfile.ZipFile(f"{target_file}.zip", "r") as zip_ref: + zip_ref.extractall(os.path.join(home, ".deepface/weights")) + logger.info("{target_file}.zip unzipped") + elif compress_type == "bz2": + bz2file = bz2.BZ2File(f"{target_file}.bz2") + data = bz2file.read() + with open(target_file, "wb") as f: + f.write(data) + logger.info("{target_file}.bz2 unzipped") + + return target_file diff --git a/deepface/models/demography/Age.py b/deepface/models/demography/Age.py index bbe99f8..e7a6a39 100644 --- a/deepface/models/demography/Age.py +++ b/deepface/models/demography/Age.py @@ -1,8 +1,9 @@ -import os -import gdown +# 3rd party dependencies import numpy as np + +# project dependencies from deepface.models.facial_recognition import VGGFace -from deepface.commons import package_utils, folder_utils +from deepface.commons import package_utils, weight_utils from deepface.models.Demography import Demography from deepface.commons.logger import Logger @@ -65,21 +66,13 @@ def load_model( # -------------------------- # load weights - - home = folder_utils.get_deepface_home() - output = os.path.join(home, ".deepface/weights/age_model_weights.h5") - - if not os.path.isfile(output): - logger.info(f"{os.path.basename(output)} will be downloaded...") - gdown.download(url, output, quiet=False) - - age_model.load_weights(output) + weight_file = weight_utils.download_weights_if_necessary( + file_name="age_model_weights.h5", source_url=url + ) + age_model.load_weights(weight_file) return age_model - # -------------------------- - - def find_apparent_age(age_predictions: np.ndarray) -> np.float64: """ Find apparent age prediction from a given probas of ages diff --git a/deepface/models/demography/Emotion.py b/deepface/models/demography/Emotion.py index 1b67ba8..7dcb95e 100644 --- a/deepface/models/demography/Emotion.py +++ b/deepface/models/demography/Emotion.py @@ -1,13 +1,9 @@ -# built-in dependencies -import os - # 3rd party dependencies -import gdown import numpy as np import cv2 # project dependencies -from deepface.commons import package_utils, folder_utils +from deepface.commons import package_utils, weight_utils from deepface.models.Demography import Demography from deepface.commons.logger import Logger @@ -96,13 +92,10 @@ def load_model( # ---------------------------- - home = folder_utils.get_deepface_home() - output = os.path.join(home, ".deepface/weights/facial_expression_model_weights.h5") + weight_file = weight_utils.download_weights_if_necessary( + file_name="facial_expression_model_weights.h5", source_url=url + ) - if not os.path.isfile(output): - logger.info(f"{os.path.basename(output)} will be downloaded...") - gdown.download(url, output, quiet=False) - - model.load_weights(output) + model.load_weights(weight_file) return model diff --git a/deepface/models/demography/Gender.py b/deepface/models/demography/Gender.py index 636a397..f682434 100644 --- a/deepface/models/demography/Gender.py +++ b/deepface/models/demography/Gender.py @@ -1,13 +1,9 @@ -# built-in dependencies -import os - # 3rd party dependencies -import gdown import numpy as np # project dependencies from deepface.models.facial_recognition import VGGFace -from deepface.commons import package_utils, folder_utils +from deepface.commons import package_utils, weight_utils from deepface.models.Demography import Demography from deepface.commons.logger import Logger @@ -72,14 +68,10 @@ def load_model( # -------------------------- # load weights + weight_file = weight_utils.download_weights_if_necessary( + file_name="gender_model_weights.h5", source_url=url + ) - home = folder_utils.get_deepface_home() - output = os.path.join(home, ".deepface/weights/gender_model_weights.h5") - - if not os.path.isfile(output): - logger.info(f"{os.path.basename(output)} will be downloaded...") - gdown.download(url, output, quiet=False) - - gender_model.load_weights(output) + gender_model.load_weights(weight_file) return gender_model diff --git a/deepface/models/demography/Race.py b/deepface/models/demography/Race.py index 8e98698..aaf9564 100644 --- a/deepface/models/demography/Race.py +++ b/deepface/models/demography/Race.py @@ -1,13 +1,9 @@ -# built-in dependencies -import os - # 3rd party dependencies -import gdown import numpy as np # project dependencies from deepface.models.facial_recognition import VGGFace -from deepface.commons import package_utils, folder_utils +from deepface.commons import package_utils, weight_utils from deepface.models.Demography import Demography from deepface.commons.logger import Logger @@ -69,14 +65,10 @@ def load_model( # -------------------------- # load weights + weight_file = weight_utils.download_weights_if_necessary( + file_name="race_model_single_batch.h5", source_url=url + ) - home = folder_utils.get_deepface_home() - output = os.path.join(home, ".deepface/weights/race_model_single_batch.h5") - - if not os.path.isfile(output): - logger.info(f"{os.path.basename(output)} will be downloaded...") - gdown.download(url, output, quiet=False) - - race_model.load_weights(output) + race_model.load_weights(weight_file) return race_model diff --git a/deepface/models/face_detection/CenterFace.py b/deepface/models/face_detection/CenterFace.py index c07571b..d8e08bd 100644 --- a/deepface/models/face_detection/CenterFace.py +++ b/deepface/models/face_detection/CenterFace.py @@ -5,10 +5,9 @@ from typing import List # 3rd party dependencies import numpy as np import cv2 -import gdown # project dependencies -from deepface.commons import folder_utils +from deepface.commons import weight_utils from deepface.models.Detector import Detector, FacialAreaRegion from deepface.commons.logger import Logger @@ -29,19 +28,9 @@ class CenterFaceClient(Detector): """ Download pre-trained weights of CenterFace model if necessary and load built model """ - home = folder_utils.get_deepface_home() - weights_path = os.path.join(home, ".deepface/weights/centerface.onnx") - - if not os.path.isfile(weights_path): - logger.info(f"Downloading CenterFace weights from {WEIGHTS_URL} to {weights_path}...") - try: - gdown.download(WEIGHTS_URL, weights_path, quiet=False) - except Exception as err: - raise ValueError( - f"Exception while downloading CenterFace weights from {WEIGHTS_URL}." - f"You may consider to download it to {weights_path} manually." - ) from err - logger.info(f"CenterFace model is just downloaded to {os.path.basename(weights_path)}") + weights_path = weight_utils.download_weights_if_necessary( + file_name="centerface.onnx", source_url=WEIGHTS_URL + ) return CenterFace(weight_path=weights_path) diff --git a/deepface/models/face_detection/Dlib.py b/deepface/models/face_detection/Dlib.py index 5651355..c96f1a3 100644 --- a/deepface/models/face_detection/Dlib.py +++ b/deepface/models/face_detection/Dlib.py @@ -1,9 +1,11 @@ +# built-in dependencies from typing import List -import os -import bz2 -import gdown + +# 3rd party dependencies import numpy as np -from deepface.commons import folder_utils + +# project dependencies +from deepface.commons import weight_utils from deepface.models.Detector import Detector, FacialAreaRegion from deepface.commons.logger import Logger @@ -30,25 +32,14 @@ class DlibClient(Detector): ) from e # check required file exists in the home/.deepface/weights folder - home = folder_utils.get_deepface_home() - filename = "shape_predictor_5_face_landmarks.dat" - filepath = os.path.join(home, ".deepface/weights/", filename) - - if not os.path.isfile(filepath): - logger.info(f"{filename + '.bz2'} is going to be downloaded") - - url = f"http://dlib.net/files/{filename + '.bz2'}" - output = filepath + ".bz2" - - gdown.download(url, output, quiet=False) - - zipfile = bz2.BZ2File(output) - data = zipfile.read() - with open(filepath, "wb") as f: - f.write(data) + weight_file = weight_utils.download_weights_if_necessary( + file_name="shape_predictor_5_face_landmarks.dat", + source_url="http://dlib.net/files/shape_predictor_5_face_landmarks.dat.bz2", + compress_type="bz2", + ) face_detector = dlib.get_frontal_face_detector() - sp = dlib.shape_predictor(filepath) + sp = dlib.shape_predictor(weight_file) detector = {} detector["face_detector"] = face_detector diff --git a/deepface/models/face_detection/FastMtCnn.py b/deepface/models/face_detection/FastMtCnn.py index d803fe9..bc792a4 100644 --- a/deepface/models/face_detection/FastMtCnn.py +++ b/deepface/models/face_detection/FastMtCnn.py @@ -1,13 +1,19 @@ +# built-in dependencies from typing import Any, Union, List + +# 3rd party dependencies import cv2 import numpy as np -from deepface.models.Detector import Detector, FacialAreaRegion -# Link -> https://github.com/timesler/facenet-pytorch -# Examples https://www.kaggle.com/timesler/guide-to-mtcnn-in-facenet-pytorch +# project dependencies +from deepface.models.Detector import Detector, FacialAreaRegion class FastMtCnnClient(Detector): + """ + Fast MtCnn Detector from github.com/timesler/facenet-pytorch + """ + def __init__(self): self.model = self.build_model() @@ -69,7 +75,7 @@ class FastMtCnnClient(Detector): "Please install using 'pip install facenet-pytorch'" ) from e - device = torch.device('cuda:0' if torch.cuda.is_available() else 'cpu') + device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") face_detector = fast_mtcnn(device=device) return face_detector diff --git a/deepface/models/face_detection/MediaPipe.py b/deepface/models/face_detection/MediaPipe.py index 3f98bd3..61a84fd 100644 --- a/deepface/models/face_detection/MediaPipe.py +++ b/deepface/models/face_detection/MediaPipe.py @@ -1,11 +1,18 @@ +# built-in dependencies from typing import Any, List -import numpy as np -from deepface.models.Detector import Detector, FacialAreaRegion -# Link - https://google.github.io/mediapipe/solutions/face_detection +# 3rd party dependencies +import numpy as np + +# project dependencies +from deepface.models.Detector import Detector, FacialAreaRegion class MediaPipeClient(Detector): + """ + MediaPipe from google.github.io/mediapipe/solutions/face_detection + """ + def __init__(self): self.model = self.build_model() @@ -69,7 +76,13 @@ class MediaPipeClient(Detector): # left_ear = (int(landmarks[5].x * img_width), int(landmarks[5].y * img_height)) facial_area = FacialAreaRegion( - x=x, y=y, w=w, h=h, left_eye=left_eye, right_eye=right_eye, confidence=confidence + x=x, + y=y, + w=w, + h=h, + left_eye=left_eye, + right_eye=right_eye, + confidence=float(confidence), ) resp.append(facial_area) diff --git a/deepface/models/face_detection/MtCnn.py b/deepface/models/face_detection/MtCnn.py index 527c9e5..014e4a5 100644 --- a/deepface/models/face_detection/MtCnn.py +++ b/deepface/models/face_detection/MtCnn.py @@ -1,6 +1,11 @@ +# built-in dependencies from typing import List + +# 3rd party dependencies import numpy as np from mtcnn import MTCNN + +# project dependencies from deepface.models.Detector import Detector, FacialAreaRegion # pylint: disable=too-few-public-methods diff --git a/deepface/models/face_detection/OpenCv.py b/deepface/models/face_detection/OpenCv.py index 6c15025..4abb6da 100644 --- a/deepface/models/face_detection/OpenCv.py +++ b/deepface/models/face_detection/OpenCv.py @@ -1,7 +1,12 @@ +# built-in dependencies import os from typing import Any, List + +# 3rd party dependencies import cv2 import numpy as np + +#project dependencies from deepface.models.Detector import Detector, FacialAreaRegion diff --git a/deepface/models/face_detection/RetinaFace.py b/deepface/models/face_detection/RetinaFace.py index a21a793..a3b1468 100644 --- a/deepface/models/face_detection/RetinaFace.py +++ b/deepface/models/face_detection/RetinaFace.py @@ -1,6 +1,11 @@ +# built-in dependencies from typing import List + +# 3rd party dependencies import numpy as np from retinaface import RetinaFace as rf + +# project dependencies from deepface.models.Detector import Detector, FacialAreaRegion # pylint: disable=too-few-public-methods diff --git a/deepface/models/face_detection/Ssd.py b/deepface/models/face_detection/Ssd.py index cc02fb7..2ccc3c5 100644 --- a/deepface/models/face_detection/Ssd.py +++ b/deepface/models/face_detection/Ssd.py @@ -1,11 +1,14 @@ +# built-in dependencies from typing import List -import os from enum import IntEnum -import gdown + +# 3rd party dependencies import cv2 import numpy as np + +# project dependencies from deepface.models.face_detection import OpenCv -from deepface.commons import folder_utils +from deepface.commons import weight_utils from deepface.models.Detector import Detector, FacialAreaRegion from deepface.commons.logger import Logger @@ -25,21 +28,17 @@ class SsdClient(Detector): model (dict) """ - home = folder_utils.get_deepface_home() - # model structure - output_model = os.path.join(home, ".deepface/weights/deploy.prototxt") - if not os.path.isfile(output_model): - logger.info(f"{os.path.basename(output_model)} will be downloaded...") - url = "https://github.com/opencv/opencv/raw/3.4.0/samples/dnn/face_detector/deploy.prototxt" - gdown.download(url, output_model, quiet=False) + output_model = weight_utils.download_weights_if_necessary( + file_name="deploy.prototxt", + source_url="https://github.com/opencv/opencv/raw/3.4.0/samples/dnn/face_detector/deploy.prototxt", + ) # pre-trained weights - output_weights = os.path.join(home, ".deepface/weights/res10_300x300_ssd_iter_140000.caffemodel") - if not os.path.isfile(output_weights): - logger.info(f"{os.path.basename(output_weights)} will be downloaded...") - url = "https://github.com/opencv/opencv_3rdparty/raw/dnn_samples_face_detector_20170830/res10_300x300_ssd_iter_140000.caffemodel" - gdown.download(url, output_weights, quiet=False) + output_weights = weight_utils.download_weights_if_necessary( + file_name="res10_300x300_ssd_iter_140000.caffemodel", + source_url="https://github.com/opencv/opencv_3rdparty/raw/dnn_samples_face_detector_20170830/res10_300x300_ssd_iter_140000.caffemodel", + ) try: face_detector = cv2.dnn.readNetFromCaffe(output_model, output_weights) @@ -50,10 +49,7 @@ class SsdClient(Detector): + "You can install it as pip install opencv-contrib-python." ) from err - return { - "face_detector": face_detector, - "opencv_module": OpenCv.OpenCvClient() - } + return {"face_detector": face_detector, "opencv_module": OpenCv.OpenCvClient()} def detect_faces(self, img: np.ndarray) -> List[FacialAreaRegion]: """ @@ -97,11 +93,17 @@ class SsdClient(Detector): bottom = 6 faces = detections[0][0] - faces = faces[(faces[:, ssd_labels.is_face] == 1) & (faces[:, ssd_labels.confidence] >= 0.90)] + faces = faces[ + (faces[:, ssd_labels.is_face] == 1) & (faces[:, ssd_labels.confidence] >= 0.90) + ] margins = [ssd_labels.left, ssd_labels.top, ssd_labels.right, ssd_labels.bottom] faces[:, margins] = np.int32(faces[:, margins] * 300) - faces[:, margins] = np.int32(faces[:, margins] * [aspect_ratio_x, aspect_ratio_y, aspect_ratio_x, aspect_ratio_y]) - faces[:, [ssd_labels.right, ssd_labels.bottom]] -= faces[:, [ssd_labels.left, ssd_labels.top]] + faces[:, margins] = np.int32( + faces[:, margins] * [aspect_ratio_x, aspect_ratio_y, aspect_ratio_x, aspect_ratio_y] + ) + faces[:, [ssd_labels.right, ssd_labels.bottom]] -= faces[ + :, [ssd_labels.left, ssd_labels.top] + ] resp = [] for face in faces: diff --git a/deepface/models/face_detection/Yolo.py b/deepface/models/face_detection/Yolo.py index 763148b..a4f5a46 100644 --- a/deepface/models/face_detection/Yolo.py +++ b/deepface/models/face_detection/Yolo.py @@ -1,9 +1,12 @@ -import os +# built-in dependencies from typing import Any, List + +# 3rd party dependencies import numpy as np -import gdown + +# project dependencies from deepface.models.Detector import Detector, FacialAreaRegion -from deepface.commons import folder_utils +from deepface.commons import weight_utils from deepface.commons.logger import Logger logger = Logger() @@ -26,7 +29,7 @@ class YoloClient(Detector): model (Any) """ - # Import the Ultralytics YOLO model + # Import the optional Ultralytics YOLO model try: from ultralytics import YOLO except ModuleNotFoundError as e: @@ -35,23 +38,12 @@ class YoloClient(Detector): "Please install using 'pip install ultralytics'" ) from e - home = folder_utils.get_deepface_home() - weight_path = os.path.join(home, PATH) - - # Download the model's weights if they don't exist - if not os.path.isfile(weight_path): - logger.info(f"Downloading Yolo weights from {WEIGHT_URL} to {weight_path}...") - try: - gdown.download(WEIGHT_URL, weight_path, quiet=False) - except Exception as err: - raise ValueError( - f"Exception while downloading Yolo weights from {WEIGHT_URL}." - f"You may consider to download it to {weight_path} manually." - ) from err - logger.info(f"Yolo model is just downloaded to {os.path.basename(weight_path)}") + weight_file = weight_utils.download_weights_if_necessary( + file_name="yolov8n-face.pt", source_url=WEIGHT_URL + ) # Return face_detector - return YOLO(weight_path) + return YOLO(weight_file) def detect_faces(self, img: np.ndarray) -> List[FacialAreaRegion]: """ diff --git a/deepface/models/face_detection/YuNet.py b/deepface/models/face_detection/YuNet.py index e44e9bd..398aed2 100644 --- a/deepface/models/face_detection/YuNet.py +++ b/deepface/models/face_detection/YuNet.py @@ -5,10 +5,9 @@ from typing import Any, List # 3rd party dependencies import cv2 import numpy as np -import gdown # project dependencies -from deepface.commons import folder_utils +from deepface.commons import weight_utils from deepface.models.Detector import Detector, FacialAreaRegion from deepface.commons.logger import Logger @@ -40,16 +39,13 @@ class YuNetClient(Detector): raise ValueError(f"YuNet requires opencv-python >= 4.8 but you have {cv2.__version__}") # pylint: disable=C0301 - url = "https://github.com/opencv/opencv_zoo/raw/main/models/face_detection_yunet/face_detection_yunet_2023mar.onnx" - file_name = "face_detection_yunet_2023mar.onnx" - home = folder_utils.get_deepface_home() - output = os.path.join(home, ".deepface/weights", file_name) - if not os.path.isfile(output): - logger.info(f"{file_name} will be downloaded...") - gdown.download(url, output, quiet=False) + weight_file = weight_utils.download_weights_if_necessary( + file_name="face_detection_yunet_2023mar.onnx", + source_url="https://github.com/opencv/opencv_zoo/raw/main/models/face_detection_yunet/face_detection_yunet_2023mar.onnx", + ) try: - face_detector = cv2.FaceDetectorYN_create(output, "", (0, 0)) + face_detector = cv2.FaceDetectorYN_create(weight_file, "", (0, 0)) except Exception as err: raise ValueError( "Exception while calling opencv.FaceDetectorYN_create module." diff --git a/deepface/models/facial_recognition/ArcFace.py b/deepface/models/facial_recognition/ArcFace.py index d64b775..6eda686 100644 --- a/deepface/models/facial_recognition/ArcFace.py +++ b/deepface/models/facial_recognition/ArcFace.py @@ -1,6 +1,5 @@ -import os -import gdown -from deepface.commons import package_utils, folder_utils +# project dependencies +from deepface.commons import package_utils, weight_utils from deepface.models.FacialRecognition import FacialRecognition from deepface.commons.logger import Logger @@ -79,20 +78,13 @@ def load_model( model = Model(inputs, embedding, name=base_model.name) # --------------------------------------- - # check the availability of pre-trained weights + weight_file = weight_utils.download_weights_if_necessary( + file_name="arcface_weights.h5", source_url=url + ) - home = folder_utils.get_deepface_home() - - file_name = "arcface_weights.h5" - output = os.path.join(home, ".deepface/weights", file_name) - - if not os.path.isfile(output): - logger.info(f"{file_name} will be downloaded to {output}") - gdown.download(url, output, quiet=False) + model.load_weights(weight_file) # --------------------------------------- - model.load_weights(output) - return model diff --git a/deepface/models/facial_recognition/DeepID.py b/deepface/models/facial_recognition/DeepID.py index 83c9749..e8217d4 100644 --- a/deepface/models/facial_recognition/DeepID.py +++ b/deepface/models/facial_recognition/DeepID.py @@ -1,6 +1,5 @@ -import os -import gdown -from deepface.commons import package_utils, folder_utils +# project dependencies +from deepface.commons import package_utils, weight_utils from deepface.models.FacialRecognition import FacialRecognition from deepface.commons.logger import Logger @@ -86,13 +85,10 @@ def load_model( # --------------------------------- - home = folder_utils.get_deepface_home() - output = os.path.join(home, ".deepface/weights/deepid_keras_weights.h5") + weight_file = weight_utils.download_weights_if_necessary( + file_name="deepid_keras_weights.h5", source_url=url + ) - if not os.path.isfile(output): - logger.info(f"{os.path.basename(output)} will be downloaded...") - gdown.download(url, output, quiet=False) - - model.load_weights(output) + model.load_weights(weight_file) return model diff --git a/deepface/models/facial_recognition/Dlib.py b/deepface/models/facial_recognition/Dlib.py index 03f5e3d..3d50521 100644 --- a/deepface/models/facial_recognition/Dlib.py +++ b/deepface/models/facial_recognition/Dlib.py @@ -1,9 +1,11 @@ +# built-in dependencies from typing import List -import os -import bz2 -import gdown + +# 3rd party dependencies import numpy as np -from deepface.commons import folder_utils + +# project dependencies +from deepface.commons import weight_utils from deepface.models.FacialRecognition import FacialRecognition from deepface.commons.logger import Logger @@ -57,7 +59,7 @@ class DlibClient(FacialRecognition): class DlibResNet: def __init__(self): - ## this is not a must dependency. do not import it in the global level. + # This is not a must dependency. Don't import it in the global level. try: import dlib except ModuleNotFoundError as e: @@ -66,21 +68,11 @@ class DlibResNet: "Please install using 'pip install dlib' " ) from e - home = folder_utils.get_deepface_home() - filename = "dlib_face_recognition_resnet_model_v1.dat" - weight_file = os.path.join(home, ".deepface/weights", filename) - - # download pre-trained model if it does not exist - if not os.path.isfile(weight_file): - logger.info(f"{filename} is going to be downloaded") - url = f"http://dlib.net/files/{filename + '.bz2'}" - output = weight_file + ".bz2" - gdown.download(url, output, quiet=False) - - zipfile = bz2.BZ2File(output) - data = zipfile.read() - with open(weight_file, "wb") as f: - f.write(data) + weight_file = weight_utils.download_weights_if_necessary( + file_name="dlib_face_recognition_resnet_model_v1.dat", + source_url="http://dlib.net/files/dlib_face_recognition_resnet_model_v1.dat.bz2", + compress_type="bz2", + ) self.model = dlib.face_recognition_model_v1(weight_file) diff --git a/deepface/models/facial_recognition/Facenet.py b/deepface/models/facial_recognition/Facenet.py index 04c60da..f1be068 100644 --- a/deepface/models/facial_recognition/Facenet.py +++ b/deepface/models/facial_recognition/Facenet.py @@ -1,6 +1,5 @@ -import os -import gdown -from deepface.commons import package_utils, folder_utils +# project dependencies +from deepface.commons import package_utils, weight_utils from deepface.models.FacialRecognition import FacialRecognition from deepface.commons.logger import Logger @@ -1666,20 +1665,10 @@ def load_facenet128d_model( """ model = InceptionResNetV1() - # ----------------------------------- - - home = folder_utils.get_deepface_home() - output = os.path.join(home, ".deepface/weights/facenet_weights.h5") - - if not os.path.isfile(output): - logger.info(f"{os.path.basename(output)} will be downloaded...") - gdown.download(url, output, quiet=False) - - # ----------------------------------- - - model.load_weights(output) - - # ----------------------------------- + weight_file = weight_utils.download_weights_if_necessary( + file_name="facenet_weights.h5", source_url=url + ) + model.load_weights(weight_file) return model @@ -1695,19 +1684,9 @@ def load_facenet512d_model( model = InceptionResNetV1(dimension=512) - # ------------------------- - - home = folder_utils.get_deepface_home() - output = os.path.join(home, ".deepface/weights/facenet512_weights.h5") - - if not os.path.isfile(output): - logger.info(f"{os.path.basename(output)} will be downloaded...") - gdown.download(url, output, quiet=False) - - # ------------------------- - - model.load_weights(output) - - # ------------------------- + weight_file = weight_utils.download_weights_if_necessary( + file_name="facenet512_weights.h5", source_url=url + ) + model.load_weights(weight_file) return model diff --git a/deepface/models/facial_recognition/FbDeepFace.py b/deepface/models/facial_recognition/FbDeepFace.py index 806eb9d..b53b393 100644 --- a/deepface/models/facial_recognition/FbDeepFace.py +++ b/deepface/models/facial_recognition/FbDeepFace.py @@ -1,7 +1,5 @@ -import os -import zipfile -import gdown -from deepface.commons import package_utils, folder_utils +# project dependencies +from deepface.commons import package_utils, weight_utils from deepface.models.FacialRecognition import FacialRecognition from deepface.commons.logger import Logger @@ -84,20 +82,11 @@ def load_model( # --------------------------------- - home = folder_utils.get_deepface_home() - filename = "VGGFace2_DeepFace_weights_val-0.9034.h5" - output = os.path.join(home, ".deepface/weights", filename) + weight_file = weight_utils.download_weights_if_necessary( + file_name="VGGFace2_DeepFace_weights_val-0.9034.h5", source_url=url, compress_type="zip" + ) - if not os.path.isfile(output): - logger.info(f"{filename} will be downloaded...") - output_zipped = output + ".zip" - gdown.download(url, output_zipped, quiet=False) - - # unzip VGGFace2_DeepFace_weights_val-0.9034.h5.zip - with zipfile.ZipFile(output_zipped, "r") as zip_ref: - zip_ref.extractall(os.path.join(home, ".deepface/weights")) - - base_model.load_weights(output) + base_model.load_weights(weight_file) # drop F8 and D0. F7 is the representation layer. deepface_model = Model(inputs=base_model.layers[0].input, outputs=base_model.layers[-3].output) diff --git a/deepface/models/facial_recognition/GhostFaceNet.py b/deepface/models/facial_recognition/GhostFaceNet.py index 178461e..2bb9623 100644 --- a/deepface/models/facial_recognition/GhostFaceNet.py +++ b/deepface/models/facial_recognition/GhostFaceNet.py @@ -1,12 +1,8 @@ -# built-in dependencies -import os - # 3rd party dependencies -import gdown import tensorflow as tf # project dependencies -from deepface.commons import package_utils, folder_utils +from deepface.commons import package_utils, weight_utils from deepface.models.FacialRecognition import FacialRecognition from deepface.commons.logger import Logger @@ -74,15 +70,11 @@ class GhostFaceNetClient(FacialRecognition): def load_model(): model = GhostFaceNetV1() - home = folder_utils.get_deepface_home() - output = os.path.join(home, ".deepface/weights/ghostfacenet_v1.h5") + weight_file = weight_utils.download_weights_if_necessary( + file_name="ghostfacenet_v1.h5", source_url=PRETRAINED_WEIGHTS + ) - if not os.path.isfile(output): - logger.info(f"Pre-trained weights is downloaded from {PRETRAINED_WEIGHTS} to {output}") - gdown.download(PRETRAINED_WEIGHTS, output, quiet=False) - logger.info(f"Pre-trained weights is just downloaded to {output}") - - model.load_weights(output) + model.load_weights(weight_file) return model diff --git a/deepface/models/facial_recognition/OpenFace.py b/deepface/models/facial_recognition/OpenFace.py index 74682e3..5163c95 100644 --- a/deepface/models/facial_recognition/OpenFace.py +++ b/deepface/models/facial_recognition/OpenFace.py @@ -1,7 +1,8 @@ -import os -import gdown +# 3rd party dependencies import tensorflow as tf -from deepface.commons import package_utils, folder_utils + +# project dependencies +from deepface.commons import package_utils, weight_utils from deepface.models.FacialRecognition import FacialRecognition from deepface.commons.logger import Logger @@ -380,16 +381,11 @@ def load_model( # ----------------------------------- - home = folder_utils.get_deepface_home() - output = os.path.join(home, ".deepface/weights/openface_weights.h5") + weight_file = weight_utils.download_weights_if_necessary( + file_name="openface_weights.h5", source_url=url + ) - if not os.path.isfile(output): - logger.info(f"{os.path.basename(output)} will be downloaded...") - gdown.download(url, output, quiet=False) - - # ----------------------------------- - - model.load_weights(output) + model.load_weights(weight_file) # ----------------------------------- diff --git a/deepface/models/facial_recognition/SFace.py b/deepface/models/facial_recognition/SFace.py index 4bcc9ec..0f1d421 100644 --- a/deepface/models/facial_recognition/SFace.py +++ b/deepface/models/facial_recognition/SFace.py @@ -1,14 +1,12 @@ # built-in dependencies -import os from typing import Any, List # 3rd party dependencies import numpy as np import cv2 as cv -import gdown # project dependencies -from deepface.commons import folder_utils +from deepface.commons import weight_utils from deepface.models.FacialRecognition import FacialRecognition from deepface.commons.logger import Logger @@ -55,14 +53,11 @@ def load_model( Construct SFace model, download its weights and load """ - home = folder_utils.get_deepface_home() - output = os.path.join(home, ".deepface/weights/face_recognition_sface_2021dec.onnx") + weight_file = weight_utils.download_weights_if_necessary( + file_name="face_recognition_sface_2021dec.onnx", source_url=url + ) - if not os.path.isfile(output): - logger.info(f"{os.path.basename(output)} weights will be downloaded...") - gdown.download(url, output, quiet=False) - - model = SFaceWrapper(model_path=output) + model = SFaceWrapper(model_path=weight_file) return model diff --git a/deepface/models/facial_recognition/VGGFace.py b/deepface/models/facial_recognition/VGGFace.py index cc22940..f307ad7 100644 --- a/deepface/models/facial_recognition/VGGFace.py +++ b/deepface/models/facial_recognition/VGGFace.py @@ -1,8 +1,11 @@ +# built-in dependencies from typing import List -import os -import gdown + +# 3rd party dependencies import numpy as np -from deepface.commons import package_utils, folder_utils + +# project dependencies +from deepface.commons import package_utils, weight_utils from deepface.modules import verification from deepface.models.FacialRecognition import FacialRecognition from deepface.commons.logger import Logger @@ -133,14 +136,11 @@ def load_model( model = base_model() - home = folder_utils.get_deepface_home() - output = os.path.join(home, ".deepface/weights/vgg_face_weights.h5") + weight_file = weight_utils.download_weights_if_necessary( + file_name="vgg_face_weights.h5", source_url=url + ) - if not os.path.isfile(output): - logger.info(f"{os.path.basename(output)} will be downloaded...") - gdown.download(url, output, quiet=False) - - model.load_weights(output) + model.load_weights(weight_file) # 2622d dimensional model # vgg_face_descriptor = Model(inputs=model.layers[0].input, outputs=model.layers[-2].output) diff --git a/deepface/models/spoofing/FasNet.py b/deepface/models/spoofing/FasNet.py index f1a1cab..5eb6f92 100644 --- a/deepface/models/spoofing/FasNet.py +++ b/deepface/models/spoofing/FasNet.py @@ -1,6 +1,3 @@ -# Minivision's Silent-Face-Anti-Spoofing Repo licensed under Apache License 2.0 -# Ref: github.com/minivision-ai/Silent-Face-Anti-Spoofing/blob/master/src/model_lib/MiniFASNet.py - # built-in dependencies from typing import Union @@ -9,15 +6,18 @@ import cv2 import numpy as np # project dependencies -from deepface.commons import folder_utils, file_utils +from deepface.commons import weight_utils from deepface.commons.logger import Logger logger = Logger() -# pylint: disable=line-too-long, too-few-public-methods +# pylint: disable=line-too-long, too-few-public-methods, nested-min-max class Fasnet: """ Mini Face Anti Spoofing Net Library from repo: github.com/minivision-ai/Silent-Face-Anti-Spoofing + + Minivision's Silent-Face-Anti-Spoofing Repo licensed under Apache License 2.0 + Ref: github.com/minivision-ai/Silent-Face-Anti-Spoofing/blob/master/src/model_lib/MiniFASNet.py """ def __init__(self): @@ -29,21 +29,18 @@ class Fasnet: "You must install torch with `pip install pytorch` command to use face anti spoofing module" ) from err - home = folder_utils.get_deepface_home() device = torch.device("cuda:0" if torch.cuda.is_available() else "cpu") self.device = device # download pre-trained models if not installed yet - file_utils.download_external_file( + first_model_weight_file = weight_utils.download_weights_if_necessary( file_name="2.7_80x80_MiniFASNetV2.pth", - exact_file_path=f"{home}/.deepface/weights/2.7_80x80_MiniFASNetV2.pth", - url="https://github.com/minivision-ai/Silent-Face-Anti-Spoofing/raw/master/resources/anti_spoof_models/2.7_80x80_MiniFASNetV2.pth", + source_url="https://github.com/minivision-ai/Silent-Face-Anti-Spoofing/raw/master/resources/anti_spoof_models/2.7_80x80_MiniFASNetV2.pth", ) - file_utils.download_external_file( + second_model_weight_file = weight_utils.download_weights_if_necessary( file_name="4_0_0_80x80_MiniFASNetV1SE.pth", - exact_file_path=f"{home}/.deepface/weights/4_0_0_80x80_MiniFASNetV1SE.pth", - url="https://github.com/minivision-ai/Silent-Face-Anti-Spoofing/raw/master/resources/anti_spoof_models/4_0_0_80x80_MiniFASNetV1SE.pth", + source_url="https://github.com/minivision-ai/Silent-Face-Anti-Spoofing/raw/master/resources/anti_spoof_models/4_0_0_80x80_MiniFASNetV1SE.pth", ) # guarantees Fasnet imported and torch installed @@ -56,9 +53,7 @@ class Fasnet: second_model = FasNetBackbone.MiniFASNetV1SE(conv6_kernel=(5, 5)).to(device) # load model weight for first model - state_dict = torch.load( - f"{home}/.deepface/weights/2.7_80x80_MiniFASNetV2.pth", map_location=device - ) + state_dict = torch.load(first_model_weight_file, map_location=device) keys = iter(state_dict) first_layer_name = keys.__next__() @@ -74,9 +69,7 @@ class Fasnet: first_model.load_state_dict(state_dict) # load model weight for second model - state_dict = torch.load( - f"{home}/.deepface/weights/4_0_0_80x80_MiniFASNetV1SE.pth", map_location=device - ) + state_dict = torch.load(second_model_weight_file, map_location=device) keys = iter(state_dict) first_layer_name = keys.__next__() @@ -191,7 +184,6 @@ def _get_new_box(src_w, src_h, bbox, scale): y = bbox[1] box_w = bbox[2] box_h = bbox[3] - # pylint: disable=nested-min-max scale = min((src_h - 1) / box_h, min((src_w - 1) / box_w, scale)) new_width = box_w * scale new_height = box_h * scale From 3e2df1bf105511f13c4a464a70a3936b61077d3b Mon Sep 17 00:00:00 2001 From: Sefik Ilkin Serengil Date: Sat, 31 Aug 2024 13:42:26 +0100 Subject: [PATCH 2/2] f string pring --- deepface/commons/weight_utils.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/deepface/commons/weight_utils.py b/deepface/commons/weight_utils.py index ad0d15b..2c2508e 100644 --- a/deepface/commons/weight_utils.py +++ b/deepface/commons/weight_utils.py @@ -54,12 +54,12 @@ def download_weights_if_necessary( if compress_type == "zip": with zipfile.ZipFile(f"{target_file}.zip", "r") as zip_ref: zip_ref.extractall(os.path.join(home, ".deepface/weights")) - logger.info("{target_file}.zip unzipped") + logger.info(f"{target_file}.zip unzipped") elif compress_type == "bz2": bz2file = bz2.BZ2File(f"{target_file}.bz2") data = bz2file.read() with open(target_file, "wb") as f: f.write(data) - logger.info("{target_file}.bz2 unzipped") + logger.info(f"{target_file}.bz2 unzipped") return target_file