File size: 7,425 Bytes
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
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
# Entraîner, annoter, évaluer le modèle CRNN

Ce document explique comment lancer chacune des trois étapes : annoter de
nouvelles images, ré-entraîner le modèle, évaluer sa précision. Les scripts
utilisés vivent dans le dépôt d'origine (`annotator/`, `train/` à la racine),
pas dans `yely_ai_module/` — ce dossier livrable embarque une copie de
référence de `train/` pour la reproductibilité (voir §"Où ça vit" plus bas).

## Vue d'ensemble du pipeline data → modèle

```
1. Annoter          annotator/annotate.py
        │            (dessine le rectangle LCD + saisit prix/volume/prix_litre)
        ▼
   annotator/annotations/annotations.json  (+ crops dans annotations/crops/)
        │
2. Découper en lignes  annotator/split_lines.py
        │            (1 image = 3 valeurs → 3 sous-images mono-ligne)
        ▼
   annotator/dataset_lines/{train,val}/
        │
3. Convertir au format doctr  train/prepare_doctr_dataset.py
        ▼
   annotator/dataset_doctr/{train,val}/  (images/ + labels.json)
        │
4. Entraîner  train/finetune_doctr.py
        ▼
   train/models/crnn_fuel_pump_best.pt  (+ history.json)
        │
5. Évaluer  train/test_model.py
```

## 1. Annoter de nouvelles images

```bash
cd annotator
python annotate.py --images ../images/        # nouvelles photos
python annotate.py --images ../images/ --resume   # reprendre où on s'était arrêté
python annotate.py --review                    # voir un résumé des annotations existantes
```

Pour chaque image : dessiner un rectangle autour de l'écran LCD (clic +
glisser), puis saisir dans le terminal les valeurs affichées (prix, volume,
prix du litre). Voir `annotator/README.md` pour le détail des raccourcis.

**Ce qui compte le plus pour améliorer le modèle** (voir `docs/LIMITATIONS.md`) :
annoter des photos avec des **valeurs différentes** de celles déjà présentes,
pas juste plus de photos des mêmes tickets. Utiliser
`yely_ai_module/tools/check_seen_image.py` pour vérifier qu'une photo
candidate n'est pas déjà (quasi-)présente dans le jeu annoté :

```bash
python yely_ai_module/tools/check_seen_image.py chemin/vers/nouvelle_photo.jpg
```

## 2. Régénérer le dataset d'entraînement

**Toujours dans cet ordre**, et **jamais pendant qu'un entraînement tourne**
(le chargement des images se fait à la volée pendant l'entraînement — les
régénérer en même temps fait planter le script avec un `FileNotFoundError`,
vécu concrètement pendant cette session) :

```bash
cd annotator
python split_lines.py              # annotations.json -> dataset_lines/

cd ../train
python prepare_doctr_dataset.py    # dataset_lines/ -> dataset_doctr/
```

Les deux scripts nettoient maintenant leur dossier de sortie avant de
régénérer (corrigé cette session — une même image pouvait sinon se
retrouver à la fois en train et en val d'un run à l'autre, faussant
l'évaluation).

**Vérification recommandée avant d'entraîner** : ouvrir
`annotator/dataset_lines/review/review_sheet.jpg`, qui montre un échantillon
d'images découpées à côté du label attendu — permet de repérer un mauvais
découpage avant de perdre du temps à entraîner dessus.

## 3. Lancer l'entraînement

```bash
cd train
python finetune_doctr.py                      # 80 epochs par défaut
python finetune_doctr.py --epochs 60 --patience 12
python finetune_doctr.py --from-scratch       # si pas de connexion internet (pas de poids pré-entraînés)
```

- Le modèle est sauvegardé dans `train/models/crnn_fuel_pump_best.pt` à
  chaque fois que la perte de validation s'améliore (pas seulement à la fin) —
  s'arrêter en cours de route (Ctrl+C, crash) ne perd donc pas tout.
- `--patience N` : arrête l'entraînement si la perte de validation ne
  s'améliore plus pendant N epochs (évite de continuer à surapprendre inutilement).
- Sur CPU (pas de GPU disponible), compter ~1.5-3 min/epoch sur le jeu de
  données actuel (~270 échantillons train). Un entraînement complet peut
  donc prendre plusieurs heures — lancer en arrière-plan
  (`... &` ou un terminal dédié) plutôt qu'en bloquant.
- À la fin (ou à l'arrêt anticipé), `train/models/history.json` contient
  la courbe complète (perte/accuracy par epoch) — sert de preuve pour le
  rapport de test (§15 du cahier des charges).

## 4. Évaluer le modèle

```bash
cd train
python test_model.py                          # évalue sur tout le set de validation
python test_model.py --image ../images/pompe.jpg   # teste une seule image
```

`test_model.py` calcule, sur le jeu de validation :
- **Exact-match accuracy** : proportion de lignes lues à 100% correctement
  (c'est la métrique citée dans `docs/LIMITATIONS.md`).
- **CER** (Character Error Rate) et **WER** : à quel point une prédiction
  fausse est "proche" de la bonne réponse (ex. "10000" lu "1O000" a un CER
  faible même si l'exact-match échoue) — plus informatif que l'accuracy
  seule pour juger si le modèle progresse.
- La liste des erreurs (jusqu'à 15 affichées), utile pour repérer des
  motifs d'erreur récurrents (un chiffre systématiquement confondu, une
  ligne toujours mal découpée...).

## Où ça vit (dépôt d'origine vs dossier livrable)

- **Annotation et préparation du dataset** (`annotator/`) : uniquement à la
  racine du dépôt d'origine, pas dupliqué dans `yely_ai_module/` (le jeu de
  ~155 images sources n'est volontairement pas inclus dans le livrable).
- **Entraînement** (`train/`) : présent aux deux endroits. La copie dans
  `yely_ai_module/train/` est une référence pour la reproductibilité
  (documentation technique) ; pour ré-entraîner réellement, utiliser la
  version à la racine du dépôt, qui a accès à `annotator/dataset_doctr/`.
- **Script `train/infer.py`** : ancien script d'inférence autonome
  (antérieur à `yely_ai_module/app/recognizer.py`), gardé pour test rapide
  en ligne de commande. Avait le même bug de découpage à 2 lignes (au lieu
  de 3) que celui corrigé dans `preprocessing.py` — corrigé aussi. Pour
  tester le pipeline réellement livré (avec règles métier, API), utiliser
  `yely_ai_module/app/`, pas ce script.

## Si le modèle donne de mauvais résultats en test manuel

Avant de conclure "le modèle n'est pas bon", vérifier dans l'ordre :

1. **Quel script a été utilisé ?** `train/infer.py` et `yely_ai_module/app/`
   ont des logiques de détection d'écran différentes (`detect_lcd_region`
   vs `detect_screen_region`) — l'un peut réussir là où l'autre échoue sur
   la même photo.
2. **La zone détectée est-elle la bonne ?** Les deux scripts peuvent
   confondre le bandeau de marque ("Shell FuelSave...") avec l'écran LCD sur
   certaines photos (voir `docs/PREPROCESSING.md`) — sauvegarder et regarder
   le crop intermédiaire avant d'incriminer le CRNN.
3. **La photo est-elle inédite ou proche du jeu d'entraînement ?**
   (`tools/check_seen_image.py`) — le modèle est attendu comme moins bon sur
   des valeurs qu'il n'a jamais vues, c'est documenté et mesuré
   (`docs/LIMITATIONS.md`), pas une surprise.
4. **Quelle précision réelle attendre ?** 70.2% exact-match sur les lignes
   de validation (`train/models/v2/history.json`) — donc environ 3 lectures
   sur 10 avec au moins un caractère faux sont *attendues* à ce stade, pas
   un signe que quelque chose est cassé.