Ré-entraîner un réseau pré-entraîné à la détection d'objets dans des images


Acquis d'apprentissage visés :
- Savoir modifier le fichier de configuration d'un réseau TOD pré-entrainé, pour l'adapter à ses besoins.
- Savoir continuer l'entraînement supervisé d'un réseau TOD pré-entraîné.
- Savoir exporter les poids du réseau entrainé dans un format utilisable.

Durée approximative : plusieurs heures (dépend des ressources CPU & RAM de ton ordinateur).

Plan de l’activité

Cette activité se décompose en 3 étapes :

  1. Modifier le fichier de configuration du réseau pré-entraîné pour décrire la configuration d’entraînement propre à ton travail.
  2. Lancer l’entraînement supervisé.
  3. Exporter les poids du réseau entrainé dans un format utilisable.

0. Préliminaires

Pour simplifier l’écriture des commandes Linux à taper dans le terminal, tu peux définir dans le fichier config_tf2:

Exemple

Avec le projet faces_cubes et le réseau faster_rcnn_resnet50_v1_640x640_coco17_tpu-8 :

# From within tod_tf2
user@host $ echo 'export PTN=faster_rcnn_resnet50_v1_640x640_coco17_tpu-8' >> config_tf2
user@host $ echo 'export PTN_DIR=faces_cubes/training/$PTN' >> config_tf2

puis, après avoir tapé la commande source config_tf2, tu peux vérifier que les 2 variables sont bien définies :

user@host $ env | grep PTN      # pour vérifier
PTN_DIR=faces_cubes/training/faster_rcnn_resnet50_v1_640x640_coco17_tpu-8
PTN=faster_rcnn_resnet50_v1_640x640_coco17_tpu-8

1. Modifier le fichier de configuration

Le fichier de configuration pipeline.config présent dans le dossier pre-trained/<pre-trained_net> doit être copié dans le dossier cible <project>/training/<pre-trained_net>.

Avec le projet faces_cubes et le réseau pré-entrainé choisi :

# From within tod_tf2
user@host $ cp pre-trained/$PTN/pipeline.config $PTN_DIR

Exemple

Avec le projet faces_cubes et le réseau faster_rcnn_resnet50_v1_640x640_coco17_tpu-8 :

Line Parameter name Description Initial value Value Comment
010 num_classes nombre de classe d’objets 90 2 les deux classes one et two
077 max_detections_per_class nombre max de détection
par classe
100 4 4 cubes max par image
078 max_total_detections nombre max total de détections 100 4 4 cubes max par image
093 batch_size nombre d’images à traiter avant
mise à jour des poids du réseau
64 1, 2… une valeur trop élevée risque
de faire dépasser la capacité
mémoire RAM de ta machine.
À régler en fonction de la
quantité de RAM de
ta machine.
097 num_steps Nombre max d’itérations
d’entraînement
25000 1000 une valeur trop grande
donne des temps de calcul
prohibitifs et un risque
de sur-entraînement
113 fine_tune_checkpoint chemin des fichiers de sauvegarde
des poids du réseau pré-entraîné
‘PATH_TO_BE_CONFIGURED’ ‘pre-trained/
faster_rcnn_resnet50_v1_640x640_coco17_tpu-8/
checkpoint/ckpt-0’
se termine par /ckpt-0
qui est le préfixe des
fichiers dans le dossier
.../checkpoint/
114 fine_tune_checkpoint_type Choix de l’algorithme :
“classification” ou “detection”
‘classification’ ‘detection’ -> détection d’objets
120 max_number_of_boxes Nombre max de boîtes englobantes
dans chaque image
100 4 4 faces de cubes dans une image
122 use_bfloat16 true pour les architectures TPU
false pour CPU
true false choix du CPU
126 label_map_path chemin du fichier des labels ‘PATH_TO_BE_CONFIGURED’ ‘faces_cubes/training/label_map.pbtxt’ utilisé pour l’entraînement
128 input_path fichier des données d’entraînement
au format tfrecord
‘PATH_TO_BE_CONFIGURED’ ‘faces_cubes/training/train.record’ utilisé pour l’entraînement
139 label_map_path chemin du fichier des labels ‘PATH_TO_BE_CONFIGURED’ ‘faces_cubes/training/label_map.pbtxt’ utilisé pour l’évaluation
143 input_path fichier des données de test
au format tfrecord
‘PATH_TO_BE_CONFIGURED’ ‘faces_cubes/training/test.record" utilisé pour l’évaluation

2 Lance l’entraînement

⚠️ Il est très important de bien vérifier le contenu du fichier $PTN_DIR/pipeline.configure avant de lancer l’entraînement : une bonne pratique est de le faire vérifier par quelqu’un d’autre…

⚠️ Ne mettre des valeurs de batch_size > 2 que si ton ordinateur possède un bon CPU avec au moins 6 Gio de RAM !
Exemple : pour une entraînement avec 15 images avec num_steps=1000, sur un PC portable avec un processeur Intel core i7 et 8 Gio RAM :

Copie le fichier models/research/object_detection/model_main_tf2.py dans la racine tod_tf2 :

# From within tod_tf2
(tf2) user@host $ cp models/research/object_detection/model_main_tf2.py .

Maintenant lance l’entraînement avec la commande :

# From within tod_tf2
(tf2) user@host $ python model_main_tf2.py --model_dir=$PTN_DIR/checkpoint1 --pipeline_config_path=$PTN_DIR/pipeline.config

Les fichiers des poids entraînés seront écrits dans le dossier $PTN_DIR/checkpoint1 : si tu relances l’entraînement, tu peux utiliser checkpoint2, checkpoint3… pour séparer des essais successifs.

Le module tensorflow est assez verbeux et l’entraînement est long à démarrer…
Au bout d’un “certain temps” (qui peut être assez long, plusieurs dizaines de minutes avec un CPU ordinaire), les logs s’affichent à l’écran, en particulier les lignes qui commencent par INFO montrant que l’entraînement est en cours :

...
...
INFO:tensorflow:Step 100 per-step time 11.094s
I0123 17:51:15.919782 140056729301632 model_lib_v2.py:705] Step 100 per-step time 11.094s
INFO:tensorflow:{'Loss/BoxClassifierLoss/classification_loss': 0.13388917,
 'Loss/BoxClassifierLoss/localization_loss': 0.017869305,
 'Loss/RPNLoss/localization_loss': 0.0029150385,
 'Loss/RPNLoss/objectness_loss': 0.0007381027,
 'Loss/regularization_loss': 0.0,
 'Loss/total_loss': 0.15541162,
 'learning_rate': 0.014666351}
I0123 17:51:15.920520 140056729301632 model_lib_v2.py:708] {'Loss/BoxClassifierLoss/classification_loss': 0.13388917,
 'Loss/BoxClassifierLoss/localization_loss': 0.017869305,
 'Loss/RPNLoss/localization_loss': 0.0029150385,
 'Loss/RPNLoss/objectness_loss': 0.0007381027,
 'Loss/regularization_loss': 0.0,
 'Loss/total_loss': 0.15541162,
 'learning_rate': 0.014666351}
...
INFO:tensorflow:Step 1000 per-step time 10.638s
I0123 20:30:50.425828 140056729301632 model_lib_v2.py:705] Step 1000 per-step time 10.638s
INFO:tensorflow:{'Loss/BoxClassifierLoss/classification_loss': 0.05049885,
 'Loss/BoxClassifierLoss/localization_loss': 0.0066467496,
 'Loss/RPNLoss/localization_loss': 0.0011727745,
 'Loss/RPNLoss/objectness_loss': 0.0002043869,
 'Loss/regularization_loss': 0.0,
 'Loss/total_loss': 0.05852276,
 'learning_rate': 0.0266665}
I0123 20:30:50.426177 140056729301632 model_lib_v2.py:708] {'Loss/BoxClassifierLoss/classification_loss': 0.05049885,
 'Loss/BoxClassifierLoss/localization_loss': 0.0066467496,
 'Loss/RPNLoss/localization_loss': 0.0011727745,
 'Loss/RPNLoss/objectness_loss': 0.0002043869,
 'Loss/regularization_loss': 0.0,
 'Loss/total_loss': 0.05852276,
 'learning_rate': 0.0266665}

En cas d’arrêt brutal du programme avec le message “Processus arrêté”, ne pas hésiter à diminer la valeur du paramètre batch_size jusquà 2, voire 1 si nécessaire….
Même avec batch_size=2, le processus Python peut nécessiter plusieurs Gio de RAM à lui tout seul, ce qui peut mettre certains portables en difficulté…

Dans l’exemple ci-dessus, on voit des logs tous les 100 pas, avec environ ~10.7 secondes par pas, soit environ 18 minutes entre chaque affichage et ~3h de calcul pour les 1000 pas. Ce calcul est fait avec batch_size=2 sur un CPU Intel i7.

Une fois l’entraînement terminé tu peux analyser les statistiques d’entraînement avec tensorboard en tapant la commande :

# From within tod_tf2
(tf2) user@host:~ $ tensorboard --logdir=$PTN_DIR/checkpoint1/train
Serving TensorBoard on localhost; to expose to the network, use a proxy or pass --bind_all
TensorBoard 2.11.2 at http://localhost:6006/ (Press CTRL+C to quit)
...

tensorBOARD lance un serveur HTTP en local sur ta machine, et tu peux ouvrir la page avec un navigateur pour voir les courbes d’analyse en faisant CTRL + clic avec le curseur de la souris positionné sur l’adresse http://localhost:6006/ :

tensorflow

On peut voir sur les figures suivantes l’influence de la valeur du paramètre batch_size sur la qualité de l’apprentissage : un batch_size=2 donne de meilleures courbes de loss que’un batch_size=1, mais le calcul est plus long et prend plus de mémoire :

Entraînement avec batch_size=1, num_steps=1000 :
tensorflow

Entraînement avec batch_size=2, num_steps=1000 :
tensorflow

Entraînement avec batch_size=4, num_steps=1000 :
tensorflow

3. Exporter les poids du réseau ré-entraîné

Copie le script Python exporter_main_v2.py situé dans le dossier models/reasearch/object_detection/ et lance le pour extraire le graph d’inférence entraîné et le sauvegarder dans un fichier saved_model.pb. Ce fichier pourra être rechargé ultérieurement pour exploiter le réseau entraîné :

# From within tod_tf2
(tf2) user@host $ cp models/research/object_detection/exporter_main_v2.py .
(tf2) user@host $ python exporter_main_v2.py --input_type image_tensor --pipeline_config_path $PTN_DIR/pipeline.config --trained_checkpoint_dir $PTN_DIR/checkpoint1 --output_directory $PTN_DIR/saved_model1
...some stuff....

Le script Python créé le fichier saved_model.pb dans le dossier $PTN_DIR/saved_model1/saved_model :

# From within tod_tf2
(tf2) user@host:~ $ tree faces_cubes/training/
faces_cubes/training/
├── faster_rcnn_resnet50_v1_640x640_coco17_tpu-8
│   ├── checkpoint1
│   │   ├── checkpoint
│   │   ├── ckpt-1.data-00000-of-00001
│   │   ├── ckpt-1.index
│   │   ├── ckpt-2.data-00000-of-00001
│   │   ├── ckpt-2.index
│   │   └── train
│   │       └── events.out.tfevents.1635373645.pikatchou.30316.0.v2
│   ├── pipeline.config
│   └── saved_model1
│       ├── checkpoint
│       │   ├── checkpoint
│       │   ├── ckpt-0.data-00000-of-00001
│       │   └── ckpt-0.index
│       ├── pipeline.config
│       └── saved_model
│           ├── assets
│           ├── saved_model.pb
│           └── variables
│               ├── variables.data-00000-of-00001
│               └── variables.index
├── label_map.txt
├── test.record
└── train.record