Comment classer des photos dans 600 classes à l'aide de neuf millions d'images ouvertes

Sandwiches, visualisés à l'aide de Google Open Images Explorer

Si vous envisagez de créer un classificateur d'images mais que vous avez besoin de données de formation, ne cherchez pas plus loin que Google Open Images.

Cet ensemble de données d'images massives contient plus de 30 millions d'images et 15 millions de boîtes englobantes. C’est 18 téraoctets de données d’image!

De plus, Open Images est beaucoup plus ouvert et accessible que certains autres jeux de données d'image à cette échelle. Par exemple, ImageNet a des licences restrictives.

Toutefois, il n’est pas facile pour les développeurs, sur des machines uniques, de parcourir autant de données. Vous devez télécharger et traiter plusieurs fichiers de métadonnées et utiliser leur propre espace de stockage (ou demander l’accès à un compartiment de Google Cloud).

D’autre part, il n’existe pas beaucoup d’entraînements de formation aux images personnalisés dans la nature, car ils sont difficiles à créer et à partager.

Dans cet article, nous allons créer et distribuer un simple pipeline d'apprentissage machine de bout en bout à l'aide d'Open Images.

Nous verrons comment créer votre propre jeu de données autour de l’une des 600 étiquettes incluses dans les données du cadre de sélection des images ouvertes.

Nous allons montrer notre travail en construisant des «sandwiches ouverts». Ce sont des classificateurs d'images simples et reproductibles conçus pour répondre à une question séculaire: un hamburger est-il un sandwich?

Voulez-vous voir le code? Vous pouvez suivre dans le référentiel sur GitHub.

Télécharger les données

Nous devons télécharger les données pertinentes avant de pouvoir faire quoi que ce soit avec elles.

C'est le principal défi à relever lorsque vous utilisez Google Open Images (ou tout ensemble de données externe). Il n’existe pas de moyen facile de télécharger un sous-ensemble de données. Nous devons écrire un script qui le fait pour nous.

J’ai écrit un script Python qui cherche dans les métadonnées de l’ensemble de données Open Images les mots-clés que vous spécifiez. Il trouve les URL d'origine des images correspondantes (sur Flickr), puis les télécharge sur le disque.

La puissance de Python témoigne de ce que vous pouvez faire tout cela en seulement 50 lignes de code:

Ce script vous permet de télécharger le sous-ensemble d’images brutes contenant des informations sur le cadre de sélection pour n’importe quel sous-ensemble de catégories de notre choix:

$ git clone https://github.com/quiltdata/open-images.git
$ cd open-images /
$ conda env create -f environment.yml
$ source activer quilt-open-images-dev
$ cd src / openimager /
$ python openimager.py "Sandwiches" "Hamburgers"

Les catégories sont organisées de manière hiérarchique.

Par exemple, sandwich et hamburger sont les deux sous-étiquettes de nourriture (mais hamburger n'est pas une sous-étiquette de sandwich - hmm).

Nous pouvons visualiser l’ontologie sous forme d’arbre radial en utilisant Vega:

Vous pouvez voir une version interactive annotée de cette carte (et télécharger le code qui la derrière) ici.

Toutes les catégories dans Open Images ne sont pas associées à des données de cadre de sélection.

Mais ce script vous permettra de télécharger n’importe quel sous-ensemble des 600 étiquettes disponibles. Voici un aperçu de ce qui est possible:

football, jouet, oiseau, chat, vase, sèche-cheveux, kangourou, couteau, porte-documents, étui à crayons, balle de tennis, clou, talons hauts, sushi, gratte-ciel, arbre, camion, violon, vin, roue, baleine, coupe-pizza, pain , hélicoptère, citron, chien, éléphant, requin, fleur, mobilier, avion, cuillère, banc, cygne, cacahuète, appareil photo, flûte, casque, grenade, couronne…

Pour les besoins de cet article, nous nous limiterons à deux: hamburger et sandwich.

Nettoyez-le, recadrez-le

Une fois que nous avons exécuté le script et localisé les images, nous pouvons les inspecter avec matplotlib pour voir ce que nous avons:

importer matplotlib.pyplot en tant que plt
depuis matplotlib.image import imread
% matplotlib inline
importation os
fig, axarr = plt.subplots (1, 5, figsize = (24, 4))
pour i, img in énumérer (os.listdir ('../ data / images /') [: 5]):
    axarr [i] .imshow (imread ('../ data / images /' + img))
Cinq exemples d’images {hamburger, sandwich} de Google Open Images V4.

Ces images ne sont pas faciles à former. Ils ont tous les problèmes associés à la construction d'un jeu de données en utilisant une source externe à partir d'Internet public.

Ce petit échantillon montre les différentes tailles, orientations et occlusions possibles dans nos classes cibles.

Dans un cas, nous n’avons même pas réussi à télécharger l’image réelle. Au lieu de cela, nous avons eu un espace réservé nous disant que l'image que nous recherchions a depuis été supprimée!

Le téléchargement de ces données nous fournit quelques milliers d’échantillons d’image comme ceux-ci. La prochaine étape consiste à tirer parti des informations du cadre de sélection pour découper nos images dans les parties sandwich-ha et hamburger-y.

Voici un autre tableau d'images, cette fois-ci avec les cadres de sélection inclus, pour montrer en quoi cela consiste:

Boîtes de délimitation. Remarque (1) le jeu de données comprend des «représentations» et (2) les images brutes peuvent contenir de nombreuses instances d'objet.

Ce cahier Jupyter annoté dans le référentiel de démonstration GitHub effectue ce travail.

Je vais omettre de montrer ce code ici parce que c'est un peu compliqué. C’est d’autant plus que nous devons également (1) refactoriser nos métadonnées d’image pour les faire correspondre aux images découpées et (2) extraire les images qui ont été supprimées depuis. Vérifiez définitivement le cahier si vous souhaitez voir le code.

Après avoir exécuté le code du bloc-notes, nous aurons un dossier images_cropped sur le disque contenant toutes les images recadrées.

Construire le modèle

Une fois les données téléchargées, rognées et nettoyées, nous sommes prêts à former le modèle.

Nous allons former un réseau de neurones de convolution (ou «CNN») sur les données.

Les CNN sont un type particulier de réseau de neurones qui construisent progressivement des fonctionnalités de niveau supérieur à partir de groupes de pixels couramment trouvés dans les images.

La pondération d'une image sur ces différentes caractéristiques est ensuite pondérée pour générer un résultat de classification final.

Cette architecture fonctionne extrêmement bien car elle tire parti de la localité. En effet, tout pixel a probablement beaucoup plus de choses en commun avec les pixels proches que les pixels éloignés.

Les CNN ont également d’autres propriétés intéressantes, telles que la tolérance au bruit et l’invariance d’échelle (dans une certaine mesure). Ceux-ci améliorent encore leurs propriétés de classification.

Si vous n’êtes pas familier avec CNN, je vous recommande d’écraser l’excellent «Fonctionnement des réseaux de neurones convolutifs» de Brandon Rohrer pour en apprendre davantage à leur sujet.

Nous allons former un réseau de neurones convolutifs très simple et voir comment cela donne des résultats décents pour notre problème. J'utilise Keras pour définir et former le modèle.

Nous commençons par disposer les images dans une certaine structure de répertoires:

images_cropped /
    sandwich/
        une_image.jpg
        some_other_image.jpg
        ...
    Hamburger/
        yet_another_image.jpg
        ...

Nous pointons ensuite Keras vers ce dossier en utilisant le code suivant:

Keras inspectera les dossiers d'entrée et déterminera qu'il existe deux classes dans notre problème de classification. Il attribuera des noms de classe en fonction des noms de sous-dossiers et créera des «générateurs d'image» qui serviront à partir de ces dossiers.

Mais nous ne retournons pas les images elles-mêmes. Au lieu de cela, nous retournons des sélections sous-échantillonnées, biaisées et agrandies de manière aléatoire à partir des images (via train_datagen.flow_from_directory).

Ceci est un exemple d'augmentation de données en action.

L'augmentation des données consiste à alimenter un classificateur d'images avec des versions rognées et déformées de manière aléatoire d'un jeu de données en entrée. Cela nous aide à surmonter la petite taille de notre ensemble de données. Nous pouvons former notre modèle sur une seule image plusieurs fois. Chaque fois, nous utilisons un segment légèrement différent de l’image prétraitée de manière légèrement différente.

Avec notre saisie de données définie, l'étape suivante consiste à définir le modèle lui-même:

Ceci est un modèle de réseau neuronal convolutionnel simple. Il ne contient que trois couches de convolution: une couche de post-traitement densément connectée juste avant la couche de sortie et une forte régularisation sous la forme d'une couche de suppression et d'activation de relu.

Tous ces éléments concourent à rendre plus difficile la suralimentation de ce modèle. Ceci est important, étant donné la petite taille de notre jeu de données en entrée.

Enfin, la dernière étape correspond réellement au modèle.

Ce code sélectionne une taille de pas d’époque déterminée par la taille de notre échantillon d’image et la taille de lot choisie (16). Ensuite, il s'entraîne sur ces données pour 50 époques.

La formation est susceptible d'être suspendue tôt par le rappel EarlyStopping. Ceci retourne le modèle le plus performant au-delà de la limite de 50 époques s'il ne voit pas d'amélioration du score de validation des quatre époques précédentes.

Nous avons choisi une valeur de patience aussi importante en raison de la variabilité importante de la perte de validation du modèle.

Ce schéma d'entraînement simple permet d'obtenir un modèle avec une précision d'environ 75%:

              rappel de précision soutien f1-score

           0 0,90 0,59 0,71 1399
           1 0,64 0,92 0,75 1109

   micro moy. 0,73 0,73 0,73 2508
   macro moyenne 0,77 0,75 0,73 2508
moyenne pondérée 0,78 0,73 0,73 2508

Il est intéressant de noter que notre modèle manque de confiance en ce qui concerne la classification des hamburgers (classe 0) mais trop confiant pour la classification des hamburgers (classe 1).

90% des images classées comme hamburgers sont en réalité des hamburgers. Mais seulement 59% de tous les hamburgers sont classés correctement.

En revanche, 64% seulement des images classées en tant que sandwich sont en réalité des sandwichs. Mais 92% des sandwichs sont classés correctement.

Ces résultats sont conformes à la précision de 80% obtenue par François Chollet en appliquant un modèle très similaire à un sous-ensemble de taille similaire du jeu de données classique Cats vs. Dogs.

La différence est probablement principalement due à l'augmentation du niveau d'occlusion et de bruit dans le jeu de données Google Open Images V4.

Le jeu de données comprend également des illustrations ainsi que des images photographiques. Celles-ci prennent parfois de grandes libertés artistiques rendant la classification plus difficile. Vous pouvez choisir de les supprimer lorsque vous construisez un modèle vous-même.

Cette performance peut être encore améliorée en utilisant des techniques d'apprentissage par transfert. Pour en savoir plus, consultez le blog de François Chollet, auteur de Keras, intitulé «Construire de puissants modèles de classification des images en utilisant très peu de données».

Distribuer le modèle

Maintenant que nous avons créé un jeu de données personnalisé et formé un modèle, il serait dommage que nous ne le partagions pas.

Les projets d’apprentissage automatique doivent être reproductibles. Je décris la stratégie suivante dans un article précédent, «Reproduire un modèle d’apprentissage automatique construit en quatre lignes de code».

  • Séparez les dépendances en composants de données, de code et d’environnement.
  • La version des dépendances de données contrôle (1) la définition du modèle et (2) les données d'apprentissage. Enregistrez-les dans un stockage blob versionné, par exemple. Amazon S3 avec Quilt T4.
  • La version des dépendances de code contrôle le code utilisé pour former le modèle (utilisez git).
  • La version des dépendances d'environnement contrôle l'environnement utilisé pour former le modèle. Dans un environnement de production, il s’agit probablement d’un fichier Docker, mais vous pouvez utiliser localement pip ou conda.
  • Pour fournir à une personne une copie recyclable du modèle, donnez-lui le tuple {données, code, environnement} correspondant.

En suivant ces principes, tout ce dont vous avez besoin pour former votre propre copie de ce modèle s’insère parfaitement dans une poignée de lignes de code:

git clone https://github.com/quiltdata/open-images.git
cond env env -f open-images / environment.yml
source activer quilt-open-images-dev
python -c "import t4; t4.Package.install ('quilt / open_images', dest = 'open-images /', registry = 's3: // exemple de quilt')"

Pour en savoir plus sur {data, code, environment}, voir le référentiel GitHub et / ou l'article correspondant.

Conclusion

Dans cet article, nous avons présenté un pipeline d’apprentissage automatique de la classification des images de bout en bout. Nous avons tout couvert, du téléchargement / transformation d'un jeu de données à la formation d'un modèle. Nous l'avons ensuite distribué de manière à ce que tout le monde puisse le reconstruire plus tard.

Comme les jeux de données personnalisés sont difficiles à générer et à distribuer, une multitude d’exemples de jeux de données qui sont utilisés partout dans le temps sont apparus. Ce n’est pas parce qu’ils sont vraiment bons (ils ne le sont pas). Au lieu de cela, c’est parce qu’ils sont faciles.

Par exemple, le cours intensif d'apprentissage automatique récemment publié par Google utilise beaucoup le jeu de données sur le logement en Californie. Ces données ont maintenant presque deux décennies!

Envisagez plutôt d'explorer de nouveaux horizons. Utiliser des images réelles de l'Internet vivant avec des ventilations catégoriques intéressantes. C'est plus facile que vous ne le pensez!