Technologie

Introduction à Green, le modèle de classification des Plantes Médicinales avec MobileNetV2 et Focal Loss

Armel Yara
Introduction à Green, le modèle de classification des Plantes Médicinales avec MobileNetV2 et Focal Loss

Introduction à Green, le modèle de classification des Plantes Médicinales avec MobileNetV2 et Focal Loss

Afin de sauvegarder la mémoire de l'utilisation des plantes dites médicinales de l’Afrique en général et de la Côte d’ivoire en particulier, nous avons pensé à développer une bibliothèque numérique accessible à tous, sans distinction de classe sociale ou d'origine et ce avec les outils dont nous disposons actuellement. 

La base fondamentale de cette bibliothèque est un modèle d’apprentissage profond qui permet la reconnaissance des plantes qui servent à l’usage médicinal traditionnel.  

Ainsi, nous vous présentons aujourd’hui Green, notre modèle de deep learning conçu pour identifier quatre plantes médicinales traditionnelles. Ce modèle alimente l'application mobile Saafe (Soigner Archiver Arbre Feuille) et démontre comment combiner le transfert par apprentissage, les fonctions de pertes personnalisées et techniques d'augmentation de données pour obtenir des performances robustes avec un dataset limité.

Notre principal défi est de classifier 4 espèces de plantes médicinales que sont l’Artemisia (Artemisia annua) qui a des propriétés antipaludiques, le Carica (Carica papaya) qui est utilisé pour la santé digestive, le Goyavier (Psidium guajava) contre la diarrhée et enfin le Kinkeliba (Combretum micranthum) pour lutter contre la fièvre, la fatigue et le paludisme dont les contraintes sont les suivantes: 

- Dataset limité : 1,164 images seulement

- Déséquilibre des classes : 20.7% à 30.6% par classe

- Déploiement mobile : modèle léger requis

- Contraintes temps réel : inférence rapide nécessaire

Architecture du Modèle

Choix de MobileNetV2

MobileNetV2 a été sélectionné pour plusieurs raisons techniques :

base_model = tf.keras.applications.MobileNetV2(

    include_top=False,

    weights='imagenet',

    input_tensor=inputs,

    pooling='avg'

)

base_model.trainable = False  # Transfer learning avec base gelée

Les avantages :

- Inverted Residuals : réduction de la complexité computationnelle

- Linear Bottlenecks : préservation des caractéristiques importantes

- Lightweight : 2.3M paramètres totaux, 82K entraînables

- Pré-entraîné ImageNet : knowledge transfer efficace

Architecture Complète

Input (224×224×3)

MobileNetV2 Base (frozen)

Global Average Pooling

Dropout(0.6) ← Forte régularisation

Dense(64, ReLU) + L2(0.02) ← Feature extraction

Batch Normalization ← Stabilisation

Dropout(0.3) ← Régularisation supplémentaire

Dense(4, Softmax) + L2(0.02) ← Classification finale

Paramètres clés :

- Total : 2,340,484 paramètres

- Entraînables : 82,372 (3.5%)

- Non-entraînables : 2,258,112

Focal Loss : La Clé de la Performance


Pourquoi Focal Loss ?

La Categorical Cross-Entropy standard traite tous les exemples de manière égale. Avec un dataset limité et déséquilibré, cela pose un problème :

Cross-Entropy standard

loss = -Σ y_true * log(y_pred)

Problèmes :

- Les exemples faciles dominent le gradient

- Les classes minoritaires sont sous-représentées

- Pas de focus sur les hard examples


Implémentation de Focal Loss

Vous trouverez le code complet sur Kaggle

L’impact de Gamma

𝛄

Comportement

Usage

0

Cross-Entropy standard

Baseline

1

Réduction modérée du poids des easy examples

Déséquilibre léger

2

Forte focalisation sur hard examples

Notre choix

5

Focalisation extrême

Risque d'instabilité


Un exemple concret :

# Easy example : p_t = 0.9

focal_weight = (1 - 0.9)^2 = 0.01  # Poids très réduit

# Hard example : p_t = 0.3

focal_weight = (1 - 0.3)^2 = 0.49  # Poids important

# Ratio : 0.49 / 0.01 = 49x plus d'attention sur les hard examples !


Pipeline de Données et Augmentation


Stratégie d'Augmentation Agressive

Avec seulement 931 images d'entraînement, l'augmentation est cruciale(Code complet sur Kaggle) :

Nous justifions nos choix par les paramètres suivants :

  • Rotations importantes (±108°) : les plantes peuvent être photographiées sous n'importe quel angle

  • Flips vertical + horizontal : pas d'orientation canonique pour les feuilles

  • Variations photométriques : conditions d'éclairage variables en milieu naturel

Pipeline Optimisé(Code complet sur Kaggle)

Nos optimisations clés sont les suivantes: 

  • num_parallel_calls=AUTOTUNE : TensorFlow optimise automatiquement le parallélisme

  • prefetch(AUTOTUNE) : prépare le batch suivant pendant l'entraînement du batch actuel

  • shuffle(1000) : buffer de 1000 images pour randomisation efficace


Stratified Split : Éviter le Class Collapse

Le Problème avec Random Split

# ❌ BAD : Split aléatoire

train_ds, val_ds = tf.keras.utils.image_dataset_from_directory(

    data_dir,

    validation_split=0.2,

    subset="both",

    seed=42

)

Le problème avec un petit dataset est que le split aléatoire peut créer des déséquilibres :

- Classe A : 90% en train, 10% en validation

- Classe B : 70% en train, 30% en validation

- Risque de validation set non représentatif


Alors notre solution est d’utiliser Stratified Split:

from sklearn.model_selection import train_test_split

train_paths, val_paths, train_labels, val_labels = train_test_split(

    all_image_paths,

    all_labels,

    test_size=0.2,

    random_state=42,

    stratify=all_labels  # ← La clé !

)

Résultat : distribution identique dans train et validation

Classe

Train %

Validation %

Différence

Artemisia

23.6%

23.6%

0.0%

Carica

30.6%

30.5%

0.1%

Goyavier

20.7%

20.6%

0.1%

Kinkeliba

25.0%

25.3%

0.3%

Impact : validation accuracy plus fiable et pas de class collapse !

Optimisation et Régularisation

Learning Rate Schedule : Cosine Decay

steps_per_epoch = len(train_labels) // batch_size

total_steps = steps_per_epoch * epochs

lr_schedule = tf.keras.optimizers.schedules.CosineDecay(

    initial_learning_rate=0.0005,  # LR initial

    decay_steps=total_steps,

    alpha=0.01  # LR final = 0.01 * initial = 0.000005

)

Les avantages du Cosine Decay sont la décroissance douce comparé à un step decay brutal, il évite les oscillations en fin d'entraînement et enfin un LR(Learning Rate) final non-nul pour fine-tuning.


Stack de Régularisation

1. Dropout (60% + 30%)

x = tf.keras.layers.Dropout(0.6)(x)  # Après GAP

# ...

x = tf.keras.layers.Dropout(0.3)(x)  # Après Dense


2. L2 Regularization

kernel_regularizer=tf.keras.regularizers.l2(0.02)


3. Batch Normalization

x = tf.keras.layers.BatchNormalization()(x)


4. Label Smoothing (15%)

# Dans Focal Loss

y_true = y_true * 0.85 + 0.15/4  # Soft labels


5. Class Weights

# Pondération dynamique inversement proportionnelle à la fréquence

class_weights = {

    0: 1.076,  # Artemisia (sous-représenté)

    1: 0.769,  # Carica (surreprésenté)

    2: 1.276,  # Goyavier (le plus sous-représenté)

    3: 0.999   # Kinkeliba (équilibré)

}


Early Stopping Intelligent

callbacks = [

    tf.keras.callbacks.EarlyStopping(

        monitor='val_accuracy',

        patience=15,  # Attend 15 epochs sans amélioration

        restore_best_weights=True,  # Restaure les meilleurs poids

        mode='max'

    ),

    tf.keras.callbacks.ModelCheckpoint(

        filepath='models/best_model_v7.keras',

        monitor='val_accuracy',

        save_best_only=True,

        mode='max'

    )

]


Métriques et Évaluation

Métriques Multi-dimensionnelles

model.compile(

    optimizer=tf.keras.optimizers.Adam(learning_rate=lr_schedule),

    loss=FocalLoss(gamma=2.0, alpha=0.25, label_smoothing=0.15),

    metrics=[

        tf.keras.metrics.CategoricalAccuracy(name='accuracy'),

        tf.keras.metrics.TopKCategoricalAccuracy(k=2, name='top2_accuracy')

    ]

)

Top-2 Accuracy : crucial pour une app mobile

  • Accuracy : 69.10%

  • Top-2 Accuracy : 88.41%  ← L'app peut proposer 2 suggestions


Analyse de la Matrice de Confusion

cm = confusion_matrix(y_true, y_pred)

# Analyse per-class

for i, class_name in enumerate(class_names):

    class_mask = y_true == i

    class_acc = (y_pred[class_mask] == i).mean()

    print(f"{class_name}: {class_acc*100:.2f}%")

les résultats obtenus sont Artemisia: 67.27%, Carica: 73.24%, Goyavier: 60.42% et enfin Kinkeliba: 71.19%


Leçons Apprises

1. Dataset Quality > Quantity

Avec seulement 1,164 images :

- Stratified split crucial

- Augmentation agressive nécessaire

- Transfer learning indispensable


2. Loss Function Matters

Focal Loss vs Cross-Entropy :

- +12% accuracy sur classes minoritaires

- Convergence plus stable

- Pas de class collapse

3. Régularisation Multi-niveaux

Stack de régularisation :

Dropout (0.6 + 0.3)

+ L2 (0.02)

+ Batch Normalization

+ Label Smoothing (0.15)

+ Early Stopping (patience=15)

= Modèle robuste sans overfitting

4. Validation Set Design

Le split stratifié a éliminé :

- Validation accuracy instable

- Class collapse sur certaines runs

- Métriques non représentatives

5. Mobile-First Architecture

MobileNetV2 offre le meilleur trade-off :

- Légèreté : 2.3 MB en FP16

- Performance : 69% accuracy, 88% top-2

- Vitesse : 40ms sur smartphone


Le modèle Green démontre qu'avec une architecture bien pensée et des techniques modernes (Focal Loss, stratified split, régularisation multi-niveaux), il est possible d'obtenir des performances robustes même avec un dataset limité.

Le projet présente un modèle performant avec une précision de 69,10 % et 88,41 % en top-2. Il est optimisé pour le déploiement mobile (taille de 2,3 Mo, inférence en 40 ms). Des techniques comme le split stratifié ont été utilisées pour éviter l'effondrement des classes, et la Focal Loss a été employée pour gérer le déséquilibre des données.

Le code complet est disponible sur GitHub


Références

Sandler et al., "MobileNetV2: Inverted Residuals and Linear Bottlenecks", CVPR 2018

Lin et al., "Focal Loss for Dense Object Detection", ICCV 2017

Shorten & Khoshgoftaar, "A survey on Image Data Augmentation for Deep Learning", Journal of Big Data 2019

Yosinski et al., "How transferable are features in deep neural networks?", NeurIPS 2014


Pour toute question technique, ouvrez un issue sur le dépôt GitHub

Résumé par IA

Trop long ? Obtenez un résumé rapide de cet article généré par l'IA.

Vous Pourriez Aussi Aimer
Recherche de suggestions...
Statistiques de l'article
Engagement des lecteurs avec cet article.

176

Vues

0

Commentaires

📧 Restez informé

Recevez une notification par email à chaque nouvel article ou modification

Commentaires (0)

Aucun commentaire pour le moment. Soyez le premier à commenter !

Laisser un commentaire