点选上方关注,All in AI中国
初学者的教程,在OCT视网膜影象上的pytorch中使用vgg16架构实现迁移学习
深度学习有可能通过对人类专家难以分类的部分进行处理,并能快速检查大量影象从而彻底改变疾病诊断和管理。
好吧,如果你完全没有意识到像epoch、CNN和其他与深度学习和pytorch相关的基本术语,那么我建议您在读本篇文章之前先了解一番。
关于资料集
视网膜OCT影象的该资料集是从Kaggle资料集获得的。这里有四类影象:CNV、DME、DRUSEN和NORMAL

(最左侧)脉络膜新生血管(CNV),具有新生血管膜(白色箭头)和相关的视网膜下液(箭头)。(左中)糖尿病性黄斑水肿(DME)与视网膜增厚相关的视网膜内液(箭头)。(中右)早期AMD中存在多个玻璃疣(箭头)。(最右侧)具有保留的中心凹轮廓且没有任何视网膜液/水肿的正常视网膜。关于OCT
光学相干断层扫描(OCT)是一种使用相干光捕获生物组织的高分辨率影象的成像技术。
OCT被眼科医生大量使用以获得眼睛视网膜的高分辨率影象。眼睛的视网膜更像是相机中的胶片。OCT影象可用于诊断许多视网膜相关的眼病。在某些情况下,单独的OCT可以产生诊断(例如黄斑裂孔)。然而,在其他疾病,尤其是视网膜血管疾病中,安排额外的检查(例如荧光血管造影)可能是有帮助的。探索资料集
让我们试着看看每个类别中的影象数量和影象的大小。

我们得到一个数据框,其中包含测试、训练和验证资料夹中每个类别的影象计数,通过这个资料框架,我们可以对资料集有一些基本的直觉。

验证资料集中只有9个影象(极少数)我们有大约37k的CNV训练影象,26k的NORMAL和11k和8k的DME和DRUSEN影象预处理
要为我们的网络准备影象,我们必须将它们调整为224 x 224,并通过减去平均值并除以标准偏差来标准化每个颜色通道。我们还将在此阶段增加我们的训练资料,这些操作是使用影象变换完成的,影象变换为神经网络准备资料。

这有助于我们视觉化训练集中影象的宽度和高度范围

当我们在预先训练的网络中使用影象时,我们必须将它们重塑为224 x 224的尺寸,这是影象的大小,也是模型所需要的大小。大于此的影象将被截断,而较小的影象将被新增内容。
资料扩充
由于影象数量有限,我们可以使用影象增强来人为地增加网络“看到”的影象数量。这意味着,对于训练,我们会随机调整大小并裁剪影象,然后将其水平翻转。对每个时期应用不同的随机变换(在训练时),因此网络有效地看到同一影象的许多不同版本。
在标准化之前,所有资料也都转换为Torch张量。验证和测试资料不是扩充的,而是调整大小和标准化的。
资料迭代器
为避免一次性将所有资料载入到内存中,我们使用了训练DataLoaders。
首先,我们从影象资料夹建立一个数据集物件,然后将它们传递给DataLoader。在训练时,DataLoader将从磁盘载入影象,应用转换并生成批处理。为了训练和验证,我们将遍历相应DataLoader中的所有批次。一个关键方面是在将资料传递到网络之前对其进行混洗。这意味着影象类别的排序在每次通过资料时都会发生变化(一次通过资料是一个训练epoch)。

使用预先训练的模型(VGG-16)
预训练背后的想法是与许多影象识别任务相关的CNN提取特征的早期卷积层。后面的完全连线的图层通过学习更高级别的特征来专门处理特定资料集。
因此,我们可以使用已经训练过的卷积层,同时只训练我们自己的资料集上的完全连线的层。事实证明,经过预先训练的网络可以在各种任务中取得相当的成功,并且可以显著缩短训练时间,并且通常可以提高工作效率。
VGG-16架构
分类器是我们将训练的模型的一部分。但是,对于vgg,我们只需要在分类器中训练最后几层,甚至不需要训练所有完全连线的层。
vgg16的分类器部分,具有1000个out_features
通过将requires_grad设定为False,我们冻结了网络中的所有现有图层为了构建我们的自定义分类器,我们使用nn.Sequential()模组,它允许我们一个接一个地指定每个层最终输出将是log概率,我们可以在负对数似然丢失(NLLL)中使用。只需将整个模型移动到GPU上即可我已经跳过了上面部分的程式码,您可以在我的Github储存库pytorch-notebooks/Retinal-image-classification at master · pawangeek/pytorch-notebooks · GitHub或Kaggle中检视它们

135,310,404 total parameters.
1,049,860 training parameters.
类到索引的对映
为了跟踪模型所做的预测,我们建立了类到索引和索引到类的对映。这将让我们知道给定预测的实际类。

[(0, \'CNV\'), (1, \'DME\'), (2, \'DRUSEN\'), (3, \'NORMAL\')]
所以我们的完整模型是预训练的vgg +自定义分类器。这是一个很长的模型,不可能在这里释出。尽管如此,我还是设法通过使用torchsummary从我们上一个自定义模组中获取了快照
我们模型的自定义分类器
128是我们的批处理大小,如果这不适合您的GPU,您可能需要减少batch_size我们有4个类进行分类,这在最后一层非常清楚训练损失和优化
损失(标准):根据模型引数(权重)跟踪损耗本身和损耗梯度
优化器:使用梯度更新引数(权重)

损失是负对数似然,优化器是Adam优化器。PyTorch中的负对数似然性需要对数概率,因此我们需要将模型的最终层中传递log softmax的原始输出。训练
对于训练,我们通过训练DataLoader遍历,每次通过模型传递一个批处理。我们训练一定数量的epoch直到停止。
在每次批处理之后,我们计算损失(使用标准(输出,目标)),然后使用loss.backward()计算相对于模型引数的损失梯度。这使用的是自动微分和反向传播来计算梯度。*计算梯度后,我们呼叫optimizer.step()来使用梯度更新模型引数。这是在每个训练批次上完成的,因此我们正在实施随机梯度下降(或者更确切地说是具有称为Adam的动量的版本)。对于每个批处理,我们还计算监控的准确性,并且在训练循环完成后,我们开始验证循环。这将用于进行提前停止。当许多时期的验证损失没有减少时,提前停止会停止训练。每次验证损失确实减少时,都会储存模型权重,以便稍后载入到最佳模型中。提前停止是防止训练资料过度拟合的有效方法。如果我们继续训练,训练损失将继续减少,但验证损失将增加,因为模型开始记住训练资料。提前停止可以防止这种情况发生通过在每个训练时期结束时迭代验证资料并计算损失来实现提前停止。我们每次都使用完整的验证资料,并记录损失是否减少。如果它没有多个epoch,我们停止训练,检索最佳权重,并返回它们。在验证循环中,我们确保不更新模型引数。训练结果
我们可以通过检视历史来检查训练进度。


正如预期的那样,训练损失随着epoch的推移而不断下降。没有大量的过度拟合,可能是因为我们使用的是Dropout。由于损失的分歧,进一步训练中所获得的收益并不多。
验证丢失显示由于验证影象数量较少而导致的异常行为
随着损失的增加,训练精度提高,而验证精度一般趋于平稳。该模型能够立即达到约79%的准确度,表明在Imagenet上学习的卷积权重能够轻松传输到我们的资料集。
注意:这里我们的验证资料集中,每个类只有9张影象
测试我们的模型
在对模型进行训练以确定验证资料没有进一步改进之后,我们需要对它从未见过的资料进行测试。为了最终估计模型的效能,我们需要使用holdout测试资料。在这里,我们将检视单个预测以及整个测试资料集的损失和准确性。

上述函式可以对单个影象进行预测。它将返回最高概率和类。

模型研究
虽然该模型执行良好,但可能采取的步骤可以使其更好。通常,弄清楚如何改进模型的最佳方法是调查其错误(注意:这也是一种有效的自我改进方法。)
好吧,看起来我们的模型在测试集上执行良好。让我们试着对它们有更多的直觉。
这个函式显示图片以及来自模型的topk预测。影象上的标题显示了真正的类。



这些都很简单,所以我很高兴模型没有问题!
结论
我们能够看到使用PyTorch的基础知识以及迁移学习的概念。以及我们如何在医学科学领域中使用这种影象感测技术完整的程式码可以在我的GitHub储存库中找到pytorch-notebooks/Retinal-image-classification at master · pawangeek/pytorch-notebooks · GitHub





























