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 DrGreen 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



Auteur: Équipe DrGreen

Licence : Apache 2.0

Date : Décembre 2025


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...
Cet article vous a-t-il été utile ?
Faites-nous savoir ce que vous en pensez.

📧 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

Vous commentez en tant que :