File size: 5,345 Bytes
b510add
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3020394
 
 
 
 
 
 
 
 
 
 
 
 
b510add
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
# Limites identifiées — modèle CRNN (§15 du cahier des charges)

## Précision actuelle

Le modèle CRNN (`crnn_vgg16_bn`, fine-tuné à partir des poids pré-entraînés
Mindee) livré dans `models/crnn_fuel_pump_best.pt` atteint **70.2% de
précision exacte par ligne** en validation (epoch 32, voir
`train/models/v2/history.json`) — en progression depuis la version initiale
à ~55% (`train/models/history.json`), grâce au correctif de redimensionnement
(voir point 3) et à l'ajout de 3 images avec des valeurs inédites au jeu
d'annotation. C'est encore en dessous du seuil de 90% visé initialement
(`IMPLEMENTATION_PLAN.md`), mais un progrès net et mesuré sur un vrai
jeu de validation (sans fuite train/val — voir point 4).

## Causes identifiées

1. **Diversité des valeurs quasi nulle dans le jeu de données.** 310
   échantillons au total (155 images sources découpées en lignes), mais
   seulement **30 valeurs distinctes** — 8 valeurs à elles seules
   représentent ~89% du dataset (probablement des photos en rafale des
   mêmes transactions). Le modèle a donc très peu d'occasions d'apprendre à
   généraliser la lecture de chiffres inédits ; il est plus proche de la
   mémorisation d'un nombre restreint de motifs que d'une reconnaissance de
   caractères robuste.

2. **Découpage ligne-par-ligne imprécis pour 86% des images sources.**
   `annotator/dataset_lines/split_report.json` montre que seulement 22/154
   images ont utilisé la détection précise par projection de texte ; 132/154
   sont tombées sur le repli "proportionnel" (division en bandes de hauteur
   égale), qui peut couper à travers les chiffres ou inclure du bruit —
   corrompant l'alignement image↔label pour la majorité de l'entraînement.

3. **Incohérence corrigée entre entraînement et inférence (resize).**
   À l'entraînement, chaque crop était étiré de force à une largeur fixe de
   256px sans préserver le ratio d'aspect (`train/finetune_doctr.py`,
   `collate_fn`), alors qu'à l'inférence le ratio d'aspect était préservé
   (`preprocess_crop`). Le modèle apprenait donc sur des chiffres déformés
   différemment de ce qu'il voit réellement en production. **Corrigé** :
   le redimensionnement d'entraînement préserve maintenant le ratio d'aspect
   et complète par du padding, comme à l'inférence.

4. **Fuite train/val corrigée.** Relancer `split_lines.py` après avoir
   ajouté des annotations réassignait des images entre train et val (le
   split dépend d'un tirage aléatoire sur la liste complète), mais les
   anciens fichiers n'étaient pas supprimés avant d'écrire les nouveaux —
   une même image pouvait donc se retrouver à la fois dans train ET val,
   gonflant artificiellement l'accuracy de validation. **Corrigé** :
   `split_lines.py` et `prepare_doctr_dataset.py` nettoient maintenant les
   dossiers de sortie avant de régénérer. Le 70.2% actuel est mesuré après
   ce correctif — donc fiable.

## Toujours vrai malgré l'amélioration à 70.2%

Le facteur limitant reste le même : le dataset est petit et peu diversifié
en valeurs. 70.2% de lignes exactement correctes n'est pas suffisant pour
une mise en production telle quelle — voir §"Recommandations" ci-dessous,
qui restent d'actualité.

## Recommandations pour dépasser 70%

- **Collecter plus de transactions distinctes** (valeurs de prix/volume
  variées, pas seulement plus de photos des mêmes tickets) — c'est le levier
  le plus impactant, mais aussi le plus long à mettre en œuvre.
- **Revoir le découpage des lignes** : ajuster les seuils de
  `annotator/split_lines.py::_detect_text_bands` (actuellement 86% des
  images tombent sur le repli proportionnel), ou annoter directement les
  bounding box par valeur plutôt que par écran complet.
- **Vérifier visuellement** `annotator/dataset_lines/review/review_sheet.jpg`
  avant tout nouvel entraînement, pour écarter les crops mal découpés.
- Envisager de la **data augmentation** (légères rotations, variations de
  luminosité/contraste) pour compenser partiellement le manque de diversité.

## Bug de classification qualité corrigé (flou vs sombre)

`app/quality.py` vérifiait le flou (variance du Laplacien) avant la
luminosité. Or la variance du Laplacien dépend elle-même du contraste, qui
s'effondre dans une image sombre même quand les contours sont nets : une
photo prise dans un environnement peu éclairé mais parfaitement stable
pouvait donc être classée à tort `"blurry"` ("reprendre la photo, image
floue") au lieu de `"dark"` ("reprendre la photo avec plus de lumière") —
deux diagnostics qui appellent un geste correctif différent côté
utilisateur. **Corrigé** : la luminosité (`dark`/`bright`) est maintenant
vérifiée avant le flou, qui n'est un diagnostic fiable que sur une image
déjà correctement exposée.

## Ce qui reste fiable indépendamment du modèle

La détection d'écran, le contrôle qualité (flou/luminosité), le moteur de
règles métier (cohérence montant/litres/prix, seuil de confiance, blocage)
et l'API ne dépendent pas de la précision du CRNN — ce sont des composants
séparés et testés indépendamment (voir `tests/`). Une amélioration future du
modèle de reconnaissance s'intègre donc sans changer le reste du pipeline.