--- library_name: py-feat pipeline_tag: image-feature-extraction license: mit --- # xgb_au ## Model Description xgb_au combines histogram of oriented gradient feature extraction with gradient boosting to predict facial action units from single frame images. ## Model Details - **Model Type**: Gradient Boosting (XGB) - **Framework**: sklearn ## Model Sources - **Repository**: [GitHub Repository](https://github.com/cosanlab/py-feat) - **Paper**: [Py-feat: Python facial expression analysis toolbox](https://link.springer.com/article/10.1007/s42761-023-00191-4) ## Citation If you use the svm_au model in your research or application, please cite the following paper: Cheong, J.H., Jolly, E., Xie, T. et al. Py-Feat: Python Facial Expression Analysis Toolbox. Affec Sci 4, 781–796 (2023). https://doi.org/10.1007/s42761-023-00191-4 ``` @article{cheong2023py, title={Py-feat: Python facial expression analysis toolbox}, author={Cheong, Jin Hyun and Jolly, Eshin and Xie, Tiankang and Byrne, Sophie and Kenney, Matthew and Chang, Luke J}, journal={Affective Science}, volume={4}, number={4}, pages={781--796}, year={2023}, publisher={Springer} } ``` ## Example Useage ```python import numpy as np from skops.io import dump, load, get_untrusted_types from huggingface_hub import hf_hub_download class XGBClassifier: def __init__(self) -> None: self.au_keys = [ "AU1", "AU2", "AU4", "AU5", "AU6", "AU7", "AU9", "AU10", "AU11", "AU12", "AU14", "AU15", "AU17", "AU20", "AU23", "AU24", "AU25", "AU26", "AU28", "AU43" ] self.weights_loaded = False def load_weights(self, scaler_upper=None, pca_model_upper=None, scaler_lower=None, pca_model_lower=None, scaler_full=None, pca_model_full=None, classifiers=None): self.scaler_upper = scaler_upper self.pca_model_upper = pca_model_upper self.scaler_lower = scaler_lower self.pca_model_lower = pca_model_lower self.scaler_full = scaler_full self.pca_model_full = pca_model_full self.classifiers = classifiers self.weights_loaded = True def pca_transform(self, frame, scaler, pca_model, landmarks): if not self.weights_loaded: raise ValueError('Need to load weights before running pca_transform') else: transformed_frame = pca_model.transform(scaler.transform(frame)) return np.concatenate((transformed_frame, landmarks), axis=1) def detect_au(self, frame, landmarks): if not self.weights_loaded: raise ValueError('Need to load weights before running detect_au') else: landmarks = np.concatenate(landmarks) landmarks = landmarks.reshape(-1, landmarks.shape[1] * landmarks.shape[2]) pca_transformed_upper = self.pca_transform(frame, self.scaler_upper, self.pca_model_upper, landmarks) pca_transformed_lower = self.pca_transform(frame, self.scaler_lower, self.pca_model_lower, landmarks) pca_transformed_full = self.pca_transform(frame, self.scaler_full, self.pca_model_full, landmarks) pred_aus = [] for key in self.au_keys: classifier = self.classifiers[key] if key in ["AU1", "AU2", "AU7"]: au_pred = classifier.predict_proba(pca_transformed_upper)[:, 1] elif key in ["AU11", "AU14", "AU17", "AU23", "AU24", "AU26"]: au_pred = classifier.predict_proba(pca_transformed_lower)[:, 1] else: au_pred = classifier.predict_proba(pca_transformed_full)[:, 1] pred_aus.append(au_pred) return np.array(pred_aus).T def __init__(self) -> None: self.weights_loaded = False def load_weights(self, scaler_upper=None, pca_model_upper=None, scaler_lower=None, pca_model_lower=None, scaler_full=None, pca_model_full=None, classifiers=None): self.scaler_upper = scaler_upper self.pca_model_upper = pca_model_upper self.scaler_lower = scaler_lower self.pca_model_lower = pca_model_lower self.scaler_full = scaler_full self.pca_model_full = pca_model_full self.classifiers = classifiers self.weights_loaded = True def pca_transform(self, frame, scaler, pca_model, landmarks): if not self.weights_loaded: raise ValueError('Need to load weights before running pca_transform') else: transformed_frame = pca_model.transform(scaler.transform(frame)) return np.concatenate((transformed_frame, landmarks), axis=1) def detect_au(self, frame, landmarks): """ Note that here frame is represented by hogs """ if not self.weights_loaded: raise ValueError('Need to load weights before running detect_au') else: landmarks = np.concatenate(landmarks) landmarks = landmarks.reshape(-1, landmarks.shape[1] * landmarks.shape[2]) pca_transformed_upper = self.pca_transform(frame, self.scaler_upper, self.pca_model_upper, landmarks) pca_transformed_lower = self.pca_transform(frame, self.scaler_lower, self.pca_model_lower, landmarks) pca_transformed_full = self.pca_transform(frame, self.scaler_full, self.pca_model_full, landmarks) aus_list = sorted(self.classifiers.keys(), key=lambda x: int(x[2::])) pred_aus = [] for keys in aus_list: if keys in ["AU1", "AU4", "AU6"]: au_pred = self.classifiers[keys].predict(pca_transformed_upper) elif keys in ["AU11", "AU12", "AU17"]: au_pred = self.classifiers[keys].predict(pca_transformed_lower) elif keys in [ "AU2", "AU5", "AU7", "AU9", "AU10", "AU14", "AU15", "AU20", "AU23", "AU24", "AU25", "AU26", "AU28", "AU43", ]: au_pred = self.classifiers[keys].predict(pca_transformed_full) else: raise ValueError("unknown AU detected") pred_aus.append(au_pred) pred_aus = np.array(pred_aus).T return pred_aus # Load model and weights au_model = XGBClassifier() model_path = hf_hub_download(repo_id="py-feat/xgb_au", filename="xgb_au_classifier.skops") unknown_types = get_untrusted_types(file=model_path) loaded_model = load(model_path, trusted=unknown_types) au_model.load_weights(scaler_upper = loaded_model.scaler_upper, pca_model_upper = loaded_model.pca_model_upper, scaler_lower = loaded_model.scaler_lower, pca_model_lower = loaded_model.scaler_full, pca_model_full=loaded_model.pca_model_full, classifiers=loaded_model.classifiers) # Test model frame = "path/to/your/test_image.jpg" # Replace with your loaded image landmarks = np.array([...]) # Replace with your landmarks data pred = au_model.detect_au(frame, landmarks) print(pred) ```