Petit comparatif sur deux méthodes permettant de chargeur un dataset pour entrainer un réseau de neurones via Tensorflow et Keras.
Fit()
Cela permet d’envoyer en un seul coup l’ensemble du dataset au réseau de neurones. En conséquence, on doit être sur que le dataset puisse rentrer en RAM.
C’est donc plutôt adapté pour les petits dataset.
Générer les fichiers numpy en local
On commence par définir nos tableau qui vont contenir nos images. Pour cela je vous donne deux méthodes différentes :
Maintenant on va parcourir un dossier supposé contenant nos images que l’on souhaite ajouter à nos deux précédents tableau. Je vous montre selon les deux types d’initialisation faîte précédemment. Pour chaque image que l’on aura, on va devoir les ouvrir et les transformer en tenseur de taille 3 (largeur x hauteur x canal, ou canal=3 si RGB ou canal=1 si Noir/Blanc). Une couleur peut avoir un gradient allant de 0 à 255, selon son intensité. Pour chaque pixel, on aura alors des triplets (0<Intensité rouge<255, 0<intensité vert<255, 0<intensité bleu<255). Pour des raisons d’optimisation, les réseaux apprennent plus facilement sur des valeurs normalisés. Pour cela, je vais divisé par 255 les valeurs, pour avoir des valeurs comprises entre 0 et 1.
Maintenant on les enregistre en local :
Charger les fichiers numpy
On a plus qu’a charger les fichiers précédemment sauvegardé en local, et de les fournir directement au réseau via la méthode fit():
Fit_Generator()
On se sert de générateurs afin d’envoyer des mini-lots (batch) de notre dataset au réseau.
C’est donc plutôt adapté pour les grands dataset et convient donc mieux aux problématiques rencontré dans la vie réel. Cela permet en plus d’ajouter de la data augmentation à la volée, donc pratique !
Besoin de data augmentation ?
C’est ici que l’on défini notre data augmentation. Vous pouvez laisser vide si vous n’en souhaitez pas. On laisse juste la normalisation des données, comme vu précédemment :
Chargement des données
On peut charger les données directement via un dossier spécifique ou via un dataframe de pandas. Gardez un seed identique permettant de synchro les deux générateurs sur les mêmes images en entrée entre sa donnée et son label.
Via un dossier spécifique
Via un datafame pandas
Train & Validation set depuis un même dossier commun
Simple exemple pour de la segmentation d’image. Mais selon votre problématique vous devrez changez dans la méthode flow_from_directory/dataframe le class_mode (type de vos données en Y, catégorie, binaire, etc.) et le classes (liste de vos classes [chiens, chats, etc.])
Nous avons vu dans le chapitre précédent comment stocker en local des données simples.
On va s’attarder cette fois-ci à comment stocker des informations plus nombreuses, plus complexes et ce de façon plus ordonnée, en utilisant des bases de données SQL.
On va réaliser une simple to-do app, avec possibilité d’ajouter une note, ou d’en supprimer, avec une liste permettant de toute les afficher.
On ne peut utiliser n’importe quel outils pour persister des données car nous sommes sur un projet Expo, nous empêchant d’accéder aux modules natifs de iOS et Android. SQLite est un moyen fonctionnant avec des projets Expo.
Objectifs
Stocker localement des informations via une base de donnée SQL
Prérequis
Installez le package pour utiliser SQLite :
expo install expo-sqlite
Nous l’importerons dans nos fichiers de la manière suivante :
import*asSQLitefrom'expo-sqlite';
Base de données & CRUD
CRUD : diminutif correspondant aux requêtes basique, à savoir Create, Read, Update et Delete.
Création de la base de données
Rien de plus simple, une seule ligne suffit :
On donne un nom à notre base, en argument. Celle-ci n’est crée qu’une seule et unique fois. Si on rappelle cette même méthode, on récupère la base de donnée crée auparavant, aucun risque de doublon.
Création de la table NOTE
On va maintenant créer notre table. Je vous montre la façon la plus simple de réaliser des transaction SQL vers notre base :
Requête SQL des plus basique avec le mot clé CREATE TABLE. On lui donne un nom de table, ainsi que la définitions de nos colonnes. Un ID auto-incrémenté pour garantir l’unicité de nos données, ainsi qu’un attribut TEXT qui contiendra le contenu de nos notes.
Nos deux attributs ne peuvent être null, et on leur défini un type, soit Text ou Integer.
Optimiser les requêtes
Je préfère une autre annotation que la précédente pour questionner la base de données, récupérer nos objets et leurs affecter des transformations. Je trouve plus clair et simple à l’utilisation. On définit notre modèle de requête avec une promesse :
On pourra utiliser ce modèle dans des fonctions async, via un appel par un await. On pourra utiliser des then() et catch() à l’appel du service dans nos vues, permettant par exemple d’afficher à l’utilisateur dans une popup si une note à bien été ajouté ou si dans le cas inverse afficher un message d’erreur avec son origine.
Récupérer toute les notes
On définit une interface pour les objets que l’on va récupérer en base. Cela nous facilitera leurs manipulations au sein de notre application :
On fait appel à notre modèle pour questionner la base :
On récupère nos objets via la requête. On va itérer sur notre résultat de requête pour re-typer correctement nos objets.
Ajouter une note
Seule différence, on va ici passer en argument le contenu de ma note que l’on souhaite persister en base. Pas besoin de lui passer un ID pour la note, car celle-ci est généré automatiquement en base. Nous avons défini cette option tout à l’heure, lors de la création de la table.
Supprimer une note
Quasiment identique au point précédent, sauf qu’ici on lui passe un ID de note à notre fonction, étant donné que c’est l’attribut qui défini l’unicité de mes items dans ma table NOTE :
Récupération des items dans la vue
Nous venons de créer notre base ainsi que des opérations CRUD permettant d’interagir avec elle. On va désormais créer une nouvelle vue, avec un champ de texte permettant de donner du contenu à une note, un bouton pour ajouter cette note, une liste scrollable permettant de naviguer sur l’ensemble de nos notes en base, et leur associé à chacun un bouton pour les supprimer.
Définition du state de notre vue
On commence par créer le squelette de base de notre vue :
On utilise ici un composant de classe et non un composant fonctionnel. On a besoin d’utiliser un state pour l’affichage dynamique du contenu de notre liste scrollable. On défini un attribut myNoteList correspondant à une liste de l’ensemble de nos notes en base, ainsi qu’un second attribut note correspondant au champ de texte remplissable par l’utilisateur pour créer une nouvelle note. On initialise les deux attributs dans le constructeur.
Définition des méthodes de notre vue
On défini les méthodes pour mettre à jour nos éléments, pour ajouter une note, ainsi que la supprimer :
La méthode componentDidMount() est une méthode standardisé de React, permettant d’être appelé une seule et unique fois et ce à la fin de la création du composant. On lui demande à l’ouverture de notre page, d’initialiser notre liste avec le contenu de notre base de données.
Définition des éléments visuels de notre vue
Ici rien de bien complexe. J’ai créer un titre de page, un champ de texte avec un bouton pour ajouter une note. Une liste scrollable présentant l’ensemble des notes en base, ainsi qu’une option permettant de les supprimer :
J’ai utilisé des icones Ionicons inclus dans Expo, qui s’adapte en fonction de si vous êtes sur Android ou iOS via la méthode Platform.OS, encapsulé dans des TouchableOpacity, pour rendre un peu plus esthétique mes boutons d’interactions, ainsi que des flexbox pour avoir une touche de responsive design.
Conclusion
Vous venez de voir comment créer très simplement une base de donnée pour votre application React Native tournant sous Expo, comment l’interroger et surtout comment récupérer et afficher le résultats dans une belle vue responsive.
Nous venons de voir au chapitre précédent comment organiser une navigation complexe et imbriquée pour une application avec une architecture grandissante.
Nous allons voir aujourd’hui comment stocker des données plutôt simple, par exemple des paramètres de l’application comme l’activation ou non d’un thème clair ou sombre.
On ne peut utiliser n’importe quel outils pour persister des données car nous sommes sur un projet Expo, nous empêchant d’accéder aux modules natifs de iOS et Android. AsyncStorage est un moyen fonctionnant avec des projets Expo.
AsyncStorage nous permet de persister des données en local sur le smartphone, de façon asynchrone et non crypté. Les informations sont sauvegardé en clair, donc éviter de stocker des données sensibles tel que des mots de passes.
Le stockage s’effectue sous forme de couple tel quel : <Clé, Valeur>.
On ne peut stocker que des string, donc pour des éléments plus complexe tel que des objets, on devra utiliser JSON.stringify() pour la conversion en JSON lors de la sauvegarde d’une donnée, et utiliser JSON.parse() pour lire un objet.
Sauvegarder des données
Pour un string
Pour un objet
Lire des données
Pour un string
Pour un objet
En pratique
On va faire un exemple tout bête, à savoir charger le nom d’un utilisateur à l’appui d’un bouton.
Méthode d’écriture & lecture de donnée
On commence par définir nos deux méthodes pour charger et sauvegarder une donnée :
On appellera la méthode initProfileName() dans l’entrée de notre l’application (App.tsx) pour initialiser notre donnée.
Mise à jour de notre vue
On crée un état initialisé à ‘Invité’. On aura une méthode appelant notre fonction pour lire notre donnée via AsyncStorage, définit précédemment. Et enfin une méthode render() pour afficher un champ de texte, et un bouton bindé avec la fonction de chargement de notre donnée locale :
Conclusion
On vient de voir comment stocker des informations simple en local. Nous allons voir au prochain chapitre comment stocker des informations plus complexe et surtout en quantités plus importantes.
Projet qui consiste à reproduire le fonctionnement d’un radar automatique.
Comment fait-il, à partir d’une photo, pour reconnaître l’emplacement d’une plaque d’immatriculation, afin d’en lire les caractères ?
On s’intéressera ici dans cette première partie à la constitution du dataset nécessaire pour entraîner des modèles de réseau de neurones pour réaliser un apprentissage profond.
Vous avez une multitude de technique en traitement de l’image pour réaliser une lecture de caractère sur une image. Mais j’ai souhaité rester dans le domaine de la data-science, en pensant au réseau de neurones à convolution français le plus connu au monde, à savoir leNet-5 de Y.Le Cun, qui permet de transcrire en texte des chiffres écrit à la main sur une image.
Qui dit deep learning, dit nécessité de beaucoup de données.
Quels types de données
Je suis partie sur l’architecture suivante :
Entraîner un premier réseau de neurones, pour qu’il puisse repérer une plaque d’immatriculation au sein d’une photo. On va utiliser un CNN des plus standard. Il va prendre en entrée des images de voiture, et nous extraire les coordonnées d’un rectangle contenant la plaque. Nous pourrons l’extraire par la suite de l’image pour la fournir à notre second réseau.
Notre premier dataset sera constitué de 2 parties :
partie 1 : regroupe des images de voitures.
partie 2 : un fichier CSV ou n’importe quel format permettant de stocker le nom d’une image de voiture (exemple: image1.png) associés aux coordonnées du rectangle contenant la plaque.
Entraîner un second réseau de neurones qui va prendre en entrée la sortie du premier réseau, à savoir une image sous forme de rectangle, contenant la plaque d’immatriculation de la voiture. Celui-ci encore sera un CNN standard. Il donnera en sortie, du texte, représentant les caractères présents sur la plaque d’immatriculation de la voiture.
Ce second dataset lui aussi sera en deux parties :
partie 1 : regroupe des images de plaques d’immatriculation.
partie 2 : un fichier CSV ou n’importe quel format permettant de stocker le nom d’une image d’une plaque (exemple: image1.png) associés au caractères présent sur la plaque.
Constituer son jeu de données
Je vais vous présenter quelques techniques afin de récolter et réunir des données.
Dataset pré-existant
Comme tout bon informaticien, on sait que c’est inutile de réinventer la roue. En effectuant quelques recherches, vous avez déjà de fortes chances que des chercheurs ou autres développeurs aient déjà fait le travail pour vous. En recherchant des articles scientifiques sur des moteurs de recherches spécifique ( Google Scholar, Arxiv, etc.), on peut trouver des travaux sur des reconnaissances comme celle que je souhaite réaliser. Vous pouvez des fois tomber pile sur ce que vous cherchez et gagner grandement en temps (phase de récolte, nettoyage & régulation des données, etc.), c’est tout bénéf pour vous. Ou des fois tomber comme pour moi, sur des données, mais qui ne s’adapte pas pleinement à mon cas précis pour plusieurs raisons :
Pas de dataset sur des plaques exclusivement françaises
Certains dataset ont des images de qualité médiocre
Certains dataset ont très peu de données ( une centaine… )
Comme expliqué dans le point précédent, j’ai un type de données bien précis. C’est d’ailleurs pour cette raison que j’ai repoussé x fois de faire ce tutoriel, car la constitution du dataset aller être un casse-tête terrible, me demandant des fois si je ne devrais pas passer des journées entières sur la rocade Bordelaise à photographier le passage du moindre véhicule 🤣
Crawling & Scraping
En effectuant des recherches sur le net, vous pouvez trouver des sites comme Google image, Twitter, Instagram, etc, contenant des images de voiture ou de plaque. Une première solution serait de réaliser des requêtes BigQuery afin de pouvoir tout télécharger (pour google), ou faire du web crawling et scraping (pour les autres réseaux). On va s’attarder sur cette seconde solution 😀
Cela consiste en quoi ? ( Théorie )
Faisons simple.
Le web crawling est le fait d’utiliser des robots afin de circuler et parcourir un site web de façon scripter, automatique, dans l’ensemble de son domaine.
Le web scraping est le fait d’utiliser des robots afin de récupérer des informations d’un site, de télécharger ses images, en bref récupérer l’ensemble de son DOM.
On va bosser avec des Dataframes Pandas, donc on va rester sur du Python. Et ça tombe bien, car il se prête bien à ce type d’utilisation. Les principales librairies de crawl/scrap sont les suivantes :
BeautifulSoup : libraire des plus simples, donc très pratique pour ce genre de petit projet. Je l’ai utilisé pour récolter des datas pour de la détection de harcèlement.
Scrapy : bien plus complet, il s’apparente à un framework à part entière, donc plus compliqué à prendre en main mais permet beaucoup plus de chose.
Pour un projet aussi simple j’aurais dû partir sur BS, mais pour le goût du défi je suis parti sur Scrapy pour découvrir de nouvelles choses. C’est vrai que BS nécessite que quelques lignes de code pour récupérer des données, chose un poil plus complexe avec Scrapy.
Initialiser un projet Scrapy
On commence par installer notre paquet :
pip install scrapy
Vous pouvez l’installer aussi via Anaconda.
Dans une console initialiser un nouveau projet :
scrapy startproject Nom_De_Ton_Projet
Vous allez avoir l’architecture suivante :
Projet
__init__.py
middlewares.py : permet de définir des customisations sur le mécanisme de comment procède le spider
pipelines.py : pour créer des pipelines. Les items scrapé sont envoyé là-dedans pour y affecter de nouvelles choses, comme vérifier la présence de doublon, de nettoyer des datas, qu’ils contiennent bien les champs souhaités, etc. ( on s’en fou )
settings.py : fichier de configuration du projet. Définissez vos vitesses de crawl, de parallélisation, nom de l’agent, etc.
scrapy.cfg : fichier de configuration de déploiement ( on s’en fou )
SPIDERS/
__init__.py
On a vraiment besoin que du strict minimal concernant les outils que nous propose ce framework.
On va juste s’attarder un poil sur le settings.py. Ce genre de technique est très peu apprécié car vous pouvez littéralement surcharger les accès à un site. Vérifier que le site ne possède pas une API publique permettant de récupérer les données souhaitées.
Pour rester courtois, renseignez les champs BOT_NAME et USER_AGENT. Ce qui donne pour ma part :
BOT_NAME = 'Crawl&Scrap'
USER_AGENT = 'Bastien Maurice (+https://deeplylearning.fr/)'
Utiliser des vitesses de crawl/scrap et un nombre de requête concurrente de façon raisonné :
CONCURRENT_REQUESTS = 16
Scrapy propose même des outils permettant d’ajuster sa vitesse de requêtes de façon intelligente :
AUTOTHROTTLE_ENABLED = True
AUTOTHROTTLE_START_DELAY = 5
AUTOTHROTTLE_MAX_DELAY = 60
AUTOTHROTTLE_TARGET_CONCURRENCY = 1.0 (le plus important)
Squelette minimal d’un spider
Un spider est un composant qui va scrap un type de donnée. Nous souhaitons scrap deux types de données, nous aurons alors deux spiders. Voici le code minimal lors de la création d’un spider :
name est le nom du spider
allowed_domains est un tableau contenant les noms de domaines autorisés pour notre spider
start_urls est un tableau contenant les URL de points de départ par où commencer à scrap
La méthode __init__ est le constructeur de la classe. On va définir deux méthode (start et end) qui seront exécuté lors de l’appel de signaux (signals.spider_closed & signals.spider_opened) correspondant au lancement et à la clôture du scraper.
La méthode parse est la méthode appelé par Scrapy, c’est ici que toute la magie du scraping va se dérouler et ou on devra définir ce que l’on souhaite récupérer du site distant 😎
Coder notre spider pour le dataset 1 & 2 😏 ( Simple parsage )
La première idée était d’utiliser ces deux méthodes sur un maximum de site afin de récupérer un maximum de donnée. Seul bémol, j’aurais dû écrire à la main mon fichier CSV pour y ajouter le numéro des plaques. Mais j’ai réussi en creusant dans mes recherches, à trouver un site qui expose des images de plaques, avec diverses infos :
Choix de la nationalité de la plaque ( voiture française dans notre cas exclusivement )
Photo de la voiture en entier
Photo de la plaque d’immatriculation (généré automatiquement, ce n’est pas un crop de la plaque de la photo)
Date d’ajout
Pseudo de l’utilisateur qui a ajouté
On va pouvoir récupérer à la fois des données pour le dataset 1 et pour le dataset 2.
Créons un nouveau fichier, scraper.py dans le dossier ‘spider‘ de notre projet Scrapy. Ajoutons-lui les attributs suivants :
csvFilepath : chemin de destination vers mon fichier CSV, qui va contenir les données de ma plaque d’immatriculation. Je souhaite que à chaque donnée on récupère les données suivantes :
date : date à laquelle la photo a été upload sur le site distant
heure : heure à laquelle la photo a été upload sur le site distant
voitureMarque : marque de la voiture
voitureModele : modèle de la voiture
imgGlobalName : nom de l’image de la voiture global que je vais enregistrer en local
imgPlaqueName : nom de l’image de la plaque que je vais enregistrer en local
plateNumber : numéro de la plaque d’immatriculation
page : numéro de la page en cours de scraping
maxPage : nombre de page max à parser
DIRECTORY_IMG_PLATE : dossier de destination pour enregistrer les images PNG de la plaque seule
DIRECTORY_IMG_GLOBAL : dossier de destination pour enregistrer les images PNG de la voiture globale
GLOBAL_DATA : fichier CSV qui sera lu par la librairie Pandas
L’attribut urllib.urlopener va être extrêmement important. Il peut vous arriver que le site distant vous remonte une erreur, signifiant qu’il bloque les spiders qui scrap des datas. On va camoufler notre spider en lui associant une version pour le faire ressembler à une connexion venant d’un humain. Vous pouvez lui donner d’autres versions, peu importe qu’il vienne de Mozilla, Chrome, Firefox, de même pour les versions…
On va pouvoir ainsi scrap nos data comme souhaité 😁
Je connecte mes signaux :
Début du scrap : je demande à Pandas de charger mon fichier CSV contenant l’ensemble de mes datas
Fin du scrap : je demande à Pandas de sauvegarder mes nouvelles données en plus des anciennes en local
Et enfin la méthode parse qui permet de récupérer nos données, de les nettoyer :
Quelques infos utiles :
La méthode xpath me renvoi de base un object xpath
La méthode .get() me converti mon object xpath en string
L’attribut xpath du sélecteur text() me renvoi le champ text, d’une balise <division>Coucou</division par exemple
L’attribut xpath du sélecteur @src me renvoi le champ src, d’une balise <img src= »lien_vers_image« > par exemple
L’attribut xpath du sélecteur @altme renvoi le champ alt, d’une balise <img alt= »infos_utiles« > par exemple
Coder notre spider pour le dataset 2 😏 ( Utilisation de leur API )
Je me suis dit pour augmenter notre dataset de façon bien plus conséquente, qu’il serait intéressant d’avoir un générateur de plaque avec des caractères aléatoire. Une image de plaque d’immat est simple à réaliser en effet. Et il se trouve que sur ce même site il y a un système permettant de réaliser nos plaques sur mesure via leur API :
Comme vous pouvez le voir, on peut choisir nos plaques selon :
La nationalité
Le type de standard
Le nombre de rangé
Le département
L’ensemble des caractères de la plaque
Après avoir remplis l’ensemble de ces informations, le site vous génère la plaque selon vos numéros choisi. J’ai souhaité rendre ce processus de façon automatique. Etant donnée que c’est nous qui rentrons les lettres voulues, on pourra les récupérer pour les inscrire dans notre fichier de données CSV.
Avant de se lancer dans le code, il va falloir faire une petite analyse du site, pour savoir comment générer une plaque en utilisant l’API, sans que celle-ci nous soit indiqué explicitement. En effet, contrairement à des outils tel que Sélénium, Scrapy ne peut faire des interactions directement avec le javascript, comme par exemple simuler des clics de souris sur des boutons. On a donc besoin de l’accès de l’API.
En utilisant les outils de Chrome qui sont intégrés, on va aller chercher que fait ce bouton lors d’un événement (click), et lire le code source de la page. En remontant dans les parents du bouton, on aperçoit le formulaire qu’envoi le bouton lors d’un clique. Il envoi l’action « /fr/informer » avec comme méthode « post » :
On va maintenant aller voir du côté réseaux et des paquets qui y sont échangés. Vous pouvez enregistrer sur des périodes, l’ensemble des requêtes qui transite de vous au serveur, permettant de voir les informations qui y sont échangés. J’ai lancé mon enregistrement, puis j’ai cliqué sur le bouton pour générer une plaque. Dans l’onglet Network, vous aurez pleins de requêtes. A vous de les analyser pour récupérer les informations dont vous souhaitez.
J’ai réussi à retrouver l’action appelé par mon bouton :
On peut observer dans la partie Form Data, que plusieurs paramètres ont transités lors de l’appel à l’API. Celles-ci sont les données permettant de générer la plaque, donnée par les champs de texte vu précédemment et rempli par l’utilisateur. Nous devrons donc induire de nouvelles notions pour coder ce nouveau spider, afin d’y injecter des paramètres lors de notre requête au site distant.
Nous venons d’analyser brièvement le site. Passons à la pratique.
Créons un nouveau fichier, plateGenerator.py dans le dossier ‘spider‘ de notre projet Scrapy que voici :
Pas de nouvelles choses comparées à l’exemple précédant. On garde une version custom pour les en-têtes URL pour by-pass le 403 forbidden.
Je définis deux nouvelles fonctions. Celles-ci vont me permettre de me générer de façon aléatoire soit seulement des lettres, soit des chiffres, de longueur que je souhaite. Elles vont me permettre de générer les valeurs de mes plaques générées :
On va utiliser la méthode « start_requests ». Celle-ci est appelé de base, par rapport à notre url défini dans « start_urls » :
L’ensemble du code est documenté ligne à ligne.
La dernière ligne, avec le mot clé ‘yield’, va nous permettre de générer une requête basée sur des données de formulaires. On lui donne les données de la plaque que l’on souhaite générer à l’API. Le paramètre « meta » n’est utilisé que pour passer des informations de ma fonction « start_requests » à ma méthode « parse ».
Cette requête appelé va être interprété par notre méthode « parse ». Comme pour le premier cas, c’est ici que tout la magie du scrapping s’opère :
Ajuster ses données
Ajout des coordonnées de la plaque dans le dataset 1
Après avoir craw/scrap le site en question, on se retrouve avec la photo de la voiture, le numéro de sa plaque, mais pas la position (X, Y) où se trouve la plaque sur la photo de la voiture. Cela aurait été fait dans des datasets pré-existant. Etant donné que je le constitue moi-même, je vais devoir le réaliser moi-même.
Vous avez plusieurs logiciels sur Github vous permettant d’ouvrir des images, de placer des rectangles, et celui-ci vous renvoi les coordonnées et vous permet de constituer un fichier CSV avec l’ensemble des coordonnées des images de votre dataset. ça risque d’être long et répétitif. C’est pour cela que je suis parti pour créer mon propre logiciel me permettant de tout automatiser. Cela risque de me prendre du temps, mais à terme, d’en gagner pas mal de façon proportionnelle à la taille de mon dataset.
Coder son propre logiciel
Nous avons vu les limites pour constituer un dataset.
Que cela soit en reprenant le travail d’autres personne malgré qu’il ne corresponde pas à 100% de notre objectif. Ou le fait qu’il soit incomplet (manque de la positions X,Y de la plaque d’immatriculation au sein de la photo) lorsque on le réalise soit même par crawl/scrap. Ou encore que l’on manque cruellement de données.
Une possible solution pourrait être de créer son propre logiciel pour générer des images ?
On pourrait réaliser un système de génération de plaque d’immatriculation pour remplir le dataset 2 (comme le fait l’API du site précédent), ou encore coller ces plaques générées sur des photos aléatoires de Google. En effet, notre réseau de neurones 1 n’a pour but que de détecter, de localiser, et de fournir la position de la plaque au sein de la photo, rien de plus. Donc que l’on prenne de vraies photos de voiture avec de vraies plaques d’immatriculations placé au vrai endroit revient au même pour notre réseau que de générer une plaque aléatoire, et de l’insérer dans une photo aléatoire.
Je dit presque, car il y aura toujours une différences entre de vraies photos et des photos/plaques générés. Il ne faudrait pas entraîner notre réseau sur des données qu’il ne rencontrera pas à nouveau, du moins des données semblables. Les fonds générés ne devraient pas gêner notre système, contrairement à nos plaques que l’on va générer :
Plaque plus ou moins inclinés et non droite selon la prise de photo
Plaque plus ou moins éclairés selon le soleil
Ombre plus ou moins importante selon le soleil
Plaque plus ou moins propre (boue, moustiques, etc.)
On peut prévoir d’avance des risques d’avoir quelques soucis en utilisant notre système tel quel. Il ne pourrait reconnaître que des plaques parfaitement blanches, et droite, ce qui risque de peu arriver dans la réalité sur le terrain. Il faut donc permettre à notre réseau de mieux généraliser, et donc lui fournir des cas d’exemples pour qu’il puisse apprendre plus ‘intelligemment’. Il faudra donc ajouter à notre logiciel de génération de plaque le moyen de pouvoir répondre au problématiques précédents :
Permettre d’ajouter une rotation et
Permettre d’ajouter un effet de perspective
Permettre d’ajouter du bruit,
Permettre d’ajouter des assombrissement et/ou tâche
Ces effets permettront de se rapprocher un peu plus à la réalité des plaques d’immatriculation que l’on retrouve en service. Ces effets devront être généré de façon aléatoire, et ceux dans des proportions minimal et maximal définit par des intervalles.
L’article se faisant déjà assez long, je ferais un article dédié à mon logiciel de générateur de plaque, DeeplyPlate.
Conclusion
Au bout de cette première partie je vous ait données quelques pistes pour :
Circuler sur un site via Scrapy
Coder son premier spider pour récupérer des données sur le net
Les données que vous souhaitez ne seront pas forcement existante sur le net, ou sous un format spécifique à votre utilisation. C’est pour cela que je vous montre que vous pouvez réaliser votre propre logiciel assez rapidement, en 10-15 jours de travail régulier pour soit réaliser de façon artificielle vos données, ou encore créer votre propre logiciel de data augmentation afin d’augmenter la taille de vos données aussi petite soient-elles.
Je vous propose de passer à la Partie 2. On s’attaquera cette fois-ci à comment faire de la détection d’objets sur une image. Nous allons montrer comment entraîner un modèle pour qu’il puisse nous fournir les coordonnées sur une image donnée, de l’emplacement d’une plaque d’immatriculation. Nous pourrons ensuite découper cette partie de l’image afin de le donner à un second modèle, afin qu’il puisse nous lire et extraire sous forme de texte les valeurs de la plaque. Mais celle-ci se fera en Partie 3 😎
Remerciement
Le tutoriel n’aurait pu être possible sans le site Platesmania. Pour préserver la stabilité du site, ne crawler/scraper qu’avec un nombre de requête et parallèles raisonnable.
Lorsque j’ai voulu me lancer dans la data visualisation intégrée à un site web, j’ai directement voulu utiliser la librairie la plus célèbre en la matière, à savoir D3.js. Mais j’ai trouvé une alternative qui m’a interpellé car basé à la fois sur D3.js ainsi que Stack.gl, permettant de réaliser des graphiques plus interactifs, à première vue.
Celle-ci est disponible à la fois en Python, R, et enfin Javascript, celle qui nous intéresse dans notre article. Et c’est pour cette raison que je l’écris, car celui-ci n’est pas vraiment disponible en Typescript et bien intégré à l’écosystème d’Angular, qui a des notions de modules, de composants, etc.
On utilisera des données du Covid19 pour alimenter en data nos graphiques. C’est parti !
Quelques infos sur Plotly.js
Pour créer un graphique, on va avoir besoin de trois choses principalement qui se découpe de la façon suivante :
Data
Un objet data qui va contenir l’ensemble des points (ordonnées Y, et abscisse X) que l’on souhaite afficher sur notre graphique.
On le défini dans notre composant en Typescript.
Layout
Un objet layout qui définit les caractéristiques générales au niveau de l’UI de notre graphique, comme le titre, la taille de notre graphique, etc. Si l’on souhaite modifier l’allure d’une courbe en particulier, cela se fera dans l’objet data cependant.
On le défini dans notre composant en Typescript.
Config
C’est l’objet final crée, qui englobe notre objet Data ainsi que notre objet Layout.
On le défini dans notre composant en Typescript, et on ira le binder avec notre fichier de vue en HTML.
Intégration de Plotly.js
Je commence par initialiser un nouveau projet Angular pour illustrer notre exemple. Je vous renvoie sur un précédent article, expliquant comment initialiser une application Angular.
On installe via npm les modules nécessaires :
npm install angular-plotly.js plotly.js
On ajoute le module Plotly à notre module globall App :
Dans votre fichier de configuration tsconfig.json, passez ‘target’ en ‘es5’, si vous avez une erreur dans votre console comme quoi Plotly n’est pas défini dans votre document.
Création d’un graphique avec une courbe
Partie vue
On ajout un composant ‘plotly-plot’. Celui-ci est composé de plusieurs directives et attributs :
fxFlex & Style : directive FlexLayout de Angular, permettant à notre composant de prendre toute la hauteur et largeur du parent disponible
useResizeHandler : directive permettant de resize automatiquement le graphique selon la taille de la fenêtre
data: object contenant l’ensemble des données du graphique
config: object contenant la configuration général de notre graphique
layout: object contenant la configuration graphique de notre graphique
Partie composant
On déclare nos attributs généraux :
J’initialise mes précédents attributs dans le constructeur du composant :
Par la suite, je vais charger mon fichier de données. J’utilise un fichier CSV qui va être lu en local via le httpClient :
Enfin, ma fonction permettant de parser mon fichier CSV de string :
Le plus important sont les lignes suivantes :
4-5 : création de tableau temporaire, contenant nos données
14-15: on remplit nos tableau déclarés précédemment des données du fichier CSV en cours de parsage
23-24: ajout de nos nouvelles données
Voici le résultat de ce que l’on obtient selon le type de graphique que l’on choisit dans notre objet de data :
Vous avez une multitude de type de graphique selon ce que vous voulez donner comme aspect à vos données, je vous laisse lire la doc pour en savoir plus.
Création d’un graphique avec une multitude de courbe
On va reprendre l’exemple précédent, et y ajouter une nouvelle courbe concernant les cas soignés. Je vais enlever quelques données en début de pandémie, étant donné que l’on a eu des cas à partir du 1er Mars à peu près. Cela permettra une meilleure visibilité pour mon tutoriel.
On commence par ajouter une nouvelle courbe en ajoutant une donnée dans notre tableau de données. On fait cela comme précédemment, dans le constructeur du composant :
Vous pouvez apercevoir quelques changements comparé à la première partie de ce tutoriel :
marker : permet d’affecter une couleur à notre courbe
name : nom de la courbe dans la légende
legendgroup : permet de grouper plusieurs courbes dans un même groupe, et de pouvoir les cacher en cliquant dessus dans la légende pour toute les faire disparaître
La dernière étape va être de modifier notre fonction de parsing de notre fichier CSV qui contient nos données, afin de récupérer des informations pour une seconde courbes, qui sera elle concernant les cas soignés :
Lignes 4 : L’axe X des abscisses ne change pas, puisque on veut garder nos dates.
Lignes 6 et 18 : On va créer un nouveau tableau contenant des nombres, et le remplir de la même façon que précédemment, mais avec un indice différent et donc une donnée différente.
Lignes 29-30 : correspond à notre second objet de données créer précédemment. On fait attention de lui affecter en abscisses nos données DATE, et en ordonnés notre tableau contenant le nombre de cas soignés.
Voici le résultat de ce que l’on obtient selon le type de graphique que l’on choisit dans notre objet de data :
Quelques exemples de customisation de l’UI
Je vous présente quelques attributs plutôt chouettes pour changer rapidement le sous type de nos graphiques que je vous ai présenté précédemment, à savoir Scatter et Bar
Vous avez moyen de vraiment poussé beaucoup de chose dans l’UI du graphique, regardez la documentation si vous voulez des envies bien précises.
Sous-type de BAR
L’attribut ‘barmod’ se définit dans l’objet LAYOUT de notre graphique ( attribut ‘layout’ dans nos exemples précédents )
Espacement de BAR
Vous pouvez gérer l’espacement entre les bars pour optimiser la lisibilité de votre graphique. Vous avez deux arguments pour cela :
bargap : espacement entre les bars d’un même groupe
bargroupgap : espacement entre les bars de groupes différents
Ces deux arguments se définissent dans l’objet LAYOUT.
Sous-type de SCATTER
L’attribut ‘mode’ se définit dans l’objet DATA de notre graphique ( attribut ‘allData’ dans nos exemples précédents )
Conclusion
Vous avez donc accès pleinement à la librairie Plotly.js dans votre application Angular.
Rien de bien complexe sur son intégration donc, juste un zeste déroutant d’utiliser du Javascript dans du Typescript, on mélange du typage fort avec des objets que l’on remplit d’attributs à la volé.
Vous pouvez ajouter des events de clic, de listener, pour rendre tout cela un peu plus dynamique comme par exemple divers chargements de données pour combiner plusieurs sources, modifier en temps réel l’allure et l’UI des graphiques, etc.
Je vous propose aujourd’hui de réaliser une carte choroplèthe. C’est une carte de chaleur mettant en évidences certaines zones de différents gradients de couleurs pour montrer une intensité plus ou moins forte sur un type de donnée.
C’est d’actualité, je vous propose une carte de la France, découpé en Région, mettant en évidence l’évolution du COVID-19 sur une date donnée.
Leaflet, Openlayers pour ne citer que les plus grands, sont des librairies javascript permettant d’afficher des cartes, et d’y ajouter une multitude d’actions. Vous pouvez ajouter des dessins, des actions, des couleurs, zones, marqueurs, etc. Le but principal est de les rendre interactives pour mettre en évidences toute sorte de chose.
OpenLayers : considéré comme la référence actuellement, c’est un vrai framework à part entière. Permet donc de réaliser des choses très poussées.
Leaflet : certainement le plus populaire. Certaines fonctionnalités ne pourront pas être aussi poussé que Openlayers, car plus léger. Il marque cependant des points quant à sa prise en main, qui s’en fera plus rapidement.
Intégration de Leaflet
Intégration & affichage du fond de carte
Installation de la librairie
On installe Leaflet et son module NPM facilitant son utilisation via :
On installe les définitions de types pour se faciliter la vie pour coder : npm install --save-dev @types/leaflet
Import de la librairie
On intègre le module Leaflet dans la partie ‘Imports’ de notre fichier de définition de notre module principal :
Ajout du fond de carte
On commence par la mise en place de notre carte dans la vue. Pour cela on créer une division avec un composant leaflet :
Pour la partie back, on va définir un objet contenant les caractéristiques de notre carte qui sera bindé avec la vue :
Rien de bien complexe. On ajoute un layer à nos options qui est le fond de notre carte, en le faisant pointer au service de cartographie de Openstreetmap. On lui définit un niveau de zoom maximum utilisable par l’utilisateur, ainsi qu’un bandeau de droit d’auteur qui s’affichera en bas à droite de la carte.
On ajoute en plus des options d’initialisation que l’on retrouvera par défaut lorsque on arrive sur la page de la carte, à savoir le niveau de zoom actuelle de la carte ainsi que le point (latitude, longitude) à afficher au centre de notre écran.
Style de la carte
Si vous avez suivi les instructions, vous devriez vous retrouver avec une carte bien cassé, et c’est normal 😂
On va y remédier en ajoutant un fichier CSS de style, permettant un affichage correct de notre carte. Cet ajout de ce fichier de style se réalise dans notre fichier de configuration de notre application, à savoir angular.json :
Ajout de données GeoJSON
Type des données
Le GeoJSON est un format de donnée géospatial, suivant le format JSON. Pour faire simple, cela consiste à réunir une multitude de points GPS (latitude et longitude) afin de créer des marqueurs sur la carte. Selon le type des données, vous pouvez ainsi dessiner des traits, rectangle et toute sorte de polygone sur la carte via ces points. On va alors exploiter ces possibilités afin de découper notre France en région.
Il existe déjà une multitude de dataset GeoJSON avec toute sorte de découpage, que ça soit en fonction d’état, de départements, etc. Plus vous aurez de points au sein de votre fichier, et plus vos tracés seront précis. Cependant votre fichier sera alors plus lourd, alourdissant notre page et donc les temps de chargement.
Voici la structure de mon fichier des Régions de France :
Nous avons 18 objets, représentant nos 18 régions.
Chaque région comporte les éléments suivants :
properties : contient des données, comme le nom de la région. C’est ici que nous ajouterons le nombre de cas actifs de patient du Covid19.
geometry : contient les couples Latitude/Longitude de points permettant les tracés de chaque région.
Je vais ajouter mes données à la main dans mon objet properties, en ajoutant un nouvel attribut :
« confirmed »: « 10 »
Je le fais à la main car peu de donnée, et surtout choisit aléatoirement. Le but n’est pas de montrer les vraies stats mais de vous montrer comment afficher ces données. Je vous laisse le soin d’ajouter des vraies données avec des scripts Python pour manipuler ces objets ci 😎
Affichage des données
On va ajouter une nouvelle ‘couche’ contenant nos données des régions sur notre carte. Pour cela on ajout dans notre vue dans notre composant leaflet, l’attribut leafletLayers que l’on va bind avec notre contrôleur :
On initialise ce nouvel attribut dans notre composant :
On ajoute ensuite nos données de nos régions :
J’initialise nos données dans un hook Angular, ngOnInit, pour être sûr que la carte Leaflet soit bien déjà initialisée. J’utilise ensuite le module HttpClient pour lire note fichier de donnée en local, disposé dans mon dossier des Assets. Je vais ensuite les ajouter dans mon attribut layers, via la méthode geoJSON de Leaflet qui permet de lire des données GeoJSON. J’initialise mes régions avec une couleur bleu en fond, une certaine opacité et épaisseur de bordure, qui sert à délimiter les régions entre elle.
Changer l’UI d’une région à son survol
On va améliorer l’interface de notre carte, en mettant en évidence la région survolée.
Je vais définir deux objets définissant les états graphiques que peuvent prendre nos régions. Soit elle est normale, soit elle est en cours de survolage par la souris de l’utilisateur. On fait deux style différents afin de remonter l’information à l’utilisateur pour lui montrer sur quoi il pointe :
On va aller modifier la fonction qui ajoute notre layers de données de nos régions afin de lui affecter un style définit précédemment :
On en profite pour leur ajouter des listeners. Vous pouvez voir que sur mon layer des régions, j’ajoute deux listener :
mouseover : quand l’utilisateur passe la souris sur une région
mouseout : quand l’utilisateur enlève la souris d’une région
click : quand un utilisateur clique sur une région, mais je ne l’utiliserais pas pour ce tutoriel ci
On affecte à nos deux listener deux fonctions qui seront appelé à chaque fois qu’un event sera exécuté.
L’event pour mettre en surbrillance une région :
L’event pour rétablir les styles par défaut :
Notez la syntaxe qui diffère entre les deux, mais réalise la même action. a vous de choisir celle que vous préférez.
Coloriser la région en fonction des data
On va pouvoir passer au cœur du projet, à savoir créer nos gradients de couleurs sur nos différentes régions. On va créer une nouvelle méthode qui va être appeler lors de la lecture de notre fichier de donnée GeoJSON, juste après que l’on ait mis nos listener sur l’ensemble de nos régions :
On reviendra un peu plus tard sur l’action qu’effectue l’appel à la méthode updateLegendValues().
On ajoute deux nouveaux attributs à notre classe :
Le premier correspond à un tableau rempli de nombre. Il va nous définir plus tard les intervalles de valeurs, permettant des comparaisons afin de décider si telle région appartient à tel ou tel intervalle selon sa valeur de cas confirmés. Quant au second, il va contenir des string de code hexadécimal de couleur, il en aura autant que d’intervalle défini dans le tableau précédent.
On va les initialiser dans notre constructeur de notre classe :
J’ai crée le gradient de couleur à la main, vous avez des sites sur le net pour vous aider à les faire selon vos couleurs. Je suis parti dans mon exemple autour d’un gradient de rouge.
Pour la suite, on va simplement re-parser notre layer contenant l’ensemble de nos régions, et changer leur style. En parcourant nos régions, on va récupérer notre attribut confirmed représentant le nombre de cas confirmé au Covid19. On souhaite en fonction de leur valeur affecter une couleur différente. On va donc pour l’attribut fillColor, lui passer une fonction qui prendre en entrée l’attribut ‘confirmed‘ :
Cette fonction renvoi en fonction de son entrée, un code hexadécimal de couleur. Je pense que la fonction peut être optimisé. En effet je fais à la main les comparaisons entre 6 intervalles de valeurs, correspondant chacune d’entre elle à 6 couleurs d’intensités différentes.
Il nous manque juste une seule chose, vous vous souvenez de ma fonction updateLegendValues() ? Que j’ai parlé un poil plus haut, et qui est appelé au début de ma fonction updateStyleMap(). Celle-ci va nous permettre de remplir notre tableau des intervalles, que l’on utilise dans la fonction getColor() pour assigner une couleur du tableau selectedLegendColorGradient en comparant aux intervalles de selectedLegendInfos.
On va encore une fois parser notre layer des régions, pour y récupérer la valeur max de l’attribut confirmed. Celle fonction aussi peut être grandement optimisé mais j’ai opté pour la simplicité pour ce tutoriel. Une fois la valeur max récupéré, je vais créer autant d’intervalle que je souhaite pour faire autant de gradient que je souhaite. Je suis partie sur 6 gradients de Rouge différent. Je créer ces intervalles en fonction de ma valeur maximale de cas crée auparavant, de façon linéaire. A vous de choisir quel algorithme vous souhaitez pour créer vos gradients, si vous voulez des intervalles avec autant d’écarts entre eux comme j’ai souhaité le faire ou en fonction d’autre chose. C’est selon vos souhaits selon comment vous souhaitez mettre en valeur vos données une fois sur la carte.
Affichage d’une légende
On vient de coloriser notre carte, mais on ne sait guerre comment elles sont exposées avec des chiffres précis. C’est pour cela que je vous proposer d’ajouter une légende pour préciser à quoi correspond chacun de nos gradients de couleur.
Je commence par ajouter une nouvelle division dans notre vue pour cette légende :
J’y ajoute un titre.
J’y ajoute une première boucle pour itérer sur l’ensemble de nos gradients de couleur, que j’inclus sous forme de petits carrés.
J’y ajout une seconde boucle pour itérer sur l’ensemble de nos intervalles de valeurs.
Vous pouvez voir que j’ai des appels de type fx dans mes balises. C’est du à l’utilisation d’une bibliothèque disponible dans Angular, FlexLayout, permettant de manier les flexbox directement dans le fichier HTML plutôt que de style CSS, je trouve cela un poil plus clair, mais ce n’est que mon opinion. Vous pouvez l’installer via npm (npm i -s @angular/flex-layout @angular/cdk).
Pour finaliser ma légende, et avoir cet effet de superposition de ma légende sur ma carte, on va parler d’index. Pour cela on va ajouter attribuer des classes à nos division dans notre fichier HTML :
Ajout d’une classe lastPlan pour notre carte
Ajout d’une première classe firstPlan et d’une seconde classe legend, pour notre légende
On y ajouter le SCSS suivant :
La classe firstPlan permet de mettre en premier plan notre légende
La classe lastPlan permet de mettre notre carte en second plan. Vous pouvez jouer avec les index de façon infini pour créer autant de plan que vous souhaitez utiliser plus de deux plans.
La classe squareLegend permet de définir la taille des carrés contenant nos couleurs.
La classe legend permet de définir le conteneur de l’ensemble de notre légende, de sa position sur l’écran ainsi que sa taille.
Affichage de data via popup
Je vous propose d’ajouter sur notre carte un popup, qui s’affiche au survol d’une région en affichant le nombre de cas confirmé au Covid19 qu’elle a.
On commence par créer deux nouvelles variables qui seront affiché dans notre vue :
Comme les noms qu’elles portent, la première pour afficher le nom de la région et la seconde pour afficher le nombre de cas. On les initialise à null dans le constructeur de notre composant.
On modifie notre fonction lors de l’événement mouseover, afin qu’elle affecte la valeur de la région et du nombre de cas à nos deux variables précédentes :
On utilise la classe ChangeDetectorRef dans la dernière ligne de notre fonction, qui offre des possibilités pour forcer les mises à jour de l’interface. On n’oublie pas de l’instancier en privée dans le constructeur du composant :
On modifie la fonction concernant l’événement mouseout, afin qu’elle supprime nos deux valeurs lorsque l’on sort d’une région :
Nous venons de modifier la partie du contrôleur, passons à la vue. On va créer une nouvelle division contenant notre popup :
Celle-ci ne s’affiche que si regionName contient une valeur. Vous pouvez voir que l’on a attribuer la classe css firstPlan pour qu’elle s’affiche dessus notre carte Leafleat, ainsi que la classe legendTop, définit dans notre fichier de style scss :
L’article touche à sa fin, vous devriez avoir le résultat suivant 😎
Conclusion
Vous avez donc accès pleinement à la librairie Leaflet.js dans votre application Angular.
Rien de bien complexe sur son intégration donc, juste un zeste déroutant d’utiliser du Javascript dans du Typescript, on mélange du typage fort avec des objets que l’on remplit d’attributs à la volé.
Vous pouvez faire des choses bien plus pousser. Réaliser une multitude de layers, que vous pouvez contrôler leur affichage ou non, ajouter une multitude de données dans vos GeoJSON pour binder avec des éléments dans Angular, pour réaliser par exemple un suivi du Covid19 mais sur plusieurs jours pour réaliser quelque chose de plus dynamique. Ou encore dessiner tout une multitude de polygone complexes, rendre leur affichage dynamique au sein même de la carte pour faire bouger automatiquement des marqueurs par exemple.
Dans cet article je vais introduire le sujet autour de la data visualisation. Je ne ferrais qu’introduire et je n’irais pas plus loin car c’est un domaine dans laquelle les formations en mathématiques, statistiques et probabilités sont le cœur du métier et qui forme les data scientist. Ce sont des personnes qui vont analyser des bases de données et extraire des informations, afin de trouver d’éventuelle corrélations entres elle. En effet, il se peut que certains facteurs puissent influer les autres. Connaître ces informations peut ajouter de la plus-value aux entreprises. Mieux vous connaîtrez votre marché et les besoins des clients, plus vous optimiserez les ventes de vos produits.
Prenons un exemple simple. Il y a fort à parier que les ventes de parapluie soient plus importantes en hiver, qu’en été. Et cela peut venir d’un principal facteur, qu’est la météo.
Le secteur étant large, je vais me consacrer qu’a une infime partie du domaine. Je vais me servir de plusieurs bibliothèques, tout cela en python :
Matplotlib : la plus connue de toute, elle permet de faire beaucoup, beaucoup de chose. Pour rapidement résumer, elle permet de réaliser très simplement des graphiques 2D.
Seaborn : elle se base sur la librairie précédente, et propose des graphiques encore plus détaillés pour pousser d’avantage l’aspect data visualisation.
Comme d’habitude, les sources du dataset utilisé et l’ensemble de mon code est disponible sur mon profil Github.
C’est parti ! 😎
Origine du dataset
Nous avons comme jeu de donnée diverses mesures médicales prises sur 768 patients. Celui-ci va vous permettre via 7 attributs différents nous permettre de déceler une quelconque relation si une personne est diabétique ou non. Nous avons les attributs suivants :
Pregnancies : nombre d’enfant
Glucose : taux de glucose dans le plasma sanguin (mm Hg)
Blood pressure : pression artérielle
Skin thinckness : épaisseur de peau au niveau du triceps (mm)
Insulin : taux d’insuline (mu U/mL)
BMI : indice de masse corporel (IMC, poids en kg / ( taille en m)²)
Diabete pedigree function
Age (année)
Outcome : la sortie qui sera 0 pour non diabétique, et 1 pour diabétique
On peut noter que le dataset n’est franchement pas équilibré :
Premiers pas
On comparant les 3 graphiques précédent, on peut réaliser déjà quelques observations qui pourraient influencer ou non le fait d’être diabétique. Cela reste purement statistique et donc n’en fait pas une science absolue :
Glucose : il semblerait qu’un taux plus important de glucose dans le sang soit perçue chez une personne diabétique
Skin thickness : on peut voir qu’une personne diabétique à une peau plus fine en moyenne
Insulin : une valeur légèrement plus forte serait présente chez une personne diabétique
Sur certains attributs, on ne peut trouver d’informations concluantes :
Pour pouvoir entrainer nos modèles, il nous faut d’énormes quantités de données. En effet, la quantité et surtout la qualité de notre dataset va avoir un rôle majeur pour l’élaboration d’un modèle de bonne facture. En effet, il est logique d’avoir avoir des données qui soient comparable entre elle. Quand je dis comparable, c’est qu’elles aient le même format, la même taille et longueur, etc. Et c’est à partir de ces contraintes que commence les problèmes. En effet, avoir des data spécifique selon notre problème avec les points précèdent cité peut souvent relever de l’impossible. C’est là que la data augmentation va pouvoir nous être grandement utile.
Le principe de data augmentation repose sur le principe d’augmenter de façon artificielle nos donnée, en y appliquant des transformations. On va pouvoir augmenter la diversité et donc le champ d’apprentissage de notre modèle, qui va pouvoir mieux s’adapter pour prédire de nouvelles données. Le principe de cette méthode est relativement simple, celle-ci est montré par l’image suivante concernant de l’augmentation sur des images :
En partant d’une simple image, nous pouvons la dupliquer autant de fois que nous avons des types de transformation différentes à lui appliquer. Et nous pouvons en augmenter davantage en croisant ces effets sur une même image, et en y appliquant différents valeurs de l’effet dans une fourchette donnée, pour avoir un résultat plus ou moins poussé.
Voici un exemple de mel-spectrogramme, dont on à appliquer des transformations à un extrait audio sain, sur le mot ‘Bonjour’. (Figure 1)
On peut aussi imaginer un grand nombre de transformation sur des données audios.
– Tempo : change la vitesse de parole de l’enregistrement sans en changer la longueur. (Figure 3)
– Pitch : change l’intonation de la voix (plus aigüe ou plus grave). (Figure 2)
Et la liste peut être plus longue : bandpass, equalizer, highpass, lowpass, chorus, delay, stretch, contrast, etc.