feat: RAPPORT FINITO

This commit is contained in:
Laureηt 2022-05-25 23:47:36 +02:00
parent 47995e0393
commit bd8893d089
No known key found for this signature in database
GPG key ID: D88C6B294FD40994
3 changed files with 162 additions and 126 deletions

BIN
docs/foireux.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 623 KiB

View file

@ -20,7 +20,7 @@ Le but de ce projet est de permettre la reconnaissance (classification) de voitu
Pour acquérir les quelques 400 000 images de notre dataset, nous avons simplement écrit un script capable d'automatiser la customisation des modèles ainsi que la prise de screenshots sur un téléphone android. Il nous aura fallu environ 18 heures pour constituer notre dataset.
Notre dataset est un dossier contenant toutes nos images et une base de données sqlite3 faisant le lien entre les noms de nos screenshots (des uuids) et les paramètres de la voiture dans l'image. Nous avions prévu à l'origine d'enregistrer bien plus d'informations que la simple correspondance entre une image et le modèle de voiture, mais cette tache était trop complexe (et peu utile, quoiqu'il aurait été interessant de voir comment certains accessoires influe sur la prédiction des modèles).
Notre dataset est un dossier contenant toutes nos images et une base de données sqlite3 faisant le lien entre les noms de nos screenshots (des uuids) et les paramètres de la voiture dans l'image. Nous avions prévu à l'origine d'enregistrer bien plus d'informations que la simple correspondance entre une image et le modèle de voiture, mais cette tache était trop complexe (et peu utile, quoiqu'il aurait été intéressant de voir comment certains accessoires influe sur la prédiction des modèles).
Ainsi, par exemple d'après notre fichier sqlite3, `ec7d32da-ad24-11ec-813b-e0d4e8390134.jpg` correspond au modèle de voiture 2 (la werewolf) à la team 0 (les bleus), à la couleur primaire 50%, à la couleur secondaire 0%, au chapeau n°12 (le Rasta), au sticker n°1 (le Kana), à la roue n°4 (l'Helicoprion) et à la 3ème rotation.
@ -51,7 +51,7 @@ test_size=38087 (0.1) -> (1191 batch)
## Chargement de nos données
Comme nous possédons un grand nombre d'images et comme celles-ci sont réliées à une base de donnéee sqlite3, nous allons devoir utiliser une [structure spéciale](https://www.tensorflow.org/tutorials/load_data/csv#using_tfdata) (pipeline) de Tensorflow pour charger les images progressivement en mémoire (car notre dataset set très probablement de taille supérieur à la RAM de notre machine).
Comme nous possédons un grand nombre d'images et comme celles-ci sont réliées à une base de donnéee sqlite3, nous allons devoir utiliser une [structure spéciale](https://www.tensorflow.org/tutorials/load_data/csv#using_tfdata) (pipeline) de Tensorflow pour charger les images progressivement en mémoire (car notre dataset est très probablement de taille supérieur à la RAM de notre machine).
## Exemple du dataset
@ -75,13 +75,13 @@ Comme nous possédons un grand nombre d'images et comme celles-ci sont réliées
## Augmentation
Pour empecher l'overfitting à tout prix, nous allons utiliser l'augmentation, via la librairie albumentations (nous augmenterons uniquement nos données de training).
Pour empêcher l'overfitting à tout prix, nous allons utiliser l'augmentation, via la librairie albumentations (nous augmenterons uniquement nos données de training).
Nous pouvons dans un premier temps doubler gratuitement notre dataset avec un flip horizontal, en effet, par exemple, une octane vue depuis un mirroir est toujours une octane.
Ensuite, nous allons randomiser les couleurs de nos images (via la transformation ColorJitter) pour forcer notre modèle à ne pas se fier aux couleurs. Notre modèle devrait donc en toute logique se concentrer sur la structure de notre image.
Enfin, pour rendre plus robuste la reconnaisance de structure, nous allons enlever de manière aléatoire des carrés de pixels dans nos images. Cela forcera notre modèle à observer des patterns plus généraux dans nos images, plutôt que de se fier qu'à une poignée de pixels spécifiques.
Enfin, pour rendre plus robuste la reconnaissance de structure, nous allons enlever de manière aléatoire des carrés de pixels dans nos images. Cela forcera notre modèle à observer des patterns plus généraux dans nos images, plutôt que de se fier qu'à une poignée de pixels spécifiques.
Voici quelques images augmentées.
@ -89,7 +89,7 @@ Voici quelques images augmentées.
## Modèle
Nous avons choisi de créer un simple réseau convolutif. De part se nature notre réseau ne nécéssite pas beaucoups de paramètres, et donc utiliser des modèles existants pré-entrainés ralenti notre apprentissage. De plus, les features de nos images sont assez spécifiques et les modèles classiques n'y sont pas adapté.
Nous avons choisi de créer un simple réseau convolutif. De par sa nature notre réseau ne nécessite pas beaucoup de paramètres, et donc utiliser des modèles existants pré-entrainés ralentit notre apprentissage. De plus, les features de nos images sont assez spécifiques et les modèles classiques n'y sont pas adaptés.
```python
model = Sequential(
@ -113,7 +113,7 @@ model = Sequential(
)
```
Nous utilisons de plus une régularisation L1 (de 0.025 dans notre cas) pour réduire au maximum le nombre de poids nécéssaires. Il serait donc interessant d'essayer de réduire notre réseau à son strict nécéssaire, mais nous n'avons pas eu le temps de le faire par la suite.
Nous utilisons de plus une régularisation L1 (de 0.025 dans notre cas) pour réduire au maximum le nombre de poids nécessaires. Il serait donc intéressant d'essayer de réduire notre réseau à son strict nécessaire, mais nous n'avons pas eu le temps de le faire par la suite.
```
@ -155,20 +155,20 @@ _________________________________________________________________
### Historique d'entrainement
Voici l'entrainement de notre réseau sur 20 epochs.
Il nous faut environ 1 minute pour une epoch, ainsi le temps totalement de l'entrainement de notre modèle est de 23 minutes.
Il nous faut environ 1 minute pour une epoch, ainsi le temps total pour l'entrainement de notre modèle est de 23 minutes.
![](history.png)
On observe que notre loss tend vers zéro et que notre accuracy tend vers 1.
Nos résultats sont plutôt statisfaisant. On remarque cependant un écart entre notre training accuracy et notre validation accuracy, cela est surement dû à notre régularisation un peu forte, mais il est important de dire que comparer le training et la validation perd son sens dans notre cas puisque les images n'ont rien à voir.
Nos résultats sont plutôt statisfaisants. On remarque cependant un écart entre notre training accuracy et notre validation accuracy, cela est sûrement dû à notre régularisation un peu forte, mais il est important de dire que comparer le training et la validation perd son sens dans notre cas puisque les images n'ont rien à voir.
### Matrice de confusion
![](confusion.png)
Voici la matrice de confusion de notre modèle sur notre dataset.
Notre modèle se trompe donc rarement, on observer cependant qu'il aura tendance à confondre l'octane avec d'autres voitures.
(De même on se rend compte que notre dataset de test n'est pas vraiment équilibré, cela vient de la manière dont nous l'avons construit, il serait plus rigoureux de le contruire équilibré. Le même problème s'applique donc à notre dataset de validation et cela biaise surement notre apprentissage).
Notre modèle se trompe donc rarement, on observe cependant qu'il aura tendance à confondre l'octane avec d'autres voitures.
(De même on se rend compte que notre dataset de test n'est pas vraiment équilibré, cela vient de la manière dont nous l'avons construit, il serait plus rigoureux de le construire équilibré. Le même problème s'applique donc à notre dataset de validation et cela biaise surement notre apprentissage).
### Grad-cam
@ -176,24 +176,33 @@ Pour nous permettre de mieux analyser ce qu'observe notre réseau nous avons uti
![](gradcam.png)
On observe alors bien que notre réseau se concentre bien sur la forme des voitures. Par exemple sur les octane vu de derrière, on remarque que celui-ci se concentre principalement sur ses phares, qui sont uniques parmis tous les autres modèles.
On observe alors bien que notre réseau se concentre bien sur la forme des voitures. Par exemple sur les octane vus de derrière, on remarque que celui-ci se concentre principalement sur ses phares, qui sont uniques parmi tous les autres modèles.
On remarque de même que notre modèle se concentre parfois sur le sol dessous la voiture, probablement que celui-ci n'est pas visible avec certains modèles.
Une dernière remarquer est que le modèle observe parfois le "complémentaire" de la voiture et non la voiture elle-même.
Une dernière remarque est que le modèle observe parfois le "complémentaire" de la voiture et non la voiture elle-même.
### Cas foireux
Il est intéressant de regarder les cas pour lesquels notre modèle s'est trompé dans sa classification, et d'essayer de trouver une interpretation:
Il est intéressant de regarder les cas pour lesquels notre modèle s'est trompé dans sa classification.
On observe ainsi que notre modèle se trompe sur des images erronées, comme la n°32498 du dataset de test, ou la n°35695:
![](32498.png)
![](35695.png)
De même lors de l'occurrence d'évènements exceptionnels, notre prédiction est erronée.
Par exemple sur l'image n°6746, un confetti s'est glissé juste devant notre voiture:
![](6746.png)
De manière générale, on observe que notre modèle se trompe la plupart du temps quand la voiture porte un chapeau qui modifie beaucoup ses caractéristiques, comme un très grand/haut (ou très petit) chapeau:
![](foireux.png)
Il est aussi intéressant de voir comment réagit notre modèle à des modèles de voiture qu'il n'a jamais vu (puisque la saison 2 du jeu est sortit entre temps):
![](new.png)
## Conclusion
Ça marche bien ptdrr.
Notre notebook est entièrement reporductible, puisque tous les générateurs de nombres aléatoires ont été seedés.
Notre notebook est entièrement reporductible, puisque tous les générateurs de nombres aléatoires ont été seedés.

File diff suppressed because one or more lines are too long