From 6cc36922d41e9612c69923b1c3a6be6a4d42f296 Mon Sep 17 00:00:00 2001 From: Sefik Ilkin Serengil Date: Thu, 28 Mar 2024 19:59:09 +0000 Subject: [PATCH] OOP adopted for find embeddings - standard FR models are now using find embeddings method from its super FacialRecognition - find embeddings renamed to forward. --- deepface/basemodels/ArcFace.py | 12 ------------ deepface/basemodels/DeepID.py | 12 ------------ deepface/basemodels/Dlib.py | 5 +++-- deepface/basemodels/Facenet.py | 24 ------------------------ deepface/basemodels/FbDeepFace.py | 12 ------------ deepface/basemodels/GhostFaceNet.py | 5 ----- deepface/basemodels/OpenFace.py | 12 ------------ deepface/basemodels/SFace.py | 5 +++-- deepface/basemodels/VGGFace.py | 8 ++++++-- deepface/models/FacialRecognition.py | 13 +++++++++---- deepface/modules/representation.py | 2 +- tests/face-recognition-how.py | 4 ++-- 12 files changed, 24 insertions(+), 90 deletions(-) diff --git a/deepface/basemodels/ArcFace.py b/deepface/basemodels/ArcFace.py index 3c8d6f0..0ec0834 100644 --- a/deepface/basemodels/ArcFace.py +++ b/deepface/basemodels/ArcFace.py @@ -56,18 +56,6 @@ class ArcFaceClient(FacialRecognition): self.input_shape = (112, 112) self.output_shape = 512 - def find_embeddings(self, img: np.ndarray) -> List[float]: - """ - find embeddings with ArcFace model - Args: - img (np.ndarray): pre-loaded image in BGR - Returns - embeddings (list): multi-dimensional vector - """ - # model.predict causes memory issue when it is called in a for loop - # embedding = model.predict(img, verbose=0)[0].tolist() - return self.model(img, training=False).numpy()[0].tolist() - def load_model( url="https://github.com/serengil/deepface_models/releases/download/v1.0/arcface_weights.h5", diff --git a/deepface/basemodels/DeepID.py b/deepface/basemodels/DeepID.py index 66e31f9..65a797f 100644 --- a/deepface/basemodels/DeepID.py +++ b/deepface/basemodels/DeepID.py @@ -52,18 +52,6 @@ class DeepIdClient(FacialRecognition): self.input_shape = (47, 55) self.output_shape = 160 - def find_embeddings(self, img: np.ndarray) -> List[float]: - """ - find embeddings with DeepId model - Args: - img (np.ndarray): pre-loaded image in BGR - Returns - embeddings (list): multi-dimensional vector - """ - # model.predict causes memory issue when it is called in a for loop - # embedding = model.predict(img, verbose=0)[0].tolist() - return self.model(img, training=False).numpy()[0].tolist() - def load_model( url="https://github.com/serengil/deepface_models/releases/download/v1.0/deepid_keras_weights.h5", diff --git a/deepface/basemodels/Dlib.py b/deepface/basemodels/Dlib.py index 19f333c..225aaf8 100644 --- a/deepface/basemodels/Dlib.py +++ b/deepface/basemodels/Dlib.py @@ -23,9 +23,10 @@ class DlibClient(FacialRecognition): self.input_shape = (150, 150) self.output_shape = 128 - def find_embeddings(self, img: np.ndarray) -> List[float]: + def forward(self, img: np.ndarray) -> List[float]: """ - find embeddings with Dlib model - different than regular models + Find embeddings with Dlib model + Overwritten because it is different than regular models Args: img (np.ndarray): pre-loaded image in BGR Returns diff --git a/deepface/basemodels/Facenet.py b/deepface/basemodels/Facenet.py index d048f6c..e3183d4 100644 --- a/deepface/basemodels/Facenet.py +++ b/deepface/basemodels/Facenet.py @@ -56,18 +56,6 @@ class FaceNet128dClient(FacialRecognition): self.input_shape = (160, 160) self.output_shape = 128 - def find_embeddings(self, img: np.ndarray) -> List[float]: - """ - find embeddings with FaceNet-128d model - Args: - img (np.ndarray): pre-loaded image in BGR - Returns - embeddings (list): multi-dimensional vector - """ - # model.predict causes memory issue when it is called in a for loop - # embedding = model.predict(img, verbose=0)[0].tolist() - return self.model(img, training=False).numpy()[0].tolist() - class FaceNet512dClient(FacialRecognition): """ @@ -80,18 +68,6 @@ class FaceNet512dClient(FacialRecognition): self.input_shape = (160, 160) self.output_shape = 512 - def find_embeddings(self, img: np.ndarray) -> List[float]: - """ - find embeddings with FaceNet-512d model - Args: - img (np.ndarray): pre-loaded image in BGR - Returns - embeddings (list): multi-dimensional vector - """ - # model.predict causes memory issue when it is called in a for loop - # embedding = model.predict(img, verbose=0)[0].tolist() - return self.model(img, training=False).numpy()[0].tolist() - def scaling(x, scale): return x * scale diff --git a/deepface/basemodels/FbDeepFace.py b/deepface/basemodels/FbDeepFace.py index 278f5cc..dc3faba 100644 --- a/deepface/basemodels/FbDeepFace.py +++ b/deepface/basemodels/FbDeepFace.py @@ -56,18 +56,6 @@ class DeepFaceClient(FacialRecognition): self.input_shape = (152, 152) self.output_shape = 4096 - def find_embeddings(self, img: np.ndarray) -> List[float]: - """ - find embeddings with OpenFace model - Args: - img (np.ndarray): pre-loaded image in BGR - Returns - embeddings (list): multi-dimensional vector - """ - # model.predict causes memory issue when it is called in a for loop - # embedding = model.predict(img, verbose=0)[0].tolist() - return self.model(img, training=False).numpy()[0].tolist() - def load_model( url="https://github.com/swghosh/DeepFace/releases/download/weights-vggface2-2d-aligned/VGGFace2_DeepFace_weights_val-0.9034.h5.zip", diff --git a/deepface/basemodels/GhostFaceNet.py b/deepface/basemodels/GhostFaceNet.py index 7a19ddf..5a65102 100644 --- a/deepface/basemodels/GhostFaceNet.py +++ b/deepface/basemodels/GhostFaceNet.py @@ -72,11 +72,6 @@ class GhostFaceNetClient(FacialRecognition): self.output_shape = 512 self.model = load_model() - def find_embeddings(self, img: np.ndarray) -> List[float]: - # model.predict causes memory issue when it is called in a for loop - # embedding = model.predict(img, verbose=0)[0].tolist() - return self.model(img, training=False).numpy()[0].tolist() - def load_model(): model = GhostFaceNetV1() diff --git a/deepface/basemodels/OpenFace.py b/deepface/basemodels/OpenFace.py index 9b32bd6..4d410ab 100644 --- a/deepface/basemodels/OpenFace.py +++ b/deepface/basemodels/OpenFace.py @@ -39,18 +39,6 @@ class OpenFaceClient(FacialRecognition): self.input_shape = (96, 96) self.output_shape = 128 - def find_embeddings(self, img: np.ndarray) -> List[float]: - """ - find embeddings with OpenFace model - Args: - img (np.ndarray): pre-loaded image in BGR - Returns - embeddings (list): multi-dimensional vector - """ - # model.predict causes memory issue when it is called in a for loop - # embedding = model.predict(img, verbose=0)[0].tolist() - return self.model(img, training=False).numpy()[0].tolist() - def load_model( url="https://github.com/serengil/deepface_models/releases/download/v1.0/openface_weights.h5", diff --git a/deepface/basemodels/SFace.py b/deepface/basemodels/SFace.py index b0ed967..6fd7649 100644 --- a/deepface/basemodels/SFace.py +++ b/deepface/basemodels/SFace.py @@ -25,9 +25,10 @@ class SFaceClient(FacialRecognition): self.input_shape = (112, 112) self.output_shape = 128 - def find_embeddings(self, img: np.ndarray) -> List[float]: + def forward(self, img: np.ndarray) -> List[float]: """ - find embeddings with SFace model - different than regular models + Find embeddings with SFace model + Overwritten because it is different than regular models Args: img (np.ndarray): pre-loaded image in BGR Returns diff --git a/deepface/basemodels/VGGFace.py b/deepface/basemodels/VGGFace.py index e2221ac..09f5d91 100644 --- a/deepface/basemodels/VGGFace.py +++ b/deepface/basemodels/VGGFace.py @@ -47,9 +47,12 @@ class VggFaceClient(FacialRecognition): self.input_shape = (224, 224) self.output_shape = 4096 - def find_embeddings(self, img: np.ndarray) -> List[float]: + def forward(self, img: np.ndarray) -> List[float]: """ - find embeddings with VGG-Face model + Generates embeddings using the VGG-Face model. + This method incorporates an additional normalization layer, + necessitating the override of the forward method. + Args: img (np.ndarray): pre-loaded image in BGR Returns @@ -57,6 +60,7 @@ class VggFaceClient(FacialRecognition): """ # model.predict causes memory issue when it is called in a for loop # embedding = model.predict(img, verbose=0)[0].tolist() + # having normalization layer in descriptor troubles for some gpu users (e.g. issue 957, 966) # instead we are now calculating it with traditional way not with keras backend embedding = self.model(img, training=False).numpy()[0].tolist() diff --git a/deepface/models/FacialRecognition.py b/deepface/models/FacialRecognition.py index 4e636a5..228c9f8 100644 --- a/deepface/models/FacialRecognition.py +++ b/deepface/models/FacialRecognition.py @@ -18,7 +18,12 @@ class FacialRecognition(ABC): input_shape: Tuple[int, int] output_shape: int - - @abstractmethod - def find_embeddings(self, img: np.ndarray) -> List[float]: - pass + def forward(self, img: np.ndarray) -> List[float]: + if not isinstance(self.model, Model): + raise ValueError( + "You must overwrite forward method if it is not a keras model," + f"but {self.model_name} not overwritten!" + ) + # model.predict causes memory issue when it is called in a for loop + # embedding = model.predict(img, verbose=0)[0].tolist() + return self.model(img, training=False).numpy()[0].tolist() diff --git a/deepface/modules/representation.py b/deepface/modules/representation.py index a956efd..95c1a1e 100644 --- a/deepface/modules/representation.py +++ b/deepface/modules/representation.py @@ -104,7 +104,7 @@ def represent( # custom normalization img = preprocessing.normalize_input(img=img, normalization=normalization) - embedding = model.find_embeddings(img) + embedding = model.forward(img) resp_obj = {} resp_obj["embedding"] = embedding diff --git a/tests/face-recognition-how.py b/tests/face-recognition-how.py index c084767..fde6d3e 100644 --- a/tests/face-recognition-how.py +++ b/tests/face-recognition-how.py @@ -23,11 +23,11 @@ logger.info(f"target_size: {target_size}") img1 = DeepFace.extract_faces(img_path="dataset/img1.jpg", target_size=target_size)[0]["face"] img1 = np.expand_dims(img1, axis=0) # to (1, 224, 224, 3) -img1_representation = model.find_embeddings(img1) +img1_representation = model.forward(img1) img2 = DeepFace.extract_faces(img_path="dataset/img3.jpg", target_size=target_size)[0]["face"] img2 = np.expand_dims(img2, axis=0) -img2_representation = model.find_embeddings(img2) +img2_representation = model.forward(img2) img1_representation = np.array(img1_representation) img2_representation = np.array(img2_representation)