Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat/batch predict age and gender #1396

Open
wants to merge 4 commits into
base: master
Choose a base branch
from

Conversation

NatLee
Copy link

@NatLee NatLee commented Dec 6, 2024

Tickets

#441
#678
#1069
#1101

What has been done

With this PR, new predicts function to support batch predictions.

How to test

Use this class, user can load model and predict in batch.

class AgeGenderModel():
    """
    Age and gender model
    """
    def __init__(self):
        self.target_size = (224, 224)
        self.age_model, self.gender_model = self.load()

    def load(self) -> Tuple:
        age_model = modeling.build_model(task="facial_attribute", model_name="Age")
        gender_model = modeling.build_model(task="facial_attribute", model_name="Gender")
        return age_model, gender_model

    def process_data(self, data: np.ndarray) -> np.ndarray:
        """
        Process input image data
        """
        img_content = data[:, :, ::-1] # rgb to bgr
        img_content = preprocessing.resize_image(
            img=img_content,
            target_size=self.target_size
        )
        return img_content

    def predict(self, data: np.ndarray) -> Tuple[np.ndarray, np.ndarray]:
        """
        Predict age and gender for one input image
        """
        img_content = self.process_data(data)
        age = self.age_model.predict(img_content)
        gender = self.gender_model.predict(img_content)
        return gender, age

    def predicts(self, data: List[np.ndarray]) -> Tuple[List, List]:
        """
        Predict age and gender for batch input images
        """
        img_contents = [self.process_data(img_content) for img_content in data]
        ages = self.age_model.predicts(img_contents)
        genders = self.gender_model.predicts(img_contents)
        return genders, ages 

Time Costs for 10 Images:

Original for-loop prediction: 1.91108 seconds

Loading split Age and Gender models: 0.00002 seconds
Batch prediction: 0.58243 seconds
Single prediction: 0.03749 seconds

Here's my test script:

from deepface import DeepFace
import cv2
import time
# Load one face
img = cv2.imread("./test.png")

# Make it as a list
imgs = [img] * 10

# For-loop predict
start = time.time()
print("=====For-loop Predict=====")
for img in imgs:
    objs = DeepFace.analyze(
    img_path=img,
    actions=['age', 'gender'],
    )
print(f"Time: {time.time() - start:.5f}s")

# Load models
print("=====Load Split Models=====")
start = time.time()
model = AgeGenderModel()
print(f"Time: {time.time() - start:.5f}s")

# Batch Predict
start = time.time()
genders, ages = model.predicts(imgs)
print("=====Batch Predict=====")
print(genders, ages)
print(f"Time: {time.time() - start:.5f}s")

# Single Predict
start = time.time()
gender, age = model.predict(img)
print("=====Single Predict=====")
print(gender, age)
print(f"Time: {time.time() - start:.5f}s")

predicts is placed in age and gender clients to keep the DeepFace.analyze function logic.

Thank you for taking time to go through this feedback. :)

@h-alice
Copy link

h-alice commented Dec 6, 2024

Bump
Really needs this feature.

@serengil
Copy link
Owner

serengil commented Dec 6, 2024

I don't support having another predicts function. Instead, you can add that logic under predict.

1- predict accepts both single image and list of images as

img: Union[np.ndarray, List[np.ndarray]]

2- in predict function, you can check the type of img, and redirect it to your logic if it is list as

if isinstance(img, np.ndarray):
   # put old predict logic here
elif isinstance(img, np.ndarray):
   # put your batch processing logic here

3- this new logic is worth to have its own unit tests. possibly, you can add some unit tests here.

4- return type of predict should be Union[np.float64, np.ndarray]

5- You should also update the interface in DeepFace.py

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants