Prévention de la cécité oculaire en prédisant les stades de la rétinopathie diabétique
Preventing ocular blindness by predicting stages of diabetic retinopathy.
Introduction
La rétinopathie diabétique est une affection oculaire qui provoque des modifications des vaisseaux sanguins de la rétine. Lorsqu’elle n’est pas traitée, elle entraîne une perte de vision. Il est donc crucial de détecter les stades de la rétinopathie diabétique pour prévenir la cécité. Cette étude de cas porte sur la détection de la cécité oculaire à partir des symptômes de la sévérité de la rétinopathie diabétique afin d’empêcher la personne de devenir aveugle. Les données ont été collectées dans des zones rurales par différents experts cliniques formés à l’utilisation de caméras rétiniennes (caméras qui photographient l’arrière de l’œil). Ces photos ont été prises dans différentes conditions d’imagerie. En 2019, Kaggle a organisé une compétition (APTOS 2019 Blindness Detection) pour détecter les stades de la rétinopathie diabétique ; nos données proviennent de la même compétition Kaggle. La détection précoce de cette rétinopathie diabétique peut accélérer le traitement et réduire considérablement le risque de perte de vision.
L’intervention manuelle d’experts cliniques formés nécessite du temps et des efforts, surtout dans les pays en développement. Par conséquent, l’objectif principal de cette étude de cas est d’utiliser une technologie efficace pour détecter la sévérité de la maladie et prévenir la cécité. Nous mettons en œuvre des techniques d’apprentissage profond pour obtenir des résultats efficaces dans la classification de la sévérité de la maladie.
Objectifs d’apprentissage
- Comprendre la rétinopathie diabétique : Apprenez à connaître l’affection oculaire et son impact sur la vision, en mettant l’accent sur l’importance d’une détection précoce.
- Fondements de l’apprentissage profond : Explorez les bases de l’apprentissage profond et sa pertinence dans le diagnostic de la rétinopathie diabétique.
- Prétraitement et augmentation des données : Comprenez comment préparer et améliorer efficacement l’ensemble de données pour l’entraînement des modèles d’apprentissage profond.
- Sélection et évaluation du modèle : Apprenez à choisir et à évaluer les performances des modèles d’apprentissage profond pour la classification de la sévérité.
- Déploiement pratique : Découvrez le déploiement du meilleur modèle à l’aide de Flask pour des prédictions réelles.
Cet article a été publié dans le cadre du Data Science Blogathon.
- Un guide complet de l’architecture UNET | Maîtrise de la segmentation d’images
- Une approche systématique pour choisir la meilleure technologie/fournisseur version MLOps
- 4 façons dont vous ne pouvez pas utiliser l’interpréteur de code ChatGPT qui perturberont vos analyses
Problème commercial
Ici, la sévérité de la maladie d’une personne est classée en cinq catégories, c’est-à-dire une classification multi-classes car la personne ne peut être reconnue que par l’un des niveaux de gravité.
Contraintes commerciales
La précision et l’interprétabilité sont essentielles dans le domaine médical. En effet, des prédictions erronées peuvent conduire à l’ignorance, ce qui peut coûter la vie à une personne. Nous n’avons pas de contraintes strictes en termes de latence, mais nous devons obtenir des résultats précis.
Description de l’ensemble de données
L’ensemble de données comprend 3 662 images de rétine étiquetées de patients cliniques, pour lesquelles des experts cliniciens formés catégorisent chaque image en termes de sévérité de la rétinopathie diabétique, comme suit :
0 – Aucune rétinopathie diabétique,
1 – Légère
2 – Modérée
3 – Sévère
4 – Rétinopathie diabétique proliférante.
Le tableau ci-dessus indique que nos images d’ensemble de données sont identifiées par l’un des stades de la rétinopathie diabétique.
Métrique de performance
Nous utilisons le Quadratic weighted Kappa et la matrice de confusion comme métriques d’évaluation pour notre classification multi-classes.
Le Kappa mesure l’accord (similarité) entre les étiquettes réelles et prédites. Un score de Kappa de 1,0 indique que les prédictions et les étiquettes réelles sont identiques, un score de Kappa de -1 indique que les prédictions sont très différentes des étiquettes réelles. Notre objectif pour cette métrique est d’obtenir un score de Kappa supérieur à 0,6.
La métrique Kappa joue un rôle crucial dans le diagnostic médical, car dans le cas d’un score de -1, elle indique à quel point les deux évaluateurs (évaluateurs prédits et réels) sont similaires et impose une pénalité en cas de désaccord. Par exemple, dans notre cas, si notre étiquette prédite est 0 et l’étiquette réelle est 1, cela pose un problème grave pour le patient car ce cas sera ignoré car aucun diagnostic supplémentaire n’est recommandé pour le patient.
Comme nous le savons, la matrice de confusion est utilisée pour évaluer les performances d’un modèle de classification. La matrice compare les valeurs cibles réelles à celles prédites par notre modèle. Cela nous donne une vue d’ensemble de la performance de notre modèle de classification et des types d’erreurs qu’il commet.
Analyse exploratoire des données et prétraitement
Vérifions la distribution de nos données en traçant un graphique à barres.
v=df['diagnosis'].value_counts().plot(kind='bar')
À partir du graphique ci-dessus, nous pouvons déduire que nos données sont clairement déséquilibrées. Nous devons nous assurer d’équilibrer nos données pour éviter d’obtenir des résultats inexacts.
Nous pouvons appliquer des poids de classe pour maintenir l’uniformité dans l’ensemble de données afin d’obtenir une distribution uniforme dans les données.
Notre ensemble de données d’entraînement ne contient que 3 662 images, donc l’ensemble de données fourni par Kaggle est très petit. Il est souhaitable de surajuster en raison de l’entraînement sur le petit ensemble de données, donc ici le prétraitement joue un rôle crucial dans de meilleures performances en augmentant nos ensembles de données. Nous nous tournons donc vers l’augmentation des données pour améliorer nos ensembles de données. Avant l’augmentation des données, nous devons vérifier les conditions de l’image, comme si les images sont très sombres, ont un arrière-plan noir supplémentaire et sont des images de différentes tailles d’image. Par conséquent, nous devons appliquer des techniques de lissage aux images pour maintenir l’uniformité de la qualité de l’image en recadrant les arrière-plans noirs supplémentaires, en redimensionnant les images à une taille d’image typique, etc.
À partir de ce qui précède, nous pouvons observer que notre ensemble de données contient des images de différentes tailles avec un recadrage horizontal, un recadrage vertical et des régions noires supplémentaires.
Nous appliquons les techniques de lissage ci-dessous pour obtenir toutes les images de qualité uniforme.
Fonction de recadrage
→ Fonction de recadrage – utilisation pour supprimer les parties sombres supplémentaires autour de l’image
def crop(img,tol=7):
# ici tol est la tolérance
'''
cette fonction de recadrage est utilisée pour supprimer les parties sombres autour de l'image
'''
if img.ndim==2:
# cette boucle est utilisée pour recadrer les images GRIS
mask=img>tol
return img[np.ix_(mask.any(1),mask.any(0))]
elif img.ndim==3:
# cette boucle est utilisée pour recadrer les images couleur
grayimg=cv2.cvtColor(img,cv2.COLOR_RGB2GRAY)
mask=grayimg>tol
shap=img[:,:,0][np.ix_(mask.any(1),mask.any(0))].shape[0]
if shap==0:
# l'image est trop sombre donc nous recadrons tout
return img
else:
img0=img[:,:,0][np.ix_(mask.any(1),mask.any(0))]
img1=img[:,:,1][np.ix_(mask.any(1),mask.any(0))]
img2=img[:,:,2][np.ix_(mask.any(1),mask.any(0))]
img=np.stack([img0,img1,img2],axis=-1)
return img #import csv
La figure ci-dessous indique qu’après l’application de la fonction, nous obtenons des images en recadrant les parties sombres autour.
→ La fonction de recadrage circulaire recadre une image de manière circulaire en prenant pour référence le centre.
def circlecrop(img):
'''
utilisé pour recadrer l'image de manière circulaire à partir du centre de l'image
'''
h,w,d= img.shape
x = int(w/2)
y = int(h/2)
r = np.amin((x,y))
circle_img = np.zeros((h,w), np.uint8)
cv2.circle(circle_img, (x,y), int(r), 1, thickness=-1)
img = cv2.bitwise_and(img, img, mask=circle_img)
return img
La figure ci-dessous est obtenue après l’application de la fonction de recadrage circulaire
Fonction de Ben Graham
→ Fonction de Ben Graham – Cette fonction est appliquée pour améliorer la luminosité de l’image
def ben(img,sigmaX=10):
'''
Méthode de Ben Graham pour améliorer les conditions d'éclairage.
'''
image=cv2.addWeighted( img,4, cv2.GaussianBlur( img , (0,0) , sigmaX) ,-4 ,128)
return image
La figure ci-dessous indique qu’après l’application de la fonction de Ben Graham, nous avons amélioré les conditions d’éclairage de l’image.
Vérifions les images de la rétine prétraitées après l’application des fonctions ci-dessus.
Comme notre ensemble de données est très petit, nous risquons de subir un surajustement. Pour surmonter cette situation, nous devons augmenter nos données d’entraînement. Augmentez les données en utilisant des techniques d’augmentation telles que la symétrie horizontale, la symétrie verticale, la rotation des images, le zoom et le réglage de la luminosité.
from keras_preprocessing.image import ImageDataGenerator
datagen=ImageDataGenerator(horizontal_flip=True,vertical_flip=True,rotation_range=360,
brightness_range=[0.5, 1],
zoom_range = 0.2,rescale=1./255.,validation_split=0.25)
validation_datagen = ImageDataGenerator(rescale = 1./255)
train_generator=datagen.flow_from_dataframe(
dataframe=df,
directory="prep",
x_col="add",
y_col="diagnosis",
subset="training",
batch_size=12,
seed=42,
shuffle=True,
class_mode="categorical",
target_size=(256, 256))
Comme nous avons utilisé une division de validation de 0,25, nous obtenons 2 747 images d’entraînement et 915 images de validation.
Ici, chaque image est répliquée cinq fois car nous avons utilisé cinq techniques de symétrie horizontale, de symétrie verticale, de plage de rotation, de plage de luminosité et de plage de zoom.
Modèle d’apprentissage profond
Tout d’abord, nous construisons un modèle de base avec une architecture CNN simple.
inp=Input(shape=(256,256,3))
x=Conv2D(32,(3,3),activation='relu')(inp)
x=MaxPooling2D(pool_size=(2, 2))(x)
x=Dropout(0.5)(x)
x=Flatten()(x)
x=BatchNormalization()(x)
x=Dense(5, activation='softmax')(x)
Pour le modèle ci-dessus, nous obtenons un score kappa de 0,554, ce qui n’est pas acceptable pour prédire le stade de la maladie.
Nous nous tournons vers le transfert d’apprentissage pour utiliser le modèle pré-entraîné afin d’obtenir un score kappa élevé.
VGG-16
model_vgg16= VGG16(weights='imagenet', include_top=False,input_shape=(256,256, 3))
x=GlobalAveragePooling2D()(model_vgg16.layers[-1].output)
x=Dropout(0.5)(x)
x=Dense(5, activation='softmax')(x)
→Score kappa d’entraînement : 0,913
→Score d’exactitude d’entraînement : 0,817
Avec le modèle ci-dessus, nous obtenons un score kappa de 0,913
DENSENET
modeldense=DenseNet121(weights='imagenet', include_top=False,input_shape=(256,256, 3))
x=GlobalAveragePooling2D()(modeldense.layers[-1].output)
x=Dropout(0.5)(x)
x=Dense(5, activation='softmax')(x)
→Score kappa d’entraînement : 0,933
→Score d’exactitude d’entraînement : 0,884
Avec le modèle ci-dessus, nous obtenons un score kappa de 0,933
RESNET
modelres152=ResNet152(weights='imagenet', include_top=False,input_shape=(256,256, 3))
x=GlobalAveragePooling2D()(modelres152.layers[-1].output)
x=Dropout(0.5)(x)
x=Dense(5, activation='softmax')(x)
→Score kappa d’entraînement : 0,910
→Score d’exactitude d’entraînement : 0,844
Avec le modèle ci-dessus, nous obtenons un score kappa de 0,91
EFFICIENTNET
Après avoir implémenté différents modèles efficaces tels que EEfficientNetB0, B3, B4, et B7, nous pouvons obtenir de meilleurs résultats en utilisant EfficientNetB7.
modeleffB7 = EfficientNetB7(weights='imagenet', include_top=False, input_shape=(256,256, 3))
x = GlobalAveragePooling2D()(modeleffB7.layers[-1].output)
x = Dropout(0.5)(x)
x = Flatten()(x)
x = Dense(5, activation='softmax')(x)
→Score de Cohen Kappa d’entrainement : 0,877
→Score d’exactitude d’entrainement : 0,838
A partir du modèle ci-dessus, nous obtenons un score de kappa de 0,877
XCEPTION
modelxcep = Xception(weights='imagenet', include_top=False, input_shape=(256,256, 3))
x = GlobalAveragePooling2D()(modelxcep.layers[-1].output)
x = Dropout(0.5)(x)
x = Flatten()(x)
x = Dense(5, activation='softmax')(x)
→Score de Cohen Kappa d’entrainement : 0,925
→Score d’exactitude d’entrainement : 0,854
A partir du modèle ci-dessus, nous obtenons un score de kappa de 0,925
A partir du modèle ci-dessus, nous observons que le modèle Denset obtient un meilleur score de Kappa. Nous choisissons donc notre modèle Denset comme le meilleur et nous nous dirigeons vers la prédiction d’étape.
Prédiction en utilisant notre meilleur modèle
Prédire les étapes en utilisant notre meilleur modèle :
X = '/content/00a8624548a9.png'
img = cv2.imread(X)
img = crop(img)
img = cv2.resize(img, (256,256), interpolation=cv2.INTER_AREA)
img = circlecrop(img)
img = ben(img)
img = np.reshape(img, [1,256,256,3])
cd = ImageDataGenerator(horizontal_flip=True, vertical_flip=True,
rotation_range=360, brightness_range=[0.5, 1],
zoom_range = 0.2, rescale=1./255)
cg = cd.flow(img, batch_size=1)
tp = model.predict(cg)
op = np.argmax(tp)
if op == 0:
matter = "Étape 0 - Pas de rétinopathie diabétique"
elif op == 1:
matter = "Étape 1 - Légère"
elif op == 2:
matter = "Étape 2 - Modérée"
elif op == 3:
matter = "Étape 3 - Sévère"
elif op == 4:
matter = "Étape 4 - Rétinopathie diabétique proliférative"
print(matter)
A partir de l’image ci-dessus, nous pouvons observer que notre meilleur modèle prédit les étapes de la rétinopathie diabétique.
Déploiement de notre modèle en utilisant Flask
J’ai utilisé Flask pour déployer mon modèle afin que nous puissions prédire l’étape de la rétinopathie diabétique de notre image rétinienne téléchargée. Voici la vidéo des instances en cours d’exécution de mon modèle déployé.
Conclusion
En conclusion, ce blog a mis en évidence le pouvoir transformateur de l’apprentissage profond dans la détection de la rétinopathie diabétique et la prévention de la perte de vision. Grâce à une détection précoce et une classification précise de la gravité, l’IA peut améliorer considérablement les résultats des patients. L’applicabilité réelle de ces techniques à travers le déploiement de modèles utilisant Flask met en évidence leur praticité dans les contextes de soins de santé.
La recherche continue sur les techniques d’augmentation et l’affinement des modèles améliorera encore les capacités de diagnostic. En exploitant le potentiel de l’IA, nous pouvons révolutionner le diagnostic médical et ouvrir la voie à un avenir plus sain.
- Les modèles d’apprentissage profond tels que VGG-16, DENSENET, RESNET, EFFICIENTNET et XCEPTION ont efficacement classifié la gravité de la rétinopathie diabétique.
- Le modèle performant, DENSENET, a obtenu des scores Kappa élevés, démontrant sa capacité à effectuer des prédictions précises.
- La prétraitement et l’augmentation des données sont essentiels pour améliorer les performances et la généralisabilité du modèle.
- Le déploiement de Flask met en évidence l’applicabilité pratique de l’apprentissage profond dans des scénarios réels, facilitant un diagnostic et un traitement efficaces.
- La recherche continue sur les techniques d’augmentation et l’affinement des modèles offre la possibilité d’améliorer encore l’exactitude du diagnostic et de faire progresser le diagnostic médical grâce à l’IA.
Travaux futurs
- Nous pouvons mettre en œuvre plus de techniques d’augmentation.
- Nous pouvons essayer différentes couches de convolution sur nos modèles.
- Nous avons besoin de récupérer plus d’images rétiniennes pour l’entrainement.
Foire aux questions
Références
- https://github.com/btgraham/SparseConvNet/blob/kaggle_Diabetic_Retinopathy_competition/competitionreport.pdf
- https://arxiv.org/abs/1905.11946
- https://arxiv.org/abs/0704.1028
- https://www.kaggle.com/xhlulu/aptos-2019-densenet-keras-starter
- https://www.kaggle.com/c/aptos2019-blindness-detection/discussion/108065
Les médias présentés dans cet article ne sont pas la propriété d’Analytics Vidhya et sont utilisés à la discrétion de l’auteur.
We will continue to update IPGirl; if you have any questions or suggestions, please contact us!
Was this article helpful?
93 out of 132 found this helpful
Related articles
- Top 18 constructeurs de sites Web basés sur l’IA en 2023
- Implémentation de ParDo et DoFn dans Apache Beam en détails
- Révolutionner la robotique une pince imprimée en 3D qui fonctionne sans électronique
- Génération de données synthétiques avec Python
- Tous les grands modèles de langage (LLM) que vous devez connaître en 2023
- Votre modèle est-il bon? Une plongée approfondie dans les métriques avancées de Amazon SageMaker Canvas
- Une nouvelle recherche en IA propose le modèle PanGu-Coder2 et le cadre RRTF qui améliorent efficacement les modèles de langage pré-entraînés de grande taille pour la génération de code.