Press "Enter" to skip to content

通过预测糖尿病视网膜病变的阶段来预防视力丧失

介绍

糖尿病视网膜病变是一种导致视网膜血管变化的眼部疾病。如果不及时治疗,会导致视力丧失。因此,检测糖尿病视网膜病变的阶段对于预防眼盲至关重要。本案例研究旨在从糖尿病视网膜病变症状中检测眼盲,以防止患者眼盲。这些数据是通过各种训练有素的临床专家使用眼底相机(拍摄眼部后部的相机)在农村地区收集的。这些照片是在各种成像条件下拍摄的。2019年,Kaggle举办了一个竞赛(APTOS 2019盲人检测),用于检测糖尿病视网膜病变的阶段;我们的数据来自同一个Kaggle竞赛。早期发现糖尿病视网膜病变可以加快治疗并显著降低视力丧失的风险。

通过预测糖尿病视网膜病变的阶段来预防视力丧失 四海 第1张

训练有素的临床专家的人工干预需要时间和精力,尤其是在不发达国家。因此,本案例研究的主要目标是使用高效的技术来检测疾病的严重程度,以预防眼盲。我们采用深度学习技术来获得对疾病严重程度进行分类的有效结果。

学习目标

  • 了解糖尿病视网膜病变:了解眼部疾病及其对视力的影响,强调早期检测的重要性。
  • 深度学习基础知识:探索深度学习的基础知识及其在诊断糖尿病视网膜病变中的相关性。
  • 数据预处理和增强:了解如何有效地准备和增强用于训练深度学习模型的数据集。
  • 模型选择和评估:学习选择和评估用于严重程度分类的深度学习模型。
  • 实际部署:了解使用Flask进行实际预测的最佳模型的部署。

本文是数据科学博客马拉松的一部分。

业务问题

在这里,人的病情严重程度被分为五个类别,即多类别分类,因为一个人只能被识别为其中一种严重程度。

业务约束

在医疗领域,准确性和可解释性非常重要。因为错误的预测会导致忽视病情,可能夺走一个人的生命,我们没有任何严格的延迟关注,但我们必须对结果准确。

数据集描述

数据集包括3,662张已标记的临床患者视网膜图像,训练有素的临床专家根据糖尿病视网膜病变的严重程度对每个图像进行分类,如下所示。

0 — 无糖尿病视网膜病变,

1 — 轻度,

2 — 中度,

3 — 重度,

4 — 弥漫性糖尿病视网膜病变。

通过预测糖尿病视网膜病变的阶段来预防视力丧失 四海 第2张

上表表示我们的数据集图像被识别为糖尿病视网膜病变的其中一个阶段。

性能指标

我们采用加权Kappa系数和混淆矩阵作为多类别分类的评估指标。

Kappa系数衡量实际标签和预测标签之间的一致性(相似性)。Kappa系数为1.0表示预测和实际标签相同,Kappa系数为-1表示预测与实际标签相差很大。我们的目标是获得大于0.6的Kappa系数。

Kappa系数在医学诊断中起着关键作用,因为在得分为-1的情况下,它表示两个评分者(预测评分者和实际评分者)的相似性,并对不一致性进行惩罚。例如,在我们的案例中,如果我们的预测标签为0,实际标签为1,则对患者来说这是一个严重的问题,因为这种情况将被忽视,不建议对患者进行进一步的诊断。

正如我们所知,混淆矩阵用于评估分类模型的性能,该矩阵将实际目标值与模型预测的值进行比较。这使我们能够全面了解分类模型的性能以及其产生的错误类型。

探索性数据分析与预处理

让我们通过绘制条形图来检查我们数据的分布。

v=df['diagnosis'].value_counts().plot(kind='bar')

通过预测糖尿病视网膜病变的阶段来预防视力丧失 四海 第3张

从上面的图中,我们可以推断出我们的数据明显不平衡。我们需要确保平衡我们的数据,以防止得到不准确的结果。

我们可以应用类别权重来维持数据集的一致性,以获得数据的均匀分布。

我们的训练数据集只包含3,662张图像,所以Kaggle提供的数据集非常小。由于在小数据集上训练,过拟合是可取的,因此在性能更好方面,预处理在增加我们的数据集方面发挥关键作用。因此,我们采用数据增强来改进我们的数据集。在进行数据增强之前,我们需要检查图像的条件,因为数据是从各种来源收集的,例如图像是否非常暗,是否有额外的黑色背景,以及图像的各种尺寸。因此,我们需要应用平滑技术来处理图像,以保持图像质量的一致性,如裁剪额外的黑色背景,将图像调整为典型图像尺寸等。

通过预测糖尿病视网膜病变的阶段来预防视力丧失 四海 第4张

从上面,我们可以观察到我们的数据集包含具有水平裁剪、垂直裁剪和额外黑色区域的不同尺寸的图像。

我们应用以下平滑技术来获得所有图像的统一质量。

裁剪函数

→ 裁剪函数-用于删除图像周围的额外暗部

def crop(img,tol=7):
 # 这里tol是容差
 '''
 这个裁剪函数用于删除图像周围的暗部
 '''

 if img.ndim==2:
# 这个循环用于裁剪灰度图像
   mask=img>tol
   return img[np.ix_(mask.any(1),mask.any(0))]
 elif img.ndim==3:
# 这个循环用于裁剪彩色图像
   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:
# 图像太暗,我们裁剪掉所有东西
     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

下图表示应用该函数后,我们通过裁剪周围的暗部获得的图像。

通过预测糖尿病视网膜病变的阶段来预防视力丧失 四海 第5张

→ 圆形裁剪函数通过参考中心来对图像进行圆形裁剪。

def circlecrop(img):
 '''
 用于从图像中心圆形裁剪图像
 '''

 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

下图是应用圆形裁剪函数后得到的结果。

通过预测糖尿病视网膜病变的阶段来预防视力丧失 四海 第6张

Ben Graham的函数

→ Ben Graham的函数-此函数用于改善图像亮度

def ben(img,sigmaX=10):
 '''
 Ben Graham的方法改善光照条件。

 '''
 image=cv2.addWeighted( img,4, cv2.GaussianBlur( img , (0,0) , sigmaX) ,-4 ,128)
 return image

在应用本·格雷厄姆(Ben Graham)的函数之后,下图表明我们改善了图像的光照条件。

通过预测糖尿病视网膜病变的阶段来预防视力丧失 四海 第7张

让我们在应用上述函数后检查预处理的视网膜图像。

通过预测糖尿病视网膜病变的阶段来预防视力丧失 四海 第8张

由于我们的数据集非常小,可能会导致过拟合。为了克服这种情况,我们需要增加我们的训练数据。使用数据增强技术,如水平翻转、垂直翻转、旋转图像、缩放和设置亮度,增加数据。

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

由于我们将验证拆分设置为0.25,我们获得2,747个训练图像和915个验证图像。

这里每个图像被复制了五次,因为我们使用了五种技术:水平翻转、垂直翻转、旋转范围、亮度范围和缩放范围。

深度学习模型

首先,我们使用简单的CNN架构构建一个基准模型。

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)

对于上述模型,我们得到了0.554的Kappa得分,这对于预测疾病的阶段是不可接受的。

我们转向迁移学习,使用预训练模型以获得高的Kappa得分。

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)

→训练Cohen Kappa得分:0.913

→训练准确率得分:0.817

从上述模型中,我们得到了0.913的Kappa得分

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)

→训练Cohen Kappa得分:0.933

→训练准确率得分:0.884

从上述模型中,我们得到了0.933的Kappa得分

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)

→训练Cohen Kappa得分:0.910

→训练准确率得分:0.844

从上述模型中,我们得到了0.91的Kappa得分

EFFICIENTNET

在实施了EEfficientNetB0、B3、B4和B7等各种高效模型之后,我们可以使用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)

→ 训练 Cohen Kappa 得分:0.877

→ 训练准确率得分:0.838

从上述模型中,我们得到了一个 Kappa 得分为 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)

→ 训练 Cohen Kappa 得分:0.925

→ 训练准确率得分:0.854

从上述模型中,我们得到了一个 Kappa 得分为 0.925

通过预测糖尿病视网膜病变的阶段来预防视力丧失 四海 第9张

从上述模型中,我们观察到 Denset 模型获得了更高的 Kappa 得分。因此,我们选择我们的 Denset 模型作为最佳模型,并进行阶段预测。

使用我们的最佳模型进行预测

使用我们的最佳模型进行预测阶段:

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 = "阶段 0 - 无糖尿病视网膜病变"
elif op == 1:
    matter = "阶段 1 - 轻度"
elif op == 2:
    matter = "阶段 2 - 中度"
elif op == 3:
    matter = "阶段 3 - 重度"
elif op == 4:
    matter = "阶段 4 - 增生性糖尿病视网膜病变"
print(matter)

从上述图像中,我们可以观察到我们的最佳模型预测了糖尿病视网膜病变的阶段。

使用 Flask 部署我们的模型

我使用 Flask 部署了我的模型,以便我们可以预测上传的视网膜图像的色盲阶段。以下是我部署的模型运行实例的视频。

结论

总之,本博客展示了深度学习在检测糖尿病视网膜病变和预防视力损失方面的变革能力。通过早期检测和准确的严重程度分类,人工智能可以显著改善患者的预后结果。使用 Flask 部署模型的实际适用性突出了它们在医疗环境中的实用性。

通过增强技术和模型优化的持续研究,将进一步提高诊断能力。通过发挥人工智能的潜力,我们可以革新医学诊断,为更健康的未来铺平道路。

  • 深度学习模型,如 VGG-16、DENSENET、RESNET、EFFICIENTNET 和 XCEPTION,有效地对糖尿病视网膜病变的严重程度进行分类。
  • 最佳性能模型 DENSENET 实现了高 Kappa 得分,证明了它准确预测的能力。
  • 数据预处理和增强对于提高模型的性能和泛化能力至关重要。
  • Flask 部署展示了深度学习在实际场景中的实用性,有助于高效的诊断和治疗。
  • 持续研究增强技术和模型优化有助于进一步提高诊断准确性,推进使用人工智能的医学诊断。

未来工作

  • 我们可以实施更多的增强技术。
  • 我们可以尝试在模型中使用不同的卷积层。
  • 需要获取更多用于训练的视网膜图像。

常见问题

 参考资料

  • 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

本文中显示的媒体内容不归Analytics Vidhya所有,而是根据作者的自由裁量使用。

Leave a Reply

Your email address will not be published. Required fields are marked *