Spaces:
Paused
Paused
version 1
Browse files- converted_txt/DST_Rapport_final_Reco_plant.txt +2565 -0
- requirements.txt +5 -0
- step1_read_pdf.py +29 -0
- step2_chunk.py +24 -0
- step3_docling.py +65 -0
- step3_embed.py +23 -0
- step3_llamaindex.py +55 -0
- step3_llamaindex_evol.py +66 -0
- step4_faiss.py +54 -0
- step4_llamaindex.py +212 -0
- step4b_shell.py +48 -0
- tester.py +12 -0
converted_txt/DST_Rapport_final_Reco_plant.txt
ADDED
@@ -0,0 +1,2565 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
Projet Datascientest
|
2 |
+
Reconnaissance de plantes
|
3 |
+
|
4 |
+
Rapport final
|
5 |
+
|
6 |
+
Ela CIMEN
|
7 |
+
Yao N Guessan Roland KONAN
|
8 |
+
Yacine MADI SAID
|
9 |
+
Nicolas RINCÉ
|
10 |
+
|
11 |
+
09/06/2025
|
12 |
+
|
13 |
+
|
14 |
+
|
15 |
+
|
16 |
+
|
17 |
+
|
18 |
+
|
19 |
+
|
20 |
+
|
21 |
+
|
22 |
+
|
23 |
+
|
24 |
+
|
25 |
+
|
26 |
+
|
27 |
+
|
28 |
+
Table des matières
|
29 |
+
|
30 |
+
Partie 1 : Cadrage du projet ...................................................................................................5
|
31 |
+
|
32 |
+
Contexte ........................................................................................................................................ 5
|
33 |
+
|
34 |
+
Objectifs ........................................................................................................................................ 5
|
35 |
+
|
36 |
+
Description des macro-objectifs .................................................................................................... 5
|
37 |
+
Localiser et classifier l’espèce d’une plante dans une image ......................................................................5
|
38 |
+
Localiser et classifier la maladie éventuelle touchant la plante dans cette même image ............................5
|
39 |
+
Bâtir une application renvoyant les informations de ces classifications à l’utilisateur sur la base d’une
|
40 |
+
photographie prise sur son smartphone. ..................................................................................................6
|
41 |
+
|
42 |
+
Jalons du projet ............................................................................................................................. 6
|
43 |
+
|
44 |
+
Schéma de fonctionnement de l’application ................................................................................. 6
|
45 |
+
|
46 |
+
Niveaux d’expertise ...................................................................................................................... 7
|
47 |
+
Niveaux d’expertise interne ......................................................................................................................7
|
48 |
+
Recours à expertise externe .....................................................................................................................7
|
49 |
+
|
50 |
+
Partie 2 : Exploration et DataViz ............................................................................................7
|
51 |
+
|
52 |
+
Jeux de données ............................................................................................................................ 7
|
53 |
+
Soumis et exploités ..................................................................................................................................7
|
54 |
+
Soumis et non exploités ...........................................................................................................................8
|
55 |
+
Constats ...................................................................................................................................................8
|
56 |
+
|
57 |
+
Pertinence ..............................................................................................................................9
|
58 |
+
|
59 |
+
Variables ....................................................................................................................................... 9
|
60 |
+
|
61 |
+
Description .................................................................................................................................. 10
|
62 |
+
|
63 |
+
Limitation des données ............................................................................................................... 10
|
64 |
+
|
65 |
+
Partie 3 : Pré-Processing et feature engineering..................................................................11
|
66 |
+
|
67 |
+
Création du dataframe des caractéristiques................................................................................ 11
|
68 |
+
|
69 |
+
Nettoyage des données et étapes de traitement ........................................................................ 11
|
70 |
+
|
71 |
+
Transformations des données ..................................................................................................... 12
|
72 |
+
Traitement des images ........................................................................................................................... 12
|
73 |
+
|
74 |
+
Visualisations et Statistiques....................................................................................................... 14
|
75 |
+
Corrélation entre variables du dataframe .............................................................................................. 14
|
76 |
+
Relations avec les variables cibles ......................................................................................................... 14
|
77 |
+
|
78 |
+
Distribution des données ............................................................................................................ 14
|
79 |
+
Distribution des espèces dans le dataframe “high quality” ...................................................................... 14
|
80 |
+
Distribution des espèces dans le dataframe “low quality” ....................................................................... 15
|
81 |
+
Mesure d’amélioration de la qualité des images ..................................................................................... 15
|
82 |
+
|
83 |
+
Analyses statistiques ................................................................................................................... 17
|
84 |
+
|
85 |
+
Conclusions pré-modélisation ..................................................................................................... 18
|
86 |
+
|
87 |
+
Partie 4 : Modélisation ........................................................................................................18
|
88 |
+
|
89 |
+
Classification du problème .......................................................................................................... 18
|
90 |
+
|
91 |
+
Type de problème de machine learning ...................................................................................... 18
|
92 |
+
|
93 |
+
Tâches de machine learning ........................................................................................................ 18
|
94 |
+
|
95 |
+
Métriques de performance utilisées pour comparer les modèles ............................................... 18
|
96 |
+
Métrique principale ................................................................................................................................ 18
|
97 |
+
Métriques secondaires ........................................................................................................................... 18
|
98 |
+
|
99 |
+
Choix du modèle et optimisation ................................................................................................ 19
|
100 |
+
Algorithmes testés ................................................................................................................................. 19
|
101 |
+
Résultats par modèle ............................................................................................................................. 19
|
102 |
+
KERAS ........................................................................................................................................... 19
|
103 |
+
1-
|
104 |
+
FastAI............................................................................................................................................ 23
|
105 |
+
2-
|
106 |
+
Torch ............................................................................................................................................ 24
|
107 |
+
3-
|
108 |
+
AlexNet ......................................................................................................................................... 26
|
109 |
+
4-
|
110 |
+
|
111 |
+
Optimisation ............................................................................................................................... 29
|
112 |
+
Phase 1 .................................................................................................................................................. 29
|
113 |
+
Phase 2 .................................................................................................................................................. 35
|
114 |
+
|
115 |
+
Stratégies de traitement des images Cassava ............................................................................. 41
|
116 |
+
1. Augmentation massive des classes minoritaires .................................................................................. 41
|
117 |
+
2. Filtrage basé sur un score multi-critères ............................................................................................. 42
|
118 |
+
3. Relabellisation automatique basée sur le score ................................................................................... 42
|
119 |
+
4. Fine-tuning des modèles sur les nouveaux datasets ............................................................................ 43
|
120 |
+
5. Résultats obtenus ............................................................................................................................... 43
|
121 |
+
6. Analyse des résultats .......................................................................................................................... 44
|
122 |
+
7. Conclusion de l’étude d’amélioration sur Cassava ............................................................................... 45
|
123 |
+
Étude de l’ensemblage des modèles ....................................................................................................... 46
|
124 |
+
Conclusion sur le choix des ensembles de modèles ................................................................................. 49
|
125 |
+
|
126 |
+
Partie 5 : Conclusions tirées .................................................................................................49
|
127 |
+
|
128 |
+
Difficultés rencontrées pendant le projet.................................................................................... 49
|
129 |
+
Principal verrou scientifique rencontré ................................................................................................... 49
|
130 |
+
|
131 |
+
Difficultés détaillées par catégorie .............................................................................................. 49
|
132 |
+
Prévisionnel ........................................................................................................................................... 49
|
133 |
+
Jeux de données..................................................................................................................................... 50
|
134 |
+
Compétences techniques/théoriques ..................................................................................................... 50
|
135 |
+
Pertinence ............................................................................................................................................. 50
|
136 |
+
IT ........................................................................................................................................................... 50
|
137 |
+
Autres .................................................................................................................................................... 51
|
138 |
+
|
139 |
+
Bilan .....................................................................................................................................51
|
140 |
+
|
141 |
+
Contribution principale dans l'atteinte des objectifs ................................................................... 51
|
142 |
+
|
143 |
+
Modifications depuis la dernière itération .................................................................................. 51
|
144 |
+
|
145 |
+
Résultats obtenus et comparaison au benchmark....................................................................... 51
|
146 |
+
|
147 |
+
Performances atteintes ............................................................................................................... 51
|
148 |
+
Comparaison aux benchmarks de la littérature ....................................................................................... 51
|
149 |
+
|
150 |
+
Atteinte des objectifs du projet................................................................................................... 52
|
151 |
+
Objectif 1 : Classification des espèces (✅ Atteint) .................................................................................. 52
|
152 |
+
Objectif 2 : Détection des maladies (⚠ Partiellement atteint)................................................................. 52
|
153 |
+
Objectif 3 : Application Streamlit (✅ En cours) ....................................................................................... 52
|
154 |
+
|
155 |
+
Processus métier d'inscription .................................................................................................... 52
|
156 |
+
Agriculture de précision ......................................................................................................................... 52
|
157 |
+
Services aux professionnels .................................................................................................................... 52
|
158 |
+
Applications grand public ....................................................................................................................... 52
|
159 |
+
|
160 |
+
Suite du projet .....................................................................................................................52
|
161 |
+
|
162 |
+
Pistes d'amélioration des performances ..................................................................................... 52
|
163 |
+
Amélioration des données ...................................................................................................................... 52
|
164 |
+
|
165 |
+
Optimisations architecturales ..................................................................................................... 53
|
166 |
+
Techniques avancées.............................................................................................................................. 53
|
167 |
+
|
168 |
+
Déploiement et optimisation ...................................................................................................... 53
|
169 |
+
|
170 |
+
Contribution à l'accroissement de la connaissance scientifique .................................................. 53
|
171 |
+
Avancées méthodologiques .................................................................................................................... 53
|
172 |
+
|
173 |
+
Connaissances domaine-spécifiques ........................................................................................... 53
|
174 |
+
|
175 |
+
Impact scientifique et sociétal .................................................................................................... 54
|
176 |
+
|
177 |
+
|
178 |
+
|
179 |
+
|
180 |
+
|
181 |
+
Partie 1 : Cadrage du projet
|
182 |
+
|
183 |
+
Contexte
|
184 |
+
|
185 |
+
La cible du projet est d’offrir à un individu, ne bénéficiant pas de l’expertise pour reconnaître
|
186 |
+
une plante et sa maladie éventuelle, la capacité de l’identifier via l’appareil photo de son
|
187 |
+
smartphone
|
188 |
+
|
189 |
+
● Du point de vue technique, il s’agit d’utiliser des algorithmes de machine learning,
|
190 |
+
pour analyser les images et classifier les espèces de plantes, détecter les maladies et
|
191 |
+
réaliser des analyses statistiques afin de déterminer, le cas échéant, les corrélations
|
192 |
+
entre espèces de plantes et maladies associées.
|
193 |
+
|
194 |
+
● Du point de vue économique, l’application construite pourra aider un certain nombre
|
195 |
+
(agriculteurs, distributeurs de plantes, paysagiste, …) à détecter
|
196 |
+
d’acteurs
|
197 |
+
précocement les maladies et éviter des pertes de récoltes ou de chiffre d’affaires, et
|
198 |
+
minimiser les coûts associés aux traitements tardifs.
|
199 |
+
|
200 |
+
● Du point de vue scientifique, l’utilisation de cette application pourrait offrir un
|
201 |
+
support durable au recensement des espèces, renforcer l’échange de connaissances
|
202 |
+
entre chercheurs, en particulier sur le maintien de la bio-diversité, sensibiliser écoliers,
|
203 |
+
étudiants et grand public à la connaissance des espèces et leur conservation, être
|
204 |
+
élargi à la recherche des causes des maladies à l’aide de données additionnelles
|
205 |
+
(géographie, climat, …)
|
206 |
+
|
207 |
+
Objectifs
|
208 |
+
|
209 |
+
Description des macro-objectifs
|
210 |
+
|
211 |
+
Localiser et classifier l’espèce d’une plante dans une image
|
212 |
+
|
213 |
+
La photographie initiale prise par l’utilisateur sera analysée au regard de critères
|
214 |
+
d’acceptabilité comparables aux conditions d’entraînement de l’algorithme de classification
|
215 |
+
(niveau de flou, luminosité, contraste, etc). Elle sera ensuite retraitée (format JPEG, RGB,
|
216 |
+
redimensionnement et éventuellement retraitement du niveau de flou afin de faciliter le
|
217 |
+
diagnostic). Ce premier algorithme de classification, entraîné sur la base totale des images
|
218 |
+
décrite en page 14 et de méta-données pouvant y être rattachées aura été testé sur une base
|
219 |
+
constituée de 20% des images concernées avec un objectif d’accuracy de 95%. La base totale
|
220 |
+
des images aura été probablement corrigée afin de minimiser les déséquilibres entre classes.
|
221 |
+
|
222 |
+
Localiser et classifier la maladie éventuelle touchant la plante dans cette même image
|
223 |
+
|
224 |
+
|
225 |
+
|
226 |
+
|
227 |
+
|
228 |
+
|
229 |
+
|
230 |
+
|
231 |
+
|
232 |
+
|
233 |
+
|
234 |
+
|
235 |
+
|
236 |
+
La photographie retraitée, ou la photographie d’origine subissant de nouveaux filtres, sera
|
237 |
+
soumise à un second algorithme de classification, entraîné sur la base totale des images
|
238 |
+
décrite en page 14 et de méta-données pouvant y être rattachées (telles que le niveau de bleu
|
239 |
+
dans l’image qui est un premier prédicteur du caractère malade ou non de la plante) et testé
|
240 |
+
sur une base constituée de 20% des images concernées avec un objectif d’accuracy de 95%
|
241 |
+
des feuilles malades.
|
242 |
+
|
243 |
+
Bâtir une application renvoyant les informations de ces classifications à l’utilisateur sur la base
|
244 |
+
d’une photographie prise sur son smartphone.
|
245 |
+
|
246 |
+
L’application sera développée sur Streamlit conformément au schéma de l’application
|
247 |
+
présentée en Page 6 en veillant à des règles d’ergonomie de « base » (éviter les images de
|
248 |
+
fond, contraste des couleurs pour faciliter la lecture, usage des couleurs limité à une gamme
|
249 |
+
réduite, boutons de navigation explicites, etc.)
|
250 |
+
Jalons du projet
|
251 |
+
|
252 |
+
Schéma de fonctionnement de l’application
|
253 |
+
|
254 |
+
|
255 |
+
|
256 |
+
|
257 |
+
|
258 |
+
|
259 |
+
|
260 |
+
|
261 |
+
|
262 |
+
|
263 |
+
|
264 |
+
Niveaux d’expertise
|
265 |
+
|
266 |
+
Niveaux d’expertise interne
|
267 |
+
|
268 |
+
Nom
|
269 |
+
|
270 |
+
Algorithmie
|
271 |
+
|
272 |
+
Dév. Appli
|
273 |
+
mobile
|
274 |
+
|
275 |
+
Statistiques
|
276 |
+
|
277 |
+
Gestion
|
278 |
+
projet
|
279 |
+
|
280 |
+
Botanique
|
281 |
+
|
282 |
+
Ela CIMEN
|
283 |
+
|
284 |
+
Roland KONAN
|
285 |
+
|
286 |
+
Yacine MADI SAID
|
287 |
+
|
288 |
+
Nicolas RINCÉ
|
289 |
+
|
290 |
+
2/5
|
291 |
+
|
292 |
+
4/5
|
293 |
+
|
294 |
+
3/5
|
295 |
+
|
296 |
+
2/5
|
297 |
+
|
298 |
+
0/5
|
299 |
+
|
300 |
+
2/5
|
301 |
+
|
302 |
+
5/5
|
303 |
+
|
304 |
+
0/5
|
305 |
+
|
306 |
+
3/5
|
307 |
+
|
308 |
+
3/5
|
309 |
+
|
310 |
+
2/5
|
311 |
+
|
312 |
+
4/5
|
313 |
+
|
314 |
+
4/5
|
315 |
+
|
316 |
+
4/5
|
317 |
+
|
318 |
+
4/5
|
319 |
+
|
320 |
+
4/5
|
321 |
+
|
322 |
+
3/5
|
323 |
+
|
324 |
+
2/5
|
325 |
+
|
326 |
+
1/5
|
327 |
+
|
328 |
+
1/5
|
329 |
+
|
330 |
+
Recours à expertise externe
|
331 |
+
|
332 |
+
Nous n’avons pas eu recours à des experts externes à proprement parler (en-dehors de
|
333 |
+
Damien évidemment !) mais avons réalisé de nombreuses recherches afin de nous guider,
|
334 |
+
notamment sur les sujets suivants :
|
335 |
+
|
336 |
+
● Taille des images standard utilisée dans les algorithmes de reconnaissance d’image ;
|
337 |
+
● Détermination du niveau de flou d’une image et seuil d’acceptabilité pour la
|
338 |
+
|
339 |
+
reconnaissance d’images (150 de Laplacienne) ;
|
340 |
+
|
341 |
+
● Retraitement des niveaux de flous ;
|
342 |
+
● Déséquilibre acceptable entre classes sur le fichier d’entraînement (1 à 10) ;
|
343 |
+
|
344 |
+
Nombre minimal d’images à soumettre à l’algorithme par classe (1.000).
|
345 |
+
|
346 |
+
Partie 2 : Exploration et DataViz
|
347 |
+
|
348 |
+
Jeux de données
|
349 |
+
Soumis et exploités
|
350 |
+
|
351 |
+
https://www.kaggle.com/vbookshelf/v2-plant-seedlings-dataset
|
352 |
+
|
353 |
+
● Arborescence de 12 dossiers pour 12 espèces de jeune pousse les plus répandue au
|
354 |
+
|
355 |
+
Danemark
|
356 |
+
Il n’y a qu’un seul dataset (non séparé en test/train) contenant 5539 images
|
357 |
+
|
358 |
+
●
|
359 |
+
● Volumétries restreintes aux images d’espèces végétales : 100%
|
360 |
+
|
361 |
+
https://www.kaggle.com/vipoooool/new-plant-diseases-dataset
|
362 |
+
|
363 |
+
● Fichier d’images de feuilles d’arbres fruitiers, de légumineuses et de céréales,
|
364 |
+
|
365 |
+
malades ou saines
|
366 |
+
|
367 |
+
● Dataset d’entraînement de 70.295 images
|
368 |
+
● Dataset de test de 17.572 images
|
369 |
+
● Volumétries restreintes aux images d’espèces végétales : 100%
|
370 |
+
|
371 |
+
https://www.kaggle.com/saroz014/plant-disease
|
372 |
+
|
373 |
+
|
374 |
+
|
375 |
+
|
376 |
+
|
377 |
+
|
378 |
+
|
379 |
+
|
380 |
+
|
381 |
+
● Fichier d’images de feuilles d’arbres fruitiers, de légumineuses et de céréales,
|
382 |
+
|
383 |
+
malades ou saines
|
384 |
+
|
385 |
+
● Dataset d’entraînement de 43.456 images
|
386 |
+
● Dataset de test de 10.849 images
|
387 |
+
● Volumétries restreintes aux images d’espèces végétales : 100%
|
388 |
+
|
389 |
+
https://www.kaggle.com/abdallahalidev/plantvillage-dataset
|
390 |
+
|
391 |
+
● Fichier d’images de feuilles d’arbres fruitiers, de légumineuses et de céréales,
|
392 |
+
|
393 |
+
malades ou saines
|
394 |
+
|
395 |
+
● 3 Datasets de 54305 images chacun avec les mêmes images en couleur, niveau de
|
396 |
+
|
397 |
+
gris et prétraité.
|
398 |
+
|
399 |
+
● Volumétries restreintes aux images d’espèces végétales : 100%
|
400 |
+
|
401 |
+
Soumis et non exploités
|
402 |
+
|
403 |
+
https://storage.googleapis.com/openimages/web/download.html et
|
404 |
+
https://cocodataset.org/#home
|
405 |
+
|
406 |
+
● Non exploité car bases de données non spécifiquement axées sur les plantes, de
|
407 |
+
volumétrie limitée sur cette dernière catégorie, sans discrimination entre plantes
|
408 |
+
saines et plantes malades, dont le seul intérêt était la présence de masques qui ne
|
409 |
+
serviront pas dans les algorithmes choisis.
|
410 |
+
|
411 |
+
Constats
|
412 |
+
|
413 |
+
● Les 3 dernières bases de données soumises et exploitées se sont révélées redondantes
|
414 |
+
et provenant d’un même set d’images initial. Nous n’avons donc conservé que la base
|
415 |
+
d’origine
|
416 |
+
test
|
417 |
+
d’entraînement
|
418 |
+
données
|
419 |
+
les
|
420 |
+
(https://www.kaggle.com/vipoooool/new-plant-diseases-dataset)
|
421 |
+
|
422 |
+
fusionnant
|
423 |
+
|
424 |
+
de
|
425 |
+
|
426 |
+
en
|
427 |
+
|
428 |
+
et
|
429 |
+
|
430 |
+
● La première base nous est apparue trop limitée en nombre d’images (moins de 500
|
431 |
+
images par espèces), peu exploitable en raison de la part de l’image réservée au
|
432 |
+
végétal (il s’agit de jeunes pousses) et trop spécifique (12 espèces provenant du
|
433 |
+
Danemark). Nous l’avons donc abandonnée.
|
434 |
+
|
435 |
+
● Compte tenu de la limitation du dataset à des arbres fruitiers et de céréales et de
|
436 |
+
légumineuses, nous avons recherché d’autres datasets permettant d’étendre la
|
437 |
+
reconnaissance à d’autres plantes (canne à sucre, maïs et vigne) comme exposé dans
|
438 |
+
le tableau ci-dessous. Comme pour le reste des datasets, ces images sont libres de
|
439 |
+
droits.
|
440 |
+
|
441 |
+
https://www.kaggle.com/datasets/nirmalsankalana/sugarcane-leaf-disease-dataset
|
442 |
+
|
443 |
+
● Dataset d’images de feuilles de canne à sucre saine et malades
|
444 |
+
● 2569 images, séparées en 5 répertoires (1 par maladie et 1 pour celles en bonne
|
445 |
+
|
446 |
+
santé)
|
447 |
+
|
448 |
+
● Volumétries restreintes aux images d’espèces végétales : 100%
|
449 |
+
|
450 |
+
https://www.kaggle.com/datasets/nirmalsankalana/grape400-dataset
|
451 |
+
|
452 |
+
|
453 |
+
|
454 |
+
|
455 |
+
|
456 |
+
|
457 |
+
|
458 |
+
|
459 |
+
|
460 |
+
|
461 |
+
● Datasets d’images de feuilles de vigne saines et malades
|
462 |
+
● 1600 images séparées en 4 répertoires (1 par maladie et 1 pour celles en bonne
|
463 |
+
|
464 |
+
santé)
|
465 |
+
|
466 |
+
● Volumétries restreintes aux images d’espèces végétales : 100%
|
467 |
+
|
468 |
+
https://www.kaggle.com/datasets/shuvokumarbasak4004/rose-leaf-disease-dataset
|
469 |
+
|
470 |
+
● Datasets d’images de feuilles de rose saines et malades
|
471 |
+
● 14,910 images séparées en 3 répertoires (test, train, validation)
|
472 |
+
● Volumétries restreintes aux images d’espèces végétales : 100%
|
473 |
+
|
474 |
+
https://www.kaggle.com/datasets/nirmalsankalana/cassava-leaf-disease-classification
|
475 |
+
|
476 |
+
● Datasets d’images de feuilles de cassave saines et malades
|
477 |
+
● 21 397 images séparées en 5 répertoires (1 par maladie et 1 pour celles en bonne
|
478 |
+
|
479 |
+
santé)
|
480 |
+
|
481 |
+
● Volumétries restreintes aux images d’espèces végétales : 100%
|
482 |
+
|
483 |
+
Pertinence
|
484 |
+
Variables
|
485 |
+
|
486 |
+
● La reconnaissance des plantes, puis du caractère sain ou malade, va s’appuyer sur les
|
487 |
+
images sélectionnées. Le sujet de la pertinence des variables ne s’applique donc pas
|
488 |
+
de la même manière que sur un problème de classification basé sur un fichier de
|
489 |
+
données textuelles ou numériques. Les principales variables dans ce cadre seront les
|
490 |
+
pixels de chaque image.
|
491 |
+
|
492 |
+
● Néanmoins, la sélection des images s’est appuyée dans une première phase
|
493 |
+
sur un fichier .csv répertoriant les principales caractéristiques des images (cf. section
|
494 |
+
suivante sur le pre-processing) : niveau de flou, luminosité, contraste, taille des
|
495 |
+
images, type de l’image (.jpeg, .png, …) .
|
496 |
+
|
497 |
+
● C’est dans ce même fichier que nous avons logé les deux variables cibles : le nom de la
|
498 |
+
|
499 |
+
plante, d’une part, le caractère sain ou malade d’autre part.
|
500 |
+
|
501 |
+
● Un troisième fichier de données devra être constitué pour abriter les données
|
502 |
+
|
503 |
+
descriptives à afficher sur l’application streamlit.
|
504 |
+
|
505 |
+
|
506 |
+
|
507 |
+
|
508 |
+
|
509 |
+
|
510 |
+
|
511 |
+
|
512 |
+
Description
|
513 |
+
|
514 |
+
Le dataframe global contient 126 668 images pour 19 espèces.
|
515 |
+
|
516 |
+
Limitation des données
|
517 |
+
|
518 |
+
● Limitations liées au périmètre des données : la première limitation concerne le
|
519 |
+
|
520 |
+
périmètre des plantes et végétaux présents dans la base. Dès lors, l’application ne
|
521 |
+
pourra pas être utilisée pour reconnaître « toutes » les espèces de plantes. La
|
522 |
+
généralisation de l’application ne pourrait venir que de l’élargissement du périmètre
|
523 |
+
des plantes concernées.
|
524 |
+
|
525 |
+
● Limitations liées à l’hétérogénéité des données : la seconde limitation concerne
|
526 |
+
|
527 |
+
l’hétérogénéité des données étudiées, qui a mené à l’exclusion des images de jeunes
|
528 |
+
pousses trop éloignées de la majorité de la base d’images que nous avons pu
|
529 |
+
constituer, et insuffisamment nombreuses pour les intégrer dans le jeu
|
530 |
+
d’entraînement. De même, cela limitera la portée de l’application.
|
531 |
+
|
532 |
+
|
533 |
+
|
534 |
+
|
535 |
+
|
536 |
+
|
537 |
+
|
538 |
+
● Limitations liées au déséquilibre des classes : la troisième limitation concerne le
|
539 |
+
|
540 |
+
déséquilibre entre plantes avec une surreprésentation de certaines espèces dont en
|
541 |
+
particulier les tomates.
|
542 |
+
|
543 |
+
● Limitations liées à la qualité des données : la quatrième limitation touche la qualité
|
544 |
+
des données parmi les images retenues, et notamment leur degré de flou qui est
|
545 |
+
primordial dans la reconnaissance des images
|
546 |
+
|
547 |
+
● Limitations liées à la taille du dataset : la cinquième limitation concerne la taille de
|
548 |
+
|
549 |
+
l’ensemble des images ainsi constituées qui doit être limitée afin de tenir compte des
|
550 |
+
temps de traitement de l’algorithme.
|
551 |
+
|
552 |
+
Partie 3 : Pré-Processing et feature engineering
|
553 |
+
|
554 |
+
Création du dataframe des caractéristiques
|
555 |
+
|
556 |
+
Afin de faciliter la sélection des images nous avons créé un dataframe contenant les
|
557 |
+
caractéristiques de l’ensemble des images issues des dataset qui présente la structure
|
558 |
+
suivante :
|
559 |
+
|
560 |
+
● FileName : nom du fichier,
|
561 |
+
● FilePath : chemin vers le dataset initial,
|
562 |
+
● Extension : extension de l’image
|
563 |
+
● Species :espèce,
|
564 |
+
● Disease : maladie,
|
565 |
+
● FileSize : taille de l’image,
|
566 |
+
● Width : largeur de l’image,
|
567 |
+
● Height : hauteur de l’image,
|
568 |
+
● Contrast : moyenne du contraste
|
569 |
+
● Luminosity: moyenne de la luminosité
|
570 |
+
● RedMean: moyenne de vert
|
571 |
+
● GreenMean : moyenne de vert
|
572 |
+
● BlueMean : moyenne de bleu
|
573 |
+
● Blur : moyenne de flou
|
574 |
+
|
575 |
+
Nettoyage des données et étapes de traitement
|
576 |
+
|
577 |
+
Définition des critères de sélection :
|
578 |
+
|
579 |
+
● Flou > 500
|
580 |
+
● Contraste > 2
|
581 |
+
● Luminosité < 200
|
582 |
+
● Nombre maximum d’image =12500
|
583 |
+
● nombre minimum d’image =1250
|
584 |
+
|
585 |
+
|
586 |
+
|
587 |
+
|
588 |
+
|
589 |
+
|
590 |
+
|
591 |
+
|
592 |
+
|
593 |
+
|
594 |
+
A partir du dataframe initial, on parcourt l’ensemble des images grâce au FilePath pour
|
595 |
+
appliquer nos critères de qualité et créer un dataframe (df_high_quality)
|
596 |
+
réunissant uniquement les images qui passent le test.
|
597 |
+
|
598 |
+
Ceux ne passant pas les critères de qualité vont être intégré à un dataframe différent
|
599 |
+
(df_low_quality) pour être traité.
|
600 |
+
|
601 |
+
Transformations des données
|
602 |
+
|
603 |
+
Traitement des images
|
604 |
+
Plusieurs traitements sont appliqués aux images dans le but d’améliorer leur qualité. Les
|
605 |
+
traitements incluent des ajustements sur la luminosité, le contraste, la netteté (flou et
|
606 |
+
netteté), ainsi que des redimensionnements.
|
607 |
+
|
608 |
+
Les étapes sont détaillées ci-dessous :
|
609 |
+
|
610 |
+
1. Ajustement de la luminosité
|
611 |
+
|
612 |
+
La fonction `adjust_brightness(image)` permet de modifier la luminosité d'une image en
|
613 |
+
utilisant la méthode `ImageEnhance.Brightness` de la bibliothèque `PIL`. Le facteur de
|
614 |
+
luminosité, défini par `brightness_factor`, est appliqué à l'image. Après ajustement, la
|
615 |
+
luminosité moyenne de l'image (calculée sur une conversion en niveaux de gris) est
|
616 |
+
renvoyée pour référence.
|
617 |
+
|
618 |
+
2. Augmentation du contraste
|
619 |
+
|
620 |
+
La fonction `process_contrast(image)` augmente le contraste de l'image à l'aide de
|
621 |
+
`ImageEnhance.Contrast`. Le facteur de contraste, défini par `contrast_factor`, est appliqué
|
622 |
+
pour rendre les différences entre les pixels plus marquées. Après traitement, la fonction
|
623 |
+
calcule et renvoie la variance de l'image en niveaux de gris (une mesure du contraste).
|
624 |
+
|
625 |
+
3. Calcul du flou (Netteté)
|
626 |
+
|
627 |
+
La fonction `calculate_blurriness(image)` utilise la méthode du Laplacien pour calculer le flou
|
628 |
+
d’une image. Le flou est mesuré par la variance de la matrice du Laplacien sur l'image en
|
629 |
+
niveaux de gris. Une faible variance indique un flou plus élevé, tandis qu'une haute variance
|
630 |
+
indique une image plus nette.
|
631 |
+
|
632 |
+
4. Augmentation de la netteté
|
633 |
+
|
634 |
+
La fonction `increase_sharpness(image)` est utilisée pour améliorer la netteté de l'image.
|
635 |
+
Cela se fait par l'application de la méthode `ImageEnhance.Sharpness`. Un facteur de
|
636 |
+
netteté, `sharpness_factor`, est défini pour contrôler l’intensité de l'amélioration. Après
|
637 |
+
avoir ajusté la netteté, la fonction calcule et renvoie également le niveau de flou après
|
638 |
+
traitement pour évaluer l’effet de la netteté appliquée.
|
639 |
+
|
640 |
+
|
641 |
+
|
642 |
+
|
643 |
+
|
644 |
+
|
645 |
+
|
646 |
+
|
647 |
+
|
648 |
+
5. Redimensionnement de l’image
|
649 |
+
|
650 |
+
La fonction `resize_image(image, width, height)` redimensionne les images à une taille
|
651 |
+
spécifiée (ici, 256x256 pixels). Cette opération est réalisée avec la méthode `resize()` de PIL
|
652 |
+
en utilisant l'algorithme `LANCZOS`, qui permet de préserver la qualité de l'image lors du
|
653 |
+
redimensionnement.
|
654 |
+
|
655 |
+
6. Configuration des paramètres globaux
|
656 |
+
|
657 |
+
Les facteurs de traitement sont définis avant le traitement :
|
658 |
+
|
659 |
+
●
|
660 |
+
|
661 |
+
●
|
662 |
+
●
|
663 |
+
|
664 |
+
`brightness_factor` : Ajuste la luminosité (ici fixé à 0.8 pour une légère réduction de
|
665 |
+
la luminosité).
|
666 |
+
`contrast_factor` : Augmente le contraste (ici fixé à 1.5 pour un contraste plus élevé).
|
667 |
+
`sharpness_factor` : Améliore la netteté (ici fixé à 4.0 pour une forte amélioration de
|
668 |
+
la netteté).
|
669 |
+
|
670 |
+
● Taille de redimensionnement : Les images sont redimensionnées à 256x256 pixels
|
671 |
+
|
672 |
+
pour une normalisation de la taille.
|
673 |
+
|
674 |
+
7. Exécution et enregistrement des résultats
|
675 |
+
|
676 |
+
Une fois les images traitées, le DataFrame Low_quality_processed contenant les
|
677 |
+
informations des images traitées est enregistré dans un fichier CSV. Ce fichier peut être
|
678 |
+
utilisé pour des analyses ultérieures ou pour vérifier les modifications apportées à chaque
|
679 |
+
image.
|
680 |
+
|
681 |
+
8. Combinaison dans un dataframe global
|
682 |
+
|
683 |
+
Les dataframes High_quality et Low_quality_processed sont combinés dans un nouveau
|
684 |
+
dataframe df_recombined_quality.
|
685 |
+
|
686 |
+
|
687 |
+
|
688 |
+
|
689 |
+
|
690 |
+
|
691 |
+
Visualisations et Statistiques
|
692 |
+
|
693 |
+
Corrélation entre variables du dataframe
|
694 |
+
|
695 |
+
On constate que les variables de luminosité et de niveau de rouge, vert et bleu sont très bien
|
696 |
+
corrélées. En revanche, à l’exception du couple (“Blur”,”Filesize”), les autres variables sont
|
697 |
+
peu corrélées entre elles.
|
698 |
+
|
699 |
+
Relations avec les variables cibles
|
700 |
+
|
701 |
+
Nous n’avons pas identifié de relations entre la variable ‘species’ et le reste des variables. En
|
702 |
+
revanche, en première approche, nous avons noté une corrélation entre le niveau de
|
703 |
+
“jaune” des images et la variable saine ou malade sur une partie du jeu de données (cf.
|
704 |
+
Analyse statistiques).
|
705 |
+
|
706 |
+
Distribution des données
|
707 |
+
|
708 |
+
Distribution des espèces dans le dataframe “high quality”
|
709 |
+
|
710 |
+
|
711 |
+
|
712 |
+
|
713 |
+
|
714 |
+
|
715 |
+
|
716 |
+
|
717 |
+
|
718 |
+
Dans le dataframe des images de bonnes qualités, il y a 79 599 images, dont les trois
|
719 |
+
premières espèces représentent + 45% du total.
|
720 |
+
|
721 |
+
Distribution des espèces dans le dataframe “low quality”
|
722 |
+
|
723 |
+
Il y a 47 069 images, on peut remarquer que l’ensemble des images des espèces cassave, riz,
|
724 |
+
et sucre de canne ne sont présentes que sur le dataframe de mauvaise qualité.
|
725 |
+
|
726 |
+
Mesure d’amélioration de la qualité des images
|
727 |
+
|
728 |
+
Distribution du flou avant/après retraitements
|
729 |
+
|
730 |
+
D'après la visualisation, la densité des valeurs de flou a augmenté après traitement, ce qui
|
731 |
+
suggère une amélioration de la qualité des images. En effet, on peut observer que le pic de
|
732 |
+
l'histogramme a migré de 500 avant le traitement à 2000 après le traitement, ce qui indique
|
733 |
+
|
734 |
+
|
735 |
+
|
736 |
+
|
737 |
+
|
738 |
+
|
739 |
+
|
740 |
+
|
741 |
+
|
742 |
+
que les images sont devenues plus nettes et moins floues après avoir subi les ajustements
|
743 |
+
sur la netteté.
|
744 |
+
|
745 |
+
Analyse du contraste et de la luminosité avant et après retraitement
|
746 |
+
|
747 |
+
Les boîtes à moustaches montrent que le retraitement a amélioré la qualité des images en
|
748 |
+
réduisant les valeurs aberrantes. Pour le contraste, la médiane est restée stable, mais les
|
749 |
+
valeurs très faibles de contraste ont été corrigées, et la gamme des valeurs s'est élargie. De
|
750 |
+
même, pour la luminosité, la médiane est inchangée, mais les images trop lumineuses ont
|
751 |
+
été ajustées, créant une distribution plus homogène. En résumé, les traitements ont réduit
|
752 |
+
les extrêmes tout en maintenant une stabilité de la médiane.
|
753 |
+
|
754 |
+
Analyse du redimensionnement
|
755 |
+
|
756 |
+
Avant retraitement, les images avaient des dimensions très variées, ce qui compliquait leur
|
757 |
+
analyse et leur traitement uniforme. Cette hétérogénéité des tailles pouvait entraîner des
|
758 |
+
biais lors de l'application de modèles d'apprentissage automatique ou d'autres analyses
|
759 |
+
d'images, car les réseaux de neurones et les algorithmes de traitement d'images nécessitent
|
760 |
+
des entrées de taille uniforme. Après retraitement, toutes les images ont été
|
761 |
+
redimensionnées à une taille standard de 256x256 pixels, un format couramment utilisé
|
762 |
+
dans la datascience. Cette normalisation permet non seulement de faciliter l'analyse et
|
763 |
+
l'entraînement des modèles, mais elle garantit également que toutes les images sont
|
764 |
+
traitées de manière cohérente, améliorant ainsi la performance des modèles d'analyse et de
|
765 |
+
classification.
|
766 |
+
|
767 |
+
|
768 |
+
|
769 |
+
|
770 |
+
|
771 |
+
Analyses statistiques
|
772 |
+
|
773 |
+
Le niveau de bleu semble être le plus discriminant entre feuilles saines et feuilles malades,
|
774 |
+
probablement lié à la présence de tâches de couleur jaune (R+V) sur la plupart de ces
|
775 |
+
dernières.
|
776 |
+
|
777 |
+
Si on réalise un test de student pour tester l’hypothèse que les niveaux de bleu sont
|
778 |
+
significativement différents entre des feuilles saines et des feuilles malades, on trouve une
|
779 |
+
statistique t de 128 et une valeur p très proche de 0, ce qui prouve que ce niveau de bleu est
|
780 |
+
discriminant.
|
781 |
+
|
782 |
+
Ceci est confirmé par une première approche de classification via un premier modèle
|
783 |
+
Random Forest mené en prenant pour Target le statut (Sain/Malade) et en Data, la moyenne
|
784 |
+
de bleu, rouge, vert, le contraste et la luminosité donne un taux de bonne prédiction de
|
785 |
+
88%.
|
786 |
+
|
787 |
+
Le graphique ci-contre montre l’importance des variables dans la contribution à la
|
788 |
+
classification et confirme en contributeur principal le niveau de bleu.
|
789 |
+
|
790 |
+
Le taux de bonne prédiction de la classe malade est de 93,5% mais le modèle ne fonctionne
|
791 |
+
pas correctement pour le classement des images saines (taux de prédiction de 74%)
|
792 |
+
|
793 |
+
▪
|
794 |
+
|
795 |
+
Un premier modèle Random Forest ent
|
796 |
+
|
797 |
+
pour le classement des images saines (taux de prédiction de
|
798 |
+
|
799 |
+
|
800 |
+
|
801 |
+
|
802 |
+
|
803 |
+
|
804 |
+
|
805 |
+
|
806 |
+
Conclusions pré-modélisation
|
807 |
+
|
808 |
+
Nous disposons au terme de cette étape d’un fichier homogène en termes de qualité
|
809 |
+
d’images, d’une quantité a priori suffisante pour appliquer un algorithme de reconnaissance,
|
810 |
+
au déséquilibre entre classes moins marqué que sur les données d’origine, et qui affiche déjà
|
811 |
+
quelques variables discriminantes sur l’une des deux variables cibles.
|
812 |
+
|
813 |
+
Partie 4 : Modélisation
|
814 |
+
|
815 |
+
Classification du problème
|
816 |
+
|
817 |
+
Type de problème de machine learning
|
818 |
+
|
819 |
+
La cible du projet est d’offrir à un individu, ne bénéficiant pas de l’expertise pour reconnaître
|
820 |
+
une plante et sa maladie éventuelle, la capacité de l’identifier via l’appareil photo de son
|
821 |
+
smartphone. Il s’agit donc d’un problème de classification des espèces ainsi que des maladies
|
822 |
+
associées sur la base des images qui seront soumises par l’utilisateur.
|
823 |
+
|
824 |
+
Tâches de machine learning
|
825 |
+
|
826 |
+
La tâche associée est la reconnaissance d’images, spécifiquement de feuilles associées à 18
|
827 |
+
espèces végétales (fruits, légumineuses, céréales), dont les contours puis les détails sont
|
828 |
+
progressivement analysées à travers les couches du réseau de neurones modélisé.
|
829 |
+
|
830 |
+
Métriques de performance utilisées pour comparer les modèles
|
831 |
+
|
832 |
+
A ce stade nous avons choisi 2 métriques.
|
833 |
+
|
834 |
+
Métrique principale
|
835 |
+
|
836 |
+
Accuracy : Compte tenu de la limitation du déséquilibre entre classes obtenu après la phase
|
837 |
+
de pre-processing, nous avons choisi de retenir l’Accuracy comme métrique principale, définie
|
838 |
+
comme le rapport entre le nombre de bonnes prédictions et le nombre total de prédictions.
|
839 |
+
|
840 |
+
Métriques secondaires
|
841 |
+
|
842 |
+
Loss : Nous avons également jaugé la rapidité de la convergence du modèle en suivant la
|
843 |
+
notion de loss à chaque époque de l’apprentissage.
|
844 |
+
|
845 |
+
Selon les modèles et afin de nous assurer, malgré le faible déséquilibre de classes, que les
|
846 |
+
classes les moins représentées soient correctement traitées, nous avons observé dans certains
|
847 |
+
cas quelle était la k-ème Accuracy la plus faible parmi les classes proposées au modèle.
|
848 |
+
|
849 |
+
|
850 |
+
|
851 |
+
|
852 |
+
|
853 |
+
|
854 |
+
|
855 |
+
|
856 |
+
|
857 |
+
|
858 |
+
|
859 |
+
|
860 |
+
|
861 |
+
|
862 |
+
|
863 |
+
|
864 |
+
|
865 |
+
|
866 |
+
Choix du modèle et optimisation
|
867 |
+
|
868 |
+
Algorithmes testés
|
869 |
+
Nous avons retenu 6 algorithmes :
|
870 |
+
|
871 |
+
● 3 algorithmes Keras avec les modèles ResNet50V2, EfficientNetB0 et
|
872 |
+
|
873 |
+
EfficientNetV2M;
|
874 |
+
|
875 |
+
● 1 algorithme FastAI avec le modèle efficientnet_b0
|
876 |
+
● 2 algorithmes Torch, l’un avec transfer learning (MobileNetV2, adapté pour une
|
877 |
+
application mobile comme c’est l’objectif ici) et l’autre sans transfer learning
|
878 |
+
|
879 |
+
● 1 algorithme AlexNet
|
880 |
+
|
881 |
+
Résultats par modèle
|
882 |
+
|
883 |
+
1- KERAS
|
884 |
+
|
885 |
+
Keras est une bibliothèque open-source de haut niveau pour la création et l'entraînement de
|
886 |
+
modèles d'apprentissage profond (deep learning). Elle a été développée par François Chollet
|
887 |
+
en 2015 et est maintenant intégrée directement dans TensorFlow, où elle sert d'interface
|
888 |
+
principale pour construire et entraîner des réseaux de neurones. Pour notre étude nous
|
889 |
+
avons décidé de comparer 3 modèles de réseau de neurones : ResNet50V2,EfficientNetB0 et
|
890 |
+
EfficientNetV2M en transfert learning et en fine tuning.
|
891 |
+
|
892 |
+
Description des modèles
|
893 |
+
|
894 |
+
ResNet50V2 :
|
895 |
+
|
896 |
+
● Architecture : ResNet50V2 (Residual Networks) utilise des blocs résiduels, ce qui
|
897 |
+
permet de mieux entraîner des réseaux profonds en atténuant le problème de
|
898 |
+
dégradation de la performance.
|
899 |
+
|
900 |
+
● Profundité : 50 couches.
|
901 |
+
|
902 |
+
● Performance : Bon compromis entre précision et temps de calcul, particulièrement
|
903 |
+
|
904 |
+
efficace pour des tâches classiques de classification d'images (ImageNet).
|
905 |
+
|
906 |
+
● Avantages : C'est un modèle classique très utilisé avec des performances solides sur
|
907 |
+
|
908 |
+
de nombreuses applications.
|
909 |
+
|
910 |
+
●
|
911 |
+
|
912 |
+
Inconvénients : Moins efficace en termes de computation par rapport aux
|
913 |
+
architectures récentes comme EfficientNet.
|
914 |
+
|
915 |
+
EfficientNetB0 :
|
916 |
+
|
917 |
+
● Architecture : EfficientNet utilise une méthode d'optimisation appelée "compound
|
918 |
+
scaling", qui ajuste simultanément la profondeur, la largeur et la résolution de
|
919 |
+
l'image, offrant ainsi une meilleure efficacité énergétique et une précision
|
920 |
+
|
921 |
+
|
922 |
+
|
923 |
+
|
924 |
+
|
925 |
+
|
926 |
+
|
927 |
+
|
928 |
+
|
929 |
+
|
930 |
+
|
931 |
+
|
932 |
+
|
933 |
+
|
934 |
+
supérieure.
|
935 |
+
|
936 |
+
● Profundité : Moins profond que ResNet50V2, mais beaucoup plus efficace pour les
|
937 |
+
|
938 |
+
mêmes performances.
|
939 |
+
|
940 |
+
● Performance : Généralement plus rapide et plus efficace que ResNet50V2 pour la
|
941 |
+
|
942 |
+
même précision.
|
943 |
+
|
944 |
+
● Avantages : Très efficace en termes de taille du modèle et d'utilisation des
|
945 |
+
|
946 |
+
ressources, il donne de bons résultats même avec des réseaux moins profonds.
|
947 |
+
|
948 |
+
●
|
949 |
+
|
950 |
+
Inconvénients : Moins éprouvé que ResNet50V2 dans certaines configurations.
|
951 |
+
|
952 |
+
EfficientNetV2M :
|
953 |
+
|
954 |
+
● Architecture : Une amélioration de l'EfficientNet original, qui intègre des techniques
|
955 |
+
|
956 |
+
de fusion des convolutions et un meilleur équilibrage des ressources.
|
957 |
+
|
958 |
+
● Profundité : Plus profond que EfficientNetB0, ce qui le rend potentiellement plus
|
959 |
+
|
960 |
+
puissant, mais aussi plus lourd en termes de calcul.
|
961 |
+
|
962 |
+
● Performance : Très performant sur des tâches complexes et des jeux de données
|
963 |
+
|
964 |
+
volumineux, surpassant souvent EfficientNetB0 et ResNet50V2.
|
965 |
+
|
966 |
+
● Avantages : Très performant tout en restant optimisé pour des ressources limitées.
|
967 |
+
|
968 |
+
●
|
969 |
+
|
970 |
+
Inconvénients : Modèle plus complexe et potentiellement plus long à entraîner
|
971 |
+
comparé à EfficientNetB0.
|
972 |
+
|
973 |
+
Résultats
|
974 |
+
|
975 |
+
L'entraînement a été effectué 55 classes qui résultent du croisement espèce et maladie. Pour
|
976 |
+
chaque modèle nous avons effectué un entraînement en transfert learning sur 10 époques
|
977 |
+
avec les couches du modèle freezées. Nous avons dans une seconde étape nous avons
|
978 |
+
effectué du fine tuning des modèles entraînés sur 30 époques avec les 30 dernières couches
|
979 |
+
non freezées.
|
980 |
+
|
981 |
+
Etape Transfer learning
|
982 |
+
|
983 |
+
Etape Fine tuning
|
984 |
+
|
985 |
+
Modèle
|
986 |
+
|
987 |
+
ResNet50V2
|
988 |
+
|
989 |
+
EfficientNetB0
|
990 |
+
|
991 |
+
EfficientNetV2M
|
992 |
+
|
993 |
+
ResNet50V2
|
994 |
+
|
995 |
+
EfficientNetB0
|
996 |
+
|
997 |
+
EfficientNetV2M
|
998 |
+
|
999 |
+
Accuracy
|
1000 |
+
|
1001 |
+
0.92
|
1002 |
+
|
1003 |
+
0.92
|
1004 |
+
|
1005 |
+
0.91
|
1006 |
+
|
1007 |
+
0.95
|
1008 |
+
|
1009 |
+
0.95
|
1010 |
+
|
1011 |
+
0.95
|
1012 |
+
|
1013 |
+
|
1014 |
+
|
1015 |
+
|
1016 |
+
|
1017 |
+
|
1018 |
+
|
1019 |
+
|
1020 |
+
|
1021 |
+
|
1022 |
+
|
1023 |
+
|
1024 |
+
|
1025 |
+
|
1026 |
+
|
1027 |
+
|
1028 |
+
|
1029 |
+
Les 3 modèles plafonnent à 0.95 après le fine tuning. En effet, les résultats de la classification
|
1030 |
+
des images de l’espèce cassava sont très mauvais sur les trois modèles. Il faudra dans une
|
1031 |
+
seconde étape étudier en détail ces images.
|
1032 |
+
|
1033 |
+
Exemple de classification report avec un zoom sur l'espèce cassava.
|
1034 |
+
|
1035 |
+
Graphe comparatif de l’évolutions de la précision et de la perte des trois modèles
|
1036 |
+
|
1037 |
+
|
1038 |
+
|
1039 |
+
|
1040 |
+
|
1041 |
+
|
1042 |
+
|
1043 |
+
|
1044 |
+
|
1045 |
+
|
1046 |
+
Comparaison du f1-score par classe et par modèles
|
1047 |
+
|
1048 |
+
|
1049 |
+
|
1050 |
+
|
1051 |
+
|
1052 |
+
|
1053 |
+
2- FastAI
|
1054 |
+
|
1055 |
+
Fastai est une librairie open-source de haut niveau pour le deep learning.
|
1056 |
+
Construite sur PyTorch, elle a pour objectif de simplifier les entraînements de modèles,
|
1057 |
+
accélérer les déploiements de modèles tout en conservant la performance et les
|
1058 |
+
fonctionnalités avancées de Pytorch.
|
1059 |
+
|
1060 |
+
Le modèle sélectionné pour l'entraînement est efficientnet_b0. Proposé par Google, il est le
|
1061 |
+
plus petit des modèles de la famille EfficientNet, ce qui le rend pertinent pour son utilisation
|
1062 |
+
sur du matériel avec des ressources limitées (smartphone, tablette).
|
1063 |
+
|
1064 |
+
En analysant les résultats de performance à chaque itération, on constate que :
|
1065 |
+
|
1066 |
+
1) La perte de validation suit une tendance à la baisse, passant de 0.3093 à 0.1281.
|
1067 |
+
Rejoignant la perte d'entraînement, ce qui suppose une bonne généralisation du
|
1068 |
+
modèle
|
1069 |
+
|
1070 |
+
2) La précision croît jusqu'à atteindre 95% sur 5 epoch seulement, avec un taux d’erreur
|
1071 |
+
|
1072 |
+
à 4%, ce qui implique une très bonne performance du modèle.
|
1073 |
+
|
1074 |
+
|
1075 |
+
|
1076 |
+
|
1077 |
+
|
1078 |
+
|
1079 |
+
3- Torch
|
1080 |
+
|
1081 |
+
Description des modèles
|
1082 |
+
|
1083 |
+
2 modèles ont été testés sous Torch :
|
1084 |
+
|
1085 |
+
● 1 modèle simple avec Transfer Learning, basé sur
|
1086 |
+
|
1087 |
+
le modèle pré-entraîné
|
1088 |
+
MobileNetV2, dont les couches intermédiaires sont neutralisées et seule la dernière
|
1089 |
+
couche est ajustée aux classes à prédire, puis ré-entrainée. Le choix s’est porté sur ce
|
1090 |
+
modèle car il est réputé être idéal pour des applications embarquées sur mobile,
|
1091 |
+
impliquant des contraintes de calcul (puissance limitée du matériel) ou nécessitant un
|
1092 |
+
fonctionnement en temps réel.
|
1093 |
+
|
1094 |
+
● 1 modèle simple sans Transfer Learning, comprenant une première couche de
|
1095 |
+
convolution analysant le couleurs RGB (3 canaux) avec 32 filtres détectant les motifs
|
1096 |
+
simples et les contours, un deuxième bloc convolutif avec 64 filtres permettant de
|
1097 |
+
capter des motifs plus complexes (formes des feuilles, textures), une couche dense
|
1098 |
+
interprétant les motifs détectés et enfin la dernière couche de sortie donnant les
|
1099 |
+
probabilités par classe de plantes. La représentation du modèle est portée en Annexes.
|
1100 |
+
|
1101 |
+
● Les 2 modèles ont été testés successivement sur 18 classes (espèces) et 58 classes
|
1102 |
+
|
1103 |
+
(croisements espèces x maladies)
|
1104 |
+
|
1105 |
+
Résultats
|
1106 |
+
|
1107 |
+
● S’agissant de la précision globale des modèles :
|
1108 |
+
|
1109 |
+
|
1110 |
+
|
1111 |
+
|
1112 |
+
|
1113 |
+
|
1114 |
+
|
1115 |
+
|
1116 |
+
|
1117 |
+
|
1118 |
+
|
1119 |
+
Modèle
|
1120 |
+
|
1121 |
+
Accuracy
|
1122 |
+
|
1123 |
+
18 classes
|
1124 |
+
|
1125 |
+
58 classes
|
1126 |
+
|
1127 |
+
transfer
|
1128 |
+
|
1129 |
+
sans
|
1130 |
+
transfer
|
1131 |
+
|
1132 |
+
transfer
|
1133 |
+
|
1134 |
+
sans
|
1135 |
+
transfer
|
1136 |
+
|
1137 |
+
99,38%
|
1138 |
+
|
1139 |
+
99,59%
|
1140 |
+
|
1141 |
+
94,79%
|
1142 |
+
|
1143 |
+
98,38%
|
1144 |
+
|
1145 |
+
3ème Accuracy la plus faible
|
1146 |
+
|
1147 |
+
98,15%
|
1148 |
+
|
1149 |
+
98,85%
|
1150 |
+
|
1151 |
+
40,44%
|
1152 |
+
|
1153 |
+
80,94%
|
1154 |
+
|
1155 |
+
Le modèle “simple” sans transfer learning apparaît plus précis avec des taux d’accuracy
|
1156 |
+
supérieur, a fortiori lorsque le nombre de classes augmentent.
|
1157 |
+
La reconnaissance des espèces est bonne et aucune d’entre elles ne montre une
|
1158 |
+
accuracy inférieure à 97%.
|
1159 |
+
|
1160 |
+
En revanche la reconnaissance des croisements espèces x maladies est plus
|
1161 |
+
problématique avec des précisions faibles sur les maladies touchant la vigne (avec des
|
1162 |
+
redondances de maladies ou des variantes de maladies qui semblent très proches qui
|
1163 |
+
seront traitées dans l’étape suivante) s’agissant du modèle sans transferlearning et de
|
1164 |
+
la cassava sur le modèle avec transferlearning.
|
1165 |
+
|
1166 |
+
● Les matrices de confusion pour les modèles à 18 classes sont présentées ci-dessous,
|
1167 |
+
|
1168 |
+
en commençant par celle du modèle MobileNetV2.
|
1169 |
+
|
1170 |
+
|
1171 |
+
|
1172 |
+
|
1173 |
+
|
1174 |
+
|
1175 |
+
|
1176 |
+
|
1177 |
+
● La convergence des modèles lors de l’apprentissage est plus rapide pour le modèle
|
1178 |
+
pré-entraîné mais ce dernier est dépassé dès la 4ème époque, la loss convergeant vers
|
1179 |
+
2,65% pour le modèle sans transfer learning 18 classes (resp. 6,27% avec 58 classes)
|
1180 |
+
et vers 6,55% pour le premier modèle 18 classes (resp. 24,75% avec 58 classes).
|
1181 |
+
|
1182 |
+
4- AlexNet
|
1183 |
+
|
1184 |
+
|
1185 |
+
|
1186 |
+
|
1187 |
+
|
1188 |
+
|
1189 |
+
AlexNet est intéressant pour la classification d'images car il a introduit une architecture de
|
1190 |
+
réseau de neurones convolutifs profonds, utilisant des couches convolutives et des unités de
|
1191 |
+
rectification linéaire (ReLU), qui a significativement amélioré la précision de la reconnaissance
|
1192 |
+
d'images sur des jeux de données complexes comme ImageNet.
|
1193 |
+
|
1194 |
+
Le modèle a été initialisé en suivant l’architecture suivante :
|
1195 |
+
|
1196 |
+
● Couches convolutives et pooling : L'architecture commence par deux couches
|
1197 |
+
convolutives suivies de couches de max-pooling pour extraire et réduire les
|
1198 |
+
caractéristiques spatiales des images. Les tailles des filtres et des strides varient pour
|
1199 |
+
capturer différents niveaux de détails.
|
1200 |
+
|
1201 |
+
● Couches convolutives supplémentaires : Trois couches convolutives supplémentaires
|
1202 |
+
sont ajoutées, suivies d'une couche de max-pooling, pour approfondir l'extraction des
|
1203 |
+
caractéristiques et capturer des motifs plus complexes dans les images.
|
1204 |
+
|
1205 |
+
● Couches entièrement connectées et régularisation : Après l'aplatissement des
|
1206 |
+
caractéristiques, deux couches entièrement connectées avec des unités de dropout
|
1207 |
+
sont utilisées pour la classification. La sortie finale est une couche dense avec une
|
1208 |
+
activation softmax pour la classification multi-classes.
|
1209 |
+
|
1210 |
+
La précision est de 80,40 % sur les données d'entraînement et de 85,40 % sur les données de
|
1211 |
+
test.
|
1212 |
+
|
1213 |
+
La perte (loss) semble globalement correcte car elle diminue au fil des époques, indiquant une
|
1214 |
+
amélioration du modèle, bien que des fluctuations soient observées sur les données
|
1215 |
+
d’entraînement.
|
1216 |
+
|
1217 |
+
L'analyse des métriques de classification indique que le modèle ne performe pas bien, avec
|
1218 |
+
des scores F1 très faibles pour toutes les classes, une précision globale de seulement 0,03, et
|
1219 |
+
des valeurs moyennes macro et pondérées également très basses, ce qui suggère une
|
1220 |
+
mauvaise capacité de généralisation et de classification des différentes catégories,
|
1221 |
+
probablement due à un déséquilibre des classes dans les données.
|
1222 |
+
|
1223 |
+
|
1224 |
+
|
1225 |
+
|
1226 |
+
|
1227 |
+
|
1228 |
+
|
1229 |
+
|
1230 |
+
Optimisation
|
1231 |
+
|
1232 |
+
Nos modèles ont été optimisés en suivant 2 phases.
|
1233 |
+
|
1234 |
+
Phase 1
|
1235 |
+
|
1236 |
+
La première phase a reposé sur :
|
1237 |
+
|
1238 |
+
● des corrections d’erreur : mesures de précision sur des images test et non les images
|
1239 |
+
|
1240 |
+
d’entraînement ;
|
1241 |
+
|
1242 |
+
● des “élagages” rapides de modèles jugés non pertinents ;
|
1243 |
+
●
|
1244 |
+
|
1245 |
+
l’utilisation de techniques de fine-tuning : choix des “optimizers”, gel/dégel de
|
1246 |
+
couches des modèles pour l’apprentissage, technique d’augmentation de data,
|
1247 |
+
ajustement des learning rates et introduction de scheduler, modification des fonctions
|
1248 |
+
de “loss”, techniques de callback, application de poids aux classes pour corriger les
|
1249 |
+
déséquilibres ;
|
1250 |
+
|
1251 |
+
● des ajustements techniques pour un apprentissage plus rapide : réorganisation du
|
1252 |
+
|
1253 |
+
code ;
|
1254 |
+
|
1255 |
+
● des choix réalisés pour le traitement de classes dont la prédiction est plus complexe
|
1256 |
+
: il s’agit principalement de la classe “Cassava” avec la suppression pure et simple de
|
1257 |
+
ces classes ou bien focus sur la précision augmentée des modèles au fur et à mesure
|
1258 |
+
du fine-tuning.
|
1259 |
+
|
1260 |
+
Abandon de modèles non pertinents
|
1261 |
+
|
1262 |
+
2 modèles testés ont été immédiatement abandonnés :
|
1263 |
+
|
1264 |
+
● Le modèle entraîné sous Pytorch sans transfer learning, en raison de son taux de
|
1265 |
+
précision sur les images tests de 83%, très inférieur aux modèles pré-entraînés testés
|
1266 |
+
dans le chapitre précédent.
|
1267 |
+
|
1268 |
+
● Le modèle AlexNet, qui affiche à la fois un temps d’entraînement trop important et un
|
1269 |
+
|
1270 |
+
taux de précision de 88%, également très en-deça des autres modèles testés.
|
1271 |
+
|
1272 |
+
Ajustements techniques pour rapidité d’apprentissage
|
1273 |
+
|
1274 |
+
Les modèles testés sous FastAI dans l’étape précédente (EfficientNetB0 et VGG12) ont été
|
1275 |
+
migrés vers TensorFlow pour les raisons suivantes :
|
1276 |
+
|
1277 |
+
● TensorFlow est plus simple à intégrer sur Firebase ;
|
1278 |
+
●
|
1279 |
+
●
|
1280 |
+
|
1281 |
+
Il est optimisé pour la performance et la taille des modèles ;
|
1282 |
+
Il intègre un large écosystème avec support pour la quantification (réduction de la
|
1283 |
+
taille des modèles) ;
|
1284 |
+
Il est compatible avec les modèles pré-entraînés comme les réseaux convolutifs (CNN)
|
1285 |
+
pour les images.
|
1286 |
+
|
1287 |
+
●
|
1288 |
+
|
1289 |
+
|
1290 |
+
|
1291 |
+
|
1292 |
+
|
1293 |
+
|
1294 |
+
|
1295 |
+
|
1296 |
+
|
1297 |
+
|
1298 |
+
|
1299 |
+
Choix réalisés pour le traitement de la Cassave
|
1300 |
+
|
1301 |
+
Le traitement de la Cassave dans les opération de “fine-tuning” du modèle ont pris deux
|
1302 |
+
formes:
|
1303 |
+
|
1304 |
+
● La suppression pure et simple de la cassave dans le cadre de l’apprentissage: c’est le
|
1305 |
+
|
1306 |
+
cas dans ce qui suit sur les entraînements de VGG12 et EfficientNetB0 sous
|
1307 |
+
TensorFlow ;
|
1308 |
+
|
1309 |
+
● Le maintien de cette espèce dans la base d’apprentissage mais, avec une recherche
|
1310 |
+
spécifique d’amélioration de la prédiction: c’est ce qui a été fait sur MobileNetV2
|
1311 |
+
sous Pytorch, et VGG16, Vit16, EfficientNetV2M et ResNet50V2 sous Keras.
|
1312 |
+
|
1313 |
+
Résultats du fine-tuning
|
1314 |
+
|
1315 |
+
MobileNetV2 sous Pytorch
|
1316 |
+
|
1317 |
+
Le modèle a été calibré et testé comme suit :
|
1318 |
+
|
1319 |
+
● # époques : 10
|
1320 |
+
|
1321 |
+
○ # époques sur le classifier : 5
|
1322 |
+
○ époques de fine tuning sur les autres couches : 5
|
1323 |
+
|
1324 |
+
● Learning rate : 0.001 pour le classifier et 0.0001 pour le fine tuning
|
1325 |
+
● Optimizer : Adam
|
1326 |
+
|
1327 |
+
L’accuracy globale est de 97,22% mais un F1-score de 65,21% seulement sur la Cassave
|
1328 |
+
Healthy
|
1329 |
+
|
1330 |
+
Le fine-tuning pour mieux prédire cette classe a consisté à:
|
1331 |
+
|
1332 |
+
● Augmentation sur les classes spécifiées : Random Horizontal Flip, Rotation aléatoire
|
1333 |
+
|
1334 |
+
jusqu’à 30%
|
1335 |
+
|
1336 |
+
● Augmentation du nombre d’époques à : 20
|
1337 |
+
● Entrainement de la dernière couche seulement
|
1338 |
+
● Learning rate : 0.0001
|
1339 |
+
● Optimizer : Adam
|
1340 |
+
|
1341 |
+
L’accuracy globale s’est avérée dégradée à 86,85% avec un F1-score de 18,80% sur la Cassave
|
1342 |
+
Healthy, ce qui a mené à l’abandon du modèle.
|
1343 |
+
|
1344 |
+
EfficientNetB0 et VGG12 sous TensorFlow
|
1345 |
+
|
1346 |
+
Le fine-tuning a consisté à:
|
1347 |
+
|
1348 |
+
● Organisation du code pour améliorer le temps d’apprentissage
|
1349 |
+
● Augmentation de la data sur le modèle
|
1350 |
+
● Ajouts des poids sur les classes pour lutter contre le déséquilibre
|
1351 |
+
● Gel/Dégel du modèle de base
|
1352 |
+
● Shuffle passé à False dans le dataset de test
|
1353 |
+
|
1354 |
+
|
1355 |
+
|
1356 |
+
|
1357 |
+
|
1358 |
+
|
1359 |
+
|
1360 |
+
|
1361 |
+
|
1362 |
+
|
1363 |
+
|
1364 |
+
Les métriques précision, recall et F1-score gagnent environ 1pt pour atteindre 95% et 98%
|
1365 |
+
pour respectivement EfficientNetB0 et VGG12. Ce dernier est donc plus performant, ce qui
|
1366 |
+
élimine le premier modèle.
|
1367 |
+
Bien que dans l’apprentissage de ces deux modèles, les classes “Cassava” aient été exclues,
|
1368 |
+
on note des classes de tomates moins bien prédites telles que celles atteintes des maladies
|
1369 |
+
“Mosaic Virus” et “Spider Mites” (Précision : 73%, Recall : 98%, F1-Score : 84%). On note
|
1370 |
+
d’ailleurs qu’à l’oeil nu la résolution de certaines images ne permet pas de détecter ces
|
1371 |
+
maladies.
|
1372 |
+
|
1373 |
+
Mosaic Virus
|
1374 |
+
|
1375 |
+
Spider Mites
|
1376 |
+
|
1377 |
+
VGG16 sous Keras
|
1378 |
+
|
1379 |
+
L’entraînement de ce modèle a donné globalement des résultats décevants.
|
1380 |
+
|
1381 |
+
Pour ce modèle, les mesures de fine-tuning ont consisté à:
|
1382 |
+
|
1383 |
+
● Réduction de la taille des images pour améliorer la vitesse d’entraînement (128x128)
|
1384 |
+
● Entraînement sur 10 époques avec freeze des paramètres
|
1385 |
+
● Puis entraînement sur 10 epoches avec unfreeze des 5 dernières couches et ajout de
|
1386 |
+
|
1387 |
+
poids pour gérer le déséquilibre des classes
|
1388 |
+
|
1389 |
+
● Learning rate (optimizer Adam) plus petit lors du dégel (0.00001 vs 0.0001 lors du
|
1390 |
+
|
1391 |
+
freeze) pour améliorer l’apprentissage
|
1392 |
+
|
1393 |
+
● Callbacks :
|
1394 |
+
|
1395 |
+
○ EarlyStopping pour arrêter l'entraînement si la perte de validation ne
|
1396 |
+
|
1397 |
+
s'améliore pas après 5 epochs
|
1398 |
+
|
1399 |
+
○ ReduceLROnPlateau pour réduire le taux d'apprentissage de 20% après 3
|
1400 |
+
|
1401 |
+
époques sans amélioration de la perte de validation
|
1402 |
+
|
1403 |
+
○ StopTrainingAtAccuracy pour arrêter l'entraînement dès que la précision
|
1404 |
+
|
1405 |
+
atteint 90%
|
1406 |
+
|
1407 |
+
On constate une baisse de l’Accuracy de 75,02% à 70,02% au terme du fine-tuning. La
|
1408 |
+
classification s’améliore sur l’ensemble des classes sauf sur la Tomate, la Cassave et la Canne
|
1409 |
+
à sucre. La faible Accuracy et la longueur de l’entraînement nous font conclure à l’abandon
|
1410 |
+
du modèle.
|
1411 |
+
|
1412 |
+
|
1413 |
+
|
1414 |
+
|
1415 |
+
|
1416 |
+
|
1417 |
+
|
1418 |
+
|
1419 |
+
|
1420 |
+
|
1421 |
+
|
1422 |
+
|
1423 |
+
ResNet50V2, EfficientNetV2M et Vit16 sous Keras
|
1424 |
+
|
1425 |
+
Pour ces 3 modèles, nous avons suivi le même plan d’entraînement suivant.
|
1426 |
+
|
1427 |
+
Phase
|
1428 |
+
d'Entraînement
|
1429 |
+
|
1430 |
+
Optimiseur
|
1431 |
+
|
1432 |
+
Scheduler de
|
1433 |
+
Learning Rate
|
1434 |
+
|
1435 |
+
Perte
|
1436 |
+
|
1437 |
+
Callbacks
|
1438 |
+
|
1439 |
+
Premier
|
1440 |
+
Entraînement
|
1441 |
+
|
1442 |
+
Adam
|
1443 |
+
|
1444 |
+
CosineDecayRestarts en
|
1445 |
+
Fine tuning
|
1446 |
+
|
1447 |
+
SparseFocalLoss
|
1448 |
+
(sans poids)
|
1449 |
+
|
1450 |
+
Deuxième
|
1451 |
+
Entraînement
|
1452 |
+
(Amélioration 1)
|
1453 |
+
|
1454 |
+
AdamW
|
1455 |
+
|
1456 |
+
CosineDecayRestarts
|
1457 |
+
|
1458 |
+
SparseFocalLoss
|
1459 |
+
(avec poids des
|
1460 |
+
classes)
|
1461 |
+
|
1462 |
+
earlystop,
|
1463 |
+
time_callback,
|
1464 |
+
printLR,
|
1465 |
+
model_checkpoint_
|
1466 |
+
callback
|
1467 |
+
|
1468 |
+
earlystop,
|
1469 |
+
time_callback,
|
1470 |
+
printLR,
|
1471 |
+
model_checkpoint_
|
1472 |
+
callback
|
1473 |
+
|
1474 |
+
Détails
|
1475 |
+
supplémentaires
|
1476 |
+
|
1477 |
+
20 epochs max en
|
1478 |
+
transfert learning, 5
|
1479 |
+
epochs max en
|
1480 |
+
finetuning avec
|
1481 |
+
toutes les couches
|
1482 |
+
dégélées
|
1483 |
+
20 epochs max de
|
1484 |
+
finetuning
|
1485 |
+
|
1486 |
+
|
1487 |
+
|
1488 |
+
|
1489 |
+
|
1490 |
+
|
1491 |
+
|
1492 |
+
Troisième
|
1493 |
+
Entraînement
|
1494 |
+
(Amélioration 2)
|
1495 |
+
|
1496 |
+
AdamW
|
1497 |
+
|
1498 |
+
CosineDecayRestarts
|
1499 |
+
|
1500 |
+
SparseFocalLoss
|
1501 |
+
(avec poids des
|
1502 |
+
classes)
|
1503 |
+
|
1504 |
+
earlystop,
|
1505 |
+
time_callback,
|
1506 |
+
printLR,
|
1507 |
+
model_checkpoint_
|
1508 |
+
callback
|
1509 |
+
|
1510 |
+
20 epochs max de
|
1511 |
+
finetuning
|
1512 |
+
Augmentation
|
1513 |
+
manuelle des images
|
1514 |
+
des classes
|
1515 |
+
minoritaires sur
|
1516 |
+
Cassava +
|
1517 |
+
augmentation ciblée
|
1518 |
+
sur ces classes
|
1519 |
+
|
1520 |
+
La troisième étape s’est avérée la plus significative en matière de gain de performance, avec
|
1521 |
+
un traitement spécifique apportée à la classe “Cassava” en augmentant manuellement les
|
1522 |
+
images des classes minoritaires et en appliquant une augmentation algorithmique ciblée.
|
1523 |
+
|
1524 |
+
Les résultats du fine-tuning par modèle sont résumés dans le tableau ci-dessous, les
|
1525 |
+
deux modèles EfficientNetV2M et ViT16 se distinguant sur les classes déséquilibrées
|
1526 |
+
comme la Cassave.
|
1527 |
+
|
1528 |
+
Modèle
|
1529 |
+
|
1530 |
+
Accuracy
|
1531 |
+
|
1532 |
+
Macro F1-
|
1533 |
+
score
|
1534 |
+
|
1535 |
+
Weighted
|
1536 |
+
F1
|
1537 |
+
|
1538 |
+
Observations clés
|
1539 |
+
|
1540 |
+
ResNet50V2
|
1541 |
+
|
1542 |
+
0.96
|
1543 |
+
|
1544 |
+
0.96
|
1545 |
+
|
1546 |
+
0.96
|
1547 |
+
|
1548 |
+
Bons résultats globaux, mais performance moyenne sur
|
1549 |
+
les classes Cassava
|
1550 |
+
|
1551 |
+
EfficientNetV2M
|
1552 |
+
|
1553 |
+
0.99
|
1554 |
+
|
1555 |
+
0.98
|
1556 |
+
|
1557 |
+
0.99
|
1558 |
+
|
1559 |
+
Meilleure performance globale, bonne gestion des
|
1560 |
+
classes déséquilibrées comme Cassava
|
1561 |
+
|
1562 |
+
ViT16
|
1563 |
+
|
1564 |
+
0.98
|
1565 |
+
|
1566 |
+
0.97
|
1567 |
+
|
1568 |
+
0.98
|
1569 |
+
|
1570 |
+
Meilleure performance globale, bonne gestion des
|
1571 |
+
classes déséquilibrées comme Cassava
|
1572 |
+
|
1573 |
+
Compte tenu du faible % de prédiction, la Cassave a fait l’objet d’un focus particulier.
|
1574 |
+
On constate que le finetuning réalisé a eu un effet spectaculaire sur la
|
1575 |
+
reconnaissance de ces classes (hausse du F1-score de 15pts environ chez
|
1576 |
+
EfficientNetV2M et ViT16) notamment sur la Cassave saine.
|
1577 |
+
|
1578 |
+
|
1579 |
+
|
1580 |
+
|
1581 |
+
|
1582 |
+
|
1583 |
+
|
1584 |
+
|
1585 |
+
S’agissant des autres classes, on relève les principaux enseignements suivants:
|
1586 |
+
|
1587 |
+
● Raisins, cerises, agrumes, pommes, pêches, etc. (classes équilibrées) : les trois
|
1588 |
+
|
1589 |
+
modèles ont des scores F1 proches de 1.00 sur toutes ces classes : aucune distinction
|
1590 |
+
significative.
|
1591 |
+
|
1592 |
+
● Sugarcane (classes mineures) : Bonne performance des trois modèles.
|
1593 |
+
|
1594 |
+
EfficientNetV2M excellent suivi de ViT16
|
1595 |
+
|
1596 |
+
● Tomato (13 sous-classes, très représenté mais varié) : Bonne performance des trois
|
1597 |
+
|
1598 |
+
modèles. EfficientNetV2M excellent suivi de ViT16
|
1599 |
+
|
1600 |
+
En conclusion, suivant les critères liant métriques de précision, de temps d’apprentissage et
|
1601 |
+
de taille du modèle, EfficientNetV2M semble devoir être privilégié.
|
1602 |
+
|
1603 |
+
Critère
|
1604 |
+
|
1605 |
+
Gagnant
|
1606 |
+
|
1607 |
+
Commentaire
|
1608 |
+
|
1609 |
+
Précision globale
|
1610 |
+
|
1611 |
+
EfficientNetV2M
|
1612 |
+
|
1613 |
+
Excellent suivi de Vit16
|
1614 |
+
|
1615 |
+
Robustesse sur classes rares
|
1616 |
+
|
1617 |
+
EfficientNetV2M
|
1618 |
+
|
1619 |
+
Meilleur équilibre F1
|
1620 |
+
|
1621 |
+
Performances Cassava
|
1622 |
+
|
1623 |
+
EfficientNetV2M
|
1624 |
+
|
1625 |
+
Résiste mieux au déséquilibre
|
1626 |
+
|
1627 |
+
Simplicité et rapidité
|
1628 |
+
entraînement
|
1629 |
+
|
1630 |
+
ResNet50V2
|
1631 |
+
|
1632 |
+
Moins lourd, mais moins performant
|
1633 |
+
|
1634 |
+
Durée d’inférence
|
1635 |
+
|
1636 |
+
ResNet50V2
|
1637 |
+
|
1638 |
+
4 fois plus rapide que EfficientNetV2M et 6 fois plus
|
1639 |
+
rapide que ViT16
|
1640 |
+
|
1641 |
+
Taille disque du modèle
|
1642 |
+
|
1643 |
+
ViT16
|
1644 |
+
|
1645 |
+
Le plus léger suivi de ResNet50V2 , EfficientNetV2M
|
1646 |
+
est deux fois plus lourd
|
1647 |
+
|
1648 |
+
|
1649 |
+
|
1650 |
+
|
1651 |
+
|
1652 |
+
|
1653 |
+
Vision Transformer pure
|
1654 |
+
|
1655 |
+
ViT16
|
1656 |
+
|
1657 |
+
Très Bon
|
1658 |
+
|
1659 |
+
Conclusion au terme de la Phase 1
|
1660 |
+
|
1661 |
+
Nous tirons de cette première phase deux enseignements:
|
1662 |
+
|
1663 |
+
● La qualité de la précision semble souffrir de la classe Cassave : quel que soit le modèle
|
1664 |
+
employé, et malgré les efforts de fine-tuning, il semble qu’une difficulté de
|
1665 |
+
reconnaissance subsiste pour cette classe. Cette difficulté est selon intrinsèquement
|
1666 |
+
lié à la qualité des images et aux problèmes apparents de labellisation. Nous nous
|
1667 |
+
interrogeons donc sur l’abandon de cette classe dans le modèle final.
|
1668 |
+
|
1669 |
+
● Les modèles affichent des tailles variables, certains sans doute incompatibles avec
|
1670 |
+
un usage mobile. En conséquence, nous décidons de retenir à ce stade deux modèles,
|
1671 |
+
l’un léger, embarqué sur mobile (VGG12), et l’autre plus puissant hébergé dans un
|
1672 |
+
cloud (EfficientNetV2M).
|
1673 |
+
|
1674 |
+
Phase 2
|
1675 |
+
|
1676 |
+
La deuxième phase a été consacrée à l’interprétation des modèles en utilisant des outils
|
1677 |
+
comme GradCam ou SHAP ainsi qu’à l’apprentissage, par lequel nous commençons cette
|
1678 |
+
phase, d’un modèle alternatif aux CNN et Transformer Standard : Swintransformer.
|
1679 |
+
|
1680 |
+
Swintransformer
|
1681 |
+
|
1682 |
+
Le modèle utilisé est un Swin Transformer pré-entraîné, adapté aux 55 classes du jeu de
|
1683 |
+
données incluant la Cassave:
|
1684 |
+
|
1685 |
+
● L’entraînement a été réalisé avec un mécanisme d’early stopping qui interrompt
|
1686 |
+
l’apprentissage si la performance sur le jeu de validation ne s’améliore plus pendant
|
1687 |
+
trois époques consécutives.
|
1688 |
+
|
1689 |
+
● L’optimiseur utilisé est AdamW, qui semble reconnu pour sa robustesse et son
|
1690 |
+
|
1691 |
+
efficacité pour ce modèle avec un learning rate de 0,0001.
|
1692 |
+
|
1693 |
+
● Des poids de classe sont calculés en fonction de la fréquence de chaque catégorie dans
|
1694 |
+
le jeu d’entraînement. Le poids de la classe « Cassava_mosaic_disease » est
|
1695 |
+
volontairement réduit afin de limiter son influence lors de l’apprentissage. Il y a en
|
1696 |
+
effet 5 fois plus d’images de Cassaves atteintes de cette maladie que dans les autres
|
1697 |
+
classes de Cassaves.
|
1698 |
+
|
1699 |
+
● À chaque époque, la fonction de coût utilisée est la CrossEntropyLoss pondérée par
|
1700 |
+
|
1701 |
+
ces poids de classe.
|
1702 |
+
|
1703 |
+
● Nous retenons le modèle ayant obtenu la meilleure performance sur le jeu de
|
1704 |
+
|
1705 |
+
validation (les images du jeu de test).
|
1706 |
+
|
1707 |
+
Dans les faits, nous avons eu besoin de 6 époques pour atteindre l’optimum avec un taux
|
1708 |
+
d’accuracy de 97,72%, un macro F1-score de 96,63% et un weighted F1-score de 97,73%.
|
1709 |
+
|
1710 |
+
|
1711 |
+
|
1712 |
+
|
1713 |
+
|
1714 |
+
|
1715 |
+
|
1716 |
+
|
1717 |
+
|
1718 |
+
|
1719 |
+
|
1720 |
+
La classe Cassave reste néanmoins encore très moyennement prédite, rejoignant ainsi la
|
1721 |
+
conclusion générale que les images qui servent à l’apprentissage pour ces classes sont sans
|
1722 |
+
doute à l’origine de ce problème de classification (qualité, labellisation) : à titre d’exemple la
|
1723 |
+
classe “Cassava_healthy” affiche un F1-score de 66%.
|
1724 |
+
|
1725 |
+
Interprétation comparée MobileNetV2 et Swintranformer
|
1726 |
+
|
1727 |
+
Afin d’interpréter les modèles, nous avons utilisé GradCam pour visualiser les régions de
|
1728 |
+
l’image ayant le plus influencé la prédiction du modèle sur la base du dernier bloc du modèle.
|
1729 |
+
|
1730 |
+
Pour une image de vigne atteinte de “Black Measles”
|
1731 |
+
|
1732 |
+
Pour une image de Cassave saine (environnement végétal)
|
1733 |
+
|
1734 |
+
Pour une deuxième image de Cassave (environnement terre)
|
1735 |
+
|
1736 |
+
Sur un modèle CNN classique comme MobileNetV2, on voit clairement apparaître la plante
|
1737 |
+
sur laquelle se concentre l’algorithme, quel que soit l’environnement pour la Cassave, ou
|
1738 |
+
même une tâche révélatrice de la maladie (Black Measles) pour la feuille de vigne.
|
1739 |
+
|
1740 |
+
|
1741 |
+
|
1742 |
+
|
1743 |
+
|
1744 |
+
|
1745 |
+
|
1746 |
+
|
1747 |
+
|
1748 |
+
|
1749 |
+
|
1750 |
+
|
1751 |
+
|
1752 |
+
|
1753 |
+
|
1754 |
+
|
1755 |
+
|
1756 |
+
|
1757 |
+
|
1758 |
+
|
1759 |
+
|
1760 |
+
|
1761 |
+
|
1762 |
+
|
1763 |
+
|
1764 |
+
|
1765 |
+
|
1766 |
+
|
1767 |
+
|
1768 |
+
|
1769 |
+
|
1770 |
+
|
1771 |
+
|
1772 |
+
|
1773 |
+
|
1774 |
+
En revanche pour SwinTransformer, GradCam affiche des zones de chaleurs sous formes de
|
1775 |
+
traits verticaux plus difficile à interpréter.
|
1776 |
+
|
1777 |
+
Interprétation EfficientNetV2M
|
1778 |
+
|
1779 |
+
Le modèle EfficientNetV2M nous avait donné une accuracy globale à 0.95 après le fine
|
1780 |
+
tuning.Cependant, les résultats de la classification des images de l’espèce cassava sont très
|
1781 |
+
mauvais :
|
1782 |
+
|
1783 |
+
Nous avons donc tâché de comprendre pourquoi le modèle classifie mal en regardant plus
|
1784 |
+
en détail les images de Cassave.
|
1785 |
+
|
1786 |
+
Nous avons choisi d’utiliser la méthode de saillance native à TensorFlow, car elle est
|
1787 |
+
pleinement compatible avec notre environnement et ne présente pas de problèmes
|
1788 |
+
d’incompatibilité, ce qui facilite son intégration.
|
1789 |
+
|
1790 |
+
1- Analyse d’un premier batch avec la carte de Saillance
|
1791 |
+
|
1792 |
+
● Les cartes sont bien générées :
|
1793 |
+
|
1794 |
+
Les zones d’attention (en rouge/orange) sont visibles sur les images et indiquent les
|
1795 |
+
régions jugées importantes par le modèle.
|
1796 |
+
|
1797 |
+
● Alignement avec les feuilles :
|
1798 |
+
|
1799 |
+
Les zones chaudes se trouvent souvent sur des parties pertinentes des feuilles
|
1800 |
+
(nervures, taches, contours), ce qui est encourageant.
|
1801 |
+
|
1802 |
+
|
1803 |
+
|
1804 |
+
|
1805 |
+
|
1806 |
+
|
1807 |
+
|
1808 |
+
|
1809 |
+
|
1810 |
+
|
1811 |
+
|
1812 |
+
|
1813 |
+
● Présence de bruit parasite :
|
1814 |
+
|
1815 |
+
Dans certaines images, des zones d’attention sont visibles en dehors des feuilles,
|
1816 |
+
notamment sur l’arrière-plan ou sur d’autres objets. Cela suggère que le modèle peut
|
1817 |
+
être distrait par des éléments non pertinents.
|
1818 |
+
|
1819 |
+
● Variabilité d’attention :
|
1820 |
+
|
1821 |
+
Le modèle ne focalise pas systématiquement sur les mêmes zones d’une image à
|
1822 |
+
l’autre, ce qui reflète à la fois une adaptation aux différences d’images et un possible
|
1823 |
+
manque de stabilité dans la reconnaissance.
|
1824 |
+
|
1825 |
+
● Zones de saillance parfois trop petites :
|
1826 |
+
|
1827 |
+
Les régions influentes sont parfois très restreintes, ce qui peut refléter une faible
|
1828 |
+
confiance du modèle ou une difficulté à localiser les bonnes zones.
|
1829 |
+
|
1830 |
+
● Présence de plusieurs feuilles :
|
1831 |
+
|
1832 |
+
Lorsqu’il y a plusieurs feuilles dans l’image, le modèle semble confus et a du mal à
|
1833 |
+
identifier la feuille centrale ou la plus pertinente pour la classification.
|
1834 |
+
|
1835 |
+
● Analyse ciblée des classes mal prédites :
|
1836 |
+
|
1837 |
+
Une attention particulière sera portée sur les classes de cassave pour lesquelles le
|
1838 |
+
modèle obtient les moins bons résultats. Cela permettra d’identifier les causes des
|
1839 |
+
erreurs et d’améliorer la robustesse du modèle.
|
1840 |
+
|
1841 |
+
2- Analyse d’un second batch sur les espèces de Cassave mal classifiées avec la carte de
|
1842 |
+
Saillance
|
1843 |
+
|
1844 |
+
|
1845 |
+
|
1846 |
+
|
1847 |
+
|
1848 |
+
|
1849 |
+
|
1850 |
+
|
1851 |
+
|
1852 |
+
|
1853 |
+
|
1854 |
+
Confirmation de l'analyse :
|
1855 |
+
L’observation globale sur les classes mal prédites confirme que le modèle ne distingue pas
|
1856 |
+
toujours correctement la feuille à analyser. Dans plusieurs cas, l’attention est
|
1857 |
+
partiellement portée sur l’arrière-plan ou sur d’autres feuilles, ce qui renforce l’idée d’une
|
1858 |
+
difficulté du modèle à isoler la feuille pertinente dans des scènes complexes.
|
1859 |
+
3- Limites de l'interprétation avec SHAP et GradCam
|
1860 |
+
|
1861 |
+
-
|
1862 |
+
|
1863 |
+
-
|
1864 |
+
|
1865 |
+
L’utilisation de SHAP DeepExplainer a été écartée pour cette architecture, car cette
|
1866 |
+
méthode n’est pas encore compatible avec toutes les couches de TensorFlow 2,
|
1867 |
+
notamment celles présentes dans EfficientNet, comme DepthwiseConv2d et BiasAdd
|
1868 |
+
L’application de Grad-CAM a rencontré des problèmes lors de l’appel du modèle avec
|
1869 |
+
TensorFlow, qui refuse de traiter correctement les entrées. Nous suspectons une
|
1870 |
+
incompatibilité avec TensorFlow 2.19 ou un problème lié à la construction du
|
1871 |
+
modèle, rendant son utilisation impossible dans cette configuration.
|
1872 |
+
|
1873 |
+
Ces difficultés techniques rencontrées avec SHAP et Grad-CAM sont aussi intrinsèquement
|
1874 |
+
liées à la complexité et à la profondeur de notre modèle EfficientNetV2M, qui comporte des
|
1875 |
+
couches spécifiques (DepthwiseConv2d, BiasAdd) rendant son interprétation plus difficile
|
1876 |
+
avec certains outils standards.
|
1877 |
+
|
1878 |
+
Interprétation VGG16
|
1879 |
+
|
1880 |
+
Pour comprendre les décisions de notre modèle VGG16, nous allons utiliser 3 outils
|
1881 |
+
d’interprétation :
|
1882 |
+
|
1883 |
+
-
|
1884 |
+
|
1885 |
+
-
|
1886 |
+
|
1887 |
+
-
|
1888 |
+
|
1889 |
+
Saliency, qui permet de mettre en évidence les pixels les plus importants d’une
|
1890 |
+
image pour une prédiction donnée.
|
1891 |
+
|
1892 |
+
SHAP (SHapley Additive exPlanations), pour visualiser les caractéristiques qui
|
1893 |
+
permettent la prédictions d’une classe sur une image.
|
1894 |
+
|
1895 |
+
LIME (Local Interpretable Model-agnostic Explanations), qui donne les
|
1896 |
+
caractéristiques d’une image qui vont le plus influencer la décision du model.
|
1897 |
+
|
1898 |
+
Image source
|
1899 |
+
|
1900 |
+
Saliency
|
1901 |
+
|
1902 |
+
LIME
|
1903 |
+
|
1904 |
+
SHAP
|
1905 |
+
|
1906 |
+
|
1907 |
+
|
1908 |
+
|
1909 |
+
|
1910 |
+
|
1911 |
+
|
1912 |
+
|
1913 |
+
|
1914 |
+
|
1915 |
+
D’après nos outils d’interprétation, on remarque que les saillances désignent bien les parties
|
1916 |
+
des images importantes pour chacune des classes. Elle reconnaît les contours des plantes et
|
1917 |
+
les différences de couleurs issues des maladies.
|
1918 |
+
|
1919 |
+
|
1920 |
+
|
1921 |
+
|
1922 |
+
|
1923 |
+
|
1924 |
+
|
1925 |
+
|
1926 |
+
|
1927 |
+
|
1928 |
+
|
1929 |
+
|
1930 |
+
|
1931 |
+
|
1932 |
+
|
1933 |
+
|
1934 |
+
|
1935 |
+
|
1936 |
+
|
1937 |
+
|
1938 |
+
|
1939 |
+
|
1940 |
+
Sur la classe “Corn_Healthy”, on peut avoir un doute sur l’angle gauche de l’image qui est
|
1941 |
+
coloré : Est-ce que ce qui est mis en valeur est le fond noir ou le contour de la plante ? Cette
|
1942 |
+
surbrillance n’étant pas mise en valeur sur le coin bas à gauche, je pense qu’il s’agit bien du
|
1943 |
+
contour de la plante, permettant sa reconnaissance.
|
1944 |
+
|
1945 |
+
La colonne SHAP contient la classe pour laquelle l’image contient le plus de caractéristiques.
|
1946 |
+
Il confirme que notre modèle est capable de capturer les motifs et les éléments visuels
|
1947 |
+
pertinents pour effectuer des prédictions précises, étant donné qu’il s’agit à chaque fois de
|
1948 |
+
la bonne classe d’image sauf pour la classe 49 (Mosaic Virus). En analysant les graphiques sur
|
1949 |
+
cette classe, on confirme que le modèle a du mal à tirer ses caractéristiques spécifiques avec
|
1950 |
+
la classe 46.
|
1951 |
+
|
1952 |
+
Stratégies de traitement des images Cassava
|
1953 |
+
|
1954 |
+
Au vu des performances modestes obtenues par nos modèles sur le sous-ensemble Cassava,
|
1955 |
+
nous avons décidé de mettre en œuvre plusieurs stratégies d'amélioration. Ces approches
|
1956 |
+
visent à renforcer la qualité des données et à améliorer la capacité des modèles à
|
1957 |
+
discriminer les classes Cassava, souvent déséquilibrées et visuellement similaires.
|
1958 |
+
|
1959 |
+
1. Augmentation massive des classes minoritaires
|
1960 |
+
|
1961 |
+
Une première approche a consisté à rééquilibrer le dataset Cassava par une augmentation
|
1962 |
+
ciblée.
|
1963 |
+
|
1964 |
+
|
1965 |
+
|
1966 |
+
|
1967 |
+
|
1968 |
+
|
1969 |
+
|
1970 |
+
|
1971 |
+
|
1972 |
+
Principe
|
1973 |
+
|
1974 |
+
• Les classes minoritaires (Healthy, Bacterial blight, Brown streak disease, Green mottle)
|
1975 |
+
ont été massivement augmentées.
|
1976 |
+
|
1977 |
+
• L’objectif était d’atteindre un volume comparable à la classe majoritaire (Cassava Mosaic
|
1978 |
+
Disease).
|
1979 |
+
|
1980 |
+
• Les techniques utilisées incluent : rotations, flips, changements de luminosité,
|
1981 |
+
contrastes, translations, etc.
|
1982 |
+
|
1983 |
+
Objectifs
|
1984 |
+
|
1985 |
+
• Apporter de la diversité visuelle aux classes sous-représentées.
|
1986 |
+
|
1987 |
+
• Réduire le biais induit par la classe majoritaire.
|
1988 |
+
|
1989 |
+
• Améliorer la généralisation du modèle sur les classes rares.
|
1990 |
+
|
1991 |
+
2. Filtrage basé sur un score multi-critères
|
1992 |
+
|
1993 |
+
Une seconde approche a consisté à filtrer les images Cassava jugées peu fiables à l’aide d’un
|
1994 |
+
score multi-critères.
|
1995 |
+
|
1996 |
+
Définition du score
|
1997 |
+
|
1998 |
+
Le score est défini comme une combinaison pondérée de trois composantes :
|
1999 |
+
|
2000 |
+
• Précision locale du soft voting : probabilité que le soft voting des modèles prédit
|
2001 |
+
correctement cette image sur le dataset d'entraînement.
|
2002 |
+
|
2003 |
+
• Confiance du soft voting : probabilité moyenne attribuée à la classe majoritaire par le
|
2004 |
+
soft voting.
|
2005 |
+
|
2006 |
+
• Accord inter-modèles : mesuré par la divergence de Kullback-Leibler (KL) entre les
|
2007 |
+
distributions de sortie des différents modèles (plus la divergence est faible, plus les modèles
|
2008 |
+
sont en accord).
|
2009 |
+
|
2010 |
+
Formule du score :
|
2011 |
+
|
2012 |
+
Score = 0.5 × Précision Soft Voting + 0.3 × Confiance Soft Voting + 0.2 × (1 - Divergence KL)
|
2013 |
+
|
2014 |
+
Seuil de filtrage
|
2015 |
+
Les images sont considérées comme peu fiables lorsque leur score se situe dans le premier
|
2016 |
+
décile (les 10 % les plus faibles). Ces images ont été exclues du dataset d’entraînement.
|
2017 |
+
|
2018 |
+
3. Relabellisation automatique basée sur le score
|
2019 |
+
|
2020 |
+
Enfin une troisième stratégie a consisté à ré-étiqueter automatiquement les images Cassava
|
2021 |
+
jugées peu fiables, plutôt que de les supprimer.
|
2022 |
+
|
2023 |
+
|
2024 |
+
|
2025 |
+
|
2026 |
+
Processus de re-labellisation
|
2027 |
+
• Les images du premier décile de score ont été re-labellisées automatiquement.
|
2028 |
+
• Le nouveau label correspond à la classe prédite par le soft voting, considérée comme
|
2029 |
+
plus fiable que le label d’origine.
|
2030 |
+
• Les autres images ont conservé leur annotation initiale.
|
2031 |
+
Objectifs
|
2032 |
+
• Corriger les labels potentiellement erronés.
|
2033 |
+
• Maintenir la taille du dataset en remplaçant les étiquettes douteuses.
|
2034 |
+
• Exploiter la confiance collective des modèles pour guider la correction.
|
2035 |
+
4. Fine-tuning des modèles sur les nouveaux datasets
|
2036 |
+
Les datasets générés (filtré, relabellisé, augmenté) ont été utilisés pour affiner les modèles
|
2037 |
+
préalablement entraînés EfficientNetV2M, ResNet50V2 et Swintransformer. Le modèle
|
2038 |
+
Convnext étant relativement plus long à entraîner, nous avons décidé de l’exclure de cette
|
2039 |
+
étude d’amélioration.
|
2040 |
+
|
2041 |
+
Méthodologie
|
2042 |
+
• Une augmentation online (flip horizontal, variation de contraste, saturation, etc.) a été
|
2043 |
+
appliquée durant le fine-tuning.
|
2044 |
+
• Le scheduler CosineDecayRestarts a permis d’ajuster dynamiquement le taux
|
2045 |
+
d’apprentissage.
|
2046 |
+
• L’optimiseur utilisé est AdamW avec un weight decay de 1e-5.
|
2047 |
+
• La fonction de perte choisie est une SparseFocalLoss (γ = 2.0), pondérée par des poids de
|
2048 |
+
classes.
|
2049 |
+
|
2050 |
+
Objectifs
|
2051 |
+
|
2052 |
+
• Exploiter les datasets nettoyés et enrichis.
|
2053 |
+
• Adapter les modèles à une distribution de données plus fiable.
|
2054 |
+
• Mesurer directement l’impact des stratégies sur les performances, notamment sur les
|
2055 |
+
classes Cassava.
|
2056 |
+
5. Résultats obtenus
|
2057 |
+
Les résultats suivants comparent les performances des modèles avant et après application
|
2058 |
+
des trois stratégies (filtrage, relabellisation, augmentation) sur l’ensemble des classes
|
2059 |
+
(global) et spécifiquement sur les classes Cassava.
|
2060 |
+
|
2061 |
+
Deux tableaux sont présentés :
|
2062 |
+
• Le premier montre l’évolution des performances globales.
|
2063 |
+
• Le second est centré sur les performances spécifiques aux classes Cassava.
|
2064 |
+
|
2065 |
+
Tableau 1 : Performances globales (Accuracy et F1-score)
|
2066 |
+
|
2067 |
+
|
2068 |
+
|
2069 |
+
|
2070 |
+
|
2071 |
+
|
2072 |
+
Tableau 2 : Performances sur le sous-ensemble Cassava
|
2073 |
+
|
2074 |
+
6. Analyse des résultats
|
2075 |
+
|
2076 |
+
|
2077 |
+
|
2078 |
+
|
2079 |
+
|
2080 |
+
Stratégie 1 : Augmentation
|
2081 |
+
|
2082 |
+
• Performances globales : légère dégradation sur l’ensemble des modèles.
|
2083 |
+
• Cassava : amélioration significative du F1-score pour SwinTransformer (+8.4%) et ResNet
|
2084 |
+
(+4.3%), malgré une légère baisse d’accuracy.
|
2085 |
+
|
2086 |
+
Conclusion
|
2087 |
+
|
2088 |
+
Une stratégie efficace pour renforcer la reconnaissance des classes minoritaires avec un
|
2089 |
+
compromis acceptable sur les performances globales.
|
2090 |
+
|
2091 |
+
Stratégie 2 : Filtrage
|
2092 |
+
|
2093 |
+
• Performances globales : scores stables sur SwinTransformer et EfficientNetV2M, mais
|
2094 |
+
déclin marqué sur ResNet.
|
2095 |
+
• Cassava : amélioration du F1-score sur SwinTransformer (+5.8%), mais chute sévère sur
|
2096 |
+
ResNet (-15%).
|
2097 |
+
|
2098 |
+
Conclusion
|
2099 |
+
Une stratégie à impact variable selon les modèles ; bénéfique pour Swin, mais sensible sur
|
2100 |
+
ResNet.
|
2101 |
+
|
2102 |
+
Stratégie 3 : Relabeling
|
2103 |
+
|
2104 |
+
• Performances globales : systématiquement inférieures au baseline.
|
2105 |
+
|
2106 |
+
• Cassava : baisse significative sur tous les modèles, notamment ResNet (-
|
2107 |
+
21.8%).
|
2108 |
+
|
2109 |
+
Conclusion
|
2110 |
+
|
2111 |
+
Une stratégie risquée sans vérification des relabels. Elle peut introduire davantage
|
2112 |
+
de bruit que de correction.
|
2113 |
+
|
2114 |
+
7. Conclusion de l’étude d’amélioration sur Cassava
|
2115 |
+
Les différentes stratégies mises en place visaient à améliorer la classification des images du
|
2116 |
+
dataset Cassava, en ciblant notamment les classes déséquilibrées ou mal étiquetées.
|
2117 |
+
Cependant, les résultats montrent que ces méthodes ont globalement entraîné une
|
2118 |
+
dégradation des performances générales, quel que soit le modèle utilisé. La perte en
|
2119 |
+
accuracy et en F1-score est visible, particulièrement sur EfficientNetV2M, qui perd jusqu’à
|
2120 |
+
2.3 % d’accuracy globale. Bien que certaines stratégies, comme l’augmentation massive,
|
2121 |
+
aient permis des gains localisés (notamment sur le F1-score des classes Cassava), ces
|
2122 |
+
améliorations ne compensent pas les pertes sur l’ensemble des classes. Nous décidons dans
|
2123 |
+
la suite de garder nos modèles baseline.
|
2124 |
+
|
2125 |
+
|
2126 |
+
|
2127 |
+
|
2128 |
+
|
2129 |
+
|
2130 |
+
|
2131 |
+
|
2132 |
+
|
2133 |
+
|
2134 |
+
Étude de l’ensemblage des modèles
|
2135 |
+
|
2136 |
+
Dans cette partie, nous étudions l’impact potentiel de l’ensemblage de modèles sur
|
2137 |
+
l’amélioration des performances de classification.
|
2138 |
+
Avant d’examiner les méthodes d’ensemblage, il est important de rappeler les performances
|
2139 |
+
des modèles pris individuellement dans leur configuration de base (sans stratégie
|
2140 |
+
d’amélioration) :
|
2141 |
+
|
2142 |
+
- EfficientNetV2M est le modèle ayant obtenu les meilleurs résultats globaux et sur
|
2143 |
+
|
2144 |
+
Cassava.
|
2145 |
+
|
2146 |
+
- Swin Transformer a montré de bonnes performances, notamment une meilleure
|
2147 |
+
|
2148 |
+
robustesse sur les classes minoritaires.
|
2149 |
+
|
2150 |
+
- ConvNext était le troisième meilleur modèle.
|
2151 |
+
- ResNet50V2, bien qu’un peu moins performant, a été retenu pour sa
|
2152 |
+
|
2153 |
+
complémentarité potentielle avec les autres modèles.
|
2154 |
+
|
2155 |
+
Ces performances individuelles servent de point de comparaison pour évaluer les gains
|
2156 |
+
apportés par l’ensemblage.
|
2157 |
+
|
2158 |
+
Complémentarité des modèles : corrélation des erreurs et divergence de Jensen-Shannon
|
2159 |
+
|
2160 |
+
L’ensemblage de modèles n’est pertinent que si les modèles présentent une certaine
|
2161 |
+
diversité d’erreurs. Pour cela, nous avons étudié :
|
2162 |
+
|
2163 |
+
-
|
2164 |
+
|
2165 |
+
-
|
2166 |
+
|
2167 |
+
-
|
2168 |
+
|
2169 |
+
La corrélation des erreurs de classification entre les modèles. Des erreurs faiblement
|
2170 |
+
corrélées indiquent une complémentarité exploitable.
|
2171 |
+
La divergence de Jensen-Shannon entre les distributions de probabilité prédites. Une
|
2172 |
+
divergence modérée à forte entre modèles indique une diversité de décisions,
|
2173 |
+
facteur clé pour améliorer les résultats via l’agrégation.
|
2174 |
+
La matrice de corrélation des erreurs ci-dessous illustre le degré de similarité dans les
|
2175 |
+
erreurs de prédiction commises par les différents modèles.
|
2176 |
+
|
2177 |
+
On observe que :
|
2178 |
+
|
2179 |
+
Les modèles ResNet50V2 et Swin Transformer ont une corrélation d’erreurs faible (0.31), ce
|
2180 |
+
qui indique une forte complémentarité.
|
2181 |
+
|
2182 |
+
|
2183 |
+
|
2184 |
+
|
2185 |
+
|
2186 |
+
|
2187 |
+
|
2188 |
+
|
2189 |
+
|
2190 |
+
|
2191 |
+
EfficientNetV2M et ConvNeXt présentent également une diversité modérée dans leurs
|
2192 |
+
erreurs vis-à-vis de ResNet50V2.
|
2193 |
+
|
2194 |
+
Le score le plus élevé entre deux modèles différents est celui entre Swin et ConvNeXt (0.51),
|
2195 |
+
ce qui reste suffisamment bas pour justifier un ensemblage.
|
2196 |
+
|
2197 |
+
Ces résultats confirment l’intérêt d’un ensemblage basé sur ces modèles, car la diversité des
|
2198 |
+
erreurs est un facteur favorable à l'amélioration globale des performances.
|
2199 |
+
|
2200 |
+
Pour compléter l’analyse, nous avons mesuré la divergence de Jensen-Shannon (JSD) entre
|
2201 |
+
les distributions de probabilités prédites par les différents modèles.
|
2202 |
+
|
2203 |
+
On constate que :
|
2204 |
+
Les modèles ResNet50V2 et Swin Transformer présentent la plus forte divergence (0.081),
|
2205 |
+
confirmant leur grande diversité de prédiction.
|
2206 |
+
EfficientNetV2M et Swin présentent également une divergence modérée (0.033), suggérant
|
2207 |
+
une complémentarité exploitable.
|
2208 |
+
À l’inverse, EfficientNetV2M et ConvNeXt sont plus proches (0.038), ce qui indique une
|
2209 |
+
certaine redondance dans leurs décisions.
|
2210 |
+
Ces résultats renforcent l’hypothèse selon laquelle un ensemblage de modèles hétérogènes
|
2211 |
+
(ResNet + Swin + EfficientNet) peut améliorer la robustesse des prédictions globales grâce à
|
2212 |
+
une diversité suffisante dans les sorties.
|
2213 |
+
|
2214 |
+
|
2215 |
+
|
2216 |
+
|
2217 |
+
|
2218 |
+
|
2219 |
+
Comparaison des performances des méthodes d’ensemblage
|
2220 |
+
|
2221 |
+
Nous avons exploré deux approches principales pour combiner les modèles :
|
2222 |
+
Soft Voting (vote pondéré par les probabilités) : chaque modèle contribue à la prédiction
|
2223 |
+
finale via sa distribution de probabilité. Nous avons initialement utilisé une pondération
|
2224 |
+
équivalente pour chaque modèle.
|
2225 |
+
Une étude systématique des coefficients de pondération n’a pas mis en évidence de
|
2226 |
+
combinaison significativement meilleure que l’équipondération.
|
2227 |
+
Cette méthode s’est avérée simple, stable, et a permis d’obtenir des résultats compétitifs.
|
2228 |
+
Stacking : cette approche consistait à utiliser un méta-modèle entraîné à partir des sorties
|
2229 |
+
des modèles de base.
|
2230 |
+
|
2231 |
+
Les performances obtenues avec le stacking n’ont pas surpassé celles du soft voting.En
|
2232 |
+
raison de la complexité de mise en œuvre et de l’absence de gain notable, nous avons
|
2233 |
+
décidé d’abandonner cette méthode au profit de l’agrégation simple.
|
2234 |
+
|
2235 |
+
Performances des ensembles
|
2236 |
+
|
2237 |
+
|
2238 |
+
|
2239 |
+
|
2240 |
+
|
2241 |
+
|
2242 |
+
Conclusion sur le choix des ensembles de modèles
|
2243 |
+
|
2244 |
+
Globalement, l’ensemble EfficientNetV2M + ResNet50V2 + SwinTransformer atteint les
|
2245 |
+
meilleures performances (accuracy = 0.9865, F1-score = 0.9856), surpassant tous les
|
2246 |
+
modèles individuels. Cela justifie pleinement l’intérêt du soft voting entre modèles
|
2247 |
+
complémentaires.
|
2248 |
+
|
2249 |
+
Pour les classes Cassava uniquement, l’ensemble EfficientNetV2M + ResNet50V2 se
|
2250 |
+
démarque légèrement, avec un F1-score de 0.8674. Il est suivi de très près par l’ensemble
|
2251 |
+
intégrant SwinTransformer (0.8658), puis par EfficientNetV2M seul (0.8655).
|
2252 |
+
Ces résultats montrent que :
|
2253 |
+
Ajouter SwinTransformer à l’ensemble améliore les performances globales sans dégrader la
|
2254 |
+
spécialisation sur Cassava.
|
2255 |
+
|
2256 |
+
EfficientNetV2M reste central dans tous les meilleurs ensembles : c’est le modèle le plus
|
2257 |
+
constant et performant, en global comme sur Cassava.
|
2258 |
+
ResNet50V2, bien que moins performant seul, apporte une complémentarité utile en
|
2259 |
+
ensemble, notamment sur les classes Cassava.
|
2260 |
+
Le stacking n’a pas permis d’amélioration notable par rapport au soft voting, tout en
|
2261 |
+
nécessitant une mise en œuvre plus complexe. Il a donc été écarté dans les configurations
|
2262 |
+
finales.
|
2263 |
+
|
2264 |
+
En tenant compte des contraintes pratiques de mise en œuvre de notre application
|
2265 |
+
(réduction des temps d'entraînement, coûts d'hébergement, vitesse d’inférence) nous
|
2266 |
+
avons décidé de sélectionner l’ensemble EfficientNetV2M + ResNet50V2.
|
2267 |
+
|
2268 |
+
Partie 5 : Conclusions tirées
|
2269 |
+
Difficultés rencontrées pendant le projet
|
2270 |
+
|
2271 |
+
Principal verrou scientifique rencontré
|
2272 |
+
Le principal verrou scientifique de ce projet s'est révélé être la qualité et la labellisation
|
2273 |
+
hétérogène des données d'images, particulièrement pour la classe Cassave, qui a
|
2274 |
+
systématiquement montré des performances de classification inférieures malgré les efforts
|
2275 |
+
de fine-tuning. Cette difficulté reflète un défi majeur en reconnaissance d'images agricoles :
|
2276 |
+
distinguer les symptômes subtils de maladies sur des images prises dans des conditions
|
2277 |
+
naturelles variables, avec des arrière-plans complexes et des variations d'éclairage.
|
2278 |
+
Difficultés détaillées par catégorie
|
2279 |
+
|
2280 |
+
Prévisionnel
|
2281 |
+
|
2282 |
+
• Temps de préprocessing sous-estimé : Le nettoyage et l'homogénéisation des
|
2283 |
+
|
2284 |
+
multiples datasets (fusion de bases redondantes, correction des déséquilibres entre
|
2285 |
+
classes) ont nécessité significativement plus de temps que prévu
|
2286 |
+
|
2287 |
+
• Complexité du fine-tuning : Les itérations successives d'optimisation des modèles,
|
2288 |
+
|
2289 |
+
particulièrement pour traiter les classes minoritaires comme la Cassave, ont multiplié
|
2290 |
+
les cycles de développement par 3
|
2291 |
+
|
2292 |
+
|
2293 |
+
|
2294 |
+
|
2295 |
+
|
2296 |
+
|
2297 |
+
|
2298 |
+
• Phase d'interprétation des modèles : L'utilisation d'outils comme GradCam et SHAP
|
2299 |
+
s'est révélée plus complexe techniquement qu'anticipé, avec des incompatibilités
|
2300 |
+
entre certaines architectures (EfficientNetV2M) et les outils d'explicabilité
|
2301 |
+
|
2302 |
+
Jeux de données
|
2303 |
+
|
2304 |
+
• Redondance non détectée initialement : Découverte tardive que 3 des 4 datasets
|
2305 |
+
|
2306 |
+
principaux provenaient de la même source originale, réduisant la diversité réelle des
|
2307 |
+
données
|
2308 |
+
|
2309 |
+
• Déséquilibre sévère : Surreprésentation massive des tomates (13 sous-classes)
|
2310 |
+
|
2311 |
+
créant un biais dans l'apprentissage
|
2312 |
+
|
2313 |
+
• Qualité hétérogène : Images de cassave systématiquement de qualité inférieure (flou
|
2314 |
+
|
2315 |
+
>500, contraste <2) nécessitant un pipeline de traitement spécifique
|
2316 |
+
|
2317 |
+
• Limitations de périmètre : Dataset limité à 19 espèces et 53 croisement espèces x
|
2318 |
+
|
2319 |
+
maladies alors que la flore mondiale compte 400 000 espèces, limitant l'applicabilité
|
2320 |
+
générale
|
2321 |
+
|
2322 |
+
Compétences techniques/théoriques
|
2323 |
+
|
2324 |
+
• Courbe d'apprentissage des architectures avancées : Maîtrise de modèles
|
2325 |
+
|
2326 |
+
•
|
2327 |
+
|
2328 |
+
complexes comme SwinTransformer et EfficientNetV2M plus longue qu'anticipé
|
2329 |
+
Interprétabilité des modèles : Compétences en explicabilité IA (SHAP, LIME,
|
2330 |
+
GradCam) acquises en cours de projet pour répondre aux exigences d'interprétation,
|
2331 |
+
parfois en avance de phase par rapport aux sprints du programme.
|
2332 |
+
|
2333 |
+
• Optimisation pour le déploiement mobile : Apprentissage des techniques de
|
2334 |
+
compression et quantification de modèles pour l'usage sur smartphone
|
2335 |
+
|
2336 |
+
Pertinence
|
2337 |
+
|
2338 |
+
● Choix architecturaux : Nécessité de réviser l'approche initiale face aux performances
|
2339 |
+
insuffisantes sur certaines classes, menant à l'exploration de modèles alternatifs
|
2340 |
+
(SwinTransformer) ou l’utilisation de certaines images pré-retraitement (Cassave)
|
2341 |
+
|
2342 |
+
● Métriques d'évaluation : Remise en question de l'accuracy comme métrique
|
2343 |
+
|
2344 |
+
principale face au déséquilibre des classes et utilisation du F1-score
|
2345 |
+
|
2346 |
+
● Stratégie de données : Questionnement sur l'inclusion/exclusion de la classe Cassave
|
2347 |
+
|
2348 |
+
dans le modèle final
|
2349 |
+
|
2350 |
+
IT
|
2351 |
+
|
2352 |
+
● Puissance computationnelle : Temps d'entraînement prohibitifs pour certains
|
2353 |
+
|
2354 |
+
modèles (EfficientNetV2M, VGG16) nécessitant l'optimisation du code et la réduction
|
2355 |
+
de la taille des images
|
2356 |
+
|
2357 |
+
● Mémoire : Contraintes mémoire lors de l'entraînement de modèles profonds avec
|
2358 |
+
|
2359 |
+
des images haute résolution
|
2360 |
+
|
2361 |
+
● Déploiement : Défis de compression des modèles pour un usage mobile tout en
|
2362 |
+
|
2363 |
+
préservant les performances
|
2364 |
+
|
2365 |
+
|
2366 |
+
|
2367 |
+
Autres
|
2368 |
+
|
2369 |
+
●
|
2370 |
+
|
2371 |
+
Incompatibilités techniques : Problèmes de compatibilité entre TensorFlow 2.19 et
|
2372 |
+
certains outils d'interprétation (SHAP DeepExplainer, GradCam)
|
2373 |
+
|
2374 |
+
● Migration entre frameworks : Passage de FastAI vers TensorFlow pour faciliter
|
2375 |
+
l'intégration Firebase, nécessitant la ré-implémentation de certains modèles
|
2376 |
+
|
2377 |
+
Bilan
|
2378 |
+
Contribution principale dans l'atteinte des objectifs
|
2379 |
+
Notre contribution principale réside dans le développement d'une pipeline complète de
|
2380 |
+
traitement et de classification d'images de plantes intégrant :
|
2381 |
+
|
2382 |
+
1. Système de tri et amélioration automatique de la qualité : Développement
|
2383 |
+
d'algorithmes de détection et correction du flou, luminosité et contraste
|
2384 |
+
|
2385 |
+
2. Architecture hybride optimisée : Comparaison systématique de 6 architectures
|
2386 |
+
|
2387 |
+
différentes avec fine-tuning spécialisé
|
2388 |
+
|
2389 |
+
3. Solution de déploiement adaptative : Proposition de deux modèles
|
2390 |
+
|
2391 |
+
complémentaires (VGG12 léger pour mobile, EfficientNetV2M puissant pour cloud)
|
2392 |
+
|
2393 |
+
Modifications depuis la dernière itération
|
2394 |
+
|
2395 |
+
Nous n’avons procédé à aucune modification. L’intégration du modèle SwinTransformer,
|
2396 |
+
atteignant 97,72% d'accuracy, a offert une alternative aux CNN traditionnels pour la
|
2397 |
+
reconnaissance de motifs complexes dans les images de plantes mais nous ne l’avons pas
|
2398 |
+
retenu compte tenu de la complexité d’interprétation avec l’outil testé (GradCam).
|
2399 |
+
|
2400 |
+
Nous avons en revanche maintenu le choix des deux modèles EfficientNetV2M et VGG12
|
2401 |
+
compte tenu de l’amélioration apportée par le fine-tuning de la classe Cassave grâce à la
|
2402 |
+
mise en place d'une augmentation de données ciblée et de pondération des classes
|
2403 |
+
permettant une amélioration de 15 points du F1-score.
|
2404 |
+
|
2405 |
+
Résultats obtenus et comparaison au benchmark
|
2406 |
+
Performances atteintes
|
2407 |
+
|
2408 |
+
● EfficientNetV2M : 95% d'accuracy globale après fine-tuning
|
2409 |
+
● SwinTransformer : 97,72% d'accuracy avec 96,63% de macro F1-score
|
2410 |
+
● VGG12 : 98% d'accuracy (après exclusion de la classe Cassave)
|
2411 |
+
|
2412 |
+
Comparaison aux benchmarks de la littérature
|
2413 |
+
Bien que le nombre de classes testées soit relativement modeste, nos résultats se
|
2414 |
+
positionnent favorablement par rapport aux références que nous avons pu collecter :
|
2415 |
+
|
2416 |
+
● PlantCLEF challenge : Evolution de 25% (2011) à 92% (2017) sur 10 000 espèces
|
2417 |
+
● Études récentes : 96-98% d'accuracy sur datasets Plant Village
|
2418 |
+
● Notre approche : 98% sur 19 espèces avec traitement de données hétérogènes et 53
|
2419 |
+
|
2420 |
+
classes en les croisant avec les maladies.
|
2421 |
+
|
2422 |
+
|
2423 |
+
|
2424 |
+
|
2425 |
+
|
2426 |
+
Atteinte des objectifs du projet
|
2427 |
+
|
2428 |
+
Objectif 1 : Classification des espèces (✅ Atteint)
|
2429 |
+
Accuracy de 98% pour la reconnaissance d'espèces avec VGG12 et SwinTransformer,
|
2430 |
+
dépassant l'objectif initial de 95%.
|
2431 |
+
|
2432 |
+
Objectif 2 : Détection des maladies (⚠ Partiellement atteint)
|
2433 |
+
95% d'accuracy globale mais performances hétérogènes selon les espèces :
|
2434 |
+
|
2435 |
+
● Excellentes : Tomates, raisins, agrumes (F1-score > 0.98)
|
2436 |
+
● Moyennes : Cassave (F1-score : 66% pour classe saine)
|
2437 |
+
● Limitation : Certaines maladies visuellement similaires (Mosaic Virus, Spider Mites)
|
2438 |
+
|
2439 |
+
Objectif 3 : Application Streamlit (✅ En cours)
|
2440 |
+
Développement d'une interface utilisateur fonctionnelle intégrant les modèles entraînés.
|
2441 |
+
|
2442 |
+
Processus métier d'inscription
|
2443 |
+
Notre modèle peut s'inscrire dans plusieurs processus métier :
|
2444 |
+
|
2445 |
+
Agriculture de précision
|
2446 |
+
|
2447 |
+
● Diagnostic précoce : Détection automatisée des maladies pour intervention rapide
|
2448 |
+
● Réduction des intrants : Ciblage précis des traitements phytosanitaires
|
2449 |
+
● Optimisation des rendements : Prévention des pertes de récolte estimées à 20-40%
|
2450 |
+
|
2451 |
+
selon la FAO
|
2452 |
+
|
2453 |
+
Services aux professionnels
|
2454 |
+
|
2455 |
+
● Conseil agricole : Outil d'aide au diagnostic pour conseillers et techniciens agricoles
|
2456 |
+
● Formation : Support pédagogique pour l'apprentissage de la reconnaissance des
|
2457 |
+
|
2458 |
+
maladies
|
2459 |
+
|
2460 |
+
● Certification : Contrôle qualité automatisé pour les filières agricoles
|
2461 |
+
|
2462 |
+
Applications grand public
|
2463 |
+
|
2464 |
+
● Jardinage amateur : Identification et conseil pour jardiniers particuliers
|
2465 |
+
● Éducation environnementale : Sensibilisation à la biodiversité végétale
|
2466 |
+
● Surveillance phytosanitaire participative : Collecte de données citoyennes pour le
|
2467 |
+
|
2468 |
+
monitoring des maladies émergentes
|
2469 |
+
|
2470 |
+
Suite du projet
|
2471 |
+
Pistes d'amélioration des performances
|
2472 |
+
|
2473 |
+
Amélioration des données
|
2474 |
+
|
2475 |
+
● Extension du dataset : Intégration de bases de données supplémentaires pour
|
2476 |
+
|
2477 |
+
couvrir plus d'espèces (objectif : passer de 19 à 100+ espèces)
|
2478 |
+
|
2479 |
+
|
2480 |
+
● Augmentation ciblée : Techniques d'augmentation spécialisées par type de maladie
|
2481 |
+
|
2482 |
+
(GANs, style transfer)
|
2483 |
+
|
2484 |
+
● Données multi-modales : Intégration d'informations contextuelles (géolocalisation,
|
2485 |
+
|
2486 |
+
saison, …)
|
2487 |
+
|
2488 |
+
Optimisations architecturales
|
2489 |
+
|
2490 |
+
● Modèles hybrides : Combinaison CNN-RNN avec réseaux Liquid Time-Constant pour
|
2491 |
+
|
2492 |
+
traitement temporel
|
2493 |
+
|
2494 |
+
● Attention mechanisms : Intégration de mécanismes d'attention pour focaliser sur les
|
2495 |
+
|
2496 |
+
zones pathologiques
|
2497 |
+
|
2498 |
+
● Architecture adaptative : Modèles capables d'ajuster leur complexité selon la
|
2499 |
+
|
2500 |
+
puissance de calcul disponible
|
2501 |
+
|
2502 |
+
Techniques avancées
|
2503 |
+
|
2504 |
+
● Apprentissage fédéré : Entraînement distribué préservant la confidentialité des
|
2505 |
+
|
2506 |
+
données agricoles
|
2507 |
+
|
2508 |
+
● Few-shot learning : Reconnaissance de nouvelles maladies avec peu d'exemples
|
2509 |
+
● Domain adaptation : Transfert de connaissances entre différentes conditions
|
2510 |
+
|
2511 |
+
climatiques et géographiques
|
2512 |
+
|
2513 |
+
Déploiement et optimisation
|
2514 |
+
|
2515 |
+
● Quantification avancée : Techniques de compression préservant mieux les
|
2516 |
+
|
2517 |
+
performances
|
2518 |
+
|
2519 |
+
● Edge computing : Optimisation pour calcul embarqué sur capteurs IoT agricoles
|
2520 |
+
● Traitement en temps réel : Pipeline optimisé pour diagnostic instantané
|
2521 |
+
|
2522 |
+
Contribution à l'accroissement de la connaissance scientifique
|
2523 |
+
|
2524 |
+
Avancées méthodologiques
|
2525 |
+
|
2526 |
+
● Pipeline de qualité d'images : Contribution à l'amélioration automatique d'images
|
2527 |
+
|
2528 |
+
agricoles en conditions naturelles
|
2529 |
+
|
2530 |
+
● Comparaison architecturale : Étude comparative systématique de 6 architectures sur
|
2531 |
+
|
2532 |
+
données agricoles hétérogènes
|
2533 |
+
|
2534 |
+
● Traitement des déséquilibres : Stratégies spécialisées pour classes minoritaires en
|
2535 |
+
|
2536 |
+
contexte agricole
|
2537 |
+
|
2538 |
+
Connaissances domaine-spécifiques
|
2539 |
+
|
2540 |
+
● Variables discriminantes : Identification du niveau de bleu comme prédicteur
|
2541 |
+
|
2542 |
+
principal du caractère sain/malade (statistique t=128)
|
2543 |
+
|
2544 |
+
● Seuils de qualité : Définition de critères quantitatifs pour la sélection d'images
|
2545 |
+
|
2546 |
+
agricoles (flou >500, contraste >2)
|
2547 |
+
|
2548 |
+
● Analyse des échecs : Documentation des limites des approches CNN sur certaines
|
2549 |
+
|
2550 |
+
pathologies visuellement similaires
|
2551 |
+
|
2552 |
+
|
2553 |
+
Impact scientifique et sociétal
|
2554 |
+
|
2555 |
+
● Démocratisation du diagnostic : Contribution à l'accessibilité de l'expertise
|
2556 |
+
|
2557 |
+
phytosanitaire
|
2558 |
+
|
2559 |
+
● Recherche participative : Cadre pour l'intégration de données citoyennes dans la
|
2560 |
+
|
2561 |
+
surveillance phytosanitaire
|
2562 |
+
|
2563 |
+
Durabilité agricole : Support à la réduction de l'usage de pesticides par un diagnostic précis
|
2564 |
+
|
2565 |
+
|
requirements.txt
ADDED
@@ -0,0 +1,5 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
streamlit
|
2 |
+
llama-cpp-python
|
3 |
+
faiss-cpu
|
4 |
+
sentence-transformers
|
5 |
+
PyMuPDF
|
step1_read_pdf.py
ADDED
@@ -0,0 +1,29 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import fitz
|
2 |
+
import sys
|
3 |
+
import os
|
4 |
+
|
5 |
+
def read_pdf(path):
|
6 |
+
if not os.path.exists(path):
|
7 |
+
print(f" Fichier non trouvé : {path}")
|
8 |
+
sys.exit(1)
|
9 |
+
|
10 |
+
doc = fitz.open(path)
|
11 |
+
all_text=""
|
12 |
+
|
13 |
+
for i,page in enumerate(doc):
|
14 |
+
text=page.get_text()
|
15 |
+
print(f"Page {i+1} - {len(text)} caractères")
|
16 |
+
print("-"*50)
|
17 |
+
print(text[:500]) # Affiche les 500 premiers caractères
|
18 |
+
print("\n")
|
19 |
+
all_text += text + "\n"
|
20 |
+
return all_text
|
21 |
+
|
22 |
+
if __name__ == "__main__":
|
23 |
+
if len(sys.argv) < 2:
|
24 |
+
print("❗ Utilisation : python step1_read_pdf.py chemin/vers/fichier.pdf")
|
25 |
+
sys.exit(1)
|
26 |
+
|
27 |
+
file_path = sys.argv[1]
|
28 |
+
text = read_pdf(file_path)
|
29 |
+
print(f"\n✅ Extraction terminée. {len(text)} caractères récupérés.")
|
step2_chunk.py
ADDED
@@ -0,0 +1,24 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import re
|
2 |
+
|
3 |
+
def chunk_text(text,chunk_size=300,overlap=50):
|
4 |
+
words =text.split()
|
5 |
+
chunks=[]
|
6 |
+
i=0
|
7 |
+
while i<len(words):
|
8 |
+
chunk=words[i:i+chunk_size]
|
9 |
+
chunks.append(" ".join(chunk))
|
10 |
+
i+=chunk_size-overlap
|
11 |
+
return chunks
|
12 |
+
|
13 |
+
if __name__ =="__main__":
|
14 |
+
from step1_read_pdf import read_pdf
|
15 |
+
|
16 |
+
text=read_pdf("data/DST_Rapport_final_Reco_plant.pdf")
|
17 |
+
|
18 |
+
print(f"\n Longueur totale du texte : {len(text)} caractères")
|
19 |
+
chunks =chunk_text(text,chunk_size=300,overlap=50)
|
20 |
+
print(f"Nombre de chunks {len(chunks)}")
|
21 |
+
|
22 |
+
for i, chunk in enumerate(chunks[:3]):
|
23 |
+
print(f"\n Chunk {i+1} ({len(chunks)})")
|
24 |
+
print(chunk[:500], "..." if len(chunk)>500 else "")
|
step3_docling.py
ADDED
@@ -0,0 +1,65 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import pickle
|
3 |
+
import faiss
|
4 |
+
import numpy as np
|
5 |
+
from pathlib import Path
|
6 |
+
from tqdm import tqdm
|
7 |
+
|
8 |
+
from docling.document_converter import DocumentConverter
|
9 |
+
from docling.chunking import HybridChunker
|
10 |
+
|
11 |
+
from llama_index.core.schema import TextNode
|
12 |
+
from llama_index.vector_stores.faiss import FaissVectorStore
|
13 |
+
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
|
14 |
+
from llama_index.core import VectorStoreIndex
|
15 |
+
|
16 |
+
# 📁 Paramètres
|
17 |
+
DOCS_DIR = "data"
|
18 |
+
VECTOR_DIR = "vectordb_docling"
|
19 |
+
INDEX_FILE = os.path.join(VECTOR_DIR, "index.faiss")
|
20 |
+
CHUNKS_FILE = os.path.join(VECTOR_DIR, "chunks.pkl")
|
21 |
+
EMBEDDING_MODEL = "intfloat/multilingual-e5-base"
|
22 |
+
|
23 |
+
os.makedirs(VECTOR_DIR, exist_ok=True)
|
24 |
+
|
25 |
+
# 📥 Conversion avec Docling
|
26 |
+
print("📥 Conversion des documents avec Docling...")
|
27 |
+
converter = DocumentConverter()
|
28 |
+
dl_docs = []
|
29 |
+
|
30 |
+
for pdf_path in Path(DOCS_DIR).glob("*.pdf"):
|
31 |
+
print(f" - 📄 {pdf_path.name}")
|
32 |
+
docling_doc = converter.convert(str(pdf_path)).document
|
33 |
+
dl_docs.append(docling_doc)
|
34 |
+
|
35 |
+
# ✂️ Chunking sémantique via HybridChunker
|
36 |
+
print("✂️ Chunking intelligent avec HybridChunker (Docling)...")
|
37 |
+
chunker = HybridChunker()
|
38 |
+
text_nodes = []
|
39 |
+
|
40 |
+
for dl_doc in dl_docs:
|
41 |
+
chunks = chunker.chunk(dl_doc=dl_doc)
|
42 |
+
for chunk in chunks:
|
43 |
+
text_nodes.append(TextNode(text=chunk.text))
|
44 |
+
|
45 |
+
print(f"✅ {len(text_nodes)} chunks générés.")
|
46 |
+
|
47 |
+
# 🔢 Embedding + FAISS index
|
48 |
+
print("🔢 Génération des embeddings et indexation FAISS...")
|
49 |
+
embed_model = HuggingFaceEmbedding(model_name=EMBEDDING_MODEL)
|
50 |
+
embedding_dim = np.array(embed_model.get_query_embedding("test")).shape[0]
|
51 |
+
faiss_index = faiss.IndexFlatL2(embedding_dim)
|
52 |
+
vector_store = FaissVectorStore(faiss_index=faiss_index)
|
53 |
+
|
54 |
+
# 🧠 Construction de l’index vectoriel
|
55 |
+
index = VectorStoreIndex(text_nodes, embed_model=embed_model, vector_store=vector_store)
|
56 |
+
|
57 |
+
# 💾 Sauvegarde
|
58 |
+
print("💾 Sauvegarde de l’index et des chunks...")
|
59 |
+
faiss.write_index(faiss_index, INDEX_FILE)
|
60 |
+
chunks = [node.get_content() for node in text_nodes]
|
61 |
+
|
62 |
+
with open(CHUNKS_FILE, "wb") as f:
|
63 |
+
pickle.dump(chunks, f)
|
64 |
+
|
65 |
+
print(f"✅ {len(chunks)} chunks sauvegardés dans {CHUNKS_FILE}")
|
step3_embed.py
ADDED
@@ -0,0 +1,23 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from sentence_transformers import SentenceTransformer
|
2 |
+
import numpy as np
|
3 |
+
|
4 |
+
EMBED_MODEL_NAME="sentence-transformers/all-MiniLM-L6-v2"
|
5 |
+
embedder=SentenceTransformer(EMBED_MODEL_NAME)
|
6 |
+
|
7 |
+
def embed_chunks(chunks):
|
8 |
+
embeddings=embedder.encode(chunks,convert_to_numpy=True,show_progress_bar=True)
|
9 |
+
return embeddings
|
10 |
+
|
11 |
+
if __name__=="__main__":
|
12 |
+
from step1_read_pdf import read_pdf
|
13 |
+
from step2_chunk import chunk_text
|
14 |
+
#Lecture du document
|
15 |
+
text=read_pdf("data/DST_Rapport_final_Reco_plant.pdf")
|
16 |
+
chunks =chunk_text(text,chunk_size=300,overlap=50)
|
17 |
+
|
18 |
+
#Embedding
|
19 |
+
embeddings=embed_chunks(chunks)
|
20 |
+
|
21 |
+
print(f"\n✅ Embeddings générés : {embeddings.shape[0]} vectors de {embeddings.shape[1]} dimensions")
|
22 |
+
print(f"Exemple (1er vecteur) :\n{embeddings[0][:5]}...")
|
23 |
+
|
step3_llamaindex.py
ADDED
@@ -0,0 +1,55 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import pickle
|
3 |
+
import faiss
|
4 |
+
import numpy as np
|
5 |
+
from llama_index.core import SimpleDirectoryReader, VectorStoreIndex
|
6 |
+
from llama_index.core.node_parser import SentenceSplitter
|
7 |
+
from llama_index.vector_stores.faiss import FaissVectorStore
|
8 |
+
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
|
9 |
+
|
10 |
+
# Paramètres
|
11 |
+
DOCS_DIR = "data"
|
12 |
+
VECTOR_DIR = "vectordb"
|
13 |
+
INDEX_FILE = os.path.join(VECTOR_DIR, "index.faiss")
|
14 |
+
CHUNKS_FILE = os.path.join(VECTOR_DIR, "chunks.pkl")
|
15 |
+
EMBEDDING_MODEL = "sentence-transformers/all-MiniLM-L6-v2"
|
16 |
+
|
17 |
+
os.makedirs(VECTOR_DIR, exist_ok=True)
|
18 |
+
|
19 |
+
# Étape 1 — Lecture
|
20 |
+
print("📥 Chargement des documents...")
|
21 |
+
documents = SimpleDirectoryReader(input_dir=DOCS_DIR).load_data()
|
22 |
+
|
23 |
+
# Étape 2 — Chunking avec overlap (512 tokens, 64 d'overlap)
|
24 |
+
print("✂️ Découpage structuré avec overlap...")
|
25 |
+
|
26 |
+
parser = SentenceSplitter(
|
27 |
+
chunk_size=512,
|
28 |
+
chunk_overlap=64,
|
29 |
+
break_on_newlines=True # 👈 Important ici
|
30 |
+
)
|
31 |
+
#parser = SentenceSplitter(chunk_size=512, chunk_overlap=64)
|
32 |
+
nodes = parser.get_nodes_from_documents(documents)
|
33 |
+
|
34 |
+
# Étape 3 — Embedding + FAISS
|
35 |
+
print("🔢 Génération des embeddings et indexation FAISS...")
|
36 |
+
embed_model = HuggingFaceEmbedding(model_name=EMBEDDING_MODEL)
|
37 |
+
|
38 |
+
# Créer un index brut FAISS
|
39 |
+
#dimension = embed_model.get_query_embedding("test").shape[0]
|
40 |
+
embedding_dim = np.array(embed_model.get_query_embedding("test")).shape[0]
|
41 |
+
faiss_index = faiss.IndexFlatL2(embedding_dim)
|
42 |
+
vector_store = FaissVectorStore(faiss_index=faiss_index)
|
43 |
+
|
44 |
+
# Création de l’index LlamaIndex avec FAISS
|
45 |
+
index = VectorStoreIndex(nodes, embed_model=embed_model, vector_store=vector_store)
|
46 |
+
|
47 |
+
# Étape 4 — Sauvegarde
|
48 |
+
print("💾 Sauvegarde de l’index et des chunks...")
|
49 |
+
#vector_store.save(INDEX_FILE)
|
50 |
+
faiss.write_index(faiss_index, INDEX_FILE)
|
51 |
+
chunks = [node.get_content() for node in nodes]
|
52 |
+
with open(CHUNKS_FILE, "wb") as f:
|
53 |
+
pickle.dump(chunks, f)
|
54 |
+
|
55 |
+
print(f"✅ {len(chunks)} chunks sauvegardés dans {CHUNKS_FILE}")
|
step3_llamaindex_evol.py
ADDED
@@ -0,0 +1,66 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import pickle
|
3 |
+
import faiss
|
4 |
+
import numpy as np
|
5 |
+
from pathlib import Path
|
6 |
+
from tqdm import tqdm
|
7 |
+
import textwrap
|
8 |
+
|
9 |
+
from llama_index.readers.file import PDFReader
|
10 |
+
from llama_index.core.node_parser import SentenceSplitter
|
11 |
+
from llama_index.vector_stores.faiss import FaissVectorStore
|
12 |
+
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
|
13 |
+
from llama_index.core import VectorStoreIndex
|
14 |
+
|
15 |
+
# 📁 Paramètres
|
16 |
+
DOCS_DIR = "data"
|
17 |
+
VECTOR_DIR = "vectordb"
|
18 |
+
INDEX_FILE = os.path.join(VECTOR_DIR, "index.faiss")
|
19 |
+
CHUNKS_FILE = os.path.join(VECTOR_DIR, "chunks.pkl")
|
20 |
+
EMBEDDING_MODEL = "dangvantuan/french-document-embedding"
|
21 |
+
|
22 |
+
os.makedirs(VECTOR_DIR, exist_ok=True)
|
23 |
+
|
24 |
+
# 📥 Chargement manuel des PDF
|
25 |
+
print("📥 Lecture des fichiers PDF...")
|
26 |
+
reader = PDFReader()
|
27 |
+
documents = []
|
28 |
+
|
29 |
+
for pdf_path in Path(DOCS_DIR).glob("*.pdf"):
|
30 |
+
print(f" - 📄 {pdf_path.name}")
|
31 |
+
docs = reader.load_data(pdf_path) # ✅ CORRECTION : path au lieu de file
|
32 |
+
documents.extend(docs)
|
33 |
+
|
34 |
+
print(f"✅ {len(documents)} documents PDF chargés.")
|
35 |
+
|
36 |
+
# ✂️ Chunking par taille de tokens (plus stable que par phrases)
|
37 |
+
print("✂️ Chunking avec SentenceSplitter (512 tokens, overlap 64)...")
|
38 |
+
parser = SentenceSplitter(chunk_size=512, chunk_overlap=64)
|
39 |
+
nodes = parser.get_nodes_from_documents(documents)
|
40 |
+
|
41 |
+
print(f"✅ {len(nodes)} chunks générés.")
|
42 |
+
|
43 |
+
# 🔍 Aperçu des 5 premiers chunks
|
44 |
+
print("\n🧩 Aperçu des 5 premiers chunks :\n")
|
45 |
+
for i, node in enumerate(nodes[:5]):
|
46 |
+
preview = textwrap.shorten(node.get_content().replace("\n", " "), width=200)
|
47 |
+
print(f"Chunk {i+1:>2}: {preview}")
|
48 |
+
|
49 |
+
# 🔢 Embedding + FAISS
|
50 |
+
print("\n🔢 Génération des embeddings et indexation FAISS...")
|
51 |
+
embed_model = HuggingFaceEmbedding(model_name=EMBEDDING_MODEL, trust_remote_code=True)
|
52 |
+
embedding_dim = np.array(embed_model.get_query_embedding("test")).shape[0]
|
53 |
+
faiss_index = faiss.IndexFlatL2(embedding_dim)
|
54 |
+
vector_store = FaissVectorStore(faiss_index=faiss_index)
|
55 |
+
|
56 |
+
# 🧠 Construction de l’index vectoriel
|
57 |
+
index = VectorStoreIndex(nodes, embed_model=embed_model, vector_store=vector_store)
|
58 |
+
|
59 |
+
# 💾 Sauvegarde
|
60 |
+
print("💾 Sauvegarde de l’index et des chunks...")
|
61 |
+
faiss.write_index(faiss_index, INDEX_FILE)
|
62 |
+
chunks = [node.get_content() for node in nodes]
|
63 |
+
with open(CHUNKS_FILE, "wb") as f:
|
64 |
+
pickle.dump(chunks, f)
|
65 |
+
|
66 |
+
print(f"\n✅ {len(chunks)} chunks sauvegardés dans {CHUNKS_FILE}")
|
step4_faiss.py
ADDED
@@ -0,0 +1,54 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import pickle
|
3 |
+
import faiss
|
4 |
+
import numpy as np
|
5 |
+
from step3_embed import embedder
|
6 |
+
|
7 |
+
# === Chemins par défaut ===
|
8 |
+
INDEX_PATH = "vectordb/index.faiss"
|
9 |
+
CHUNKS_PATH = "vectordb/chunks.pkl"
|
10 |
+
|
11 |
+
# === Création de l'index FAISS depuis des chunks de texte ===
|
12 |
+
def create_faiss_index(chunks, index_path=INDEX_PATH, chunks_path=CHUNKS_PATH):
|
13 |
+
print("🔍 Génération des embeddings...")
|
14 |
+
embeddings = embedder.encode(chunks, convert_to_numpy=True)
|
15 |
+
|
16 |
+
print("🧠 Création de l'index FAISS...")
|
17 |
+
dimension = embeddings.shape[1]
|
18 |
+
index = faiss.IndexFlatL2(dimension)
|
19 |
+
index.add(embeddings)
|
20 |
+
|
21 |
+
print("💾 Sauvegarde de l'index et des chunks...")
|
22 |
+
faiss.write_index(index, index_path)
|
23 |
+
with open(chunks_path, "wb") as f:
|
24 |
+
pickle.dump(chunks, f)
|
25 |
+
|
26 |
+
print("✅ Index créé avec succès.")
|
27 |
+
|
28 |
+
# === Chargement de l'index FAISS + chunks ===
|
29 |
+
def load_index(index_path=INDEX_PATH, chunks_path=CHUNKS_PATH):
|
30 |
+
if not os.path.exists(index_path) or not os.path.exists(chunks_path):
|
31 |
+
raise FileNotFoundError("Index ou chunks non trouvés. Veuillez d'abord exécuter la création.")
|
32 |
+
|
33 |
+
index = faiss.read_index(index_path)
|
34 |
+
with open(chunks_path, "rb") as f:
|
35 |
+
chunks = pickle.load(f)
|
36 |
+
return index, chunks
|
37 |
+
|
38 |
+
# === Recherche dans l'index ===
|
39 |
+
def search_index(index, query_embedding, top_k=3):
|
40 |
+
D, I = index.search(query_embedding, top_k)
|
41 |
+
return I[0], D[0]
|
42 |
+
|
43 |
+
|
44 |
+
if __name__ =="__main__":
|
45 |
+
from step1_read_pdf import read_pdf
|
46 |
+
from step2_chunk import chunk_text
|
47 |
+
from step3_embed import embed_chunks
|
48 |
+
#Lecture du document
|
49 |
+
text=read_pdf("data/DST_Rapport_final_Reco_plant.pdf")
|
50 |
+
chunks =chunk_text(text,chunk_size=300,overlap=50)
|
51 |
+
|
52 |
+
#Embedding
|
53 |
+
embeddings=embed_chunks(chunks)
|
54 |
+
create_faiss_index(chunks)
|
step4_llamaindex.py
ADDED
@@ -0,0 +1,212 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import signal
|
3 |
+
import sys
|
4 |
+
import pickle
|
5 |
+
import faiss
|
6 |
+
import numpy as np
|
7 |
+
import textwrap
|
8 |
+
|
9 |
+
from llama_cpp import Llama
|
10 |
+
from llama_index.core import VectorStoreIndex
|
11 |
+
from llama_index.core.schema import TextNode
|
12 |
+
from llama_index.vector_stores.faiss import FaissVectorStore
|
13 |
+
from llama_index.embeddings.huggingface import HuggingFaceEmbedding
|
14 |
+
from sentence_transformers.util import cos_sim
|
15 |
+
|
16 |
+
|
17 |
+
|
18 |
+
MAX_TOKENS=512
|
19 |
+
mode_type=[ "docling"]
|
20 |
+
#mode_type=["sentence", "docling"]
|
21 |
+
def reformulate_question(llm, question: str) -> str:
|
22 |
+
prompt = f"""Tu es un assistant expert chargé de clarifier des questions floues.
|
23 |
+
|
24 |
+
Transforme la question suivante en une question claire, explicite et complète, sans ajouter d'informations extérieures.
|
25 |
+
|
26 |
+
Question floue : {question}
|
27 |
+
Question reformulée :"""
|
28 |
+
|
29 |
+
output = llm(prompt, max_tokens=128, stop=["\n"], stream=False)
|
30 |
+
return output["choices"][0]["text"].strip()
|
31 |
+
|
32 |
+
|
33 |
+
def reformulate_with_context_v0(llm, question: str, context_sample: str) -> str:
|
34 |
+
prompt = f"""Tu es un assistant expert qui reformule les questions utilisateur en tenant compte du contexte d'un document.
|
35 |
+
|
36 |
+
Ton objectif est de transformer une question floue, vague ou incomplète en une question claire, explicite et pertinente par rapport au contexte ci-dessous.
|
37 |
+
|
38 |
+
Contexte :
|
39 |
+
{context_sample}
|
40 |
+
|
41 |
+
Question initiale : {question}
|
42 |
+
Question reformulée :"""
|
43 |
+
|
44 |
+
output = llm(prompt, max_tokens=128, stop=["\n"], stream=False)
|
45 |
+
return output["choices"][0]["text"].strip()
|
46 |
+
|
47 |
+
|
48 |
+
|
49 |
+
def reformulate_with_context(llm, question: str, context_sample: str) -> str:
|
50 |
+
prompt = f"""Tu es un assistant expert en machine learning. Ton rôle est de reformuler les questions utilisateur en tenant compte du contexte ci-dessous, extrait d’un rapport technique sur un projet de reconnaissance de maladies de plantes.
|
51 |
+
|
52 |
+
Ta mission est de transformer une question vague ou floue en une question précise et adaptée au contenu du rapport. Ne donne pas une interprétation hors sujet. Ne reformule pas en termes de produits commerciaux.
|
53 |
+
|
54 |
+
Contexte :
|
55 |
+
{context_sample}
|
56 |
+
|
57 |
+
Question initiale : {question}
|
58 |
+
Question reformulée :"""
|
59 |
+
|
60 |
+
output = llm(prompt, max_tokens=128, stop=["\n"], stream=False)
|
61 |
+
return output["choices"][0]["text"].strip()
|
62 |
+
|
63 |
+
|
64 |
+
|
65 |
+
# 🔁 top_k adaptatif
|
66 |
+
def get_adaptive_top_k(question: str) -> int:
|
67 |
+
q = question.lower()
|
68 |
+
if len(q.split()) <= 7:
|
69 |
+
return 8
|
70 |
+
elif any(w in q for w in ["liste", "résume", "quels sont", "explique", "comment"]):
|
71 |
+
return 10
|
72 |
+
else:
|
73 |
+
return 8
|
74 |
+
|
75 |
+
def rerank_nodes(question, retrieved_nodes, embed_model, top_k=3):
|
76 |
+
print(f"\n🔍 Re-ranking des {len(retrieved_nodes)} chunks pour la question : « {question} »\n")
|
77 |
+
q_emb = embed_model.get_query_embedding(question)
|
78 |
+
scored_nodes = []
|
79 |
+
|
80 |
+
for node in retrieved_nodes:
|
81 |
+
chunk_text = node.get_content()
|
82 |
+
chunk_emb = embed_model.get_text_embedding(chunk_text)
|
83 |
+
score = cos_sim(q_emb, chunk_emb).item()
|
84 |
+
scored_nodes.append((score, node))
|
85 |
+
|
86 |
+
ranked_nodes = sorted(scored_nodes, key=lambda x: x[0], reverse=True)
|
87 |
+
print(f"📊 Top {top_k} chunks les plus pertinents :\n")
|
88 |
+
for rank, (score, node) in enumerate(ranked_nodes[:top_k], start=1):
|
89 |
+
chunk_preview = textwrap.shorten(node.get_content().replace("\n", " "), width=150)
|
90 |
+
print(f"#{rank:>2} | Score: {score:.4f} | {chunk_preview}")
|
91 |
+
|
92 |
+
return [n for _, n in ranked_nodes[:top_k]]
|
93 |
+
|
94 |
+
|
95 |
+
def ask_llm(question: str, retriever, embed_model, top_k=3) -> str:
|
96 |
+
retrieved_nodes = retriever.retrieve(question)
|
97 |
+
top_nodes = rerank_nodes(question, retrieved_nodes, embed_model, top_k)
|
98 |
+
context = "\n\n".join(n.get_content()[:500] for n in top_nodes)
|
99 |
+
|
100 |
+
prompt = f"""### Instruction: En te basant uniquement sur le contexte ci-dessous, réponds à la question de manière précise et en français.
|
101 |
+
|
102 |
+
Si la réponse ne peut pas être déduite du contexte, indique : "Information non présente dans le contexte."
|
103 |
+
|
104 |
+
Contexte :
|
105 |
+
{context}
|
106 |
+
|
107 |
+
Question : {question}
|
108 |
+
### Réponse:"""
|
109 |
+
|
110 |
+
output = llm(prompt, max_tokens=MAX_TOKENS, stop=["### Instruction:"], stream=False)
|
111 |
+
return output["choices"][0]["text"].strip().split("###")[0]
|
112 |
+
|
113 |
+
|
114 |
+
|
115 |
+
def ask_llm_stream(question: str, retriever, embed_model, top_k=3) :
|
116 |
+
retrieved_nodes = retriever.retrieve(question)
|
117 |
+
top_nodes = rerank_nodes(question, retrieved_nodes, embed_model, top_k)
|
118 |
+
context = "\n\n".join(n.get_content()[:500] for n in top_nodes)
|
119 |
+
|
120 |
+
prompt = f"""### Instruction: En te basant uniquement sur le contexte ci-dessous, réponds à la question de manière précise et en français.
|
121 |
+
|
122 |
+
Si la réponse ne peut pas être déduite du contexte, indique : "Information non présente dans le contexte."
|
123 |
+
|
124 |
+
Contexte :
|
125 |
+
{context}
|
126 |
+
|
127 |
+
Question : {question}
|
128 |
+
### Réponse:"""
|
129 |
+
|
130 |
+
stream = llm(prompt, max_tokens=MAX_TOKENS, stop=["### Instruction:"], stream=True)
|
131 |
+
|
132 |
+
for chunk in stream:
|
133 |
+
print(chunk["choices"][0]["text"], end="", flush=True)
|
134 |
+
|
135 |
+
return
|
136 |
+
|
137 |
+
# 📦 Chargement global une seule fois
|
138 |
+
|
139 |
+
MODEL_PATH = "models/Nous-Hermes-2-Mistral-7B-DPO.Q4_K_M.gguf"
|
140 |
+
llm = Llama(model_path=MODEL_PATH, n_ctx=2048, n_threads=4)
|
141 |
+
|
142 |
+
embed_model = HuggingFaceEmbedding(model_name="sentence-transformers/all-MiniLM-L6-v2")
|
143 |
+
|
144 |
+
INDEXES = {}
|
145 |
+
|
146 |
+
for mode in mode_type:
|
147 |
+
vectordir = f"vectordb_{mode}" if mode != "sentence" else "vectordb"
|
148 |
+
index_file = os.path.join(vectordir, "index.faiss")
|
149 |
+
chunks_file = os.path.join(vectordir, "chunks.pkl")
|
150 |
+
|
151 |
+
print(f"📂 Chargement {mode} depuis {vectordir}...")
|
152 |
+
with open(chunks_file, "rb") as f:
|
153 |
+
chunk_texts = pickle.load(f)
|
154 |
+
nodes = [TextNode(text=chunk) for chunk in chunk_texts]
|
155 |
+
|
156 |
+
faiss_index = faiss.read_index(index_file)
|
157 |
+
vector_store = FaissVectorStore(faiss_index=faiss_index)
|
158 |
+
index = VectorStoreIndex(nodes=nodes, embed_model=embed_model, vector_store=vector_store)
|
159 |
+
|
160 |
+
INDEXES[mode] = {
|
161 |
+
"nodes": nodes,
|
162 |
+
"index": index,
|
163 |
+
}
|
164 |
+
|
165 |
+
|
166 |
+
# 🧠 Interface CLI
|
167 |
+
def exit_gracefully(sig, frame):
|
168 |
+
print("\n👋 Au revoir !")
|
169 |
+
sys.exit(0)
|
170 |
+
|
171 |
+
signal.signal(signal.SIGINT, exit_gracefully)
|
172 |
+
|
173 |
+
print("🧠 RAG CLI interactif avec LlamaIndex (CTRL+C pour quitter)")
|
174 |
+
|
175 |
+
while True:
|
176 |
+
question_raw = input("\n❓> ").strip()
|
177 |
+
if not question_raw:
|
178 |
+
continue
|
179 |
+
|
180 |
+
|
181 |
+
|
182 |
+
|
183 |
+
|
184 |
+
docling_mode = input("\n⚙️ Utiliser Docling ? (o/n) : ").strip().lower()
|
185 |
+
mode = "docling" if docling_mode in ["o", "oui", "y", "yes"] else "sentence"
|
186 |
+
|
187 |
+
print(f"\n📂 Mode sélectionné : {mode}")
|
188 |
+
|
189 |
+
index_obj = INDEXES[mode]["index"]
|
190 |
+
|
191 |
+
|
192 |
+
if len(question_raw.split()) <= 3:
|
193 |
+
retriever= index_obj.as_retriever(similarity_top_k=3)
|
194 |
+
retrieved_nodes = retriever.retrieve(question_raw)
|
195 |
+
context_sample = "\n\n".join(n.get_content()[:500] for n in retrieved_nodes[:3])
|
196 |
+
reformulated = reformulate_with_context(llm, question_raw, context_sample)
|
197 |
+
else:
|
198 |
+
reformulated = reformulate_question(llm, question_raw)
|
199 |
+
|
200 |
+
print(f"📝 Question reformulée : {reformulated}")
|
201 |
+
question = reformulated
|
202 |
+
|
203 |
+
top_k = get_adaptive_top_k(question)
|
204 |
+
print(f"🔍 top_k = {top_k} adapté à la question")
|
205 |
+
|
206 |
+
|
207 |
+
retriever = index_obj.as_retriever(similarity_top_k=top_k)
|
208 |
+
|
209 |
+
# response = ask_llm(question, retriever, embed_model, top_k=top_k)
|
210 |
+
# print(f"\n💬 Réponse : {response}")
|
211 |
+
|
212 |
+
ask_llm_stream(question, retriever, embed_model, top_k=top_k)
|
step4b_shell.py
ADDED
@@ -0,0 +1,48 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import os
|
2 |
+
import signal
|
3 |
+
import sys
|
4 |
+
|
5 |
+
from step4_faiss import load_index, search_index
|
6 |
+
from step3_embed import embedder
|
7 |
+
from llama_cpp import Llama
|
8 |
+
|
9 |
+
MODEL_PATH = "models/Nous-Hermes-2-Mistral-7B-DPO.Q4_K_M.gguf"
|
10 |
+
INDEX_PATH = "vectordb/index.faiss"
|
11 |
+
CHUNKS_PATH = "vectordb/chunks.pkl"
|
12 |
+
|
13 |
+
# Initialisation LLM
|
14 |
+
llm = Llama(model_path=MODEL_PATH, n_ctx=2048, n_threads=4)
|
15 |
+
|
16 |
+
# Chargement index et chunks
|
17 |
+
index, chunks = load_index(INDEX_PATH, CHUNKS_PATH)
|
18 |
+
|
19 |
+
if any("nicolas" in chunk.lower() for chunk in chunks):
|
20 |
+
print ("Nicolas est dans les chunks")
|
21 |
+
# Interruption propre
|
22 |
+
def exit_gracefully(sig, frame):
|
23 |
+
print("\n👋 Au revoir !")
|
24 |
+
sys.exit(0)
|
25 |
+
|
26 |
+
signal.signal(signal.SIGINT, exit_gracefully)
|
27 |
+
|
28 |
+
print("🧠 RAG CLI interactif (CTRL+C pour quitter)")
|
29 |
+
print("Pose ta question :")
|
30 |
+
while True:
|
31 |
+
question = input("\n❓> ").strip()
|
32 |
+
if not question:
|
33 |
+
continue
|
34 |
+
query_embedding = embedder.encode([question], convert_to_numpy=True)
|
35 |
+
indices, _ = search_index(index, query_embedding, top_k=3)
|
36 |
+
for i in indices:
|
37 |
+
print(f"\n--- Chunk {i} ---\n{chunks[i]}")
|
38 |
+
context = "\n\n".join([chunks[i] for i in indices])
|
39 |
+
MAX_CONTEXT_CHARS = 3000
|
40 |
+
truncated_context = context[:MAX_CONTEXT_CHARS]
|
41 |
+
prompt = f"""### Instruction: En te basant uniquement sur le contexte ci-dessous, réponds à la question de manière précise et en français.
|
42 |
+
Contexte :
|
43 |
+
{truncated_context}
|
44 |
+
Question : {question}
|
45 |
+
### Réponse:"""
|
46 |
+
# output = llm(prompt, max_tokens=128, stop=["### Instruction:"])
|
47 |
+
# response = output["choices"][0]["text"].strip().split("###")[0]
|
48 |
+
# print(f"\n💬 Réponse : {response}")
|
tester.py
ADDED
@@ -0,0 +1,12 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
from pathlib import Path
|
2 |
+
from pdfminer.high_level import extract_text
|
3 |
+
|
4 |
+
PDF_DIR = "data"
|
5 |
+
OUT_DIR = "converted_txt"
|
6 |
+
Path(OUT_DIR).mkdir(exist_ok=True)
|
7 |
+
|
8 |
+
for pdf_path in Path(PDF_DIR).glob("*.pdf"):
|
9 |
+
text = extract_text(str(pdf_path))
|
10 |
+
output_file = Path(OUT_DIR) / (pdf_path.stem + ".txt")
|
11 |
+
output_file.write_text(text, encoding="utf-8")
|
12 |
+
print(f"✅ {pdf_path.name} → {output_file.name}")
|