La reconnaissance des visages est omniprésente dans la science-fiction : le protagoniste regarde une caméra, et la caméra scanne son visage pour reconnaître la personne. Plus formellement, nous pouvons formuler la reconnaissance des visages comme une tâche de classification, où les entrées sont des images et les sorties sont les noms des personnes. Nous allons discuter d’une technique populaire de reconnaissance des visages appelée « eigenfaces ». Et au cœur des eigenfaces est une technique de réduction de la dimensionnalité non supervisée appelée analyse en composantes principales (ACP), et nous verrons comment nous pouvons appliquer cette technique générale à notre tâche spécifique de reconnaissance des visages. Téléchargez le code complet ici.
- Ne manquez pas cette offre ! L’offre se termine en Accédez à l’ensemble des 200+ cours Nouveaux cours ajoutés mensuellement Annulez à tout moment Certificats d’achèvement
- Reconnaissance des visages
- Réduction de dimensionnalité
- Analyse en composantes principales
- Aparté sur la détection de visage
- Code des faces propres
Ne manquez pas cette offre ! L’offre se termine en
- Accédez à l’ensemble des 200+ cours
- Nouveaux cours ajoutés mensuellement
- Annulez à tout moment
- Certificats d’achèvement
- Accédez à l’ensemble des 200+ cours
- Nouveaux cours ajoutés mensuellement
- Annulez à tout moment
- Certificats d’achèvement
Reconnaissance des visages
Avant de discuter de l’analyse en composantes principales, nous devons d’abord définir notre problème. La reconnaissance de visage est le défi de classer quel visage se trouve dans une image d’entrée. Ceci est différent de la détection de visage où le défi est de déterminer s’il y a un visage dans l’image d’entrée. Avec la reconnaissance des visages, nous avons besoin d’une base de données existante de visages. Étant donné une nouvelle image d’un visage, nous devons rapporter le nom de la personne.
Une façon naïve d’accomplir ceci est de prendre la nouvelle image, de l’aplatir en un vecteur, et de calculer la distance euclidienne entre elle et toutes les autres images aplaties dans notre base de données.
Il y a plusieurs inconvénients à cette approche. Tout d’abord, si nous avons une grande base de données de visages, alors faire cette comparaison pour chaque visage prendra un certain temps ! Imaginez que nous construisions un système de reconnaissance de visage pour une utilisation en temps réel ! Plus notre jeu de données est important, plus notre algorithme est lent. Mais un plus grand nombre de visages produira également de meilleurs résultats ! Nous voulons un système qui soit à la fois rapide et précis. Pour cela, nous allons utiliser un réseau de neurones ! Nous pouvons entraîner notre réseau sur notre ensemble de données et l’utiliser pour notre tâche de reconnaissance des visages.
L’utilisation directe d’un réseau neuronal pose un problème : les images peuvent être volumineuses ! Si nous avions une seule
image, nous devrions l’aplatir en un seulvecteur pour alimenter notre réseau neuronal comme entrée. Pour les images de grande taille, cela pourrait nuire à la vitesse ! Ceci est lié au deuxième problème de l’utilisation des images telles quelles dans notre approche naïve : elles sont hautement dimensionnelles ! (Uneimage est en réalité unvecteur) Une nouvelle entrée peut avoir une tonne de bruit et la comparaison de chaque pixel en utilisant la soustraction matricielle et la distance euclidienne peut nous donner une erreur élevée et des classifications erronées !
Ces problèmes sont la raison pour laquelle nous n’utilisons pas la méthode naïve. Au lieu de cela, nous aimerions prendre nos images à haute dimension et les réduire à une dimension plus petite tout en conservant l’essence ou les parties importantes de l’image.
Réduction de dimensionnalité
La section précédente motive notre raison d’utiliser une technique de réduction de dimensionnalité. La réduction de la dimensionnalité est un type d’apprentissage non supervisé où nous voulons prendre des données de plus haute dimension, comme les images, et les représenter dans un espace de plus basse dimension. Utilisons l’image suivante comme exemple.
Ces graphiques montrent les mêmes données, sauf que le graphique du bas les centre à zéro. Remarquez que nos données n’ont pas d’étiquettes associées à elles car il s’agit d’un apprentissage non supervisé ! Dans notre cas simple, la réduction de la dimensionnalité réduira ces données d’un plan 2D à une ligne 1D. Si nous avions des données 3D, nous pourrions les réduire à un plan 2D ou même à une ligne 1D.
Toutes les techniques de réduction de la dimensionnalité visent à trouver un certain hyperplan, une ligne de dimension supérieure, sur lequel projeter les points. On peut imaginer une projection comme le fait de prendre une lampe de poche perpendiculaire à l’hyperplan sur lequel on se projette et de tracer où les ombres tombent sur cet hyperplan. Par exemple, dans les données ci-dessus, si nous voulions projeter nos points sur l’axe des x, nous ferions comme si chaque point était une balle et notre lampe de poche pointerait directement vers le bas ou vers le haut (perpendiculairement à l’axe des x) et les ombres des points tomberaient sur l’axe des x. C’est une projection. Il s’agit d’une projection. Nous ne nous soucierons pas des mathématiques exactes derrière cela puisque scikit-learn peut appliquer cette projection pour nous.
Dans notre cas simple en 2D, nous voulons trouver une ligne sur laquelle projeter nos points. Après avoir projeté les points, nous avons alors des données en 1D au lieu de 2D ! De même, si nous avions des données en 3D, nous voudrions trouver un plan sur lequel projeter les points afin de réduire la dimensionnalité de nos données de 3D à 2D. Les différents types de réduction de la dimensionnalité consistent à déterminer lequel de ces hyperplans sélectionner : il en existe une infinité !
Analyse en composantes principales
Une technique de réduction de la dimensionnalité est appelée analyse en composantes principales (ACP). L’idée derrière l’ACP est que nous voulons sélectionner l’hyperplan tel que lorsque tous les points sont projetés sur celui-ci, ils sont répartis de façon maximale. En d’autres termes, nous voulons l’axe de variance maximale ! Considérons notre exemple de graphique ci-dessus. Un axe potentiel est l’axe des x ou l’axe des y, mais, dans les deux cas, ce n’est pas le meilleur axe. Cependant, si nous choisissons une ligne qui coupe nos données en diagonale, c’est l’axe où les données seraient le plus étalées !
L’axe bleu le plus long est le bon axe ! Si nous devions projeter nos points sur cet axe, ils seraient étalés au maximum ! Mais comment déterminer cet axe ? Nous pouvons emprunter un terme de l’algèbre linéaire appelé vecteurs propres ! C’est de là que vient le nom de faces propres ! Essentiellement, nous calculons la matrice de covariance de nos données et nous considérons les plus grands vecteurs propres de cette matrice de covariance. Ce sont nos axes principaux et les axes sur lesquels nous projetons nos données pour réduire les dimensions. En utilisant cette approche, nous pouvons prendre des données à haute dimension et les réduire à une dimension inférieure en sélectionnant les plus grands vecteurs propres de la matrice de covariance et en les projetant sur ces vecteurs propres.
Puisque nous calculons les axes de dispersion maximale, nous retenons les aspects les plus importants de nos données. Il est plus facile pour notre classificateur de séparer les visages lorsque nos données sont étalées par opposition à celles qui sont regroupées.
(Il existe d’autres techniques de dimensionnalité, comme l’analyse discriminante linéaire, qui utilisent l’apprentissage supervisé et sont également utilisées dans la reconnaissance des visages, mais l’ACP fonctionne vraiment bien !)
Comment cela se rapporte-t-il à notre défi de reconnaissance des visages ? Nous pouvons conceptualiser nos
images comme des points dans un espace àdimensions. Ensuite, nous pouvons utiliser l’ACP pour réduire notre espace deen quelque chose de beaucoup plus petit. Cela permettra d’accélérer nos calculs et d’être robuste au bruit et aux variations.
Aparté sur la détection de visage
Jusqu’ici, nous avons supposé que l’image d’entrée est uniquement celle d’un visage, mais, en pratique, nous ne devrions pas exiger que les images de la caméra aient un visage parfaitement centré. C’est pourquoi nous exécutons un algorithme de détection de visage prêt à l’emploi, tel qu’un classificateur en cascade formé sur les visages, pour déterminer quelle partie de l’image d’entrée contient un visage. Lorsque nous disposons de cette boîte englobante, nous pouvons facilement découper cette partie de l’image d’entrée et utiliser les visages propres sur cette tranche. (Habituellement, nous lissons cette tranche et effectuons une transformation affine pour déformer le visage s’il apparaît sous un angle). Pour nos besoins, nous supposerons que nous avons déjà des images de visages.
Code des faces propres
Maintenant que nous avons discuté de l’ACP et des faces propres, codons un algorithme de reconnaissance des visages en utilisant scikit-learn ! Tout d’abord, nous aurons besoin d’un ensemble de données. Pour nos besoins, nous utiliserons un jeu de données prêt à l’emploi de l’Université du Massachusetts appelé Labeled Faces in the Wild (LFW).
N’hésitez pas à substituer votre propre jeu de données ! Si vous voulez créer votre propre jeu de données de visages, vous aurez besoin de plusieurs photos du visage de chaque personne (sous différents angles et éclairages), ainsi que des étiquettes de vérité du sol. Plus vous utiliserez une grande variété de visages, plus le logiciel de reconnaissance sera performant. La façon la plus simple de créer un ensemble de données pour la reconnaissance de visages est de créer un dossier pour chaque personne et d’y placer les images de visages. Assurez-vous que toutes les images sont de la même taille et redimensionnez-les pour qu’elles ne soient pas trop grandes ! Rappelez-vous que l’ACP réduira la dimensionnalité de l’image lorsque nous la projetterons dans cet espace de toute façon, donc utiliser de grandes images haute définition ne sera pas utile et ralentira notre algorithme. Une bonne taille est de ~512×512 pour chaque image. Les images doivent toutes avoir la même taille afin que vous puissiez les stocker dans un tableau numpy avec les dimensions (num_examples, height, width) . (Nous supposons que les images sont en niveaux de gris). Utilisez ensuite les noms de dossiers pour désambiguïser les classes. En utilisant cette approche, vous pouvez utiliser vos propres images.
Cependant, nous allons utiliser le jeu de données LFW. Heureusement, scikit-learn peut automatiquement charger notre jeu de données pour nous dans le bon format. Nous pouvons appeler une fonction pour charger nos données. Si les données ne sont pas disponibles sur le disque, scikit-learn les téléchargera automatiquement pour nous depuis le site Web de l’Université du Massachusetts.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
import matplotlib.pyplot as plt
from sklearn.model_selection import train_test_split
from sklearn.datasets import fetch_lfw_people
from sklearn.metrics import classification_report
from sklearn.decomposition import PCA
from sklearn.neural_network import MLPClassifier
# Load data
lfw_dataset = fetch_lfw_people(min_faces_per_person=100)
_, h, w = lfw_dataset.images.shape
X = lfw_dataset.data
y = lfw_dataset.target
target_names = lfw_dataset.target_names
# split into a training and testing set
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.3)
|
L’argument de notre fonction élague juste toutes les personnes sans au moins 100 visages, réduisant ainsi le nombre de classes. Ensuite, nous pouvons extraire notre jeu de données et d’autres informations auxiliaires. Enfin, nous divisons notre ensemble de données en ensembles de formation et de test.
Maintenant, nous pouvons simplement utiliser la classe PCA de scikit-learn pour effectuer la réduction de la dimensionnalité pour nous ! Nous devons sélectionner le nombre de composantes, c’est-à-dire la dimensionnalité de sortie (le nombre de vecteurs propres sur lesquels se projeter), que nous voulons réduire, et n’hésitez pas à fignoler ce paramètre pour essayer d’obtenir le meilleur résultat ! Nous utiliserons 100 composants. De plus, nous allons blanchir nos données, ce qui est facile à faire avec un simple drapeau booléen ! (Le blanchiment fait simplement en sorte que nos données résultantes aient une variance unitaire, ce qui a été démontré pour produire de meilleurs résultats)
1
2
3
4
5
6
7
|
# Calcul d’une ACP
n_composants = 100
pca = ACP(n_composants=n_composants, whiten=True).fit(X_train)
# appliquer la transformation PCA
X_train_pca = pca.transform(X_train)
X_test_pca = pca.transform(X_test)
|
Nous pouvons appliquer la transformation pour ramener nos images à un espace à 100 dimensions. Remarquez que nous n’effectuons pas l’ACP sur l’ensemble des données, seulement sur les données d’entraînement. C’est pour que nous puissions mieux généraliser à des données non vues.
Maintenant que nous avons un vecteur à dimension réduite, nous pouvons entraîner notre réseau neuronal !
1
2
3
|
# former un réseau de neurones
print(« Fitting the classifier to the training set »)
clf = MLPClassifier(hidden_layer_sizes=(1024,), batch_size=256, verbose=True, early_stopping=True).fit(X_train_pca, y_train)
|
Pour voir comment notre réseau s’entraîne, nous pouvons définir le drapeau verbose. En outre, nous utilisons l’arrêt précoce.
Discutons de l’arrêt précoce comme une brève parenthèse. Essentiellement, notre optimiseur surveillera la précision moyenne pour l’ensemble de validation pour chaque époque. S’il remarque que notre précision de validation n’a pas augmenté de manière significative pour un certain nombre d’époques, alors nous arrêtons la formation. Il s’agit d’une technique de régularisation qui empêche notre modèle de s’adapter excessivement!
Considérez le graphique ci-dessus. Nous remarquons un surajustement lorsque la précision de notre ensemble de validation commence à diminuer. À ce moment-là, nous arrêtons immédiatement la formation pour éviter le surajustement.
Enfin, nous pouvons faire une prédiction et utiliser une fonction pour imprimer un rapport complet de qualité pour chaque classe.
1
2
|
y_pred = clf.predict(X_test_pca)
print(classification_report(y_test, y_pred, target_names=target_names)).
|
Voici un exemple de rapport de classification.
1
2
3
4
5
6
7
8
9
|
précision rappel f1-score soutien
Colin Powell 0.86 0.89 0.87 66
Donald Rumsfeld 0.85 0.61 0.71 38
George W Bush 0.88 0.94 0.91 177
Gerhard Schroeder 0.67 0.69 0.68 26
Tony Blair 0,86 0,71 0,78 35
avg / total 0,85 0,85 0,85 342
|
Notez qu’il n’y a pas de métrique de précision. La précision n’est pas le type de métrique le plus spécifique pour commencer. Au lieu de cela, nous voyons la précision, le rappel, f1-score, et le soutien. Le support est simplement le nombre de fois où cette étiquette de vérité terrain est apparue dans notre ensemble de test, par exemple, dans notre ensemble de test, il y avait en fait 35 images de Tony Blair. Le score F1 est en fait simplement calculé à partir des scores de précision et de rappel. La précision et le rappel sont des mesures plus spécifiques qu’un simple score de précision. Une valeur plus élevée pour les deux est meilleure.
Après avoir entraîné notre classificateur, nous pouvons lui donner quelques images à classer.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
# Visualisation
def plot_gallery(images, titres, h, w, rows=3, cols=4) :
plt.figure()
for i in range(rows * cols) :
plt.subplot(rows, cols, i + 1)
plt.imshow(images.reshape((h, w)), cmap=plt.cm.gray)
plt.title(titles)
plt.xticks(())
plt.yticks(())
def titles(y_pred, y_test, target_names) :
for i in range(y_pred.shape) :
pred_name = target_names].split(‘ ‘)
true_name = target_names].split(‘ ‘)
yield ‘predicted : {0}\ntrue : {1}’.format(pred_name, true_name)
prediction_titles = list(titles(y_pred, y_test, target_names))
plot_gallery(X_test, prediction_titles, h, w)
|
(fonctions plot_gallery et titles modifiées à partir de la documentation scikit-learn)
Nous pouvons voir les prédictions de notre réseau et la valeur de vérité terrain pour chaque image.
Une autre chose intéressante à visualiser sont les faces propres elles-mêmes. Rappelez-vous que l’ACP produit des vecteurs propres. Nous pouvons remodeler ces vecteurs propres en images et visualiser les faces propres.
Ces dernières représentent les visages « génériques » de notre jeu de données. Intuitivement, ce sont des vecteurs qui représentent les directions dans « l’espace du visage » et c’est ce que notre réseau neuronal utilise pour aider à la classification. Maintenant que nous avons discuté de l’approche des faces propres, vous pouvez construire des applications qui utilisent cet algorithme de reconnaissance des visages !
Nous avons discuté d’une approche populaire de la reconnaissance des visages appelée faces propres. L’essence des eigenfaces est un algorithme non supervisé de réduction de la dimensionnalité appelé analyse en composantes principales (ACP) que nous utilisons pour réduire la dimensionnalité des images en quelque chose de plus petit. Maintenant que nous avons une représentation plus petite de nos visages, nous appliquons un classificateur qui prend l’entrée de dimension réduite et produit une étiquette de classe. Pour notre classificateur, nous avons utilisé un réseau neuronal à une couche.
La reconnaissance des visages est un exemple fascinant de la fusion de la vision par ordinateur et de l’apprentissage automatique et de nombreux chercheurs travaillent encore aujourd’hui sur ce problème difficile !
De nos jours, les réseaux neuronaux convolutifs profonds sont utilisés pour la reconnaissance des visages et ont de vastes implications en termes de développement du monde professionnel. Essayez-en un sur ce jeu de données !