医学图像分类 — 肺炎诊断示例

在本文中,我讨论了计算机视觉如何在肺炎诊断中发挥作用,以胸部X射线图像的肺炎诊断为例。我使用了来自Kaggle数据集的X射线胸部图像。该数据集包含三类图像:

e44b7108b36450d797141a9d7719565d.jpeg

我使用这些数据解决以下任务:

  1. 创建一个系统,可以确定输入的X射线胸部图像属于“正常(无肺炎)”类别还是“肺炎(细菌或病毒)”类别,即2类分类器。

  2. 创建一个系统,可以确定输入的X射线胸部图像属于“正常(无肺炎)”类别还是“肺炎-细菌”类别还是“肺炎-病毒”类别,即3类分类器。

此研究的目标是基于计算机视觉从X射线胸部图像中找到最佳的诊断方法。

训练和测试数据&输入图像预处理

数据集被分为训练集和测试集。训练集包含3000张图像,其中1000张“正常(无肺炎)”,1000张“肺炎-细菌”,1000张“肺炎-病毒”,从各自的组中随机选择。其余的图像组成了测试集,因此包含了2908张图像,其中576张“正常(无肺炎)”,1777张“肺炎-细菌”,555张“肺炎-病毒”。

图像示例 — 从左到右:“正常(无肺炎)”,“肺炎-细菌”,“肺炎-病毒” — 如下所示:

e9d0c335aa33799d2d444bacbdb95835.jpeg

来自源数据集的所有图像在“train”和“test”文件夹中都被裁剪,以去除多余的区域,只留下用于诊断的区域。裁剪后的图像示例(从左到右:“正常(无肺炎)”,“肺炎-细菌”,“肺炎-病毒”)如下:

8e95c9dae39088f4216c6c819ab7c1b5.jpeg

分类器代码是使用PyTorch实现的。为了准备输入图像,以下torchvision变换被应用于最初以numpy数组形式存在的输入数据img:

img = transforms.ToTensor()(img)
img = transforms.Resize((256, 256))(img)
s, m = torch.std_mean(img, dim=(0, 1, 2))
img = transforms.Normalize(m, 2*s)(img)

输入图像被转换为torch张量,调整大小为256x256分辨率并进行归一化。我发现对统一裁剪的输入数据进行归一化可以提高分类器的质量约1%。

用于分类任务的CNN模型

以下展示了每个分类器的两个CNN模型的结果:第一个模型包含2个卷积块,第二个模型包含3个卷积块 — 表现最好。更复杂的模型表现出过拟合和在测试集上的较差质量结果。每个模型的代码示例,r_size = 256,num_classes = 2或3取决于感兴趣的类别集:

2个卷积块:

class ChestClassifier(nn.Module):
    def __init__(self):


        super(ChestClassifier, self).__init__()
        nc = 32
        nc2 = nc * 2
        sz = int(r_size/16)


        self.cnn1 = nn.Sequential(
            nn.Conv2d(3, nc, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(nc),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size = 2, stride = 2),


            nn.Conv2d(nc, nc2, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(nc2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size = 2, stride = 2),
            nn.Dropout(0.4),
        )
        self.fc1 = nn.Sequential(
            nn.Linear(sz*sz*nc2, nc2),
            nn.ReLU(inplace=True),
            nn.Linear(nc2, 2),
        )


    def forward(self, x):
        out1 = self.cnn1(x)
        out1 = torch.flatten(out1, 1)
        output = self.fc1(out1)
        return output

3个卷积块:

class ChestClassifier(nn.Module):
    def __init__(self):


        super(ChestClassifier, self).__init__()
        nc = 24
        nc2 = nc * 2
        nc4 = nc * 4
        sz = int(r_size/32)


        self.cnn1 = nn.Sequential(
            nn.Conv2d(3, nc, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(nc),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size = 2, stride = 2),


            nn.Conv2d(nc, nc2, kernel_size=3, stride=2, padding=1),
            nn.BatchNorm2d(nc2),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size = 2, stride = 2),
            nn.Dropout(0.2),


            nn.Conv2d(nc2, nc4, kernel_size=3, stride=1, padding=1),
            nn.BatchNorm2d(nc4),
            nn.ReLU(inplace=True),
            nn.MaxPool2d(kernel_size = 2, stride = 2),
            nn.Dropout(0.3),
        )
        self.fc1 = nn.Sequential(
            nn.Linear(sz*sz*nc4, nc2),
            nn.ReLU(inplace=True),
            nn.Linear(nc2, 2),
        )


    def forward(self, x):
        out1 = self.cnn1(x)
        out1 = torch.flatten(out1, 1)
        output = self.fc1(out1)
        return output

我使用了Adam优化器,并且学习率从0.001开始,训练过程中改变为0.0001。对我训练和评估的所有模型的共同注意事项是,由于我不想浪费数据进行验证集,我每隔10个epoch保存一次模型,以查看趋势,并在训练过程和测试集验证后选择最佳模型。

2类分类器,“正常(无肺炎)”或“肺炎(细菌或病毒)”&训练模型评估

用于训练的有3000张图像,用于测试的有2908张图像。我采用了技术使训练批次平衡(每类约50%的图像)。下面的结果中,“Class 0”表示“正常(无肺炎)”,“Class 1”表示“肺炎(细菌或病毒)”。

2个卷积块的模型结果:

Test set:
Class 0:
true positive for the class 0: 530, false negative for the class 0: 46
Accuracy: 92.01% on class 0


Class 1:
true positive for the class 1: 2280, false negative for the class 1: 52
Accuracy: 97.77% on class 1


true count for the whole set: 2810, false count for the whole set: 98
Mean Accuracy on all classes: 94.89%
F-measure: 0.947166128657885

3个卷积块的模型结果 — 最佳:  

Test set:
Class 0:
true positive for the class 0: 543, false negative for the class 0: 33
Accuracy: 94.27% on class 0


Class 1:
true positive for the class 1: 2279, false negative for the class 1: 53
Accuracy: 97.73% on class 1


true count for the whole set: 2822, false count for the whole set: 86
Mean Accuracy on all classes: 96.00%


F-measure: 0.954051320945519

2类分类器,“正常(无肺炎)”或“肺炎(细菌或病毒)”&“小”训练模型评估

“小”训练模型指的是在少量数据上训练的模型。医学图像的数据量较小是一个常见问题。因此,我将训练集限制为总共1000张图像,其中包括从“正常(无肺炎)”类中选取的500张图像,以及从两个“肺炎”类中选取的其他500张图像,其中包括“肺炎(细菌)”的250张和“肺炎(病毒)”的250张。测试集保持不变 — 2908张图像。在下面的结果中,“Class 0”表示“正常(无肺炎)”,“Class 1”表示“肺炎(细菌或病毒)”。

2个卷积块的模型结果:

Test set:
Class 0:
true positive for the class 0: 543, false negative for the class 0: 33
Accuracy: 94.27% on class 0


Class 1:
true positive for the class 1: 2279, false negative for the class 1: 53
Accuracy: 97.73% on class 1


true count for the whole set: 2822, false count for the whole set: 86
Mean Accuracy on all classes: 96.00%


F-measure: 0.954051320945519
3个卷积块的模型结果:
Test set:
Class 0:
true positive for the class 0: 542, false negative for the class 0: 34
Accuracy: 94.10% on class 0


Class 1:
true positive for the class 1: 2235, false negative for the class 1: 97
Accuracy: 95.84% on class 1


true count for the whole set: 2777, false count for the whole set: 131
Mean Accuracy on all classes: 94.97%


F-measure: 0.9318544993349989

“小”模型在质量上甚至可以与基于3000张训练图像的模型进行比较。这是因为类别0的大多数图像看起来与类别1的图像不同。在这种情况下,即使在训练集中每类只有几百张图像,也足够获得模型的良好质量。

3类分类器,“正常(无肺炎)”或“肺炎-细菌”或“肺炎-病毒”&训练模型评估

用于训练的有3000张图像,用于测试的有2908张图像。在下面的结果中,“Class 0”表示“正常(无肺炎)”,“Class 1”表示“肺炎-细菌”,“Class 2”表示“肺炎-病毒”。

2个卷积块的模型结果:

Class 0:
true_count: 527, false_count: 49
Accuracy: 91.49%  on class 0
false assigning to the class 1: 9, false assigning to the class 2: 40 


Class 1:
true_count: 1279, false_count: 498
Accuracy: 71.98%  on class 1
false assigning to the class 0: 37, false assigning to the class 2: 461 


Class 2:
true_count: 390, false_count: 165
Accuracy: 70.27%  on class 2
false assigning to the class 0: 31, false assigning to the class 1: 134 


true_count: 2196, false_count: 712
Mean Accuracy on all classes: 77.91%


F-measure: 0.7463764556697652

3个卷积块的模型结果 — 最佳:

Test set:
Class 0:
true_count: 537, false_count: 39
Accuracy: 93.23%  on class 0
false assigning to the class 1: 7, false assigning to the class 2: 32 


Class 1:
true_count: 1380, false_count: 397
Accuracy: 77.66%  on class 1
false assigning to the class 0: 31, false assigning to the class 2: 366 


Class 2:
true_count: 395, false_count: 160
Accuracy: 71.17%  on class 2
false assigning to the class 0: 36, false assigning to the class 1: 124 


true_count: 2312, false_count: 596
Mean Accuracy on all classes: 80.69%


F-measure: 0.7785463207941641

根据3类分类器的结果,对于肺炎的种类没有高精度的区分。结果表明,大多数识别错误是由于“肺炎-细菌”和“肺炎-病毒”之间的差异不明显。我向我的朋友,一位医生,提出了以下问题:

1. 医生是否能够在X射线胸部图像中高精度地识别“肺炎-细菌”或“肺炎-病毒”?

2. 对于“肺炎-细菌”和“肺炎-病毒”类别,准确度达到70%以上的分类器是否对诊断有用?

她的回答是:“在常规X射线上,标准病毒感染几乎是看不见的;肺纹理可能增加(这在健康驼背的人中几乎总是发生),肺门淋巴结可能增大。细菌感染会产生圆形的阴影。如果没有阴影,但有症状,会进行CT扫描。在计算机断层扫描上,合理的放射科医师会应用诊断标准,并写下“高概率”是病毒性还是细菌性的。”在她看来,准确度较高的2类分类器“正常(无肺炎)”和“肺炎(细菌或病毒)”对诊断更有用。

下面是在几个测试图像上使用2类分类器“正常(无肺炎)”和“肺炎(细菌或病毒)”训练模型的分类结果示例。这些图像已被归一化。每张图像上方的文本包含预测值和括号中的标签值:

43ae295803650e371b4498adba0e73e9.jpeg

结论

当医学图像在不同的问题类型上实际上看起来不同,医生可以高精度地识别图像中的问题时,可以基于每种类型的几百张输入图像实现这些问题类型的高质量分类器。当医生无法仅通过图像识别问题时,我们不能期望从基于这些图像的分类器中获得良好的性能。用于诊断的更复杂的方法包括异常区域的分割。

·  END  ·

HAPPY LIFE

a70460761d3c7c1816563282c3a6ff51.png

本文仅供学习交流使用,如有侵权请联系作者删除

  • 22
    点赞
  • 27
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值